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 static int chflags_warning;
89 * If not running as root generate a silent warning and return no error.
91 * If running as root return an error.
94 silentwarning(int *didwarn, const char *ctl, ...)
100 if (*didwarn == 0 && QuietOpt == 0) {
102 fprintf(stderr, "WARNING: Not running as root, ");
104 vfprintf(stderr, ctl, va);
111 hc_connect(struct HostConf *hc, int readonly)
113 if (hcc_connect(hc, readonly) < 0) {
114 fprintf(stderr, "Unable to connect to %s\n", hc->host);
117 return(hc_hello(hc));
121 hc_slave(int fdin, int fdout)
123 hcc_slave(fdin, fdout, HCDispatchTable,
124 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
128 * A HELLO RPC is sent on the initial connect.
131 hc_hello(struct HostConf *hc)
135 hctransaction_t trans;
139 bzero(hostbuf, sizeof(hostbuf));
140 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
145 trans = hcc_start_command(hc, HC_HELLO);
146 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
147 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
149 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
150 if ((head = hcc_finish_command(trans)) == NULL) {
151 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
157 fprintf(stderr, "Connected to %s but remote returned error %d\n",
158 hc->host, head->error);
163 FOR_EACH_ITEM(item, trans, head) {
164 switch(item->leafid) {
167 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
171 hc->version = HCC_INT32(item);
175 if (hc->version < HCPROTO_VERSION_COMPAT) {
176 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
179 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
180 fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
181 "expect reduced speed\n", hc->host);
184 fprintf(stderr, "Handshake failed with %s\n", hc->host);
189 rc_hello(hctransaction_t trans, struct HCHead *head)
194 FOR_EACH_ITEM(item, trans, head) {
195 if (item->leafid == LC_PATH1)
196 UseCpFile = strdup(HCC_STRING(item));
199 bzero(hostbuf, sizeof(hostbuf));
200 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
205 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
206 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
214 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
217 hctransaction_t trans;
219 if (hc == NULL || hc->host == NULL)
220 return(stat(path, st));
222 trans = hcc_start_command(hc, HC_STAT);
223 hcc_leaf_string(trans, LC_PATH1, path);
224 if ((head = hcc_finish_command(trans)) == NULL)
228 return(hc_decode_stat(trans, st, head));
232 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
235 hctransaction_t trans;
237 if (hc == NULL || hc->host == NULL)
238 return(lstat(path, st));
240 trans = hcc_start_command(hc, HC_LSTAT);
241 hcc_leaf_string(trans, LC_PATH1, path);
242 if ((head = hcc_finish_command(trans)) == NULL)
246 return(hc_decode_stat(trans, st, head));
250 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
254 bzero(st, sizeof(*st));
255 FOR_EACH_ITEM(item, trans, head)
256 hc_decode_stat_item(st, item);
261 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
263 switch(item->leafid) {
265 st->st_dev = HCC_INT32(item);
268 st->st_ino = HCC_INT64(item);
271 st->st_mode = HCC_INT32(item);
274 st->st_nlink = HCC_INT32(item);
277 st->st_uid = HCC_INT32(item);
280 st->st_gid = HCC_INT32(item);
283 st->st_rdev = HCC_INT32(item);
286 st->st_atime = (time_t)HCC_INT64(item);
289 st->st_mtime = (time_t)HCC_INT64(item);
292 st->st_ctime = (time_t)HCC_INT64(item);
295 st->st_size = HCC_INT64(item);
298 st->st_blocks = HCC_INT64(item);
301 st->st_blksize = HCC_INT32(item);
303 #ifdef _ST_FSMID_PRESENT_
305 st->st_fsmid = HCC_INT64(item);
308 #ifdef _ST_FLAGS_PRESENT_
310 st->st_flags = (uint32_t)HCC_INT64(item);
318 rc_stat(hctransaction_t trans, struct HCHead *head)
322 const char *path = NULL;
324 FOR_EACH_ITEM(item, trans, head) {
325 if (item->leafid == LC_PATH1)
326 path = HCC_STRING(item);
330 if (stat(path, &st) < 0)
332 return (rc_encode_stat(trans, &st));
336 rc_lstat(hctransaction_t trans, struct HCHead *head)
340 const char *path = NULL;
342 FOR_EACH_ITEM(item, trans, head) {
343 if (item->leafid == LC_PATH1)
344 path = HCC_STRING(item);
348 if (lstat(path, &st) < 0)
350 return (rc_encode_stat(trans, &st));
354 * Encode all entries of a stat structure.
356 * CAUTION: If you add any more entries here, be sure to
357 * increase the STAT_MAX_NUM_ENTRIES value!
359 #define STAT_MAX_NUM_ENTRIES 18
361 rc_encode_stat(hctransaction_t trans, struct stat *st)
363 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
364 hcc_leaf_int64(trans, LC_INO, st->st_ino);
365 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
366 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
367 hcc_leaf_int32(trans, LC_UID, st->st_uid);
368 hcc_leaf_int32(trans, LC_GID, st->st_gid);
369 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
370 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
371 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
372 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
373 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
374 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
375 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
376 #ifdef _ST_FSMID_PRESENT_
377 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
379 #ifdef _ST_FLAGS_PRESENT_
380 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
389 hc_opendir(struct HostConf *hc, const char *path)
391 hctransaction_t trans;
394 if (hc == NULL || hc->host == NULL)
395 return(opendir(path));
397 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
399 struct HCDirEntry *den;
402 trans = hcc_start_command(hc, HC_OPENDIR);
403 hcc_leaf_string(trans, LC_PATH1, path);
404 if ((head = hcc_finish_command(trans)) == NULL)
408 FOR_EACH_ITEM(item, trans, head) {
409 if (item->leafid == LC_DESCRIPTOR)
410 desc = HCC_INT32(item);
412 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
413 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
417 den = malloc(sizeof(*den));
418 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
419 return ((void *)desc);
422 /* hc->version >= 4: use HC_SCANDIR */
423 trans = hcc_start_command(hc, HC_SCANDIR);
424 hcc_leaf_string(trans, LC_PATH1, path);
425 if ((head = hcc_finish_command(trans)) == NULL || head->error)
427 return ((void *)head);
431 rc_opendir(hctransaction_t trans, struct HCHead *head)
434 const char *path = NULL;
438 FOR_EACH_ITEM(item, trans, head) {
439 if (item->leafid == LC_PATH1)
440 path = HCC_STRING(item);
444 if ((dir = opendir(path)) == NULL) {
447 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
448 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
457 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
462 static struct HCDirEntry denbuf;
465 if (hc == NULL || hc->host == NULL) {
466 struct dirent *sysden;
468 if ((sysden = readdir(dir)) == NULL)
470 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
474 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
475 hctransaction_t trans;
476 struct HCDirEntry *den;
478 trans = hcc_start_command(hc, HC_READDIR);
479 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
480 if ((head = hcc_finish_command(trans)) == NULL)
483 return (NULL); /* XXX errno */
484 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
486 return (NULL); /* XXX errno */
488 FOR_EACH_ITEM(item, trans, head) {
489 if (item->leafid == LC_PATH1)
490 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
492 return (den->d_name[0] ? den : NULL);
495 /* hc->version >= 4: using HC_SCANDIR */
496 denbuf.d_name[0] = 0;
498 *statpp = malloc(sizeof(struct stat));
499 bzero(*statpp, sizeof(struct stat));
500 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
501 if (item->leafid == LC_PATH1) { /* this must be the last item */
502 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
506 hc_decode_stat_item(*statpp, item);
513 if (hc->trans.state == HCT_FAIL)
515 return (denbuf.d_name[0] ? &denbuf : NULL);
519 rc_readdir(hctransaction_t trans, struct HCHead *head)
525 FOR_EACH_ITEM(item, trans, head) {
526 if (item->leafid == LC_DESCRIPTOR)
527 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
531 if ((den = readdir(dir)) != NULL)
532 hcc_leaf_string(trans, LC_PATH1, den->d_name);
539 * XXX cpdup needs to check error code to avoid truncated dirs?
542 hc_closedir(struct HostConf *hc, DIR *dir)
546 if (hc == NULL || hc->host == NULL)
547 return(closedir(dir));
549 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
550 hctransaction_t trans;
553 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
555 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
556 trans = hcc_start_command(hc, HC_CLOSEDIR);
557 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
558 if ((head = hcc_finish_command(trans)) == NULL)
561 return (-1); /* XXX errno */
569 /* hc->version >= 4: using HC_SCANDIR */
571 /* skip any remaining items if the directory is closed prematurely */
572 while (hcc_nextchaineditem(hc, head) != NULL)
574 if (hc->trans.state == HCT_FAIL || head->error)
580 rc_closedir(hctransaction_t trans, struct HCHead *head)
585 FOR_EACH_ITEM(item, trans, head) {
586 if (item->leafid == LC_DESCRIPTOR) {
587 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
589 hcc_set_descriptor(trans->hc, HCC_INT32(item),
596 return(closedir(dir));
603 rc_scandir(hctransaction_t trans, struct HCHead *head)
606 const char *path = NULL;
612 FOR_EACH_ITEM(item, trans, head) {
613 if (item->leafid == LC_PATH1)
614 path = HCC_STRING(item);
618 if ((dir = opendir(path)) == NULL)
620 while ((den = readdir(dir)) != NULL) {
621 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
622 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
623 continue; /* skip "." and ".." */
625 * Check if there's enough space left in the current packet.
626 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
627 * one is a string, so we use strlen() + 1 (terminating zero).
628 * The remaining ones are numbers; we assume sizeof(int64_t) so
629 * we're on the safe side.
631 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
632 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
633 strlen(den->d_name) + 1)) {
637 fpath = mprintf("%s/%s", path, den->d_name);
638 if (lstat(fpath, &st) == 0)
639 rc_encode_stat(trans, &st);
640 /* The name must be the last item! */
641 hcc_leaf_string(trans, LC_PATH1, den->d_name);
644 return (closedir(dir));
651 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
653 hctransaction_t trans;
660 if (NotForRealOpt && (flags & O_CREAT))
663 if (hc == NULL || hc->host == NULL) {
665 flags |= O_LARGEFILE;
667 return(open(path, flags, mode));
670 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
671 trans = hcc_start_command(hc, HC_READFILE);
672 hcc_leaf_string(trans, LC_PATH1, path);
673 if ((head = hcc_finish_command(trans)) == NULL || head->error)
675 head->magic = 0; /* used to indicate offset within buffer */
676 return (1); /* dummy */
679 nflags = flags & XO_NATIVEMASK;
687 trans = hcc_start_command(hc, HC_OPEN);
688 hcc_leaf_string(trans, LC_PATH1, path);
689 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
690 hcc_leaf_int32(trans, LC_MODE, mode);
692 if ((head = hcc_finish_command(trans)) == NULL)
696 FOR_EACH_ITEM(item, trans, head) {
697 if (item->leafid == LC_DESCRIPTOR)
698 desc = HCC_INT32(item);
700 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
701 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
705 fdp = malloc(sizeof(int));
706 *fdp = desc; /* really just a dummy */
707 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
712 rc_open(hctransaction_t trans, struct HCHead *head)
715 const char *path = NULL;
723 FOR_EACH_ITEM(item, trans, head) {
724 switch(item->leafid) {
726 path = HCC_STRING(item);
729 nflags = HCC_INT32(item);
732 mode = HCC_INT32(item);
739 flags = nflags & XO_NATIVEMASK;
740 if (nflags & XO_CREAT)
742 if (nflags & XO_EXCL)
744 if (nflags & XO_TRUNC)
748 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
749 head->error = EACCES;
756 flags |= O_LARGEFILE;
758 if ((fd = open(path, flags, mode)) < 0)
760 fdp = malloc(sizeof(int));
762 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
763 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
771 hc_close(struct HostConf *hc, int fd)
773 hctransaction_t trans;
777 if (NotForRealOpt && fd == 0x7FFFFFFF)
779 if (hc == NULL || hc->host == NULL)
782 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
783 head = (void *)hc->trans.rbuf;
784 /* skip any remaining items if the file is closed prematurely */
785 while (hcc_nextchaineditem(hc, head) != NULL)
787 if (hc->trans.state == HCT_FAIL || head->error)
792 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
795 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
797 trans = hcc_start_command(hc, HC_CLOSE);
798 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
799 if ((head = hcc_finish_command(trans)) == NULL)
810 rc_close(hctransaction_t trans, struct HCHead *head)
817 FOR_EACH_ITEM(item, trans, head) {
818 if (item->leafid == LC_DESCRIPTOR)
819 desc = HCC_INT32(item);
823 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
827 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
841 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
843 hctransaction_t trans;
851 if (hc == NULL || hc->host == NULL)
852 return(read(fd, buf, bytes));
854 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
855 head = (void *)hc->trans.rbuf;
857 if ((offset = head->magic) != 0) {
858 item = hcc_currentchaineditem(hc, head);
860 item = hcc_nextchaineditem(hc, head);
863 if (hc->trans.state == HCT_FAIL)
867 if (item->leafid != LC_DATA)
869 x = item->bytes - sizeof(*item) - offset;
870 if (x > (int)bytes) {
872 head->magic += x; /* leave bytes in the buffer */
875 head->magic = 0; /* all bytes used up */
876 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
877 buf = (char *)buf + x;
884 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
887 size_t limit = getiolimit();
888 int n = (bytes > limit) ? limit : bytes;
890 trans = hcc_start_command(hc, HC_READ);
891 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
892 hcc_leaf_int32(trans, LC_BYTES, n);
893 if ((head = hcc_finish_command(trans)) == NULL)
897 FOR_EACH_ITEM(item, trans, head) {
898 if (item->leafid == LC_DATA) {
899 x = item->bytes - sizeof(*item);
902 bcopy(HCC_BINARYDATA(item), buf, x);
903 buf = (char *)buf + x;
918 rc_read(hctransaction_t trans, struct HCHead *head)
926 FOR_EACH_ITEM(item, trans, head) {
927 switch(item->leafid) {
929 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
932 bytes = HCC_INT32(item);
938 if (bytes < 0 || bytes > 32768)
940 n = read(*fdp, buf, bytes);
943 hcc_leaf_data(trans, LC_DATA, buf, n);
951 rc_readfile(hctransaction_t trans, struct HCHead *head)
954 const char *path = NULL;
959 FOR_EACH_ITEM(item, trans, head) {
960 if (item->leafid == LC_PATH1)
961 path = HCC_STRING(item);
965 if ((fd = open(path, O_RDONLY)) < 0)
967 while ((n = read(fd, buf, 32768)) >= 0) {
968 if (!hcc_check_space(trans, head, 1, n)) {
972 hcc_leaf_data(trans, LC_DATA, buf, n);
987 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
989 hctransaction_t trans;
998 if (hc == NULL || hc->host == NULL)
999 return(write(fd, buf, bytes));
1001 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1005 size_t limit = getiolimit();
1006 int n = (bytes > limit) ? limit : bytes;
1009 trans = hcc_start_command(hc, HC_WRITE);
1010 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1011 hcc_leaf_data(trans, LC_DATA, buf, n);
1012 if ((head = hcc_finish_command(trans)) == NULL)
1016 FOR_EACH_ITEM(item, trans, head) {
1017 if (item->leafid == LC_BYTES)
1018 x = HCC_INT32(item);
1023 buf = (const char *)buf + x;
1035 rc_write(hctransaction_t trans, struct HCHead *head)
1037 struct HCLeaf *item;
1042 FOR_EACH_ITEM(item, trans, head) {
1043 switch(item->leafid) {
1045 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1048 buf = HCC_BINARYDATA(item);
1049 n = item->bytes - sizeof(*item);
1054 head->error = EACCES;
1059 if (n < 0 || n > 32768)
1061 n = write(*fdp, buf, n);
1064 hcc_leaf_int32(trans, LC_BYTES, n);
1071 * NOTE: This function returns -errno if an error occured.
1074 hc_remove(struct HostConf *hc, const char *path)
1076 hctransaction_t trans;
1077 struct HCHead *head;
1082 if (hc == NULL || hc->host == NULL) {
1089 trans = hcc_start_command(hc, HC_REMOVE);
1090 hcc_leaf_string(trans, LC_PATH1, path);
1091 if ((head = hcc_finish_command(trans)) == NULL)
1094 return(-(int)head->error);
1099 rc_remove(hctransaction_t trans, struct HCHead *head)
1101 struct HCLeaf *item;
1102 const char *path = NULL;
1104 FOR_EACH_ITEM(item, trans, head) {
1105 if (item->leafid == LC_PATH1)
1106 path = HCC_STRING(item);
1111 head->error = EACCES;
1114 return(remove(path));
1121 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1123 hctransaction_t trans;
1124 struct HCHead *head;
1128 if (hc == NULL || hc->host == NULL)
1129 return(mkdir(path, mode));
1131 trans = hcc_start_command(hc, HC_MKDIR);
1132 hcc_leaf_string(trans, LC_PATH1, path);
1133 hcc_leaf_int32(trans, LC_MODE, mode);
1134 if ((head = hcc_finish_command(trans)) == NULL)
1142 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1144 struct HCLeaf *item;
1145 const char *path = NULL;
1148 FOR_EACH_ITEM(item, trans, head) {
1149 switch(item->leafid) {
1151 path = HCC_STRING(item);
1154 mode = HCC_INT32(item);
1159 head->error = EACCES;
1164 return(mkdir(path, mode));
1171 hc_rmdir(struct HostConf *hc, const char *path)
1173 hctransaction_t trans;
1174 struct HCHead *head;
1178 if (hc == NULL || hc->host == NULL)
1179 return(rmdir(path));
1181 trans = hcc_start_command(hc, HC_RMDIR);
1182 hcc_leaf_string(trans, LC_PATH1, path);
1183 if ((head = hcc_finish_command(trans)) == NULL)
1191 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1193 struct HCLeaf *item;
1194 const char *path = NULL;
1196 FOR_EACH_ITEM(item, trans, head) {
1197 if (item->leafid == LC_PATH1)
1198 path = HCC_STRING(item);
1201 head->error = EACCES;
1206 return(rmdir(path));
1212 * Almost silently ignore chowns that fail if we are not root.
1215 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1217 hctransaction_t trans;
1218 struct HCHead *head;
1226 if (hc == NULL || hc->host == NULL) {
1227 rc = chown(path, owner, group);
1229 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1233 trans = hcc_start_command(hc, HC_CHOWN);
1234 hcc_leaf_string(trans, LC_PATH1, path);
1235 hcc_leaf_int32(trans, LC_UID, owner);
1236 hcc_leaf_int32(trans, LC_GID, group);
1237 if ((head = hcc_finish_command(trans)) == NULL)
1245 rc_chown(hctransaction_t trans, struct HCHead *head)
1247 struct HCLeaf *item;
1248 const char *path = NULL;
1249 uid_t uid = (uid_t)-1;
1250 gid_t gid = (gid_t)-1;
1253 FOR_EACH_ITEM(item, trans, head) {
1254 switch(item->leafid) {
1256 path = HCC_STRING(item);
1259 uid = HCC_INT32(item);
1262 gid = HCC_INT32(item);
1267 head->error = EACCES;
1272 rc = chown(path, uid, gid);
1274 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1282 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1284 hctransaction_t trans;
1285 struct HCHead *head;
1293 if (hc == NULL || hc->host == NULL) {
1294 rc = lchown(path, owner, group);
1296 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1300 trans = hcc_start_command(hc, HC_LCHOWN);
1301 hcc_leaf_string(trans, LC_PATH1, path);
1302 hcc_leaf_int32(trans, LC_UID, owner);
1303 hcc_leaf_int32(trans, LC_GID, group);
1304 if ((head = hcc_finish_command(trans)) == NULL)
1312 rc_lchown(hctransaction_t trans, struct HCHead *head)
1314 struct HCLeaf *item;
1315 const char *path = NULL;
1316 uid_t uid = (uid_t)-1;
1317 gid_t gid = (gid_t)-1;
1320 FOR_EACH_ITEM(item, trans, head) {
1321 switch(item->leafid) {
1323 path = HCC_STRING(item);
1326 uid = HCC_INT32(item);
1329 gid = HCC_INT32(item);
1334 head->error = EACCES;
1339 rc = lchown(path, uid, gid);
1341 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1349 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1351 hctransaction_t trans;
1352 struct HCHead *head;
1356 if (hc == NULL || hc->host == NULL)
1357 return(chmod(path, mode));
1359 trans = hcc_start_command(hc, HC_CHMOD);
1360 hcc_leaf_string(trans, LC_PATH1, path);
1361 hcc_leaf_int32(trans, LC_MODE, mode);
1362 if ((head = hcc_finish_command(trans)) == NULL)
1370 rc_chmod(hctransaction_t trans, struct HCHead *head)
1372 struct HCLeaf *item;
1373 const char *path = NULL;
1376 FOR_EACH_ITEM(item, trans, head) {
1377 switch(item->leafid) {
1379 path = HCC_STRING(item);
1382 mode = HCC_INT32(item);
1387 head->error = EACCES;
1392 return(chmod(path, mode));
1399 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1401 hctransaction_t trans;
1402 struct HCHead *head;
1406 if (!DstRootPrivs) {
1407 /* mknod() requires root privs, so don't bother. */
1412 if (hc == NULL || hc->host == NULL)
1413 return(mknod(path, mode, rdev));
1415 trans = hcc_start_command(hc, HC_MKNOD);
1416 hcc_leaf_string(trans, LC_PATH1, path);
1417 hcc_leaf_int32(trans, LC_MODE, mode);
1418 hcc_leaf_int32(trans, LC_RDEV, rdev);
1419 if ((head = hcc_finish_command(trans)) == NULL)
1427 rc_mknod(hctransaction_t trans, struct HCHead *head)
1429 struct HCLeaf *item;
1430 const char *path = NULL;
1434 FOR_EACH_ITEM(item, trans, head) {
1435 switch(item->leafid) {
1437 path = HCC_STRING(item);
1440 mode = HCC_INT32(item);
1443 rdev = HCC_INT32(item);
1448 head->error = EACCES;
1453 return(mknod(path, mode, rdev));
1460 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1462 hctransaction_t trans;
1463 struct HCHead *head;
1467 if (hc == NULL || hc->host == NULL)
1468 return(link(name1, name2));
1470 trans = hcc_start_command(hc, HC_LINK);
1471 hcc_leaf_string(trans, LC_PATH1, name1);
1472 hcc_leaf_string(trans, LC_PATH2, name2);
1473 if ((head = hcc_finish_command(trans)) == NULL)
1481 rc_link(hctransaction_t trans, struct HCHead *head)
1483 struct HCLeaf *item;
1484 const char *name1 = NULL;
1485 const char *name2 = NULL;
1487 FOR_EACH_ITEM(item, trans, head) {
1488 switch(item->leafid) {
1490 name1 = HCC_STRING(item);
1493 name2 = HCC_STRING(item);
1498 head->error = EACCES;
1501 if (name1 == NULL || name2 == NULL)
1503 return(link(name1, name2));
1506 #ifdef _ST_FLAGS_PRESENT_
1511 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1513 hctransaction_t trans;
1514 struct HCHead *head;
1520 flags &= UF_SETTABLE;
1522 if (hc == NULL || hc->host == NULL) {
1523 if ((rc = chflags(path, flags)) < 0)
1524 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1528 trans = hcc_start_command(hc, HC_CHFLAGS);
1529 hcc_leaf_string(trans, LC_PATH1, path);
1530 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1531 if ((head = hcc_finish_command(trans)) == NULL)
1539 rc_chflags(hctransaction_t trans, struct HCHead *head)
1541 struct HCLeaf *item;
1542 const char *path = NULL;
1546 FOR_EACH_ITEM(item, trans, head) {
1547 switch(item->leafid) {
1549 path = HCC_STRING(item);
1552 flags = (u_long)HCC_INT64(item);
1557 head->error = EACCES;
1562 if ((rc = chflags(path, flags)) < 0)
1563 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1573 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1575 hctransaction_t trans;
1576 struct HCHead *head;
1577 struct HCLeaf *item;
1580 if (hc == NULL || hc->host == NULL)
1581 return(readlink(path, buf, bufsiz));
1583 trans = hcc_start_command(hc, HC_READLINK);
1584 hcc_leaf_string(trans, LC_PATH1, path);
1585 if ((head = hcc_finish_command(trans)) == NULL)
1591 FOR_EACH_ITEM(item, trans, head) {
1592 if (item->leafid == LC_DATA) {
1593 r = item->bytes - sizeof(*item);
1598 bcopy(HCC_BINARYDATA(item), buf, r);
1605 rc_readlink(hctransaction_t trans, struct HCHead *head)
1607 struct HCLeaf *item;
1608 const char *path = NULL;
1612 FOR_EACH_ITEM(item, trans, head) {
1613 if (item->leafid == LC_PATH1)
1614 path = HCC_STRING(item);
1618 r = readlink(path, buf, sizeof(buf));
1621 hcc_leaf_data(trans, LC_DATA, buf, r);
1629 hc_umask(struct HostConf *hc, mode_t numask)
1631 hctransaction_t trans;
1632 struct HCHead *head;
1633 struct HCLeaf *item;
1636 return(umask(numask));
1637 if (hc == NULL || hc->host == NULL)
1638 return(umask(numask));
1640 trans = hcc_start_command(hc, HC_UMASK);
1641 hcc_leaf_int32(trans, LC_MODE, numask);
1642 if ((head = hcc_finish_command(trans)) == NULL)
1647 numask = (mode_t) ~0666U;
1648 FOR_EACH_ITEM(item, trans, head) {
1649 if (item->leafid == LC_MODE)
1650 numask = HCC_INT32(item);
1656 rc_umask(hctransaction_t trans, struct HCHead *head)
1658 struct HCLeaf *item;
1659 mode_t numask = (mode_t) ~0666U;
1661 FOR_EACH_ITEM(item, trans, head) {
1662 if (item->leafid == LC_MODE)
1663 numask = HCC_INT32(item);
1665 numask = umask(numask);
1666 hcc_leaf_int32(trans, LC_MODE, numask);
1674 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1676 hctransaction_t trans;
1677 struct HCHead *head;
1681 if (hc == NULL || hc->host == NULL)
1682 return(symlink(name1, name2));
1684 trans = hcc_start_command(hc, HC_SYMLINK);
1685 hcc_leaf_string(trans, LC_PATH1, name1);
1686 hcc_leaf_string(trans, LC_PATH2, name2);
1687 if ((head = hcc_finish_command(trans)) == NULL)
1695 rc_symlink(hctransaction_t trans, struct HCHead *head)
1697 struct HCLeaf *item;
1698 const char *name1 = NULL;
1699 const char *name2 = NULL;
1701 FOR_EACH_ITEM(item, trans, head) {
1702 switch(item->leafid) {
1704 name1 = HCC_STRING(item);
1707 name2 = HCC_STRING(item);
1712 head->error = EACCES;
1715 if (name1 == NULL || name2 == NULL)
1717 return(symlink(name1, name2));
1724 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1726 hctransaction_t trans;
1727 struct HCHead *head;
1731 if (hc == NULL || hc->host == NULL)
1732 return(rename(name1, name2));
1734 trans = hcc_start_command(hc, HC_RENAME);
1735 hcc_leaf_string(trans, LC_PATH1, name1);
1736 hcc_leaf_string(trans, LC_PATH2, name2);
1737 if ((head = hcc_finish_command(trans)) == NULL)
1745 rc_rename(hctransaction_t trans, struct HCHead *head)
1747 struct HCLeaf *item;
1748 const char *name1 = NULL;
1749 const char *name2 = NULL;
1751 FOR_EACH_ITEM(item, trans, head) {
1752 switch(item->leafid) {
1754 name1 = HCC_STRING(item);
1757 name2 = HCC_STRING(item);
1762 head->error = EACCES;
1765 if (name1 == NULL || name2 == NULL)
1767 return(rename(name1, name2));
1774 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1776 hctransaction_t trans;
1777 struct HCHead *head;
1781 if (hc == NULL || hc->host == NULL)
1782 return(utimes(path, times));
1784 trans = hcc_start_command(hc, HC_UTIMES);
1785 hcc_leaf_string(trans, LC_PATH1, path);
1786 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1787 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1788 if ((head = hcc_finish_command(trans)) == NULL)
1796 rc_utimes(hctransaction_t trans, struct HCHead *head)
1798 struct HCLeaf *item;
1799 struct timeval times[2];
1802 bzero(times, sizeof(times));
1805 FOR_EACH_ITEM(item, trans, head) {
1806 switch(item->leafid) {
1808 path = HCC_STRING(item);
1811 times[0].tv_sec = HCC_INT64(item);
1814 times[1].tv_sec = HCC_INT64(item);
1819 head->error = EACCES;
1824 return(utimes(path, times));
1828 hc_geteuid(struct HostConf *hc)
1830 hctransaction_t trans;
1831 struct HCHead *head;
1832 struct HCLeaf *item;
1834 if (hc == NULL || hc->host == NULL)
1837 if (hc->version < 3) {
1838 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1839 /* Return 0 on error, so the caller assumes root privileges. */
1843 trans = hcc_start_command(hc, HC_GETEUID);
1844 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1846 FOR_EACH_ITEM(item, trans, head) {
1847 if (item->leafid == LC_UID)
1848 return (HCC_INT32(item));
1850 return(0); /* shouldn't happen */
1854 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1856 hcc_leaf_int32(trans, LC_UID, geteuid());
1861 getmygroups(gid_t **gidlist)
1865 if ((count = getgroups(0, *gidlist)) > 0) {
1866 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1867 if ((count = getgroups(count, *gidlist)) <= 0)
1879 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1882 hctransaction_t trans;
1883 struct HCHead *head;
1884 struct HCLeaf *item;
1886 if (hc == NULL || hc->host == NULL)
1887 return (getmygroups(gidlist));
1893 if (hc->version < 3) {
1894 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1898 trans = hcc_start_command(hc, HC_GETGROUPS);
1899 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1901 FOR_EACH_ITEM(item, trans, head) {
1902 switch(item->leafid) {
1904 count = HCC_INT32(item);
1905 if (*gidlist != NULL) { /* protocol error */
1910 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1914 if (*gidlist == NULL || i >= count) { /* protocol error */
1915 if (*gidlist != NULL)
1920 (*gidlist)[i++] = HCC_INT32(item);
1928 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1933 if ((count = getmygroups(&gidlist)) < 0)
1935 hcc_leaf_int32(trans, LC_COUNT, count);
1936 for (i = 0; i < count; i++)
1937 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1938 if (gidlist != NULL)