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 struct HCDesc HCDispatchTable[] = {
51 { HC_HELLO, rc_hello },
53 { HC_LSTAT, rc_lstat },
54 { HC_OPENDIR, rc_opendir },
55 { HC_READDIR, rc_readdir },
56 { HC_CLOSEDIR, rc_closedir },
58 { HC_CLOSE, rc_close },
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 },
69 #ifdef _ST_FLAGS_PRESENT_
70 { HC_CHFLAGS, rc_chflags },
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 },
83 static int chown_warning;
84 static int chflags_warning;
87 * If not running as root generate a silent warning and return no error.
89 * If running as root return an error.
92 silentwarning(int *didwarn, const char *ctl, ...)
98 if (*didwarn == 0 && QuietOpt == 0) {
100 fprintf(stderr, "WARNING: Not running as root, ");
102 vfprintf(stderr, ctl, va);
109 hc_connect(struct HostConf *hc, int readonly)
111 if (hcc_connect(hc, readonly) < 0) {
112 fprintf(stderr, "Unable to connect to %s\n", hc->host);
115 return(hc_hello(hc));
119 hc_slave(int fdin, int fdout)
121 hcc_slave(fdin, fdout, HCDispatchTable,
122 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
127 * A HELLO RPC is sent on the initial connect.
130 hc_hello(struct HostConf *hc)
134 hctransaction_t trans;
138 bzero(hostbuf, sizeof(hostbuf));
139 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
144 trans = hcc_start_command(hc, HC_HELLO);
145 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
146 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
148 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
149 if ((head = hcc_finish_command(trans)) == NULL) {
150 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
156 fprintf(stderr, "Connected to %s but remote returned error %d\n",
157 hc->host, head->error);
162 FOR_EACH_ITEM(item, trans, head) {
163 switch(item->leafid) {
166 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
170 hc->version = HCC_INT32(item);
174 if (hc->version < HCPROTO_VERSION_COMPAT) {
175 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
178 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
179 fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
180 "expect reduced speed\n", hc->host);
183 fprintf(stderr, "Handshake failed with %s\n", hc->host);
188 rc_hello(hctransaction_t trans, struct HCHead *head)
193 FOR_EACH_ITEM(item, trans, head) {
194 if (item->leafid == LC_PATH1)
195 UseCpFile = strdup(HCC_STRING(item));
198 bzero(hostbuf, sizeof(hostbuf));
199 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
204 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
205 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
213 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
216 hctransaction_t trans;
218 if (hc == NULL || hc->host == NULL)
219 return(stat(path, st));
221 trans = hcc_start_command(hc, HC_STAT);
222 hcc_leaf_string(trans, LC_PATH1, path);
223 if ((head = hcc_finish_command(trans)) == NULL)
227 return(hc_decode_stat(trans, st, head));
231 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
234 hctransaction_t trans;
236 if (hc == NULL || hc->host == NULL)
237 return(lstat(path, st));
239 trans = hcc_start_command(hc, HC_LSTAT);
240 hcc_leaf_string(trans, LC_PATH1, path);
241 if ((head = hcc_finish_command(trans)) == NULL)
245 return(hc_decode_stat(trans, st, head));
249 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
253 bzero(st, sizeof(*st));
254 FOR_EACH_ITEM(item, trans, head)
255 hc_decode_stat_item(st, item);
260 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
262 switch(item->leafid) {
264 st->st_dev = HCC_INT32(item);
267 st->st_ino = HCC_INT64(item);
270 st->st_mode = HCC_INT32(item);
273 st->st_nlink = HCC_INT32(item);
276 st->st_uid = HCC_INT32(item);
279 st->st_gid = HCC_INT32(item);
282 st->st_rdev = HCC_INT32(item);
285 st->st_atime = (time_t)HCC_INT64(item);
288 st->st_mtime = (time_t)HCC_INT64(item);
291 st->st_ctime = (time_t)HCC_INT64(item);
294 st->st_size = HCC_INT64(item);
297 st->st_blocks = HCC_INT64(item);
300 st->st_blksize = HCC_INT32(item);
302 #ifdef _ST_FSMID_PRESENT_
304 st->st_fsmid = HCC_INT64(item);
307 #ifdef _ST_FLAGS_PRESENT_
309 st->st_flags = (uint32_t)HCC_INT64(item);
317 rc_stat(hctransaction_t trans, struct HCHead *head)
321 const char *path = NULL;
323 FOR_EACH_ITEM(item, trans, head) {
324 if (item->leafid == LC_PATH1)
325 path = HCC_STRING(item);
329 if (stat(path, &st) < 0)
331 return (rc_encode_stat(trans, &st));
335 rc_lstat(hctransaction_t trans, struct HCHead *head)
339 const char *path = NULL;
341 FOR_EACH_ITEM(item, trans, head) {
342 if (item->leafid == LC_PATH1)
343 path = HCC_STRING(item);
347 if (lstat(path, &st) < 0)
349 return (rc_encode_stat(trans, &st));
353 * Encode all entries of a stat structure.
355 * CAUTION: If you add any more entries here, be sure to
356 * increase the STAT_MAX_NUM_ENTRIES value!
358 #define STAT_MAX_NUM_ENTRIES 18
360 rc_encode_stat(hctransaction_t trans, struct stat *st)
362 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
363 hcc_leaf_int64(trans, LC_INO, st->st_ino);
364 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
365 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
366 hcc_leaf_int32(trans, LC_UID, st->st_uid);
367 hcc_leaf_int32(trans, LC_GID, st->st_gid);
368 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
369 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
370 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
371 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
372 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
373 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
374 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
375 #ifdef _ST_FSMID_PRESENT_
376 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
378 #ifdef _ST_FLAGS_PRESENT_
379 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
388 hc_opendir(struct HostConf *hc, const char *path)
390 hctransaction_t trans;
393 if (hc == NULL || hc->host == NULL)
394 return(opendir(path));
396 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
398 struct HCDirEntry *den;
401 trans = hcc_start_command(hc, HC_OPENDIR);
402 hcc_leaf_string(trans, LC_PATH1, path);
403 if ((head = hcc_finish_command(trans)) == NULL)
407 FOR_EACH_ITEM(item, trans, head) {
408 if (item->leafid == LC_DESCRIPTOR)
409 desc = HCC_INT32(item);
411 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
412 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
416 den = malloc(sizeof(*den));
417 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
418 return ((void *)desc);
421 /* hc->version >= 4: use HC_SCANDIR */
422 trans = hcc_start_command(hc, HC_SCANDIR);
423 hcc_leaf_string(trans, LC_PATH1, path);
424 if ((head = hcc_finish_command(trans)) == NULL || head->error)
426 return ((void *)head);
430 rc_opendir(hctransaction_t trans, struct HCHead *head)
433 const char *path = NULL;
437 FOR_EACH_ITEM(item, trans, head) {
438 if (item->leafid == LC_PATH1)
439 path = HCC_STRING(item);
443 if ((dir = opendir(path)) == NULL) {
446 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
447 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
456 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
461 static struct HCDirEntry denbuf;
464 if (hc == NULL || hc->host == NULL) {
465 struct dirent *sysden;
467 if ((sysden = readdir(dir)) == NULL)
469 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
473 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
474 hctransaction_t trans;
475 struct HCDirEntry *den;
477 trans = hcc_start_command(hc, HC_READDIR);
478 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
479 if ((head = hcc_finish_command(trans)) == NULL)
482 return (NULL); /* XXX errno */
483 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
485 return (NULL); /* XXX errno */
487 FOR_EACH_ITEM(item, trans, head) {
488 if (item->leafid == LC_PATH1)
489 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
491 return (den->d_name[0] ? den : NULL);
494 /* hc->version >= 4: using HC_SCANDIR */
495 denbuf.d_name[0] = 0;
497 *statpp = malloc(sizeof(struct stat));
498 bzero(*statpp, sizeof(struct stat));
499 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
500 if (item->leafid == LC_PATH1) { /* this must be the last item */
501 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
505 hc_decode_stat_item(*statpp, item);
512 return (denbuf.d_name[0] ? &denbuf : NULL);
516 rc_readdir(hctransaction_t trans, struct HCHead *head)
522 FOR_EACH_ITEM(item, trans, head) {
523 if (item->leafid == LC_DESCRIPTOR)
524 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
528 if ((den = readdir(dir)) != NULL)
529 hcc_leaf_string(trans, LC_PATH1, den->d_name);
536 * XXX cpdup needs to check error code to avoid truncated dirs?
539 hc_closedir(struct HostConf *hc, DIR *dir)
543 if (hc == NULL || hc->host == NULL)
544 return(closedir(dir));
546 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
547 hctransaction_t trans;
550 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
552 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
553 trans = hcc_start_command(hc, HC_CLOSEDIR);
554 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
555 if ((head = hcc_finish_command(trans)) == NULL)
558 return (-1); /* XXX errno */
566 /* hc->version >= 4: using HC_SCANDIR */
568 /* skip any remaining items if the directory is closed prematurely */
569 while (hcc_nextchaineditem(hc, head) != NULL)
577 rc_closedir(hctransaction_t trans, struct HCHead *head)
582 FOR_EACH_ITEM(item, trans, head) {
583 if (item->leafid == LC_DESCRIPTOR) {
584 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
586 hcc_set_descriptor(trans->hc, HCC_INT32(item),
593 return(closedir(dir));
600 rc_scandir(hctransaction_t trans, struct HCHead *head)
603 const char *path = NULL;
609 FOR_EACH_ITEM(item, trans, head) {
610 if (item->leafid == LC_PATH1)
611 path = HCC_STRING(item);
615 if ((dir = opendir(path)) == NULL)
617 while ((den = readdir(dir)) != NULL) {
618 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
619 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
620 continue; /* skip "." and ".." */
622 * Check if there's enough space left in the current packet.
623 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
624 * one is a string, so we use strlen() + 1 (terminating zero).
625 * The remaining ones are numbers; we assume sizeof(int64_t) so
626 * we're on the safe side.
628 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
629 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
630 strlen(den->d_name) + 1)) {
634 fpath = mprintf("%s/%s", path, den->d_name);
635 if (lstat(fpath, &st) == 0)
636 rc_encode_stat(trans, &st);
637 /* The name must be the last item! */
638 hcc_leaf_string(trans, LC_PATH1, den->d_name);
641 return (closedir(dir));
648 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
650 hctransaction_t trans;
657 if (hc == NULL || hc->host == NULL) {
659 flags |= O_LARGEFILE;
661 return(open(path, flags, mode));
664 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
665 trans = hcc_start_command(hc, HC_READFILE);
666 hcc_leaf_string(trans, LC_PATH1, path);
667 if ((head = hcc_finish_command(trans)) == NULL || head->error)
669 head->magic = 0; /* used to indicate offset within buffer */
670 return (1); /* dummy */
673 nflags = flags & XO_NATIVEMASK;
681 trans = hcc_start_command(hc, HC_OPEN);
682 hcc_leaf_string(trans, LC_PATH1, path);
683 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
684 hcc_leaf_int32(trans, LC_MODE, mode);
686 if ((head = hcc_finish_command(trans)) == NULL)
690 FOR_EACH_ITEM(item, trans, head) {
691 if (item->leafid == LC_DESCRIPTOR)
692 desc = HCC_INT32(item);
694 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
695 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
699 fdp = malloc(sizeof(int));
700 *fdp = desc; /* really just a dummy */
701 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
706 rc_open(hctransaction_t trans, struct HCHead *head)
709 const char *path = NULL;
717 FOR_EACH_ITEM(item, trans, head) {
718 switch(item->leafid) {
720 path = HCC_STRING(item);
723 nflags = HCC_INT32(item);
726 mode = HCC_INT32(item);
733 flags = nflags & XO_NATIVEMASK;
734 if (nflags & XO_CREAT)
736 if (nflags & XO_EXCL)
738 if (nflags & XO_TRUNC)
742 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
743 head->error = EACCES;
750 flags |= O_LARGEFILE;
752 if ((fd = open(path, flags, mode)) < 0)
754 fdp = malloc(sizeof(int));
756 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
757 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
765 hc_close(struct HostConf *hc, int fd)
767 hctransaction_t trans;
771 if (hc == NULL || hc->host == NULL)
774 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
775 head = (void *)hc->trans.rbuf;
776 /* skip any remaining items if the file is closed prematurely */
777 while (hcc_nextchaineditem(hc, head) != NULL)
784 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
787 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
789 trans = hcc_start_command(hc, HC_CLOSE);
790 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
791 if ((head = hcc_finish_command(trans)) == NULL)
802 rc_close(hctransaction_t trans, struct HCHead *head)
809 FOR_EACH_ITEM(item, trans, head) {
810 if (item->leafid == LC_DESCRIPTOR)
811 desc = HCC_INT32(item);
815 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
819 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
833 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
835 hctransaction_t trans;
843 if (hc == NULL || hc->host == NULL)
844 return(read(fd, buf, bytes));
846 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
847 head = (void *)hc->trans.rbuf;
849 if ((offset = head->magic) != 0)
850 item = hcc_currentchaineditem(hc, head);
852 item = hcc_nextchaineditem(hc, head);
855 if (item->leafid != LC_DATA)
857 x = item->bytes - sizeof(*item) - offset;
858 if (x > (int)bytes) {
860 head->magic += x; /* leave bytes in the buffer */
863 head->magic = 0; /* all bytes used up */
864 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
865 buf = (char *)buf + x;
872 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
875 size_t limit = getiolimit();
876 int n = (bytes > limit) ? limit : bytes;
878 trans = hcc_start_command(hc, HC_READ);
879 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
880 hcc_leaf_int32(trans, LC_BYTES, n);
881 if ((head = hcc_finish_command(trans)) == NULL)
885 FOR_EACH_ITEM(item, trans, head) {
886 if (item->leafid == LC_DATA) {
887 x = item->bytes - sizeof(*item);
890 bcopy(HCC_BINARYDATA(item), buf, x);
891 buf = (char *)buf + x;
906 rc_read(hctransaction_t trans, struct HCHead *head)
914 FOR_EACH_ITEM(item, trans, head) {
915 switch(item->leafid) {
917 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
920 bytes = HCC_INT32(item);
926 if (bytes < 0 || bytes > 32768)
928 n = read(*fdp, buf, bytes);
931 hcc_leaf_data(trans, LC_DATA, buf, n);
939 rc_readfile(hctransaction_t trans, struct HCHead *head)
942 const char *path = NULL;
947 FOR_EACH_ITEM(item, trans, head) {
948 if (item->leafid == LC_PATH1)
949 path = HCC_STRING(item);
953 if ((fd = open(path, O_RDONLY)) < 0)
955 while ((n = read(fd, buf, 32768)) >= 0) {
956 if (!hcc_check_space(trans, head, 1, n)) {
960 hcc_leaf_data(trans, LC_DATA, buf, n);
975 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
977 hctransaction_t trans;
983 if (hc == NULL || hc->host == NULL)
984 return(write(fd, buf, bytes));
986 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
990 size_t limit = getiolimit();
991 int n = (bytes > limit) ? limit : bytes;
994 trans = hcc_start_command(hc, HC_WRITE);
995 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
996 hcc_leaf_data(trans, LC_DATA, buf, n);
997 if ((head = hcc_finish_command(trans)) == NULL)
1001 FOR_EACH_ITEM(item, trans, head) {
1002 if (item->leafid == LC_BYTES)
1003 x = HCC_INT32(item);
1008 buf = (const char *)buf + x;
1020 rc_write(hctransaction_t trans, struct HCHead *head)
1022 struct HCLeaf *item;
1027 FOR_EACH_ITEM(item, trans, head) {
1028 switch(item->leafid) {
1030 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1033 buf = HCC_BINARYDATA(item);
1034 n = item->bytes - sizeof(*item);
1039 head->error = EACCES;
1044 if (n < 0 || n > 32768)
1046 n = write(*fdp, buf, n);
1049 hcc_leaf_int32(trans, LC_BYTES, n);
1056 * NOTE: This function returns -errno if an error occured.
1059 hc_remove(struct HostConf *hc, const char *path)
1061 hctransaction_t trans;
1062 struct HCHead *head;
1065 if (hc == NULL || hc->host == NULL) {
1072 trans = hcc_start_command(hc, HC_REMOVE);
1073 hcc_leaf_string(trans, LC_PATH1, path);
1074 if ((head = hcc_finish_command(trans)) == NULL)
1077 return(-(int)head->error);
1082 rc_remove(hctransaction_t trans, struct HCHead *head)
1084 struct HCLeaf *item;
1085 const char *path = NULL;
1087 FOR_EACH_ITEM(item, trans, head) {
1088 if (item->leafid == LC_PATH1)
1089 path = HCC_STRING(item);
1094 head->error = EACCES;
1097 return(remove(path));
1104 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1106 hctransaction_t trans;
1107 struct HCHead *head;
1109 if (hc == NULL || hc->host == NULL)
1110 return(mkdir(path, mode));
1112 trans = hcc_start_command(hc, HC_MKDIR);
1113 hcc_leaf_string(trans, LC_PATH1, path);
1114 hcc_leaf_int32(trans, LC_MODE, mode);
1115 if ((head = hcc_finish_command(trans)) == NULL)
1123 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1125 struct HCLeaf *item;
1126 const char *path = NULL;
1129 FOR_EACH_ITEM(item, trans, head) {
1130 switch(item->leafid) {
1132 path = HCC_STRING(item);
1135 mode = HCC_INT32(item);
1140 head->error = EACCES;
1145 return(mkdir(path, mode));
1152 hc_rmdir(struct HostConf *hc, const char *path)
1154 hctransaction_t trans;
1155 struct HCHead *head;
1157 if (hc == NULL || hc->host == NULL)
1158 return(rmdir(path));
1160 trans = hcc_start_command(hc, HC_RMDIR);
1161 hcc_leaf_string(trans, LC_PATH1, path);
1162 if ((head = hcc_finish_command(trans)) == NULL)
1170 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1172 struct HCLeaf *item;
1173 const char *path = NULL;
1175 FOR_EACH_ITEM(item, trans, head) {
1176 if (item->leafid == LC_PATH1)
1177 path = HCC_STRING(item);
1180 head->error = EACCES;
1185 return(rmdir(path));
1191 * Almost silently ignore chowns that fail if we are not root.
1194 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1196 hctransaction_t trans;
1197 struct HCHead *head;
1203 if (hc == NULL || hc->host == NULL) {
1204 rc = chown(path, owner, group);
1206 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1210 trans = hcc_start_command(hc, HC_CHOWN);
1211 hcc_leaf_string(trans, LC_PATH1, path);
1212 hcc_leaf_int32(trans, LC_UID, owner);
1213 hcc_leaf_int32(trans, LC_GID, group);
1214 if ((head = hcc_finish_command(trans)) == NULL)
1222 rc_chown(hctransaction_t trans, struct HCHead *head)
1224 struct HCLeaf *item;
1225 const char *path = NULL;
1226 uid_t uid = (uid_t)-1;
1227 gid_t gid = (gid_t)-1;
1230 FOR_EACH_ITEM(item, trans, head) {
1231 switch(item->leafid) {
1233 path = HCC_STRING(item);
1236 uid = HCC_INT32(item);
1239 gid = HCC_INT32(item);
1244 head->error = EACCES;
1249 rc = chown(path, uid, gid);
1251 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1259 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1261 hctransaction_t trans;
1262 struct HCHead *head;
1268 if (hc == NULL || hc->host == NULL) {
1269 rc = lchown(path, owner, group);
1271 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1275 trans = hcc_start_command(hc, HC_LCHOWN);
1276 hcc_leaf_string(trans, LC_PATH1, path);
1277 hcc_leaf_int32(trans, LC_UID, owner);
1278 hcc_leaf_int32(trans, LC_GID, group);
1279 if ((head = hcc_finish_command(trans)) == NULL)
1287 rc_lchown(hctransaction_t trans, struct HCHead *head)
1289 struct HCLeaf *item;
1290 const char *path = NULL;
1291 uid_t uid = (uid_t)-1;
1292 gid_t gid = (gid_t)-1;
1295 FOR_EACH_ITEM(item, trans, head) {
1296 switch(item->leafid) {
1298 path = HCC_STRING(item);
1301 uid = HCC_INT32(item);
1304 gid = HCC_INT32(item);
1309 head->error = EACCES;
1314 rc = lchown(path, uid, gid);
1316 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1324 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1326 hctransaction_t trans;
1327 struct HCHead *head;
1329 if (hc == NULL || hc->host == NULL)
1330 return(chmod(path, mode));
1332 trans = hcc_start_command(hc, HC_CHMOD);
1333 hcc_leaf_string(trans, LC_PATH1, path);
1334 hcc_leaf_int32(trans, LC_MODE, mode);
1335 if ((head = hcc_finish_command(trans)) == NULL)
1343 rc_chmod(hctransaction_t trans, struct HCHead *head)
1345 struct HCLeaf *item;
1346 const char *path = NULL;
1349 FOR_EACH_ITEM(item, trans, head) {
1350 switch(item->leafid) {
1352 path = HCC_STRING(item);
1355 mode = HCC_INT32(item);
1360 head->error = EACCES;
1365 return(chmod(path, mode));
1372 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1374 hctransaction_t trans;
1375 struct HCHead *head;
1377 if (!DstRootPrivs) {
1378 /* mknod() requires root privs, so don't bother. */
1383 if (hc == NULL || hc->host == NULL)
1384 return(mknod(path, mode, rdev));
1386 trans = hcc_start_command(hc, HC_MKNOD);
1387 hcc_leaf_string(trans, LC_PATH1, path);
1388 hcc_leaf_int32(trans, LC_MODE, mode);
1389 hcc_leaf_int32(trans, LC_RDEV, rdev);
1390 if ((head = hcc_finish_command(trans)) == NULL)
1398 rc_mknod(hctransaction_t trans, struct HCHead *head)
1400 struct HCLeaf *item;
1401 const char *path = NULL;
1405 FOR_EACH_ITEM(item, trans, head) {
1406 switch(item->leafid) {
1408 path = HCC_STRING(item);
1411 mode = HCC_INT32(item);
1414 rdev = HCC_INT32(item);
1419 head->error = EACCES;
1424 return(mknod(path, mode, rdev));
1431 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1433 hctransaction_t trans;
1434 struct HCHead *head;
1436 if (hc == NULL || hc->host == NULL)
1437 return(link(name1, name2));
1439 trans = hcc_start_command(hc, HC_LINK);
1440 hcc_leaf_string(trans, LC_PATH1, name1);
1441 hcc_leaf_string(trans, LC_PATH2, name2);
1442 if ((head = hcc_finish_command(trans)) == NULL)
1450 rc_link(hctransaction_t trans, struct HCHead *head)
1452 struct HCLeaf *item;
1453 const char *name1 = NULL;
1454 const char *name2 = NULL;
1456 FOR_EACH_ITEM(item, trans, head) {
1457 switch(item->leafid) {
1459 name1 = HCC_STRING(item);
1462 name2 = HCC_STRING(item);
1467 head->error = EACCES;
1470 if (name1 == NULL || name2 == NULL)
1472 return(link(name1, name2));
1475 #ifdef _ST_FLAGS_PRESENT_
1480 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1482 hctransaction_t trans;
1483 struct HCHead *head;
1487 flags &= UF_SETTABLE;
1489 if (hc == NULL || hc->host == NULL) {
1490 if ((rc = chflags(path, flags)) < 0)
1491 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1495 trans = hcc_start_command(hc, HC_CHFLAGS);
1496 hcc_leaf_string(trans, LC_PATH1, path);
1497 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1498 if ((head = hcc_finish_command(trans)) == NULL)
1506 rc_chflags(hctransaction_t trans, struct HCHead *head)
1508 struct HCLeaf *item;
1509 const char *path = NULL;
1513 FOR_EACH_ITEM(item, trans, head) {
1514 switch(item->leafid) {
1516 path = HCC_STRING(item);
1519 flags = (u_long)HCC_INT64(item);
1524 head->error = EACCES;
1529 if ((rc = chflags(path, flags)) < 0)
1530 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1540 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1542 hctransaction_t trans;
1543 struct HCHead *head;
1544 struct HCLeaf *item;
1547 if (hc == NULL || hc->host == NULL)
1548 return(readlink(path, buf, bufsiz));
1550 trans = hcc_start_command(hc, HC_READLINK);
1551 hcc_leaf_string(trans, LC_PATH1, path);
1552 if ((head = hcc_finish_command(trans)) == NULL)
1558 FOR_EACH_ITEM(item, trans, head) {
1559 if (item->leafid == LC_DATA) {
1560 r = item->bytes - sizeof(*item);
1565 bcopy(HCC_BINARYDATA(item), buf, r);
1572 rc_readlink(hctransaction_t trans, struct HCHead *head)
1574 struct HCLeaf *item;
1575 const char *path = NULL;
1579 FOR_EACH_ITEM(item, trans, head) {
1580 if (item->leafid == LC_PATH1)
1581 path = HCC_STRING(item);
1585 r = readlink(path, buf, sizeof(buf));
1588 hcc_leaf_data(trans, LC_DATA, buf, r);
1596 hc_umask(struct HostConf *hc, mode_t numask)
1598 hctransaction_t trans;
1599 struct HCHead *head;
1600 struct HCLeaf *item;
1602 if (hc == NULL || hc->host == NULL)
1603 return(umask(numask));
1605 trans = hcc_start_command(hc, HC_UMASK);
1606 hcc_leaf_int32(trans, LC_MODE, numask);
1607 if ((head = hcc_finish_command(trans)) == NULL)
1612 numask = (mode_t) ~0666U;
1613 FOR_EACH_ITEM(item, trans, head) {
1614 if (item->leafid == LC_MODE)
1615 numask = HCC_INT32(item);
1621 rc_umask(hctransaction_t trans, struct HCHead *head)
1623 struct HCLeaf *item;
1624 mode_t numask = (mode_t) ~0666U;
1626 FOR_EACH_ITEM(item, trans, head) {
1627 if (item->leafid == LC_MODE)
1628 numask = HCC_INT32(item);
1630 numask = umask(numask);
1631 hcc_leaf_int32(trans, LC_MODE, numask);
1639 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1641 hctransaction_t trans;
1642 struct HCHead *head;
1644 if (hc == NULL || hc->host == NULL)
1645 return(symlink(name1, name2));
1647 trans = hcc_start_command(hc, HC_SYMLINK);
1648 hcc_leaf_string(trans, LC_PATH1, name1);
1649 hcc_leaf_string(trans, LC_PATH2, name2);
1650 if ((head = hcc_finish_command(trans)) == NULL)
1658 rc_symlink(hctransaction_t trans, struct HCHead *head)
1660 struct HCLeaf *item;
1661 const char *name1 = NULL;
1662 const char *name2 = NULL;
1664 FOR_EACH_ITEM(item, trans, head) {
1665 switch(item->leafid) {
1667 name1 = HCC_STRING(item);
1670 name2 = HCC_STRING(item);
1675 head->error = EACCES;
1678 if (name1 == NULL || name2 == NULL)
1680 return(symlink(name1, name2));
1687 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1689 hctransaction_t trans;
1690 struct HCHead *head;
1692 if (hc == NULL || hc->host == NULL)
1693 return(rename(name1, name2));
1695 trans = hcc_start_command(hc, HC_RENAME);
1696 hcc_leaf_string(trans, LC_PATH1, name1);
1697 hcc_leaf_string(trans, LC_PATH2, name2);
1698 if ((head = hcc_finish_command(trans)) == NULL)
1706 rc_rename(hctransaction_t trans, struct HCHead *head)
1708 struct HCLeaf *item;
1709 const char *name1 = NULL;
1710 const char *name2 = NULL;
1712 FOR_EACH_ITEM(item, trans, head) {
1713 switch(item->leafid) {
1715 name1 = HCC_STRING(item);
1718 name2 = HCC_STRING(item);
1723 head->error = EACCES;
1726 if (name1 == NULL || name2 == NULL)
1728 return(rename(name1, name2));
1735 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1737 hctransaction_t trans;
1738 struct HCHead *head;
1740 if (hc == NULL || hc->host == NULL)
1741 return(utimes(path, times));
1743 trans = hcc_start_command(hc, HC_UTIMES);
1744 hcc_leaf_string(trans, LC_PATH1, path);
1745 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1746 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1747 if ((head = hcc_finish_command(trans)) == NULL)
1755 rc_utimes(hctransaction_t trans, struct HCHead *head)
1757 struct HCLeaf *item;
1758 struct timeval times[2];
1761 bzero(times, sizeof(times));
1764 FOR_EACH_ITEM(item, trans, head) {
1765 switch(item->leafid) {
1767 path = HCC_STRING(item);
1770 times[0].tv_sec = HCC_INT64(item);
1773 times[1].tv_sec = HCC_INT64(item);
1778 head->error = EACCES;
1783 return(utimes(path, times));
1787 hc_geteuid(struct HostConf *hc)
1789 hctransaction_t trans;
1790 struct HCHead *head;
1791 struct HCLeaf *item;
1793 if (hc == NULL || hc->host == NULL)
1796 if (hc->version < 3) {
1797 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1798 /* Return 0 on error, so the caller assumes root privileges. */
1802 trans = hcc_start_command(hc, HC_GETEUID);
1803 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1805 FOR_EACH_ITEM(item, trans, head) {
1806 if (item->leafid == LC_UID)
1807 return (HCC_INT32(item));
1809 return(0); /* shouldn't happen */
1813 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1815 hcc_leaf_int32(trans, LC_UID, geteuid());
1820 getmygroups(gid_t **gidlist)
1824 if ((count = getgroups(0, *gidlist)) > 0) {
1825 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1826 if ((count = getgroups(count, *gidlist)) <= 0)
1838 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1841 hctransaction_t trans;
1842 struct HCHead *head;
1843 struct HCLeaf *item;
1845 if (hc == NULL || hc->host == NULL)
1846 return (getmygroups(gidlist));
1852 if (hc->version < 3) {
1853 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1857 trans = hcc_start_command(hc, HC_GETGROUPS);
1858 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1860 FOR_EACH_ITEM(item, trans, head) {
1861 switch(item->leafid) {
1863 count = HCC_INT32(item);
1864 if (*gidlist != NULL) { /* protocol error */
1869 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1873 if (*gidlist == NULL || i >= count) { /* protocol error */
1874 if (*gidlist != NULL)
1879 (*gidlist)[i++] = HCC_INT32(item);
1887 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1892 if ((count = getmygroups(&gidlist)) < 0)
1894 hcc_leaf_int32(trans, LC_COUNT, count);
1895 for (i = 0; i < count; i++)
1896 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1897 if (gidlist != NULL)