4 * This module implements a simple remote control protocol
6 * $DragonFly: src/bin/cpdup/hcproto.c,v 1.8 2008/11/11 04:36:00 dillon Exp $
13 static int hc_decode_stat(hctransaction_t trans, struct stat *, struct HCHead *);
14 static int hc_decode_stat_item(struct stat *st, struct HCLeaf *item);
15 static int rc_encode_stat(hctransaction_t trans, struct stat *);
17 static int rc_hello(hctransaction_t trans, struct HCHead *);
18 static int rc_stat(hctransaction_t trans, struct HCHead *);
19 static int rc_lstat(hctransaction_t trans, struct HCHead *);
20 static int rc_opendir(hctransaction_t trans, struct HCHead *);
21 static int rc_readdir(hctransaction_t trans, struct HCHead *);
22 static int rc_closedir(hctransaction_t trans, struct HCHead *);
23 static int rc_scandir(hctransaction_t trans, struct HCHead *);
24 static int rc_open(hctransaction_t trans, struct HCHead *);
25 static int rc_close(hctransaction_t trans, struct HCHead *);
26 static int rc_read(hctransaction_t trans, struct HCHead *);
27 static int rc_readfile(hctransaction_t trans, struct HCHead *);
28 static int rc_write(hctransaction_t trans, struct HCHead *);
29 static int rc_remove(hctransaction_t trans, struct HCHead *);
30 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
31 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
32 static int rc_chown(hctransaction_t trans, struct HCHead *);
33 static int rc_lchown(hctransaction_t trans, struct HCHead *);
34 static int rc_chmod(hctransaction_t trans, struct HCHead *);
35 static int rc_mknod(hctransaction_t trans, struct HCHead *);
36 static int rc_link(hctransaction_t trans, struct HCHead *);
37 #ifdef _ST_FLAGS_PRESENT_
38 static int rc_chflags(hctransaction_t trans, struct HCHead *);
40 static int rc_readlink(hctransaction_t trans, struct HCHead *);
41 static int rc_umask(hctransaction_t trans, struct HCHead *);
42 static int rc_symlink(hctransaction_t trans, struct HCHead *);
43 static int rc_rename(hctransaction_t trans, struct HCHead *);
44 static int rc_utimes(hctransaction_t trans, struct HCHead *);
45 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
46 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
48 static int getmygroups(gid_t **gidlist);
50 static int silentwarning(int *, const char *, ...) __printflike(2, 3);
52 static struct HCDesc HCDispatchTable[] = {
53 { HC_HELLO, rc_hello },
55 { HC_LSTAT, rc_lstat },
56 { HC_OPENDIR, rc_opendir },
57 { HC_READDIR, rc_readdir },
58 { HC_CLOSEDIR, rc_closedir },
60 { HC_CLOSE, rc_close },
62 { HC_WRITE, rc_write },
63 { HC_REMOVE, rc_remove },
64 { HC_MKDIR, rc_mkdir },
65 { HC_RMDIR, rc_rmdir },
66 { HC_CHOWN, rc_chown },
67 { HC_LCHOWN, rc_lchown },
68 { HC_CHMOD, rc_chmod },
69 { HC_MKNOD, rc_mknod },
71 #ifdef _ST_FLAGS_PRESENT_
72 { HC_CHFLAGS, rc_chflags },
74 { HC_READLINK, rc_readlink },
75 { HC_UMASK, rc_umask },
76 { HC_SYMLINK, rc_symlink },
77 { HC_RENAME, rc_rename },
78 { HC_UTIMES, rc_utimes },
79 { HC_GETEUID, rc_geteuid },
80 { HC_GETGROUPS, rc_getgroups },
81 { HC_SCANDIR, rc_scandir },
82 { HC_READFILE, rc_readfile },
85 static int chown_warning;
86 #ifdef _ST_FLAGS_PRESENT_
87 static int chflags_warning;
91 * If not running as root generate a silent warning and return no error.
93 * If running as root return an error.
96 silentwarning(int *didwarn, const char *ctl, ...)
102 if (*didwarn == 0 && QuietOpt == 0) {
104 fprintf(stderr, "WARNING: Not running as root, ");
106 vfprintf(stderr, ctl, va);
113 hc_connect(struct HostConf *hc, int readonly)
115 if (hcc_connect(hc, readonly) < 0) {
116 fprintf(stderr, "Unable to connect to %s\n", hc->host);
119 return(hc_hello(hc));
123 hc_slave(int fdin, int fdout)
125 hcc_slave(fdin, fdout, HCDispatchTable,
126 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
130 * A HELLO RPC is sent on the initial connect.
133 hc_hello(struct HostConf *hc)
137 hctransaction_t trans;
141 bzero(hostbuf, sizeof(hostbuf));
142 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
147 trans = hcc_start_command(hc, HC_HELLO);
148 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
149 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
151 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
152 if ((head = hcc_finish_command(trans)) == NULL) {
153 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
159 fprintf(stderr, "Connected to %s but remote returned error %d\n",
160 hc->host, head->error);
165 FOR_EACH_ITEM(item, trans, head) {
166 switch(item->leafid) {
169 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
173 hc->version = HCC_INT32(item);
177 if (hc->version < HCPROTO_VERSION_COMPAT) {
178 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
181 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
182 fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
183 "expect reduced speed\n", hc->host);
186 fprintf(stderr, "Handshake failed with %s\n", hc->host);
191 rc_hello(hctransaction_t trans, struct HCHead *head)
196 FOR_EACH_ITEM(item, trans, head) {
197 if (item->leafid == LC_PATH1)
198 UseCpFile = strdup(HCC_STRING(item));
201 bzero(hostbuf, sizeof(hostbuf));
202 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
207 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
208 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
216 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
219 hctransaction_t trans;
221 if (hc == NULL || hc->host == NULL)
222 return(stat(path, st));
224 trans = hcc_start_command(hc, HC_STAT);
225 hcc_leaf_string(trans, LC_PATH1, path);
226 if ((head = hcc_finish_command(trans)) == NULL)
230 return(hc_decode_stat(trans, st, head));
234 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
237 hctransaction_t trans;
239 if (hc == NULL || hc->host == NULL)
240 return(lstat(path, st));
242 trans = hcc_start_command(hc, HC_LSTAT);
243 hcc_leaf_string(trans, LC_PATH1, path);
244 if ((head = hcc_finish_command(trans)) == NULL)
248 return(hc_decode_stat(trans, st, head));
252 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
256 bzero(st, sizeof(*st));
257 FOR_EACH_ITEM(item, trans, head)
258 hc_decode_stat_item(st, item);
263 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
265 switch(item->leafid) {
267 st->st_dev = HCC_INT32(item);
270 st->st_ino = HCC_INT64(item);
273 st->st_mode = HCC_INT32(item);
276 st->st_nlink = HCC_INT32(item);
279 st->st_uid = HCC_INT32(item);
282 st->st_gid = HCC_INT32(item);
285 st->st_rdev = HCC_INT32(item);
288 st->st_atime = (time_t)HCC_INT64(item);
291 st->st_mtime = (time_t)HCC_INT64(item);
294 st->st_ctime = (time_t)HCC_INT64(item);
297 st->st_size = HCC_INT64(item);
300 st->st_blocks = HCC_INT64(item);
303 st->st_blksize = HCC_INT32(item);
305 #ifdef _ST_FSMID_PRESENT_
307 st->st_fsmid = HCC_INT64(item);
310 #ifdef _ST_FLAGS_PRESENT_
312 st->st_flags = (uint32_t)HCC_INT64(item);
320 rc_stat(hctransaction_t trans, struct HCHead *head)
324 const char *path = NULL;
326 FOR_EACH_ITEM(item, trans, head) {
327 if (item->leafid == LC_PATH1)
328 path = HCC_STRING(item);
332 if (stat(path, &st) < 0)
334 return (rc_encode_stat(trans, &st));
338 rc_lstat(hctransaction_t trans, struct HCHead *head)
342 const char *path = NULL;
344 FOR_EACH_ITEM(item, trans, head) {
345 if (item->leafid == LC_PATH1)
346 path = HCC_STRING(item);
350 if (lstat(path, &st) < 0)
352 return (rc_encode_stat(trans, &st));
356 * Encode all entries of a stat structure.
358 * CAUTION: If you add any more entries here, be sure to
359 * increase the STAT_MAX_NUM_ENTRIES value!
361 #define STAT_MAX_NUM_ENTRIES 18
363 rc_encode_stat(hctransaction_t trans, struct stat *st)
365 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
366 hcc_leaf_int64(trans, LC_INO, st->st_ino);
367 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
368 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
369 hcc_leaf_int32(trans, LC_UID, st->st_uid);
370 hcc_leaf_int32(trans, LC_GID, st->st_gid);
371 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
372 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
373 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
374 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
375 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
376 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
377 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
378 #ifdef _ST_FSMID_PRESENT_
379 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
381 #ifdef _ST_FLAGS_PRESENT_
382 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
391 hc_opendir(struct HostConf *hc, const char *path)
393 hctransaction_t trans;
396 if (hc == NULL || hc->host == NULL)
397 return(opendir(path));
399 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
401 struct HCDirEntry *den;
404 trans = hcc_start_command(hc, HC_OPENDIR);
405 hcc_leaf_string(trans, LC_PATH1, path);
406 if ((head = hcc_finish_command(trans)) == NULL)
410 FOR_EACH_ITEM(item, trans, head) {
411 if (item->leafid == LC_DESCRIPTOR)
412 desc = HCC_INT32(item);
414 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
415 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
419 den = malloc(sizeof(*den));
420 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
421 return ((void *)desc);
424 /* hc->version >= 4: use HC_SCANDIR */
425 trans = hcc_start_command(hc, HC_SCANDIR);
426 hcc_leaf_string(trans, LC_PATH1, path);
427 if ((head = hcc_finish_command(trans)) == NULL || head->error)
429 return ((void *)head);
433 rc_opendir(hctransaction_t trans, struct HCHead *head)
436 const char *path = NULL;
440 FOR_EACH_ITEM(item, trans, head) {
441 if (item->leafid == LC_PATH1)
442 path = HCC_STRING(item);
446 if ((dir = opendir(path)) == NULL) {
449 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
450 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
459 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
464 static struct HCDirEntry denbuf;
467 if (hc == NULL || hc->host == NULL) {
468 struct dirent *sysden;
470 if ((sysden = readdir(dir)) == NULL)
472 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
476 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
477 hctransaction_t trans;
478 struct HCDirEntry *den;
480 trans = hcc_start_command(hc, HC_READDIR);
481 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
482 if ((head = hcc_finish_command(trans)) == NULL)
485 return (NULL); /* XXX errno */
486 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
488 return (NULL); /* XXX errno */
490 FOR_EACH_ITEM(item, trans, head) {
491 if (item->leafid == LC_PATH1)
492 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
494 return (den->d_name[0] ? den : NULL);
497 /* hc->version >= 4: using HC_SCANDIR */
498 denbuf.d_name[0] = 0;
500 *statpp = malloc(sizeof(struct stat));
501 bzero(*statpp, sizeof(struct stat));
502 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
503 if (item->leafid == LC_PATH1) { /* this must be the last item */
504 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
508 hc_decode_stat_item(*statpp, item);
515 if (hc->trans.state == HCT_FAIL)
517 return (denbuf.d_name[0] ? &denbuf : NULL);
521 rc_readdir(hctransaction_t trans, struct HCHead *head)
527 FOR_EACH_ITEM(item, trans, head) {
528 if (item->leafid == LC_DESCRIPTOR)
529 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
533 if ((den = readdir(dir)) != NULL)
534 hcc_leaf_string(trans, LC_PATH1, den->d_name);
541 * XXX cpdup needs to check error code to avoid truncated dirs?
544 hc_closedir(struct HostConf *hc, DIR *dir)
548 if (hc == NULL || hc->host == NULL)
549 return(closedir(dir));
551 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
552 hctransaction_t trans;
555 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
557 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
558 trans = hcc_start_command(hc, HC_CLOSEDIR);
559 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
560 if ((head = hcc_finish_command(trans)) == NULL)
563 return (-1); /* XXX errno */
571 /* hc->version >= 4: using HC_SCANDIR */
573 /* skip any remaining items if the directory is closed prematurely */
574 while (hcc_nextchaineditem(hc, head) != NULL)
576 if (hc->trans.state == HCT_FAIL || head->error)
582 rc_closedir(hctransaction_t trans, struct HCHead *head)
587 FOR_EACH_ITEM(item, trans, head) {
588 if (item->leafid == LC_DESCRIPTOR) {
589 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
591 hcc_set_descriptor(trans->hc, HCC_INT32(item),
598 return(closedir(dir));
605 rc_scandir(hctransaction_t trans, struct HCHead *head)
608 const char *path = NULL;
614 FOR_EACH_ITEM(item, trans, head) {
615 if (item->leafid == LC_PATH1)
616 path = HCC_STRING(item);
620 if ((dir = opendir(path)) == NULL)
622 while ((den = readdir(dir)) != NULL) {
623 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
624 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
625 continue; /* skip "." and ".." */
627 * Check if there's enough space left in the current packet.
628 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
629 * one is a string, so we use strlen() + 1 (terminating zero).
630 * The remaining ones are numbers; we assume sizeof(int64_t) so
631 * we're on the safe side.
633 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
634 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
635 strlen(den->d_name) + 1)) {
639 fpath = mprintf("%s/%s", path, den->d_name);
640 if (lstat(fpath, &st) == 0)
641 rc_encode_stat(trans, &st);
642 /* The name must be the last item! */
643 hcc_leaf_string(trans, LC_PATH1, den->d_name);
646 return (closedir(dir));
653 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
655 hctransaction_t trans;
662 if (NotForRealOpt && (flags & O_CREAT))
665 if (hc == NULL || hc->host == NULL) {
667 flags |= O_LARGEFILE;
669 return(open(path, flags, mode));
672 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
673 trans = hcc_start_command(hc, HC_READFILE);
674 hcc_leaf_string(trans, LC_PATH1, path);
675 if ((head = hcc_finish_command(trans)) == NULL || head->error)
677 head->magic = 0; /* used to indicate offset within buffer */
678 return (1); /* dummy */
681 nflags = flags & XO_NATIVEMASK;
689 trans = hcc_start_command(hc, HC_OPEN);
690 hcc_leaf_string(trans, LC_PATH1, path);
691 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
692 hcc_leaf_int32(trans, LC_MODE, mode);
694 if ((head = hcc_finish_command(trans)) == NULL)
698 FOR_EACH_ITEM(item, trans, head) {
699 if (item->leafid == LC_DESCRIPTOR)
700 desc = HCC_INT32(item);
702 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
703 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
707 fdp = malloc(sizeof(int));
708 *fdp = desc; /* really just a dummy */
709 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
714 rc_open(hctransaction_t trans, struct HCHead *head)
717 const char *path = NULL;
725 FOR_EACH_ITEM(item, trans, head) {
726 switch(item->leafid) {
728 path = HCC_STRING(item);
731 nflags = HCC_INT32(item);
734 mode = HCC_INT32(item);
741 flags = nflags & XO_NATIVEMASK;
742 if (nflags & XO_CREAT)
744 if (nflags & XO_EXCL)
746 if (nflags & XO_TRUNC)
750 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
751 head->error = EACCES;
758 flags |= O_LARGEFILE;
760 if ((fd = open(path, flags, mode)) < 0)
762 fdp = malloc(sizeof(int));
764 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
765 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
773 hc_close(struct HostConf *hc, int fd)
775 hctransaction_t trans;
779 if (NotForRealOpt && fd == 0x7FFFFFFF)
781 if (hc == NULL || hc->host == NULL)
784 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
785 head = (void *)hc->trans.rbuf;
786 /* skip any remaining items if the file is closed prematurely */
787 while (hcc_nextchaineditem(hc, head) != NULL)
789 if (hc->trans.state == HCT_FAIL || head->error)
794 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
797 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
799 trans = hcc_start_command(hc, HC_CLOSE);
800 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
801 if ((head = hcc_finish_command(trans)) == NULL)
812 rc_close(hctransaction_t trans, struct HCHead *head)
819 FOR_EACH_ITEM(item, trans, head) {
820 if (item->leafid == LC_DESCRIPTOR)
821 desc = HCC_INT32(item);
825 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
829 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
843 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
845 hctransaction_t trans;
853 if (hc == NULL || hc->host == NULL)
854 return(read(fd, buf, bytes));
856 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
857 head = (void *)hc->trans.rbuf;
859 if ((offset = head->magic) != 0) {
860 item = hcc_currentchaineditem(hc, head);
862 item = hcc_nextchaineditem(hc, head);
865 if (hc->trans.state == HCT_FAIL)
869 if (item->leafid != LC_DATA)
871 x = item->bytes - sizeof(*item) - offset;
872 if (x > (int)bytes) {
874 head->magic += x; /* leave bytes in the buffer */
877 head->magic = 0; /* all bytes used up */
878 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
879 buf = (char *)buf + x;
886 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
889 size_t limit = getiolimit();
890 int n = (bytes > limit) ? limit : bytes;
892 trans = hcc_start_command(hc, HC_READ);
893 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
894 hcc_leaf_int32(trans, LC_BYTES, n);
895 if ((head = hcc_finish_command(trans)) == NULL)
899 FOR_EACH_ITEM(item, trans, head) {
900 if (item->leafid == LC_DATA) {
901 x = item->bytes - sizeof(*item);
904 bcopy(HCC_BINARYDATA(item), buf, x);
905 buf = (char *)buf + x;
920 rc_read(hctransaction_t trans, struct HCHead *head)
928 FOR_EACH_ITEM(item, trans, head) {
929 switch(item->leafid) {
931 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
934 bytes = HCC_INT32(item);
940 if (bytes < 0 || bytes > 32768)
942 n = read(*fdp, buf, bytes);
945 hcc_leaf_data(trans, LC_DATA, buf, n);
953 rc_readfile(hctransaction_t trans, struct HCHead *head)
956 const char *path = NULL;
961 FOR_EACH_ITEM(item, trans, head) {
962 if (item->leafid == LC_PATH1)
963 path = HCC_STRING(item);
967 if ((fd = open(path, O_RDONLY)) < 0)
969 while ((n = read(fd, buf, 32768)) >= 0) {
970 if (!hcc_check_space(trans, head, 1, n)) {
974 hcc_leaf_data(trans, LC_DATA, buf, n);
989 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
991 hctransaction_t trans;
1000 if (hc == NULL || hc->host == NULL)
1001 return(write(fd, buf, bytes));
1003 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1007 size_t limit = getiolimit();
1008 int n = (bytes > limit) ? limit : bytes;
1011 trans = hcc_start_command(hc, HC_WRITE);
1012 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1013 hcc_leaf_data(trans, LC_DATA, buf, n);
1014 if ((head = hcc_finish_command(trans)) == NULL)
1018 FOR_EACH_ITEM(item, trans, head) {
1019 if (item->leafid == LC_BYTES)
1020 x = HCC_INT32(item);
1025 buf = (const char *)buf + x;
1037 rc_write(hctransaction_t trans, struct HCHead *head)
1039 struct HCLeaf *item;
1044 FOR_EACH_ITEM(item, trans, head) {
1045 switch(item->leafid) {
1047 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1050 buf = HCC_BINARYDATA(item);
1051 n = item->bytes - sizeof(*item);
1056 head->error = EACCES;
1061 if (n < 0 || n > 32768)
1063 n = write(*fdp, buf, n);
1066 hcc_leaf_int32(trans, LC_BYTES, n);
1073 * NOTE: This function returns -errno if an error occured.
1076 hc_remove(struct HostConf *hc, const char *path)
1078 hctransaction_t trans;
1079 struct HCHead *head;
1084 if (hc == NULL || hc->host == NULL) {
1091 trans = hcc_start_command(hc, HC_REMOVE);
1092 hcc_leaf_string(trans, LC_PATH1, path);
1093 if ((head = hcc_finish_command(trans)) == NULL)
1096 return(-(int)head->error);
1101 rc_remove(hctransaction_t trans, struct HCHead *head)
1103 struct HCLeaf *item;
1104 const char *path = NULL;
1106 FOR_EACH_ITEM(item, trans, head) {
1107 if (item->leafid == LC_PATH1)
1108 path = HCC_STRING(item);
1113 head->error = EACCES;
1116 return(remove(path));
1123 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1125 hctransaction_t trans;
1126 struct HCHead *head;
1130 if (hc == NULL || hc->host == NULL)
1131 return(mkdir(path, mode));
1133 trans = hcc_start_command(hc, HC_MKDIR);
1134 hcc_leaf_string(trans, LC_PATH1, path);
1135 hcc_leaf_int32(trans, LC_MODE, mode);
1136 if ((head = hcc_finish_command(trans)) == NULL)
1144 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1146 struct HCLeaf *item;
1147 const char *path = NULL;
1150 FOR_EACH_ITEM(item, trans, head) {
1151 switch(item->leafid) {
1153 path = HCC_STRING(item);
1156 mode = HCC_INT32(item);
1161 head->error = EACCES;
1166 return(mkdir(path, mode));
1173 hc_rmdir(struct HostConf *hc, const char *path)
1175 hctransaction_t trans;
1176 struct HCHead *head;
1180 if (hc == NULL || hc->host == NULL)
1181 return(rmdir(path));
1183 trans = hcc_start_command(hc, HC_RMDIR);
1184 hcc_leaf_string(trans, LC_PATH1, path);
1185 if ((head = hcc_finish_command(trans)) == NULL)
1193 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1195 struct HCLeaf *item;
1196 const char *path = NULL;
1198 FOR_EACH_ITEM(item, trans, head) {
1199 if (item->leafid == LC_PATH1)
1200 path = HCC_STRING(item);
1203 head->error = EACCES;
1208 return(rmdir(path));
1214 * Almost silently ignore chowns that fail if we are not root.
1217 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1219 hctransaction_t trans;
1220 struct HCHead *head;
1228 if (hc == NULL || hc->host == NULL) {
1229 rc = chown(path, owner, group);
1231 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1235 trans = hcc_start_command(hc, HC_CHOWN);
1236 hcc_leaf_string(trans, LC_PATH1, path);
1237 hcc_leaf_int32(trans, LC_UID, owner);
1238 hcc_leaf_int32(trans, LC_GID, group);
1239 if ((head = hcc_finish_command(trans)) == NULL)
1247 rc_chown(hctransaction_t trans, struct HCHead *head)
1249 struct HCLeaf *item;
1250 const char *path = NULL;
1251 uid_t uid = (uid_t)-1;
1252 gid_t gid = (gid_t)-1;
1255 FOR_EACH_ITEM(item, trans, head) {
1256 switch(item->leafid) {
1258 path = HCC_STRING(item);
1261 uid = HCC_INT32(item);
1264 gid = HCC_INT32(item);
1269 head->error = EACCES;
1274 rc = chown(path, uid, gid);
1276 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1284 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1286 hctransaction_t trans;
1287 struct HCHead *head;
1295 if (hc == NULL || hc->host == NULL) {
1296 rc = lchown(path, owner, group);
1298 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1302 trans = hcc_start_command(hc, HC_LCHOWN);
1303 hcc_leaf_string(trans, LC_PATH1, path);
1304 hcc_leaf_int32(trans, LC_UID, owner);
1305 hcc_leaf_int32(trans, LC_GID, group);
1306 if ((head = hcc_finish_command(trans)) == NULL)
1314 rc_lchown(hctransaction_t trans, struct HCHead *head)
1316 struct HCLeaf *item;
1317 const char *path = NULL;
1318 uid_t uid = (uid_t)-1;
1319 gid_t gid = (gid_t)-1;
1322 FOR_EACH_ITEM(item, trans, head) {
1323 switch(item->leafid) {
1325 path = HCC_STRING(item);
1328 uid = HCC_INT32(item);
1331 gid = HCC_INT32(item);
1336 head->error = EACCES;
1341 rc = lchown(path, uid, gid);
1343 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1351 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1353 hctransaction_t trans;
1354 struct HCHead *head;
1358 if (hc == NULL || hc->host == NULL)
1359 return(chmod(path, mode));
1361 trans = hcc_start_command(hc, HC_CHMOD);
1362 hcc_leaf_string(trans, LC_PATH1, path);
1363 hcc_leaf_int32(trans, LC_MODE, mode);
1364 if ((head = hcc_finish_command(trans)) == NULL)
1372 rc_chmod(hctransaction_t trans, struct HCHead *head)
1374 struct HCLeaf *item;
1375 const char *path = NULL;
1378 FOR_EACH_ITEM(item, trans, head) {
1379 switch(item->leafid) {
1381 path = HCC_STRING(item);
1384 mode = HCC_INT32(item);
1389 head->error = EACCES;
1394 return(chmod(path, mode));
1401 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1403 hctransaction_t trans;
1404 struct HCHead *head;
1408 if (!DstRootPrivs) {
1409 /* mknod() requires root privs, so don't bother. */
1414 if (hc == NULL || hc->host == NULL)
1415 return(mknod(path, mode, rdev));
1417 trans = hcc_start_command(hc, HC_MKNOD);
1418 hcc_leaf_string(trans, LC_PATH1, path);
1419 hcc_leaf_int32(trans, LC_MODE, mode);
1420 hcc_leaf_int32(trans, LC_RDEV, rdev);
1421 if ((head = hcc_finish_command(trans)) == NULL)
1429 rc_mknod(hctransaction_t trans, struct HCHead *head)
1431 struct HCLeaf *item;
1432 const char *path = NULL;
1436 FOR_EACH_ITEM(item, trans, head) {
1437 switch(item->leafid) {
1439 path = HCC_STRING(item);
1442 mode = HCC_INT32(item);
1445 rdev = HCC_INT32(item);
1450 head->error = EACCES;
1455 return(mknod(path, mode, rdev));
1462 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1464 hctransaction_t trans;
1465 struct HCHead *head;
1469 if (hc == NULL || hc->host == NULL)
1470 return(link(name1, name2));
1472 trans = hcc_start_command(hc, HC_LINK);
1473 hcc_leaf_string(trans, LC_PATH1, name1);
1474 hcc_leaf_string(trans, LC_PATH2, name2);
1475 if ((head = hcc_finish_command(trans)) == NULL)
1483 rc_link(hctransaction_t trans, struct HCHead *head)
1485 struct HCLeaf *item;
1486 const char *name1 = NULL;
1487 const char *name2 = NULL;
1489 FOR_EACH_ITEM(item, trans, head) {
1490 switch(item->leafid) {
1492 name1 = HCC_STRING(item);
1495 name2 = HCC_STRING(item);
1500 head->error = EACCES;
1503 if (name1 == NULL || name2 == NULL)
1505 return(link(name1, name2));
1508 #ifdef _ST_FLAGS_PRESENT_
1513 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1515 hctransaction_t trans;
1516 struct HCHead *head;
1522 flags &= UF_SETTABLE;
1524 if (hc == NULL || hc->host == NULL) {
1525 if ((rc = chflags(path, flags)) < 0)
1526 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1530 trans = hcc_start_command(hc, HC_CHFLAGS);
1531 hcc_leaf_string(trans, LC_PATH1, path);
1532 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1533 if ((head = hcc_finish_command(trans)) == NULL)
1541 rc_chflags(hctransaction_t trans, struct HCHead *head)
1543 struct HCLeaf *item;
1544 const char *path = NULL;
1548 FOR_EACH_ITEM(item, trans, head) {
1549 switch(item->leafid) {
1551 path = HCC_STRING(item);
1554 flags = (u_long)HCC_INT64(item);
1559 head->error = EACCES;
1564 if ((rc = chflags(path, flags)) < 0)
1565 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1575 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1577 hctransaction_t trans;
1578 struct HCHead *head;
1579 struct HCLeaf *item;
1582 if (hc == NULL || hc->host == NULL)
1583 return(readlink(path, buf, bufsiz));
1585 trans = hcc_start_command(hc, HC_READLINK);
1586 hcc_leaf_string(trans, LC_PATH1, path);
1587 if ((head = hcc_finish_command(trans)) == NULL)
1593 FOR_EACH_ITEM(item, trans, head) {
1594 if (item->leafid == LC_DATA) {
1595 r = item->bytes - sizeof(*item);
1600 bcopy(HCC_BINARYDATA(item), buf, r);
1607 rc_readlink(hctransaction_t trans, struct HCHead *head)
1609 struct HCLeaf *item;
1610 const char *path = NULL;
1614 FOR_EACH_ITEM(item, trans, head) {
1615 if (item->leafid == LC_PATH1)
1616 path = HCC_STRING(item);
1620 r = readlink(path, buf, sizeof(buf));
1623 hcc_leaf_data(trans, LC_DATA, buf, r);
1631 hc_umask(struct HostConf *hc, mode_t numask)
1633 hctransaction_t trans;
1634 struct HCHead *head;
1635 struct HCLeaf *item;
1638 return(umask(numask));
1639 if (hc == NULL || hc->host == NULL)
1640 return(umask(numask));
1642 trans = hcc_start_command(hc, HC_UMASK);
1643 hcc_leaf_int32(trans, LC_MODE, numask);
1644 if ((head = hcc_finish_command(trans)) == NULL)
1649 numask = (mode_t) ~0666U;
1650 FOR_EACH_ITEM(item, trans, head) {
1651 if (item->leafid == LC_MODE)
1652 numask = HCC_INT32(item);
1658 rc_umask(hctransaction_t trans, struct HCHead *head)
1660 struct HCLeaf *item;
1661 mode_t numask = (mode_t) ~0666U;
1663 FOR_EACH_ITEM(item, trans, head) {
1664 if (item->leafid == LC_MODE)
1665 numask = HCC_INT32(item);
1667 numask = umask(numask);
1668 hcc_leaf_int32(trans, LC_MODE, numask);
1676 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1678 hctransaction_t trans;
1679 struct HCHead *head;
1683 if (hc == NULL || hc->host == NULL)
1684 return(symlink(name1, name2));
1686 trans = hcc_start_command(hc, HC_SYMLINK);
1687 hcc_leaf_string(trans, LC_PATH1, name1);
1688 hcc_leaf_string(trans, LC_PATH2, name2);
1689 if ((head = hcc_finish_command(trans)) == NULL)
1697 rc_symlink(hctransaction_t trans, struct HCHead *head)
1699 struct HCLeaf *item;
1700 const char *name1 = NULL;
1701 const char *name2 = NULL;
1703 FOR_EACH_ITEM(item, trans, head) {
1704 switch(item->leafid) {
1706 name1 = HCC_STRING(item);
1709 name2 = HCC_STRING(item);
1714 head->error = EACCES;
1717 if (name1 == NULL || name2 == NULL)
1719 return(symlink(name1, name2));
1726 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1728 hctransaction_t trans;
1729 struct HCHead *head;
1733 if (hc == NULL || hc->host == NULL)
1734 return(rename(name1, name2));
1736 trans = hcc_start_command(hc, HC_RENAME);
1737 hcc_leaf_string(trans, LC_PATH1, name1);
1738 hcc_leaf_string(trans, LC_PATH2, name2);
1739 if ((head = hcc_finish_command(trans)) == NULL)
1747 rc_rename(hctransaction_t trans, struct HCHead *head)
1749 struct HCLeaf *item;
1750 const char *name1 = NULL;
1751 const char *name2 = NULL;
1753 FOR_EACH_ITEM(item, trans, head) {
1754 switch(item->leafid) {
1756 name1 = HCC_STRING(item);
1759 name2 = HCC_STRING(item);
1764 head->error = EACCES;
1767 if (name1 == NULL || name2 == NULL)
1769 return(rename(name1, name2));
1776 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1778 hctransaction_t trans;
1779 struct HCHead *head;
1783 if (hc == NULL || hc->host == NULL)
1784 return(utimes(path, times));
1786 trans = hcc_start_command(hc, HC_UTIMES);
1787 hcc_leaf_string(trans, LC_PATH1, path);
1788 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1789 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1790 if ((head = hcc_finish_command(trans)) == NULL)
1798 rc_utimes(hctransaction_t trans, struct HCHead *head)
1800 struct HCLeaf *item;
1801 struct timeval times[2];
1804 bzero(times, sizeof(times));
1807 FOR_EACH_ITEM(item, trans, head) {
1808 switch(item->leafid) {
1810 path = HCC_STRING(item);
1813 times[0].tv_sec = HCC_INT64(item);
1816 times[1].tv_sec = HCC_INT64(item);
1821 head->error = EACCES;
1826 return(utimes(path, times));
1830 hc_geteuid(struct HostConf *hc)
1832 hctransaction_t trans;
1833 struct HCHead *head;
1834 struct HCLeaf *item;
1836 if (hc == NULL || hc->host == NULL)
1839 if (hc->version < 3) {
1840 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1841 /* Return 0 on error, so the caller assumes root privileges. */
1845 trans = hcc_start_command(hc, HC_GETEUID);
1846 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1848 FOR_EACH_ITEM(item, trans, head) {
1849 if (item->leafid == LC_UID)
1850 return (HCC_INT32(item));
1852 return(0); /* shouldn't happen */
1856 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1858 hcc_leaf_int32(trans, LC_UID, geteuid());
1863 getmygroups(gid_t **gidlist)
1867 if ((count = getgroups(0, *gidlist)) > 0) {
1868 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1869 if ((count = getgroups(count, *gidlist)) <= 0)
1881 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1884 hctransaction_t trans;
1885 struct HCHead *head;
1886 struct HCLeaf *item;
1888 if (hc == NULL || hc->host == NULL)
1889 return (getmygroups(gidlist));
1895 if (hc->version < 3) {
1896 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1900 trans = hcc_start_command(hc, HC_GETGROUPS);
1901 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1903 FOR_EACH_ITEM(item, trans, head) {
1904 switch(item->leafid) {
1906 count = HCC_INT32(item);
1907 if (*gidlist != NULL) { /* protocol error */
1912 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1916 if (*gidlist == NULL || i >= count) { /* protocol error */
1917 if (*gidlist != NULL)
1922 (*gidlist)[i++] = HCC_INT32(item);
1930 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1935 if ((count = getmygroups(&gidlist)) < 0)
1937 hcc_leaf_int32(trans, LC_COUNT, count);
1938 for (i = 0; i < count; i++)
1939 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1940 if (gidlist != NULL)