Merge from vendor branch TCPDUMP:
[dragonfly.git] / bin / cpdup / hclink.c
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