HAMMER VFS - Major retooling of the refcount mechanics, and fix a deadlock
[dragonfly.git] / bin / cpdup / hclink.c
blob787f014e9f345476a5ac4d63543f037e5ee42873
1 /*
2 * HCLINK.C
4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.10 2008/05/24 17:21:36 dillon Exp $
7 */
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
13 static struct HCHead *hcc_read_command(struct HostConf *hc, hctransaction_t trans);
14 static void hcc_start_reply(hctransaction_t trans, struct HCHead *rhead);
16 int
17 hcc_connect(struct HostConf *hc)
19 int fdin[2];
20 int fdout[2];
21 const char *av[32];
23 if (hc == NULL || hc->host == NULL)
24 return(0);
26 if (pipe(fdin) < 0)
27 return(-1);
28 if (pipe(fdout) < 0) {
29 close(fdin[0]);
30 close(fdin[1]);
31 return(-1);
33 if ((hc->pid = fork()) == 0) {
35 * Child process
37 int n, m;
39 dup2(fdin[1], 1);
40 close(fdin[0]);
41 close(fdin[1]);
42 dup2(fdout[0], 0);
43 close(fdout[0]);
44 close(fdout[1]);
46 n = 0;
47 av[n++] = "ssh";
48 if (CompressOpt)
49 av[n++] = "-C";
50 for (m = 0; m < ssh_argc; m++)
51 av[n++] = ssh_argv[m];
52 av[n++] = "-T";
53 av[n++] = hc->host;
54 av[n++] = "cpdup";
55 av[n++] = "-S";
56 av[n++] = NULL;
58 execv("/usr/bin/ssh", (void *)av);
59 _exit(1);
60 } else if (hc->pid < 0) {
61 return(-1);
62 } else {
64 * Parent process. Do the initial handshake to make sure we are
65 * actually talking to a cpdup slave.
67 close(fdin[1]);
68 hc->fdin = fdin[0];
69 close(fdout[0]);
70 hc->fdout = fdout[1];
71 return(0);
75 static int
76 rc_badop(hctransaction_t trans __unused, struct HCHead *head)
78 head->error = EOPNOTSUPP;
79 return(0);
82 int
83 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
85 struct HostConf hcslave;
86 struct HCHead *head;
87 struct HCHead *whead;
88 struct HCTransaction trans;
89 int (*dispatch[256])(hctransaction_t, struct HCHead *);
90 int aligned_bytes;
91 int i;
92 int r;
94 bzero(&hcslave, sizeof(hcslave));
95 bzero(&trans, sizeof(trans));
96 bzero(dispatch, sizeof(dispatch));
97 for (i = 0; i < count; ++i) {
98 struct HCDesc *desc = &descs[i];
99 assert(desc->cmd >= 0 && desc->cmd < 256);
100 dispatch[desc->cmd] = desc->func;
102 for (i = 0; i < 256; ++i) {
103 if (dispatch[i] == NULL)
104 dispatch[i] = rc_badop;
106 hcslave.fdin = fdin;
107 hcslave.fdout = fdout;
108 trans.hc = &hcslave;
111 * Process commands on fdin and write out results on fdout
113 for (;;) {
115 * Get the command
117 head = hcc_read_command(trans.hc, &trans);
118 if (head == NULL)
119 break;
122 * Start the reply and dispatch, then process the return code.
124 head->error = 0;
125 hcc_start_reply(&trans, head);
127 r = dispatch[head->cmd & 255](&trans, head);
129 switch(r) {
130 case -2:
131 head->error = EINVAL;
132 break;
133 case -1:
134 head->error = errno;
135 break;
136 case 0:
137 break;
138 default:
139 assert(0);
140 break;
144 * Write out the reply
146 whead = (void *)trans.wbuf;
147 whead->bytes = trans.windex;
148 whead->error = head->error;
149 aligned_bytes = HCC_ALIGN(trans.windex);
150 #ifdef DEBUG
151 hcc_debug_dump(whead);
152 #endif
153 if (write(hcslave.fdout, whead, aligned_bytes) != aligned_bytes)
154 break;
156 return(0);
160 * This reads a command from fdin, fixes up the byte ordering, and returns
161 * a pointer to HCHead.
163 * The MasterMutex may or may not be held. When threaded this command
164 * is serialized by a reader thread.
166 static
167 struct HCHead *
168 hcc_read_command(struct HostConf *hc, hctransaction_t trans)
170 hctransaction_t fill;
171 struct HCHead tmp;
172 int aligned_bytes;
173 int n;
174 int r;
176 n = 0;
177 while (n < (int)sizeof(struct HCHead)) {
178 r = read(hc->fdin, (char *)&tmp + n, sizeof(struct HCHead) - n);
179 if (r <= 0)
180 goto fail;
181 n += r;
184 assert(tmp.bytes >= (int)sizeof(tmp) && tmp.bytes < 65536);
185 assert(tmp.magic == HCMAGIC);
187 if (trans) {
188 fill = trans;
189 } else {
190 fprintf(stderr, "cpdup hlink protocol error with %s (%04x)\n",
191 hc->host, tmp.id);
192 exit(1);
195 bcopy(&tmp, fill->rbuf, n);
196 aligned_bytes = HCC_ALIGN(tmp.bytes);
198 while (n < aligned_bytes) {
199 r = read(hc->fdin, fill->rbuf + n, aligned_bytes - n);
200 if (r <= 0)
201 goto fail;
202 n += r;
204 #ifdef DEBUG
205 hcc_debug_dump(head);
206 #endif
207 fill->state = HCT_REPLIED;
208 return((void *)fill->rbuf);
209 fail:
210 return(NULL);
213 static
214 hctransaction_t
215 hcc_get_trans(struct HostConf *hc)
217 return(&hc->trans);
220 void
221 hcc_free_trans(struct HostConf *hc __unused)
223 /* nop */
227 * Initialize for a new command
229 hctransaction_t
230 hcc_start_command(struct HostConf *hc, int16_t cmd)
232 struct HCHead *whead;
233 hctransaction_t trans;
235 trans = hcc_get_trans(hc);
237 whead = (void *)trans->wbuf;
238 whead->magic = HCMAGIC;
239 whead->bytes = 0;
240 whead->cmd = cmd;
241 whead->id = trans->id;
242 whead->error = 0;
244 trans->windex = sizeof(*whead);
245 trans->hc = hc;
246 trans->state = HCT_IDLE;
248 return(trans);
251 static void
252 hcc_start_reply(hctransaction_t trans, struct HCHead *rhead)
254 struct HCHead *whead = (void *)trans->wbuf;
256 whead->magic = HCMAGIC;
257 whead->bytes = 0;
258 whead->cmd = rhead->cmd | HCF_REPLY;
259 whead->id = rhead->id;
260 whead->error = 0;
262 trans->windex = sizeof(*whead);
266 * Finish constructing a command, transmit it, and await the reply.
267 * Return the HCHead of the reply.
269 struct HCHead *
270 hcc_finish_command(hctransaction_t trans)
272 struct HostConf *hc;
273 struct HCHead *whead;
274 struct HCHead *rhead;
275 int aligned_bytes;
276 int16_t wcmd;
278 hc = trans->hc;
279 whead = (void *)trans->wbuf;
280 whead->bytes = trans->windex;
281 aligned_bytes = HCC_ALIGN(trans->windex);
283 trans->state = HCT_SENT;
285 if (write(hc->fdout, whead, aligned_bytes) != aligned_bytes) {
286 #ifdef __error
287 *__error = EIO;
288 #else
289 errno = EIO;
290 #endif
291 if (whead->cmd < 0x0010)
292 return(NULL);
293 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
294 exit(1);
297 wcmd = whead->cmd;
300 * whead is invalid when we call hcc_read_command() because
301 * we may switch to another thread.
303 rhead = hcc_read_command(hc, trans);
304 if (trans->state != HCT_REPLIED || rhead->id != trans->id) {
305 #ifdef __error
306 *__error = EIO;
307 #else
308 errno = EIO;
309 #endif
310 if (wcmd < 0x0010)
311 return(NULL);
312 fprintf(stderr, "cpdup lost connection to %s\n", hc->host);
313 exit(1);
315 trans->state = HCT_DONE;
317 if (rhead->error) {
318 #ifdef __error
319 *__error = rhead->error;
320 #else
321 errno = rhead->error;
322 #endif
324 return (rhead);
327 void
328 hcc_leaf_string(hctransaction_t trans, int16_t leafid, const char *str)
330 struct HCLeaf *item;
331 int bytes = strlen(str) + 1;
333 item = (void *)(trans->wbuf + trans->windex);
334 assert(trans->windex + sizeof(*item) + bytes < 65536);
335 item->leafid = leafid;
336 item->reserved = 0;
337 item->bytes = sizeof(*item) + bytes;
338 bcopy(str, item + 1, bytes);
339 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
342 void
343 hcc_leaf_data(hctransaction_t trans, int16_t leafid, const void *ptr, int bytes)
345 struct HCLeaf *item;
347 item = (void *)(trans->wbuf + trans->windex);
348 assert(trans->windex + sizeof(*item) + bytes < 65536);
349 item->leafid = leafid;
350 item->reserved = 0;
351 item->bytes = sizeof(*item) + bytes;
352 bcopy(ptr, item + 1, bytes);
353 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
356 void
357 hcc_leaf_int32(hctransaction_t trans, int16_t leafid, int32_t value)
359 struct HCLeaf *item;
361 item = (void *)(trans->wbuf + trans->windex);
362 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
363 item->leafid = leafid;
364 item->reserved = 0;
365 item->bytes = sizeof(*item) + sizeof(value);
366 *(int32_t *)(item + 1) = value;
367 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
370 void
371 hcc_leaf_int64(hctransaction_t trans, int16_t leafid, int64_t value)
373 struct HCLeaf *item;
375 item = (void *)(trans->wbuf + trans->windex);
376 assert(trans->windex + sizeof(*item) + sizeof(value) < 65536);
377 item->leafid = leafid;
378 item->reserved = 0;
379 item->bytes = sizeof(*item) + sizeof(value);
380 *(int64_t *)(item + 1) = value;
381 trans->windex = HCC_ALIGN(trans->windex + item->bytes);
385 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
387 struct HCHostDesc *hd;
388 struct HCHostDesc *hnew;
390 hnew = malloc(sizeof(struct HCHostDesc));
391 hnew->type = type;
392 hnew->data = ptr;
394 if ((hd = hc->hostdescs) != NULL) {
395 hnew->desc = hd->desc + 1;
396 } else {
397 hnew->desc = 1;
399 hnew->next = hd;
400 hc->hostdescs = hnew;
401 return(hnew->desc);
404 void *
405 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
407 struct HCHostDesc *hd;
409 for (hd = hc->hostdescs; hd; hd = hd->next) {
410 if (hd->desc == desc && hd->type == type)
411 return(hd->data);
413 return(NULL);
416 void
417 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
419 struct HCHostDesc *hd;
420 struct HCHostDesc **hdp;
422 for (hdp = &hc->hostdescs; (hd = *hdp) != NULL; hdp = &hd->next) {
423 if (hd->desc == desc) {
424 if (ptr) {
425 hd->data = ptr;
426 hd->type = type;
427 } else {
428 *hdp = hd->next;
429 free(hd);
431 return;
434 if (ptr) {
435 hd = malloc(sizeof(*hd));
436 hd->desc = desc;
437 hd->type = type;
438 hd->data = ptr;
439 hd->next = hc->hostdescs;
440 hc->hostdescs = hd;
444 struct HCLeaf *
445 hcc_firstitem(struct HCHead *head)
447 struct HCLeaf *item;
448 int offset;
450 offset = sizeof(*head);
451 if (offset == head->bytes)
452 return(NULL);
453 assert(head->bytes >= offset + (int)sizeof(*item));
454 item = (void *)(head + 1);
455 assert(head->bytes >= offset + item->bytes);
456 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
457 return (item);
460 struct HCLeaf *
461 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
463 int offset;
465 item = (void *)((char *)item + HCC_ALIGN(item->bytes));
466 offset = (char *)item - (char *)head;
467 if (offset == head->bytes)
468 return(NULL);
469 assert(head->bytes >= offset + (int)sizeof(*item));
470 assert(head->bytes >= offset + item->bytes);
471 assert(item->bytes >= (int)sizeof(*item) && item->bytes < 65536 - offset);
472 return (item);
475 #ifdef DEBUG
477 void
478 hcc_debug_dump(struct HCHead *head)
480 struct HCLeaf *item;
481 int aligned_bytes = HCC_ALIGN(head->bytes);
483 fprintf(stderr, "DUMP %04x (%d)", (u_int16_t)head->cmd, aligned_bytes);
484 if (head->cmd & HCF_REPLY)
485 fprintf(stderr, " error %d", head->error);
486 fprintf(stderr, "\n");
487 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
488 fprintf(stderr, " ITEM %04x DATA ", item->leafid);
489 switch(item->leafid & LCF_TYPEMASK) {
490 case LCF_INT32:
491 fprintf(stderr, "int32 %d\n", *(int32_t *)(item + 1));
492 break;
493 case LCF_INT64:
494 fprintf(stderr, "int64 %lld\n", *(int64_t *)(item + 1));
495 break;
496 case LCF_STRING:
497 fprintf(stderr, "\"%s\"\n", (char *)(item + 1));
498 break;
499 case LCF_BINARY:
500 fprintf(stderr, "(binary)\n");
501 break;
502 default:
503 printf("?\n");
508 #endif