1 /* 2 * HCLINK.C 3 * 4 * This module implements a simple remote control protocol 5 * 6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.4 2007/01/17 02:34:10 pavalos Exp $ 7 */ 8 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <unistd.h> 14 #include <string.h> 15 #include <fcntl.h> 16 #include <dirent.h> 17 #include <assert.h> 18 #include <errno.h> 19 20 #include "hclink.h" 21 #include "hcproto.h" 22 23 static struct HCHead *hcc_read_command(struct HostConf *hc); 24 25 int 26 hcc_connect(struct HostConf *hc) 27 { 28 int fdin[2]; 29 int fdout[2]; 30 31 if (hc == NULL || hc->host == NULL) 32 return(0); 33 34 if (pipe(fdin) < 0) 35 return(-1); 36 if (pipe(fdout) < 0) { 37 close(fdin[0]); 38 close(fdin[1]); 39 return(-1); 40 } 41 if ((hc->pid = fork()) == 0) { 42 /* 43 * Child process 44 */ 45 dup2(fdin[1], 1); 46 close(fdin[0]); 47 close(fdin[1]); 48 dup2(fdout[0], 0); 49 close(fdout[0]); 50 close(fdout[1]); 51 execl("/usr/bin/ssh", "ssh", "-T", hc->host, "cpdup", "-S", (char *) NULL); 52 _exit(1); 53 } else if (hc->pid < 0) { 54 return(-1); 55 } else { 56 /* 57 * Parent process. Do the initial handshake to make sure we are 58 * actually talking to a cpdup slave. 59 */ 60 close(fdin[1]); 61 hc->fdin = fdin[0]; 62 close(fdout[0]); 63 hc->fdout = fdout[1]; 64 return(0); 65 } 66 } 67 68 static int 69 rc_badop(struct HostConf *hc __unused, struct HCHead *head) 70 { 71 head->error = EOPNOTSUPP; 72 return(0); 73 } 74 75 int 76 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count) 77 { 78 struct HostConf hcslave; 79 struct HCHead *head; 80 struct HCHead *whead; 81 int (*dispatch[256])(struct HostConf *, struct HCHead *); 82 int aligned_bytes; 83 int i; 84 int r; 85 86 bzero(&hcslave, sizeof(hcslave)); 87 for (i = 0; i < count; ++i) { 88 struct HCDesc *desc = &descs[i]; 89 assert(desc->cmd >= 0 && desc->cmd < 256); 90 dispatch[desc->cmd] = desc->func; 91 } 92 for (i = 0; i < 256; ++i) { 93 if (dispatch[i] == NULL) 94 dispatch[i] = rc_badop; 95 } 96 hcslave.fdin = fdin; 97 hcslave.fdout = fdout; 98 99 /* 100 * Process commands on fdin and write out results on fdout 101 */ 102 for (;;) { 103 /* 104 * Get the command 105 */ 106 head = hcc_read_command(&hcslave); 107 if (head == NULL) 108 break; 109 110 /* 111 * Start the reply and dispatch, then process the return code. 112 */ 113 head->error = 0; 114 hcc_start_command(&hcslave, head->cmd | HCF_REPLY); 115 r = dispatch[head->cmd & 255](&hcslave, head); 116 switch(r) { 117 case -2: 118 head->error = EINVAL; 119 break; 120 case -1: 121 head->error = errno; 122 break; 123 case 0: 124 break; 125 default: 126 assert(0); 127 break; 128 } 129 130 /* 131 * Write out the reply 132 */ 133 whead = (void *)hcslave.wbuf; 134 whead->bytes = hcslave.windex; 135 whead->error = head->error; 136 aligned_bytes = HCC_ALIGN(hcslave.windex); 137 #ifdef DEBUG 138 hcc_debug_dump(whead); 139 #endif 140 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes) 141 break; 142 } 143 return(0); 144 } 145 146 /* 147 * This reads a command from fdin, fixes up the byte ordering, and returns 148 * a pointer to HCHead. 149 */ 150 static 151 struct HCHead * 152 hcc_read_command(struct HostConf *hc) 153 { 154 struct HCHead *head; 155 int aligned_bytes; 156 int n; 157 int r; 158 159 n = 0; 160 while (n < (int)sizeof(struct HCHead)) { 161 r = read(hc->fdin, hc->rbuf + n, sizeof(struct HCHead) - n); 162 if (r <= 0) 163 return(NULL); 164 n += r; 165 } 166 head = (void *)hc->rbuf; 167 assert(head->bytes >= (int)sizeof(*head) && head->bytes < 65536); 168 assert(head->magic == HCMAGIC); 169 aligned_bytes = HCC_ALIGN(head->bytes); 170 while (n < aligned_bytes) { 171 r = read(hc->fdin, hc->rbuf + n, aligned_bytes - n); 172 if (r <= 0) 173 return(NULL); 174 n += r; 175 } 176 #ifdef DEBUG 177 hcc_debug_dump(head); 178 #endif 179 return(head); 180 } 181 182 /* 183 * Initialize for a new command 184 */ 185 void 186 hcc_start_command(struct HostConf *hc, int16_t cmd) 187 { 188 struct HCHead *whead = (void *)hc->wbuf; 189 190 whead->magic = HCMAGIC; 191 whead->bytes = 0; 192 whead->cmd = cmd; 193 whead->id = 0; 194 whead->error = 0; 195 hc->windex = sizeof(*whead); 196 } 197 198 /* 199 * Finish constructing a command, transmit it, and await the reply. 200 * Return the HCHead of the reply. 201 */ 202 struct HCHead * 203 hcc_finish_command(struct HostConf *hc) 204 { 205 struct HCHead *whead; 206 struct HCHead *rhead; 207 int aligned_bytes; 208 209 whead = (void *)hc->wbuf; 210 whead->bytes = hc->windex; 211 aligned_bytes = HCC_ALIGN(hc->windex); 212 if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) { 213 #ifdef __error 214 *__error = EIO; 215 #else 216 errno = EIO; 217 #endif 218 if (whead->cmd < 0x0010) 219 return(NULL); 220 fprintf(stderr, "cpdup lost connection to %s\n", hc->host); 221 exit(1); 222 } 223 if ((rhead = hcc_read_command(hc)) == NULL) { 224 #ifdef __error 225 *__error = EIO; 226 #else 227 errno = EIO; 228 #endif 229 if (whead->cmd < 0x0010) 230 return(NULL); 231 fprintf(stderr, "cpdup lost connection to %s\n", hc->host); 232 exit(1); 233 } 234 if (rhead->error) { 235 #ifdef __error 236 *__error = rhead->error; 237 #else 238 errno = rhead->error; 239 #endif 240 } 241 return (rhead); 242 } 243 244 void 245 hcc_leaf_string(struct HostConf *hc, int16_t leafid, const char *str) 246 { 247 struct HCLeaf *item; 248 int bytes = strlen(str) + 1; 249 250 item = (void *)(hc->wbuf + hc->windex); 251 assert(hc->windex + sizeof(*item) + bytes < 65536); 252 item->leafid = leafid; 253 item->reserved = 0; 254 item->bytes = sizeof(*item) + bytes; 255 bcopy(str, item + 1, bytes); 256 hc->windex = HCC_ALIGN(hc->windex + item->bytes); 257 } 258 259 void 260 hcc_leaf_data(struct HostConf *hc, int16_t leafid, const void *ptr, int bytes) 261 { 262 struct HCLeaf *item; 263 264 item = (void *)(hc->wbuf + hc->windex); 265 assert(hc->windex + sizeof(*item) + bytes < 65536); 266 item->leafid = leafid; 267 item->reserved = 0; 268 item->bytes = sizeof(*item) + bytes; 269 bcopy(ptr, item + 1, bytes); 270 hc->windex = HCC_ALIGN(hc->windex + item->bytes); 271 } 272 273 void 274 hcc_leaf_int32(struct HostConf *hc, int16_t leafid, int32_t value) 275 { 276 struct HCLeaf *item; 277 278 item = (void *)(hc->wbuf + hc->windex); 279 assert(hc->windex + sizeof(*item) + sizeof(value) < 65536); 280 item->leafid = leafid; 281 item->reserved = 0; 282 item->bytes = sizeof(*item) + sizeof(value); 283 *(int32_t *)(item + 1) = value; 284 hc->windex = HCC_ALIGN(hc->windex + item->bytes); 285 } 286 287 void 288 hcc_leaf_int64(struct HostConf *hc, int16_t leafid, int64_t value) 289 { 290 struct HCLeaf *item; 291 292 item = (void *)(hc->wbuf + hc->windex); 293 assert(hc->windex + sizeof(*item) + sizeof(value) < 65536); 294 item->leafid = leafid; 295 item->reserved = 0; 296 item->bytes = sizeof(*item) + sizeof(value); 297 *(int64_t *)(item + 1) = value; 298 hc->windex = HCC_ALIGN(hc->windex + item->bytes); 299 } 300 301 int 302 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type) 303 { 304 struct HCHostDesc *hd; 305 struct HCHostDesc *hnew; 306 307 hnew = malloc(sizeof(struct HCHostDesc)); 308 hnew->type = type; 309 hnew->data = ptr; 310 311 if ((hd = hc->hostdescs) != NULL) { 312 hnew->desc = hd->desc + 1; 313 } else { 314 hnew->desc = 1; 315 } 316 hnew->next = hd; 317 hc->hostdescs = hnew; 318 return(hnew->desc); 319 } 320 321 void * 322 hcc_get_descriptor(struct HostConf *hc, int desc, int type) 323 { 324 struct HCHostDesc *hd; 325 326 for (hd = hc->hostdescs; hd; hd = hd->next) { 327 if (hd->desc == desc && hd->type == type) 328 return(hd->data); 329 } 330 return(NULL); 331 } 332 333 void 334 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type) 335 { 336 struct HCHostDesc *hd; 337 struct HCHostDesc **hdp; 338 339 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) { 340 if (hd->desc == desc) { 341 if (ptr) { 342 hd->data = ptr; 343 hd->type = type; 344 } else { 345 *hdp = hd->next; 346 free(hd); 347 } 348 return; 349 } 350 } 351 if (ptr) { 352 hd = malloc(sizeof(*hd)); 353 hd->desc = desc; 354 hd->type = type; 355 hd->data = ptr; 356 hd->next = hc->hostdescs; 357 hc->hostdescs = hd; 358 } 359 } 360 361 struct HCLeaf * 362 hcc_firstitem(struct HCHead *head) 363 { 364 struct HCLeaf *item; 365 int offset; 366 367 offset = sizeof(*head); 368 if (offset == head->bytes) 369 return(NULL); 370 assert(head->bytes >= offset + (int)sizeof(*item)); 371 item = (void *)(head + 1); 372 assert(head->bytes >= offset + item->bytes); 373 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset); 374 return (item); 375 } 376 377 struct HCLeaf * 378 hcc_nextitem(struct HCHead *head, struct HCLeaf *item) 379 { 380 int offset; 381 382 item = (void *)((char *)item + HCC_ALIGN(item->bytes)); 383 offset = (char *)item - (char *)head; 384 if (offset == head->bytes) 385 return(NULL); 386 assert(head->bytes >= offset + (int)sizeof(*item)); 387 assert(head->bytes >= offset + item->bytes); 388 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset); 389 return (item); 390 } 391 392 #ifdef DEBUG 393 394 void 395 hcc_debug_dump(struct HCHead *head) 396 { 397 struct HCLeaf *item; 398 int aligned_bytes = HCC_ALIGN(head->bytes); 399 400 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes); 401 if (head->cmd & HCF_REPLY) 402 fprintf(stderr, " error %d", head->error); 403 fprintf(stderr, "\n"); 404 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) { 405 fprintf(stderr, " ITEM %04x DATA ", item->leafid); 406 switch(item->leafid & LCF_TYPEMASK) { 407 case LCF_INT32: 408 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1)); 409 break; 410 case LCF_INT64: 411 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1)); 412 break; 413 case LCF_STRING: 414 fprintf(stderr, "\"%s\"\n", (char *)(item + 1)); 415 break; 416 case LCF_BINARY: 417 fprintf(stderr, "(binary)\n"); 418 break; 419 default: 420 printf("?\n"); 421 } 422 } 423 } 424 425 #endif 426