inet6: require RTF_ANNOUNCE to proxy NS
[dragonfly.git] / bin / cpdup / hcproto.c
blobcc56958058d69caaed122ece7ce087cc75f3af95
1 /*
2 * HCPROTO.C
4 * This module implements a simple remote control protocol
5 */
7 #include "cpdup.h"
8 #include "hclink.h"
9 #include "hcproto.h"
11 static int hc_decode_stat(hctransaction_t trans, struct stat *, struct HCHead *);
12 static int hc_decode_stat_item(struct stat *st, struct HCLeaf *item);
13 static int rc_encode_stat(hctransaction_t trans, struct stat *);
15 static int rc_hello(hctransaction_t trans, struct HCHead *);
16 static int rc_stat(hctransaction_t trans, struct HCHead *);
17 static int rc_lstat(hctransaction_t trans, struct HCHead *);
18 static int rc_opendir(hctransaction_t trans, struct HCHead *);
19 static int rc_readdir(hctransaction_t trans, struct HCHead *);
20 static int rc_closedir(hctransaction_t trans, struct HCHead *);
21 static int rc_scandir(hctransaction_t trans, struct HCHead *);
22 static int rc_open(hctransaction_t trans, struct HCHead *);
23 static int rc_close(hctransaction_t trans, struct HCHead *);
24 static int rc_read(hctransaction_t trans, struct HCHead *);
25 static int rc_readfile(hctransaction_t trans, struct HCHead *);
26 static int rc_write(hctransaction_t trans, struct HCHead *);
27 static int rc_remove(hctransaction_t trans, struct HCHead *);
28 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
29 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
30 static int rc_chown(hctransaction_t trans, struct HCHead *);
31 static int rc_lchown(hctransaction_t trans, struct HCHead *);
32 static int rc_chmod(hctransaction_t trans, struct HCHead *);
33 static int rc_mknod(hctransaction_t trans, struct HCHead *);
34 static int rc_link(hctransaction_t trans, struct HCHead *);
35 #ifdef _ST_FLAGS_PRESENT_
36 static int rc_chflags(hctransaction_t trans, struct HCHead *);
37 #endif
38 static int rc_readlink(hctransaction_t trans, struct HCHead *);
39 static int rc_umask(hctransaction_t trans, struct HCHead *);
40 static int rc_symlink(hctransaction_t trans, struct HCHead *);
41 static int rc_rename(hctransaction_t trans, struct HCHead *);
42 static int rc_utimes(hctransaction_t trans, struct HCHead *);
43 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
44 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
46 static int getmygroups(gid_t **gidlist);
48 static int silentwarning(int *, const char *, ...) __printflike(2, 3);
50 static struct HCDesc HCDispatchTable[] = {
51 { HC_HELLO, rc_hello },
52 { HC_STAT, rc_stat },
53 { HC_LSTAT, rc_lstat },
54 { HC_OPENDIR, rc_opendir },
55 { HC_READDIR, rc_readdir },
56 { HC_CLOSEDIR, rc_closedir },
57 { HC_OPEN, rc_open },
58 { HC_CLOSE, rc_close },
59 { HC_READ, rc_read },
60 { HC_WRITE, rc_write },
61 { HC_REMOVE, rc_remove },
62 { HC_MKDIR, rc_mkdir },
63 { HC_RMDIR, rc_rmdir },
64 { HC_CHOWN, rc_chown },
65 { HC_LCHOWN, rc_lchown },
66 { HC_CHMOD, rc_chmod },
67 { HC_MKNOD, rc_mknod },
68 { HC_LINK, rc_link },
69 #ifdef _ST_FLAGS_PRESENT_
70 { HC_CHFLAGS, rc_chflags },
71 #endif
72 { HC_READLINK, rc_readlink },
73 { HC_UMASK, rc_umask },
74 { HC_SYMLINK, rc_symlink },
75 { HC_RENAME, rc_rename },
76 { HC_UTIMES, rc_utimes },
77 { HC_GETEUID, rc_geteuid },
78 { HC_GETGROUPS, rc_getgroups },
79 { HC_SCANDIR, rc_scandir },
80 { HC_READFILE, rc_readfile },
81 { HC_LUTIMES, rc_utimes },
82 #ifdef _ST_FLAGS_PRESENT_
83 { HC_LCHFLAGS, rc_chflags },
84 #endif
85 { HC_LCHMOD, rc_chmod },
88 static int chown_warning;
89 #ifdef _ST_FLAGS_PRESENT_
90 static int chflags_warning;
91 #endif
94 * If not running as root generate a silent warning and return no error.
96 * If running as root return an error.
98 static int
99 silentwarning(int *didwarn, const char *ctl, ...)
101 va_list va;
103 if (DstRootPrivs)
104 return(-1);
105 if (*didwarn == 0 && QuietOpt == 0) {
106 *didwarn = 1;
107 fprintf(stderr, "WARNING: Not running as root, ");
108 va_start(va, ctl);
109 vfprintf(stderr, ctl, va);
110 va_end(va);
112 return(0);
116 hc_connect(struct HostConf *hc, int readonly)
118 if (hcc_connect(hc, readonly) < 0) {
119 fprintf(stderr, "Unable to connect to %s\n", hc->host);
120 return(-1);
122 return(hc_hello(hc));
125 void
126 hc_slave(int fdin, int fdout)
128 hcc_slave(fdin, fdout, HCDispatchTable,
129 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
133 * A HELLO RPC is sent on the initial connect.
136 hc_hello(struct HostConf *hc)
138 struct HCHead *head;
139 struct HCLeaf *item;
140 hctransaction_t trans;
141 char hostbuf[256];
142 int error;
144 bzero(hostbuf, sizeof(hostbuf));
145 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
146 return(-1);
147 if (hostbuf[0] == 0)
148 hostbuf[0] = '?';
150 trans = hcc_start_command(hc, HC_HELLO);
151 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
152 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
153 if (UseCpFile)
154 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
155 if ((head = hcc_finish_command(trans)) == NULL) {
156 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
157 hc->host);
158 return(-1);
161 if (head->error) {
162 fprintf(stderr, "Connected to %s but remote returned error %d\n",
163 hc->host, head->error);
164 return(-1);
167 error = -1;
168 FOR_EACH_ITEM(item, trans, head) {
169 switch(item->leafid) {
170 case LC_HELLOSTR:
171 if (QuietOpt == 0)
172 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
173 error = 0;
174 break;
175 case LC_VERSION:
176 hc->version = HCC_INT32(item);
177 break;
180 if (hc->version < HCPROTO_VERSION_COMPAT) {
181 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
182 hc->host);
183 error = -1;
184 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
185 fprintf(stderr,
186 "WARNING: Remote cpdup at %s has a lower version,\n"
187 "expect reduced speed and/or functionality\n", hc->host);
189 if (error < 0)
190 fprintf(stderr, "Handshake failed with %s\n", hc->host);
191 return (error);
194 static int
195 rc_hello(hctransaction_t trans, struct HCHead *head)
197 struct HCLeaf *item;
198 char hostbuf[256];
200 FOR_EACH_ITEM(item, trans, head) {
201 if (item->leafid == LC_PATH1)
202 UseCpFile = strdup(HCC_STRING(item));
205 bzero(hostbuf, sizeof(hostbuf));
206 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
207 return(-1);
208 if (hostbuf[0] == 0)
209 hostbuf[0] = '?';
211 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
212 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
213 return(0);
217 * STAT, LSTAT
220 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
222 struct HCHead *head;
223 hctransaction_t trans;
225 if (hc == NULL || hc->host == NULL)
226 return(stat(path, st));
228 trans = hcc_start_command(hc, HC_STAT);
229 hcc_leaf_string(trans, LC_PATH1, path);
230 if ((head = hcc_finish_command(trans)) == NULL)
231 return(-1);
232 if (head->error)
233 return(-1);
234 return(hc_decode_stat(trans, st, head));
238 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
240 struct HCHead *head;
241 hctransaction_t trans;
243 if (hc == NULL || hc->host == NULL)
244 return(lstat(path, st));
246 trans = hcc_start_command(hc, HC_LSTAT);
247 hcc_leaf_string(trans, LC_PATH1, path);
248 if ((head = hcc_finish_command(trans)) == NULL)
249 return(-1);
250 if (head->error)
251 return(-1);
252 return(hc_decode_stat(trans, st, head));
255 static int
256 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
258 struct HCLeaf *item;
260 bzero(st, sizeof(*st));
261 FOR_EACH_ITEM(item, trans, head)
262 hc_decode_stat_item(st, item);
263 return(0);
266 static int
267 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
269 switch(item->leafid) {
270 case LC_DEV:
271 st->st_dev = HCC_INT32(item);
272 break;
273 case LC_INO:
274 st->st_ino = HCC_INT64(item);
275 break;
276 case LC_MODE:
277 st->st_mode = HCC_INT32(item);
278 break;
279 case LC_NLINK:
280 st->st_nlink = HCC_INT32(item);
281 break;
282 case LC_UID:
283 st->st_uid = HCC_INT32(item);
284 break;
285 case LC_GID:
286 st->st_gid = HCC_INT32(item);
287 break;
288 case LC_RDEV:
289 st->st_rdev = HCC_INT32(item);
290 break;
291 case LC_ATIME:
292 st->st_atime = (time_t)HCC_INT64(item);
293 break;
294 case LC_MTIME:
295 st->st_mtime = (time_t)HCC_INT64(item);
296 break;
297 case LC_CTIME:
298 st->st_ctime = (time_t)HCC_INT64(item);
299 break;
300 #if defined(st_atime) /* A macro, so very likely on modern POSIX */
301 case LC_ATIMENSEC:
302 st->st_atim.tv_nsec = HCC_INT32(item);
303 break;
304 case LC_MTIMENSEC:
305 st->st_mtim.tv_nsec = HCC_INT32(item);
306 break;
307 case LC_CTIMENSEC:
308 st->st_ctim.tv_nsec = HCC_INT32(item);
309 break;
310 #endif
311 case LC_FILESIZE:
312 st->st_size = HCC_INT64(item);
313 break;
314 case LC_FILEBLKS:
315 st->st_blocks = HCC_INT64(item);
316 break;
317 case LC_BLKSIZE:
318 st->st_blksize = HCC_INT32(item);
319 break;
320 #ifdef _ST_FLAGS_PRESENT_
321 case LC_FILEFLAGS:
322 st->st_flags = (uint32_t)HCC_INT64(item);
323 break;
324 #endif
326 return(0);
329 static int
330 rc_stat(hctransaction_t trans, struct HCHead *head)
332 struct HCLeaf *item;
333 struct stat st;
334 const char *path = NULL;
336 FOR_EACH_ITEM(item, trans, head) {
337 if (item->leafid == LC_PATH1)
338 path = HCC_STRING(item);
340 if (path == NULL)
341 return(-2);
342 if (stat(path, &st) < 0)
343 return(-1);
344 return (rc_encode_stat(trans, &st));
347 static int
348 rc_lstat(hctransaction_t trans, struct HCHead *head)
350 struct HCLeaf *item;
351 struct stat st;
352 const char *path = NULL;
354 FOR_EACH_ITEM(item, trans, head) {
355 if (item->leafid == LC_PATH1)
356 path = HCC_STRING(item);
358 if (path == NULL)
359 return(-2);
360 if (lstat(path, &st) < 0)
361 return(-1);
362 return (rc_encode_stat(trans, &st));
366 * Encode all entries of a stat structure.
368 * CAUTION: If you add any more entries here, be sure to
369 * increase the STAT_MAX_NUM_ENTRIES value!
371 #define STAT_MAX_NUM_ENTRIES 18
372 static int
373 rc_encode_stat(hctransaction_t trans, struct stat *st)
375 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
376 hcc_leaf_int64(trans, LC_INO, st->st_ino);
377 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
378 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
379 hcc_leaf_int32(trans, LC_UID, st->st_uid);
380 hcc_leaf_int32(trans, LC_GID, st->st_gid);
381 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
382 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
383 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
384 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
385 #if defined(st_atime)
386 hcc_leaf_int32(trans, LC_ATIMENSEC, st->st_atim.tv_nsec);
387 hcc_leaf_int32(trans, LC_MTIMENSEC, st->st_mtim.tv_nsec);
388 hcc_leaf_int32(trans, LC_CTIMENSEC, st->st_ctim.tv_nsec);
389 #endif
390 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
391 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
392 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
393 #ifdef _ST_FLAGS_PRESENT_
394 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
395 #endif
396 return(0);
400 * OPENDIR
402 DIR *
403 hc_opendir(struct HostConf *hc, const char *path)
405 hctransaction_t trans;
406 struct HCHead *head;
408 if (hc == NULL || hc->host == NULL)
409 return(opendir(path));
411 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
412 struct HCLeaf *item;
413 struct HCDirEntry *den;
414 intptr_t desc = 0;
416 trans = hcc_start_command(hc, HC_OPENDIR);
417 hcc_leaf_string(trans, LC_PATH1, path);
418 if ((head = hcc_finish_command(trans)) == NULL)
419 return (NULL);
420 if (head->error)
421 return (NULL);
422 FOR_EACH_ITEM(item, trans, head) {
423 if (item->leafid == LC_DESCRIPTOR)
424 desc = HCC_INT32(item);
426 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
427 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
428 (intmax_t)desc);
429 return (NULL);
431 den = malloc(sizeof(*den));
432 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
433 return ((void *)desc);
436 /* hc->version >= 4: use HC_SCANDIR */
437 trans = hcc_start_command(hc, HC_SCANDIR);
438 hcc_leaf_string(trans, LC_PATH1, path);
439 if ((head = hcc_finish_command(trans)) == NULL || head->error)
440 return (NULL);
441 return ((void *)head);
444 static int
445 rc_opendir(hctransaction_t trans, struct HCHead *head)
447 struct HCLeaf *item;
448 const char *path = NULL;
449 DIR *dir;
450 int desc;
452 FOR_EACH_ITEM(item, trans, head) {
453 if (item->leafid == LC_PATH1)
454 path = HCC_STRING(item);
456 if (path == NULL)
457 return(-2);
458 if ((dir = opendir(path)) == NULL) {
459 head->error = errno;
460 } else {
461 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
462 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
464 return(0);
468 * READDIR
470 struct HCDirEntry *
471 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
473 int stat_ok = 0;
474 struct HCHead *head;
475 struct HCLeaf *item;
476 static struct HCDirEntry denbuf;
478 *statpp = NULL;
479 if (hc == NULL || hc->host == NULL) {
480 struct dirent *sysden;
482 if ((sysden = readdir(dir)) == NULL)
483 return (NULL);
484 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
485 return (&denbuf);
488 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
489 hctransaction_t trans;
490 struct HCDirEntry *den;
492 trans = hcc_start_command(hc, HC_READDIR);
493 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
494 if ((head = hcc_finish_command(trans)) == NULL)
495 return (NULL);
496 if (head->error)
497 return (NULL); /* XXX errno */
498 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
499 if (den == NULL)
500 return (NULL); /* XXX errno */
501 den->d_name[0] = 0;
502 FOR_EACH_ITEM(item, trans, head) {
503 if (item->leafid == LC_PATH1)
504 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
506 return (den->d_name[0] ? den : NULL);
509 /* hc->version >= 4: using HC_SCANDIR */
510 denbuf.d_name[0] = 0;
511 head = (void *)dir;
512 *statpp = malloc(sizeof(struct stat));
513 bzero(*statpp, sizeof(struct stat));
514 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
515 if (item->leafid == LC_PATH1) { /* this must be the last item */
516 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
517 break;
518 } else {
519 stat_ok = 1;
520 hc_decode_stat_item(*statpp, item);
523 if (!stat_ok) {
524 free(*statpp);
525 *statpp = NULL;
527 if (hc->trans.state == HCT_FAIL)
528 return NULL;
529 return (denbuf.d_name[0] ? &denbuf : NULL);
532 static int
533 rc_readdir(hctransaction_t trans, struct HCHead *head)
535 struct HCLeaf *item;
536 struct dirent *den;
537 DIR *dir = NULL;
539 FOR_EACH_ITEM(item, trans, head) {
540 if (item->leafid == LC_DESCRIPTOR)
541 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
543 if (dir == NULL)
544 return(-2);
545 if ((den = readdir(dir)) != NULL)
546 hcc_leaf_string(trans, LC_PATH1, den->d_name);
547 return(0);
551 * CLOSEDIR
553 * XXX cpdup needs to check error code to avoid truncated dirs?
556 hc_closedir(struct HostConf *hc, DIR *dir)
558 struct HCHead *head;
560 if (hc == NULL || hc->host == NULL)
561 return(closedir(dir));
563 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
564 hctransaction_t trans;
565 struct dirent *den;
567 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
568 free(den);
569 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
570 trans = hcc_start_command(hc, HC_CLOSEDIR);
571 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
572 if ((head = hcc_finish_command(trans)) == NULL)
573 return (-1);
574 if (head->error)
575 return (-1); /* XXX errno */
576 return (0);
577 } else {
578 /* errno */
579 return(-1);
583 /* hc->version >= 4: using HC_SCANDIR */
584 head = (void *)dir;
585 /* skip any remaining items if the directory is closed prematurely */
586 while (hcc_nextchaineditem(hc, head) != NULL)
587 /*nothing*/ ;
588 if (hc->trans.state == HCT_FAIL || head->error)
589 return (-1);
590 return (0);
593 static int
594 rc_closedir(hctransaction_t trans, struct HCHead *head)
596 struct HCLeaf *item;
597 DIR *dir = NULL;
599 FOR_EACH_ITEM(item, trans, head) {
600 if (item->leafid == LC_DESCRIPTOR) {
601 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
602 if (dir != NULL) {
603 hcc_set_descriptor(trans->hc, HCC_INT32(item),
604 NULL, HC_DESC_DIR);
608 if (dir == NULL)
609 return(-2);
610 return(closedir(dir));
614 * SCANDIR
616 static int
617 rc_scandir(hctransaction_t trans, struct HCHead *head)
619 struct HCLeaf *item;
620 const char *path = NULL;
621 struct dirent *den;
622 DIR *dir;
623 char *fpath;
624 struct stat st;
626 FOR_EACH_ITEM(item, trans, head) {
627 if (item->leafid == LC_PATH1)
628 path = HCC_STRING(item);
630 if (path == NULL)
631 return (-2);
632 if ((dir = opendir(path)) == NULL)
633 return (-1);
634 while ((den = readdir(dir)) != NULL) {
635 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
636 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
637 continue; /* skip "." and ".." */
639 * Check if there's enough space left in the current packet.
640 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
641 * one is a string, so we use strlen() + 1 (terminating zero).
642 * The remaining ones are numbers; we assume sizeof(int64_t) so
643 * we're on the safe side.
645 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
646 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
647 strlen(den->d_name) + 1)) {
648 closedir(dir);
649 return (-1);
651 fpath = mprintf("%s/%s", path, den->d_name);
652 if (lstat(fpath, &st) == 0)
653 rc_encode_stat(trans, &st);
654 /* The name must be the last item! */
655 hcc_leaf_string(trans, LC_PATH1, den->d_name);
656 free(fpath);
658 return (closedir(dir));
662 * OPEN
665 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
667 hctransaction_t trans;
668 struct HCHead *head;
669 struct HCLeaf *item;
670 int *fdp;
671 int desc = 0;
672 int nflags;
674 if (NotForRealOpt && (flags & O_CREAT))
675 return(0x7FFFFFFF);
677 if (hc == NULL || hc->host == NULL) {
678 #ifdef O_LARGEFILE
679 flags |= O_LARGEFILE;
680 #endif
681 return(open(path, flags, mode));
684 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
685 trans = hcc_start_command(hc, HC_READFILE);
686 hcc_leaf_string(trans, LC_PATH1, path);
687 if ((head = hcc_finish_command(trans)) == NULL || head->error)
688 return (-1);
689 head->magic = 0; /* used to indicate offset within buffer */
690 return (1); /* dummy */
693 nflags = flags & XO_NATIVEMASK;
694 if (flags & O_CREAT)
695 nflags |= XO_CREAT;
696 if (flags & O_EXCL)
697 nflags |= XO_EXCL;
698 if (flags & O_TRUNC)
699 nflags |= XO_TRUNC;
701 trans = hcc_start_command(hc, HC_OPEN);
702 hcc_leaf_string(trans, LC_PATH1, path);
703 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
704 hcc_leaf_int32(trans, LC_MODE, mode);
706 if ((head = hcc_finish_command(trans)) == NULL)
707 return(-1);
708 if (head->error)
709 return(-1);
710 FOR_EACH_ITEM(item, trans, head) {
711 if (item->leafid == LC_DESCRIPTOR)
712 desc = HCC_INT32(item);
714 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
715 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
716 desc);
717 return(-1);
719 fdp = malloc(sizeof(int));
720 *fdp = desc; /* really just a dummy */
721 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
722 return(desc);
725 static int
726 rc_open(hctransaction_t trans, struct HCHead *head)
728 struct HCLeaf *item;
729 const char *path = NULL;
730 int nflags = 0;
731 int flags;
732 mode_t mode = 0666;
733 int desc;
734 int *fdp;
735 int fd;
737 FOR_EACH_ITEM(item, trans, head) {
738 switch(item->leafid) {
739 case LC_PATH1:
740 path = HCC_STRING(item);
741 break;
742 case LC_OFLAGS:
743 nflags = HCC_INT32(item);
744 break;
745 case LC_MODE:
746 mode = HCC_INT32(item);
747 break;
750 if (path == NULL)
751 return(-2);
753 flags = nflags & XO_NATIVEMASK;
754 if (nflags & XO_CREAT)
755 flags |= O_CREAT;
756 if (nflags & XO_EXCL)
757 flags |= O_EXCL;
758 if (nflags & XO_TRUNC)
759 flags |= O_TRUNC;
761 if (ReadOnlyOpt) {
762 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
763 head->error = EACCES;
764 return (0);
766 flags |= O_RDONLY;
769 #ifdef O_LARGEFILE
770 flags |= O_LARGEFILE;
771 #endif
772 if ((fd = open(path, flags, mode)) < 0)
773 return(-1);
774 fdp = malloc(sizeof(int));
775 *fdp = fd;
776 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
777 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
778 return(0);
782 * CLOSE
785 hc_close(struct HostConf *hc, int fd)
787 hctransaction_t trans;
788 struct HCHead *head;
789 int *fdp;
791 if (NotForRealOpt && fd == 0x7FFFFFFF)
792 return(0);
793 if (hc == NULL || hc->host == NULL)
794 return(close(fd));
796 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
797 head = (void *)hc->trans.rbuf;
798 /* skip any remaining items if the file is closed prematurely */
799 while (hcc_nextchaineditem(hc, head) != NULL)
800 /*nothing*/ ;
801 if (hc->trans.state == HCT_FAIL || head->error)
802 return (-1);
803 return (0);
806 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
807 if (fdp) {
808 free(fdp);
809 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
811 trans = hcc_start_command(hc, HC_CLOSE);
812 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
813 if ((head = hcc_finish_command(trans)) == NULL)
814 return(-1);
815 if (head->error)
816 return(-1);
817 return(0);
818 } else {
819 return(-1);
823 static int
824 rc_close(hctransaction_t trans, struct HCHead *head)
826 struct HCLeaf *item;
827 int *fdp = NULL;
828 int fd;
829 int desc = -1;
831 FOR_EACH_ITEM(item, trans, head) {
832 if (item->leafid == LC_DESCRIPTOR)
833 desc = HCC_INT32(item);
835 if (desc < 0)
836 return(-2);
837 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
838 return(-2);
839 fd = *fdp;
840 free(fdp);
841 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
842 return(close(fd));
845 static int
846 getiolimit(void)
848 return(32768);
852 * READ
854 ssize_t
855 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
857 hctransaction_t trans;
858 struct HCHead *head;
859 struct HCLeaf *item;
860 int *fdp;
861 int offset;
862 int r = 0;
863 int x = 0;
865 if (hc == NULL || hc->host == NULL)
866 return(read(fd, buf, bytes));
868 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
869 head = (void *)hc->trans.rbuf;
870 while (bytes) {
871 if ((offset = head->magic) != 0) {
872 item = hcc_currentchaineditem(hc, head);
873 } else {
874 item = hcc_nextchaineditem(hc, head);
876 if (item == NULL) {
877 if (hc->trans.state == HCT_FAIL)
878 r = -1;
879 return (r);
881 if (item->leafid != LC_DATA)
882 return (-1);
883 x = item->bytes - sizeof(*item) - offset;
884 if (x > (int)bytes) {
885 x = (int)bytes;
886 head->magic += x; /* leave bytes in the buffer */
888 else
889 head->magic = 0; /* all bytes used up */
890 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
891 buf = (char *)buf + x;
892 bytes -= (size_t)x;
893 r += x;
895 return (r);
898 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
899 if (fdp) {
900 while (bytes) {
901 size_t limit = getiolimit();
902 int n = (bytes > limit) ? limit : bytes;
904 trans = hcc_start_command(hc, HC_READ);
905 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
906 hcc_leaf_int32(trans, LC_BYTES, n);
907 if ((head = hcc_finish_command(trans)) == NULL)
908 return(-1);
909 if (head->error)
910 return(-1);
911 FOR_EACH_ITEM(item, trans, head) {
912 if (item->leafid == LC_DATA) {
913 x = item->bytes - sizeof(*item);
914 if (x > (int)bytes)
915 x = (int)bytes;
916 bcopy(HCC_BINARYDATA(item), buf, x);
917 buf = (char *)buf + x;
918 bytes -= (size_t)x;
919 r += x;
922 if (x < n)
923 break;
925 return(r);
926 } else {
927 return(-1);
931 static int
932 rc_read(hctransaction_t trans, struct HCHead *head)
934 struct HCLeaf *item;
935 int *fdp = NULL;
936 char buf[32768];
937 int bytes = -1;
938 int n;
940 FOR_EACH_ITEM(item, trans, head) {
941 switch(item->leafid) {
942 case LC_DESCRIPTOR:
943 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
944 break;
945 case LC_BYTES:
946 bytes = HCC_INT32(item);
947 break;
950 if (fdp == NULL)
951 return(-2);
952 if (bytes < 0 || bytes > 32768)
953 return(-2);
954 n = read(*fdp, buf, bytes);
955 if (n < 0)
956 return(-1);
957 hcc_leaf_data(trans, LC_DATA, buf, n);
958 return(0);
962 * READFILE
964 static int
965 rc_readfile(hctransaction_t trans, struct HCHead *head)
967 struct HCLeaf *item;
968 const char *path = NULL;
969 char buf[32768];
970 int n;
971 int fd;
973 FOR_EACH_ITEM(item, trans, head) {
974 if (item->leafid == LC_PATH1)
975 path = HCC_STRING(item);
977 if (path == NULL)
978 return (-2);
979 if ((fd = open(path, O_RDONLY)) < 0)
980 return(-1);
981 while ((n = read(fd, buf, 32768)) >= 0) {
982 if (!hcc_check_space(trans, head, 1, n)) {
983 close(fd);
984 return (-1);
986 hcc_leaf_data(trans, LC_DATA, buf, n);
987 if (n == 0)
988 break;
990 if (n < 0) {
991 close(fd);
992 return (-1);
994 return (close(fd));
998 * WRITE
1000 ssize_t
1001 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
1003 hctransaction_t trans;
1004 struct HCHead *head;
1005 struct HCLeaf *item;
1006 int *fdp;
1007 int r;
1009 if (NotForRealOpt)
1010 return(bytes);
1012 if (hc == NULL || hc->host == NULL)
1013 return(write(fd, buf, bytes));
1015 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1016 if (fdp) {
1017 r = 0;
1018 while (bytes) {
1019 size_t limit = getiolimit();
1020 int n = (bytes > limit) ? limit : bytes;
1021 int x = 0;
1023 trans = hcc_start_command(hc, HC_WRITE);
1024 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1025 hcc_leaf_data(trans, LC_DATA, buf, n);
1026 if ((head = hcc_finish_command(trans)) == NULL)
1027 return(-1);
1028 if (head->error)
1029 return(-1);
1030 FOR_EACH_ITEM(item, trans, head) {
1031 if (item->leafid == LC_BYTES)
1032 x = HCC_INT32(item);
1034 if (x < 0 || x > n)
1035 return(-1);
1036 r += x;
1037 buf = (const char *)buf + x;
1038 bytes -= x;
1039 if (x < n)
1040 break;
1042 return(r);
1043 } else {
1044 return(-1);
1048 static int
1049 rc_write(hctransaction_t trans, struct HCHead *head)
1051 struct HCLeaf *item;
1052 int *fdp = NULL;
1053 void *buf = NULL;
1054 int n = -1;
1056 FOR_EACH_ITEM(item, trans, head) {
1057 switch(item->leafid) {
1058 case LC_DESCRIPTOR:
1059 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1060 break;
1061 case LC_DATA:
1062 buf = HCC_BINARYDATA(item);
1063 n = item->bytes - sizeof(*item);
1064 break;
1067 if (ReadOnlyOpt) {
1068 head->error = EACCES;
1069 return (0);
1071 if (fdp == NULL)
1072 return(-2);
1073 if (n < 0 || n > 32768)
1074 return(-2);
1075 n = write(*fdp, buf, n);
1076 if (n < 0)
1077 return (-1);
1078 hcc_leaf_int32(trans, LC_BYTES, n);
1079 return(0);
1083 * REMOVE
1085 * NOTE: This function returns -errno if an error occured.
1088 hc_remove(struct HostConf *hc, const char *path)
1090 hctransaction_t trans;
1091 struct HCHead *head;
1092 int res;
1094 if (NotForRealOpt)
1095 return(0);
1096 if (hc == NULL || hc->host == NULL) {
1097 res = remove(path);
1098 if (res < 0)
1099 res = -errno;
1100 return(res);
1103 trans = hcc_start_command(hc, HC_REMOVE);
1104 hcc_leaf_string(trans, LC_PATH1, path);
1105 if ((head = hcc_finish_command(trans)) == NULL)
1106 return(-EIO);
1107 if (head->error)
1108 return(-(int)head->error);
1109 return(0);
1112 static int
1113 rc_remove(hctransaction_t trans, struct HCHead *head)
1115 struct HCLeaf *item;
1116 const char *path = NULL;
1118 FOR_EACH_ITEM(item, trans, head) {
1119 if (item->leafid == LC_PATH1)
1120 path = HCC_STRING(item);
1122 if (path == NULL)
1123 return(-2);
1124 if (ReadOnlyOpt) {
1125 head->error = EACCES;
1126 return (0);
1128 return(remove(path));
1132 * MKDIR
1135 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1137 hctransaction_t trans;
1138 struct HCHead *head;
1140 if (NotForRealOpt)
1141 return(0);
1142 if (hc == NULL || hc->host == NULL)
1143 return(mkdir(path, mode));
1145 trans = hcc_start_command(hc, HC_MKDIR);
1146 hcc_leaf_string(trans, LC_PATH1, path);
1147 hcc_leaf_int32(trans, LC_MODE, mode);
1148 if ((head = hcc_finish_command(trans)) == NULL)
1149 return(-1);
1150 if (head->error)
1151 return(-1);
1152 return(0);
1155 static int
1156 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1158 struct HCLeaf *item;
1159 const char *path = NULL;
1160 mode_t mode = 0777;
1162 FOR_EACH_ITEM(item, trans, head) {
1163 switch(item->leafid) {
1164 case LC_PATH1:
1165 path = HCC_STRING(item);
1166 break;
1167 case LC_MODE:
1168 mode = HCC_INT32(item);
1169 break;
1172 if (ReadOnlyOpt) {
1173 head->error = EACCES;
1174 return (0);
1176 if (path == NULL)
1177 return(-2);
1178 return(mkdir(path, mode));
1182 * RMDIR
1185 hc_rmdir(struct HostConf *hc, const char *path)
1187 hctransaction_t trans;
1188 struct HCHead *head;
1190 if (NotForRealOpt)
1191 return(0);
1192 if (hc == NULL || hc->host == NULL)
1193 return(rmdir(path));
1195 trans = hcc_start_command(hc, HC_RMDIR);
1196 hcc_leaf_string(trans, LC_PATH1, path);
1197 if ((head = hcc_finish_command(trans)) == NULL)
1198 return(-1);
1199 if (head->error)
1200 return(-1);
1201 return(0);
1204 static int
1205 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1207 struct HCLeaf *item;
1208 const char *path = NULL;
1210 FOR_EACH_ITEM(item, trans, head) {
1211 if (item->leafid == LC_PATH1)
1212 path = HCC_STRING(item);
1214 if (ReadOnlyOpt) {
1215 head->error = EACCES;
1216 return (0);
1218 if (path == NULL)
1219 return(-2);
1220 return(rmdir(path));
1224 * CHOWN
1226 * Almost silently ignore chowns that fail if we are not root.
1229 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1231 hctransaction_t trans;
1232 struct HCHead *head;
1233 int rc;
1235 if (NotForRealOpt)
1236 return(0);
1237 if (!DstRootPrivs)
1238 owner = -1;
1240 if (hc == NULL || hc->host == NULL) {
1241 rc = chown(path, owner, group);
1242 if (rc < 0)
1243 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1244 return(rc);
1247 trans = hcc_start_command(hc, HC_CHOWN);
1248 hcc_leaf_string(trans, LC_PATH1, path);
1249 hcc_leaf_int32(trans, LC_UID, owner);
1250 hcc_leaf_int32(trans, LC_GID, group);
1251 if ((head = hcc_finish_command(trans)) == NULL)
1252 return(-1);
1253 if (head->error)
1254 return(-1);
1255 return(0);
1258 static int
1259 rc_chown(hctransaction_t trans, struct HCHead *head)
1261 struct HCLeaf *item;
1262 const char *path = NULL;
1263 uid_t uid = (uid_t)-1;
1264 gid_t gid = (gid_t)-1;
1265 int rc;
1267 FOR_EACH_ITEM(item, trans, head) {
1268 switch(item->leafid) {
1269 case LC_PATH1:
1270 path = HCC_STRING(item);
1271 break;
1272 case LC_UID:
1273 uid = HCC_INT32(item);
1274 break;
1275 case LC_GID:
1276 gid = HCC_INT32(item);
1277 break;
1280 if (ReadOnlyOpt) {
1281 head->error = EACCES;
1282 return (0);
1284 if (path == NULL)
1285 return(-2);
1286 rc = chown(path, uid, gid);
1287 if (rc < 0)
1288 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1289 return(rc);
1293 * LCHOWN
1296 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1298 hctransaction_t trans;
1299 struct HCHead *head;
1300 int rc;
1302 if (NotForRealOpt)
1303 return(0);
1304 if (!DstRootPrivs)
1305 owner = -1;
1307 if (hc == NULL || hc->host == NULL) {
1308 rc = lchown(path, owner, group);
1309 if (rc < 0)
1310 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1311 return(rc);
1314 trans = hcc_start_command(hc, HC_LCHOWN);
1315 hcc_leaf_string(trans, LC_PATH1, path);
1316 hcc_leaf_int32(trans, LC_UID, owner);
1317 hcc_leaf_int32(trans, LC_GID, group);
1318 if ((head = hcc_finish_command(trans)) == NULL)
1319 return(-1);
1320 if (head->error)
1321 return(-1);
1322 return(0);
1325 static int
1326 rc_lchown(hctransaction_t trans, struct HCHead *head)
1328 struct HCLeaf *item;
1329 const char *path = NULL;
1330 uid_t uid = (uid_t)-1;
1331 gid_t gid = (gid_t)-1;
1332 int rc;
1334 FOR_EACH_ITEM(item, trans, head) {
1335 switch(item->leafid) {
1336 case LC_PATH1:
1337 path = HCC_STRING(item);
1338 break;
1339 case LC_UID:
1340 uid = HCC_INT32(item);
1341 break;
1342 case LC_GID:
1343 gid = HCC_INT32(item);
1344 break;
1347 if (ReadOnlyOpt) {
1348 head->error = EACCES;
1349 return (0);
1351 if (path == NULL)
1352 return(-2);
1353 rc = lchown(path, uid, gid);
1354 if (rc < 0)
1355 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1356 return(rc);
1360 * CHMOD
1363 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1365 hctransaction_t trans;
1366 struct HCHead *head;
1368 if (NotForRealOpt)
1369 return(0);
1370 if (hc == NULL || hc->host == NULL)
1371 return(chmod(path, mode));
1373 trans = hcc_start_command(hc, HC_CHMOD);
1374 hcc_leaf_string(trans, LC_PATH1, path);
1375 hcc_leaf_int32(trans, LC_MODE, mode);
1376 if ((head = hcc_finish_command(trans)) == NULL)
1377 return(-1);
1378 if (head->error)
1379 return(-1);
1380 return(0);
1384 hc_lchmod(struct HostConf *hc, const char *path, mode_t mode)
1386 hctransaction_t trans;
1387 struct HCHead *head;
1389 if (NotForRealOpt)
1390 return(0);
1391 if (hc == NULL || hc->host == NULL)
1392 return(lchmod(path, mode));
1394 trans = hcc_start_command(hc, HC_LCHMOD);
1395 hcc_leaf_string(trans, LC_PATH1, path);
1396 hcc_leaf_int32(trans, LC_MODE, mode);
1397 if ((head = hcc_finish_command(trans)) == NULL)
1398 return(-1);
1399 if (head->error)
1400 return(-1);
1401 return(0);
1404 static int
1405 rc_chmod(hctransaction_t trans, struct HCHead *head)
1407 struct HCLeaf *item;
1408 const char *path = NULL;
1409 mode_t mode = 0666;
1411 FOR_EACH_ITEM(item, trans, head) {
1412 switch(item->leafid) {
1413 case LC_PATH1:
1414 path = HCC_STRING(item);
1415 break;
1416 case LC_MODE:
1417 mode = HCC_INT32(item);
1418 break;
1421 if (ReadOnlyOpt) {
1422 head->error = EACCES;
1423 return (0);
1425 if (path == NULL)
1426 return(-2);
1427 if (head->cmd == HC_LCHMOD)
1428 return(lchmod(path, mode));
1429 else
1430 return(chmod(path, mode));
1434 * MKNOD
1437 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1439 hctransaction_t trans;
1440 struct HCHead *head;
1442 if (NotForRealOpt)
1443 return(0);
1444 if (!DstRootPrivs) {
1445 /* mknod() requires root privs, so don't bother. */
1446 errno = EPERM;
1447 return (-1);
1450 if (hc == NULL || hc->host == NULL)
1451 return(mknod(path, mode, rdev));
1453 trans = hcc_start_command(hc, HC_MKNOD);
1454 hcc_leaf_string(trans, LC_PATH1, path);
1455 hcc_leaf_int32(trans, LC_MODE, mode);
1456 hcc_leaf_int32(trans, LC_RDEV, rdev);
1457 if ((head = hcc_finish_command(trans)) == NULL)
1458 return(-1);
1459 if (head->error)
1460 return(-1);
1461 return(0);
1464 static int
1465 rc_mknod(hctransaction_t trans, struct HCHead *head)
1467 struct HCLeaf *item;
1468 const char *path = NULL;
1469 mode_t mode = 0666;
1470 dev_t rdev = 0;
1472 FOR_EACH_ITEM(item, trans, head) {
1473 switch(item->leafid) {
1474 case LC_PATH1:
1475 path = HCC_STRING(item);
1476 break;
1477 case LC_MODE:
1478 mode = HCC_INT32(item);
1479 break;
1480 case LC_RDEV:
1481 rdev = HCC_INT32(item);
1482 break;
1485 if (ReadOnlyOpt) {
1486 head->error = EACCES;
1487 return (0);
1489 if (path == NULL)
1490 return(-2);
1491 return(mknod(path, mode, rdev));
1495 * LINK
1498 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1500 hctransaction_t trans;
1501 struct HCHead *head;
1503 if (NotForRealOpt)
1504 return(0);
1505 if (hc == NULL || hc->host == NULL)
1506 return(link(name1, name2));
1508 trans = hcc_start_command(hc, HC_LINK);
1509 hcc_leaf_string(trans, LC_PATH1, name1);
1510 hcc_leaf_string(trans, LC_PATH2, name2);
1511 if ((head = hcc_finish_command(trans)) == NULL)
1512 return(-1);
1513 if (head->error)
1514 return(-1);
1515 return(0);
1518 static int
1519 rc_link(hctransaction_t trans, struct HCHead *head)
1521 struct HCLeaf *item;
1522 const char *name1 = NULL;
1523 const char *name2 = NULL;
1525 FOR_EACH_ITEM(item, trans, head) {
1526 switch(item->leafid) {
1527 case LC_PATH1:
1528 name1 = HCC_STRING(item);
1529 break;
1530 case LC_PATH2:
1531 name2 = HCC_STRING(item);
1532 break;
1535 if (ReadOnlyOpt) {
1536 head->error = EACCES;
1537 return (-0);
1539 if (name1 == NULL || name2 == NULL)
1540 return(-2);
1541 return(link(name1, name2));
1544 #ifdef _ST_FLAGS_PRESENT_
1546 * CHFLAGS
1549 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1551 hctransaction_t trans;
1552 struct HCHead *head;
1553 int rc;
1555 if (NotForRealOpt)
1556 return(0);
1557 if (!DstRootPrivs)
1558 flags &= UF_SETTABLE;
1560 if (hc == NULL || hc->host == NULL) {
1561 if ((rc = chflags(path, flags)) < 0)
1562 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1563 return (rc);
1566 trans = hcc_start_command(hc, HC_CHFLAGS);
1567 hcc_leaf_string(trans, LC_PATH1, path);
1568 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1569 if ((head = hcc_finish_command(trans)) == NULL)
1570 return(-1);
1571 if (head->error)
1572 return(-1);
1573 return(0);
1577 hc_lchflags(struct HostConf *hc, const char *path, u_long flags)
1579 hctransaction_t trans;
1580 struct HCHead *head;
1581 int rc;
1583 if (NotForRealOpt)
1584 return(0);
1585 if (!DstRootPrivs)
1586 flags &= UF_SETTABLE;
1588 if (hc == NULL || hc->host == NULL) {
1589 if ((rc = lchflags(path, flags)) < 0)
1590 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1591 return (rc);
1594 trans = hcc_start_command(hc, HC_LCHFLAGS);
1595 hcc_leaf_string(trans, LC_PATH1, path);
1596 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1597 if ((head = hcc_finish_command(trans)) == NULL)
1598 return(-1);
1599 if (head->error)
1600 return(-1);
1601 return(0);
1604 static int
1605 rc_chflags(hctransaction_t trans, struct HCHead *head)
1607 struct HCLeaf *item;
1608 const char *path = NULL;
1609 u_long flags = 0;
1610 int rc;
1612 FOR_EACH_ITEM(item, trans, head) {
1613 switch(item->leafid) {
1614 case LC_PATH1:
1615 path = HCC_STRING(item);
1616 break;
1617 case LC_FILEFLAGS:
1618 flags = (u_long)HCC_INT64(item);
1619 break;
1622 if (ReadOnlyOpt) {
1623 head->error = EACCES;
1624 return (0);
1626 if (path == NULL)
1627 return(-2);
1628 if (head->cmd == HC_LCHFLAGS)
1629 rc = lchflags(path, flags);
1630 else
1631 rc = chflags(path, flags);
1632 if (rc < 0)
1633 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1634 return(rc);
1637 #endif
1640 * READLINK
1643 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1645 hctransaction_t trans;
1646 struct HCHead *head;
1647 struct HCLeaf *item;
1648 int r;
1650 if (hc == NULL || hc->host == NULL)
1651 return(readlink(path, buf, bufsiz));
1653 trans = hcc_start_command(hc, HC_READLINK);
1654 hcc_leaf_string(trans, LC_PATH1, path);
1655 if ((head = hcc_finish_command(trans)) == NULL)
1656 return(-1);
1657 if (head->error)
1658 return(-1);
1660 r = 0;
1661 FOR_EACH_ITEM(item, trans, head) {
1662 if (item->leafid == LC_DATA) {
1663 r = item->bytes - sizeof(*item);
1664 if (r < 0)
1665 r = 0;
1666 if (r > bufsiz)
1667 r = bufsiz;
1668 bcopy(HCC_BINARYDATA(item), buf, r);
1671 return(r);
1674 static int
1675 rc_readlink(hctransaction_t trans, struct HCHead *head)
1677 struct HCLeaf *item;
1678 const char *path = NULL;
1679 char buf[1024];
1680 int r;
1682 FOR_EACH_ITEM(item, trans, head) {
1683 if (item->leafid == LC_PATH1)
1684 path = HCC_STRING(item);
1686 if (path == NULL)
1687 return(-2);
1688 r = readlink(path, buf, sizeof(buf));
1689 if (r < 0)
1690 return(-1);
1691 hcc_leaf_data(trans, LC_DATA, buf, r);
1692 return(0);
1696 * UMASK
1698 mode_t
1699 hc_umask(struct HostConf *hc, mode_t numask)
1701 hctransaction_t trans;
1702 struct HCHead *head;
1703 struct HCLeaf *item;
1705 if (NotForRealOpt)
1706 return(umask(numask));
1707 if (hc == NULL || hc->host == NULL)
1708 return(umask(numask));
1710 trans = hcc_start_command(hc, HC_UMASK);
1711 hcc_leaf_int32(trans, LC_MODE, numask);
1712 if ((head = hcc_finish_command(trans)) == NULL)
1713 return((mode_t)-1);
1714 if (head->error)
1715 return((mode_t)-1);
1717 numask = (mode_t) ~0666U;
1718 FOR_EACH_ITEM(item, trans, head) {
1719 if (item->leafid == LC_MODE)
1720 numask = HCC_INT32(item);
1722 return(numask);
1725 static int
1726 rc_umask(hctransaction_t trans, struct HCHead *head)
1728 struct HCLeaf *item;
1729 mode_t numask = (mode_t) ~0666U;
1731 FOR_EACH_ITEM(item, trans, head) {
1732 if (item->leafid == LC_MODE)
1733 numask = HCC_INT32(item);
1735 numask = umask(numask);
1736 hcc_leaf_int32(trans, LC_MODE, numask);
1737 return(0);
1741 * SYMLINK
1744 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1746 hctransaction_t trans;
1747 struct HCHead *head;
1749 if (NotForRealOpt)
1750 return(0);
1751 if (hc == NULL || hc->host == NULL)
1752 return(symlink(name1, name2));
1754 trans = hcc_start_command(hc, HC_SYMLINK);
1755 hcc_leaf_string(trans, LC_PATH1, name1);
1756 hcc_leaf_string(trans, LC_PATH2, name2);
1757 if ((head = hcc_finish_command(trans)) == NULL)
1758 return(-1);
1759 if (head->error)
1760 return(-1);
1761 return(0);
1764 static int
1765 rc_symlink(hctransaction_t trans, struct HCHead *head)
1767 struct HCLeaf *item;
1768 const char *name1 = NULL;
1769 const char *name2 = NULL;
1771 FOR_EACH_ITEM(item, trans, head) {
1772 switch(item->leafid) {
1773 case LC_PATH1:
1774 name1 = HCC_STRING(item);
1775 break;
1776 case LC_PATH2:
1777 name2 = HCC_STRING(item);
1778 break;
1781 if (ReadOnlyOpt) {
1782 head->error = EACCES;
1783 return (0);
1785 if (name1 == NULL || name2 == NULL)
1786 return(-2);
1787 return(symlink(name1, name2));
1791 * RENAME
1794 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1796 hctransaction_t trans;
1797 struct HCHead *head;
1799 if (NotForRealOpt)
1800 return(0);
1801 if (hc == NULL || hc->host == NULL)
1802 return(rename(name1, name2));
1804 trans = hcc_start_command(hc, HC_RENAME);
1805 hcc_leaf_string(trans, LC_PATH1, name1);
1806 hcc_leaf_string(trans, LC_PATH2, name2);
1807 if ((head = hcc_finish_command(trans)) == NULL)
1808 return(-1);
1809 if (head->error)
1810 return(-1);
1811 return(0);
1814 static int
1815 rc_rename(hctransaction_t trans, struct HCHead *head)
1817 struct HCLeaf *item;
1818 const char *name1 = NULL;
1819 const char *name2 = NULL;
1821 FOR_EACH_ITEM(item, trans, head) {
1822 switch(item->leafid) {
1823 case LC_PATH1:
1824 name1 = HCC_STRING(item);
1825 break;
1826 case LC_PATH2:
1827 name2 = HCC_STRING(item);
1828 break;
1831 if (ReadOnlyOpt) {
1832 head->error = EACCES;
1833 return (0);
1835 if (name1 == NULL || name2 == NULL)
1836 return(-2);
1837 return(rename(name1, name2));
1841 * UTIMES
1844 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1846 hctransaction_t trans;
1847 struct HCHead *head;
1849 if (NotForRealOpt)
1850 return(0);
1851 if (hc == NULL || hc->host == NULL) {
1852 return(utimes(path, times));
1855 trans = hcc_start_command(hc, HC_UTIMES);
1856 hcc_leaf_string(trans, LC_PATH1, path);
1857 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1858 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1859 #if defined(st_atime)
1860 hcc_leaf_int32(trans, LC_ATIMENSEC, times[0].tv_usec * 1000);
1861 hcc_leaf_int32(trans, LC_MTIMENSEC, times[1].tv_usec * 1000);
1862 #endif
1863 if ((head = hcc_finish_command(trans)) == NULL)
1864 return(-1);
1865 if (head->error)
1866 return(-1);
1867 return(0);
1871 hc_lutimes(struct HostConf *hc, const char *path, const struct timeval *times)
1873 hctransaction_t trans;
1874 struct HCHead *head;
1876 if (NotForRealOpt)
1877 return(0);
1878 if (hc == NULL || hc->host == NULL) {
1879 return(lutimes(path, times));
1882 trans = hcc_start_command(hc, HC_LUTIMES);
1883 hcc_leaf_string(trans, LC_PATH1, path);
1884 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1885 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1886 #if defined(st_atime)
1887 hcc_leaf_int32(trans, LC_ATIMENSEC, times[0].tv_usec * 1000);
1888 hcc_leaf_int32(trans, LC_MTIMENSEC, times[1].tv_usec * 1000);
1889 #endif
1890 if ((head = hcc_finish_command(trans)) == NULL)
1891 return(-1);
1892 if (head->error)
1893 return(-1);
1894 return(0);
1897 static int
1898 rc_utimes(hctransaction_t trans, struct HCHead *head)
1900 struct HCLeaf *item;
1901 struct timeval times[2];
1902 const char *path;
1904 bzero(times, sizeof(times));
1905 path = NULL;
1907 FOR_EACH_ITEM(item, trans, head) {
1908 switch(item->leafid) {
1909 case LC_PATH1:
1910 path = HCC_STRING(item);
1911 break;
1912 case LC_ATIME:
1913 times[0].tv_sec = HCC_INT64(item);
1914 break;
1915 case LC_MTIME:
1916 times[1].tv_sec = HCC_INT64(item);
1917 break;
1918 #if defined(st_atimespec) || defined(_STATBUF_ST_NSEC)
1919 case LC_ATIMENSEC:
1920 times[0].tv_usec = HCC_INT32(item) / 1000;
1921 break;
1922 case LC_MTIMENSEC:
1923 times[1].tv_usec = HCC_INT32(item) / 1000;
1924 break;
1925 #endif
1928 if (ReadOnlyOpt) {
1929 head->error = EACCES;
1930 return (0);
1932 if (path == NULL)
1933 return(-2);
1934 if (head->cmd == HC_LUTIMES)
1935 return(lutimes(path, times));
1936 else
1937 return(utimes(path, times));
1940 uid_t
1941 hc_geteuid(struct HostConf *hc)
1943 hctransaction_t trans;
1944 struct HCHead *head;
1945 struct HCLeaf *item;
1947 if (hc == NULL || hc->host == NULL)
1948 return (geteuid());
1950 if (hc->version < 3) {
1951 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1952 /* Return 0 on error, so the caller assumes root privileges. */
1953 return (0);
1956 trans = hcc_start_command(hc, HC_GETEUID);
1957 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1958 return(0);
1959 FOR_EACH_ITEM(item, trans, head) {
1960 if (item->leafid == LC_UID)
1961 return (HCC_INT32(item));
1963 return(0); /* shouldn't happen */
1966 static int
1967 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1969 hcc_leaf_int32(trans, LC_UID, geteuid());
1970 return (0);
1973 static int
1974 getmygroups(gid_t **gidlist)
1976 int count;
1978 if ((count = getgroups(0, *gidlist)) > 0) {
1979 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1980 if ((count = getgroups(count, *gidlist)) <= 0)
1981 free(*gidlist);
1983 else
1984 count = -1;
1986 else
1987 *gidlist = NULL;
1988 return (count);
1992 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1994 int count, i;
1995 hctransaction_t trans;
1996 struct HCHead *head;
1997 struct HCLeaf *item;
1999 if (hc == NULL || hc->host == NULL)
2000 return (getmygroups(gidlist));
2002 i = 0;
2003 count = 0;
2004 *gidlist = NULL;
2006 if (hc->version < 3) {
2007 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
2008 return (-1);
2011 trans = hcc_start_command(hc, HC_GETGROUPS);
2012 if ((head = hcc_finish_command(trans)) == NULL || head->error)
2013 return(-1);
2014 FOR_EACH_ITEM(item, trans, head) {
2015 switch(item->leafid) {
2016 case LC_COUNT:
2017 count = HCC_INT32(item);
2018 if (*gidlist != NULL) { /* protocol error */
2019 free(*gidlist);
2020 *gidlist = NULL;
2021 return (-1);
2023 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
2024 return (-1);
2025 break;
2026 case LC_GID:
2027 if (*gidlist == NULL || i >= count) { /* protocol error */
2028 if (*gidlist != NULL)
2029 free(*gidlist);
2030 *gidlist = NULL;
2031 return (-1);
2033 (*gidlist)[i++] = HCC_INT32(item);
2034 break;
2037 return (count);
2040 static int
2041 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
2043 int count, i;
2044 gid_t *gidlist;
2046 if ((count = getmygroups(&gidlist)) < 0)
2047 return (-1);
2048 hcc_leaf_int32(trans, LC_COUNT, count);
2049 for (i = 0; i < count; i++)
2050 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
2051 if (gidlist != NULL)
2052 free(gidlist);
2053 return (0);