Call selwakeup() from an MP-protected taskqueue.
[dragonfly.git] / bin / cpdup / hclink.c
blob2a7c67c2b821ec0feabbab2dc0b116cc9bc69cd8
1 /*
2 * HCLINK.C
4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hclink.c,v 1.4 2007/01/17 02:34:10 pavalos Exp $
7 */
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>
20 #include "hclink.h"
21 #include "hcproto.h"
23 static struct HCHead *hcc_read_command(struct HostConf *hc);
25 int
26 hcc_connect(struct HostConf *hc)
28 int fdin[2];
29 int fdout[2];
31 if (hc == NULL || hc->host == NULL)
32 return(0);
34 if (pipe(fdin) < 0)
35 return(-1);
36 if (pipe(fdout) < 0) {
37 close(fdin[0]);
38 close(fdin[1]);
39 return(-1);
41 if ((hc->pid = fork()) == 0) {
43 * Child process
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 {
57 * Parent process. Do the initial handshake to make sure we are
58 * actually talking to a cpdup slave.
60 close(fdin[1]);
61 hc->fdin = fdin[0];
62 close(fdout[0]);
63 hc->fdout = fdout[1];
64 return(0);
68 static int
69 rc_badop(struct HostConf *hc __unused, struct HCHead *head)
71 head->error = EOPNOTSUPP;
72 return(0);
75 int
76 hcc_slave(int fdin, int fdout, struct HCDesc *descs, int count)
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;
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;
92 for (i = 0; i < 256; ++i) {
93 if (dispatch[i] == NULL)
94 dispatch[i] = rc_badop;
96 hcslave.fdin = fdin;
97 hcslave.fdout = fdout;
100 * Process commands on fdin and write out results on fdout
102 for (;;) {
104 * Get the command
106 head = hcc_read_command(&hcslave);
107 if (head == NULL)
108 break;
111 * Start the reply and dispatch, then process the return code.
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;
131 * Write out the reply
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;
143 return(0);
147 * This reads a command from fdin, fixes up the byte ordering, and returns
148 * a pointer to HCHead.
150 static
151 struct HCHead *
152 hcc_read_command(struct HostConf *hc)
154 struct HCHead *head;
155 int aligned_bytes;
156 int n;
157 int r;
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;
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;
176 #ifdef DEBUG
177 hcc_debug_dump(head);
178 #endif
179 return(head);
183 * Initialize for a new command
185 void
186 hcc_start_command(struct HostConf *hc, int16_t cmd)
188 struct HCHead *whead = (void *)hc->wbuf;
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);
199 * Finish constructing a command, transmit it, and await the reply.
200 * Return the HCHead of the reply.
202 struct HCHead *
203 hcc_finish_command(struct HostConf *hc)
205 struct HCHead *whead;
206 struct HCHead *rhead;
207 int aligned_bytes;
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);
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);
234 if (rhead->error) {
235 #ifdef __error
236 *__error = rhead->error;
237 #else
238 errno = rhead->error;
239 #endif
241 return (rhead);
244 void
245 hcc_leaf_string(struct HostConf *hc, int16_t leafid, const char *str)
247 struct HCLeaf *item;
248 int bytes = strlen(str) + 1;
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);
259 void
260 hcc_leaf_data(struct HostConf *hc, int16_t leafid, const void *ptr, int bytes)
262 struct HCLeaf *item;
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);
273 void
274 hcc_leaf_int32(struct HostConf *hc, int16_t leafid, int32_t value)
276 struct HCLeaf *item;
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);
287 void
288 hcc_leaf_int64(struct HostConf *hc, int16_t leafid, int64_t value)
290 struct HCLeaf *item;
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);
302 hcc_alloc_descriptor(struct HostConf *hc, void *ptr, int type)
304 struct HCHostDesc *hd;
305 struct HCHostDesc *hnew;
307 hnew = malloc(sizeof(struct HCHostDesc));
308 hnew->type = type;
309 hnew->data = ptr;
311 if ((hd = hc->hostdescs) != NULL) {
312 hnew->desc = hd->desc + 1;
313 } else {
314 hnew->desc = 1;
316 hnew->next = hd;
317 hc->hostdescs = hnew;
318 return(hnew->desc);
321 void *
322 hcc_get_descriptor(struct HostConf *hc, int desc, int type)
324 struct HCHostDesc *hd;
326 for (hd = hc->hostdescs; hd; hd = hd->next) {
327 if (hd->desc == desc && hd->type == type)
328 return(hd->data);
330 return(NULL);
333 void
334 hcc_set_descriptor(struct HostConf *hc, int desc, void *ptr, int type)
336 struct HCHostDesc *hd;
337 struct HCHostDesc **hdp;
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);
348 return;
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;
361 struct HCLeaf *
362 hcc_firstitem(struct HCHead *head)
364 struct HCLeaf *item;
365 int offset;
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);
377 struct HCLeaf *
378 hcc_nextitem(struct HCHead *head, struct HCLeaf *item)
380 int offset;
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);
392 #ifdef DEBUG
394 void
395 hcc_debug_dump(struct HCHead *head)
397 struct HCLeaf *item;
398 int aligned_bytes = HCC_ALIGN(head->bytes);
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");
425 #endif