xref: /dragonfly/bin/cpdup/hclink.c (revision 5dfd06ac)
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