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 return (denbuf.d_name[0] ? &denbuf : NULL);
517 rc_readdir(hctransaction_t trans, struct HCHead *head)
523 FOR_EACH_ITEM(item, trans, head) {
524 if (item->leafid == LC_DESCRIPTOR)
525 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
529 if ((den = readdir(dir)) != NULL)
530 hcc_leaf_string(trans, LC_PATH1, den->d_name);
537 * XXX cpdup needs to check error code to avoid truncated dirs?
540 hc_closedir(struct HostConf *hc, DIR *dir)
544 if (hc == NULL || hc->host == NULL)
545 return(closedir(dir));
547 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
548 hctransaction_t trans;
551 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
553 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
554 trans = hcc_start_command(hc, HC_CLOSEDIR);
555 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
556 if ((head = hcc_finish_command(trans)) == NULL)
559 return (-1); /* XXX errno */
567 /* hc->version >= 4: using HC_SCANDIR */
569 /* skip any remaining items if the directory is closed prematurely */
570 while (hcc_nextchaineditem(hc, head) != NULL)
578 rc_closedir(hctransaction_t trans, struct HCHead *head)
583 FOR_EACH_ITEM(item, trans, head) {
584 if (item->leafid == LC_DESCRIPTOR) {
585 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
587 hcc_set_descriptor(trans->hc, HCC_INT32(item),
594 return(closedir(dir));
601 rc_scandir(hctransaction_t trans, struct HCHead *head)
604 const char *path = NULL;
610 FOR_EACH_ITEM(item, trans, head) {
611 if (item->leafid == LC_PATH1)
612 path = HCC_STRING(item);
616 if ((dir = opendir(path)) == NULL)
618 while ((den = readdir(dir)) != NULL) {
619 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
620 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
621 continue; /* skip "." and ".." */
623 * Check if there's enough space left in the current packet.
624 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
625 * one is a string, so we use strlen() + 1 (terminating zero).
626 * The remaining ones are numbers; we assume sizeof(int64_t) so
627 * we're on the safe side.
629 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
630 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
631 strlen(den->d_name) + 1)) {
635 fpath = mprintf("%s/%s", path, den->d_name);
636 if (lstat(fpath, &st) == 0)
637 rc_encode_stat(trans, &st);
638 /* The name must be the last item! */
639 hcc_leaf_string(trans, LC_PATH1, den->d_name);
642 return (closedir(dir));
649 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
651 hctransaction_t trans;
658 if (NotForRealOpt && (flags & O_CREAT))
661 if (hc == NULL || hc->host == NULL) {
663 flags |= O_LARGEFILE;
665 return(open(path, flags, mode));
668 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
669 trans = hcc_start_command(hc, HC_READFILE);
670 hcc_leaf_string(trans, LC_PATH1, path);
671 if ((head = hcc_finish_command(trans)) == NULL || head->error)
673 head->magic = 0; /* used to indicate offset within buffer */
674 return (1); /* dummy */
677 nflags = flags & XO_NATIVEMASK;
685 trans = hcc_start_command(hc, HC_OPEN);
686 hcc_leaf_string(trans, LC_PATH1, path);
687 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
688 hcc_leaf_int32(trans, LC_MODE, mode);
690 if ((head = hcc_finish_command(trans)) == NULL)
694 FOR_EACH_ITEM(item, trans, head) {
695 if (item->leafid == LC_DESCRIPTOR)
696 desc = HCC_INT32(item);
698 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
699 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
703 fdp = malloc(sizeof(int));
704 *fdp = desc; /* really just a dummy */
705 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
710 rc_open(hctransaction_t trans, struct HCHead *head)
713 const char *path = NULL;
721 FOR_EACH_ITEM(item, trans, head) {
722 switch(item->leafid) {
724 path = HCC_STRING(item);
727 nflags = HCC_INT32(item);
730 mode = HCC_INT32(item);
737 flags = nflags & XO_NATIVEMASK;
738 if (nflags & XO_CREAT)
740 if (nflags & XO_EXCL)
742 if (nflags & XO_TRUNC)
746 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
747 head->error = EACCES;
754 flags |= O_LARGEFILE;
756 if ((fd = open(path, flags, mode)) < 0)
758 fdp = malloc(sizeof(int));
760 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
761 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
769 hc_close(struct HostConf *hc, int fd)
771 hctransaction_t trans;
775 if (NotForRealOpt && fd == 0x7FFFFFFF)
777 if (hc == NULL || hc->host == NULL)
780 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
781 head = (void *)hc->trans.rbuf;
782 /* skip any remaining items if the file is closed prematurely */
783 while (hcc_nextchaineditem(hc, head) != NULL)
790 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
793 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
795 trans = hcc_start_command(hc, HC_CLOSE);
796 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
797 if ((head = hcc_finish_command(trans)) == NULL)
808 rc_close(hctransaction_t trans, struct HCHead *head)
815 FOR_EACH_ITEM(item, trans, head) {
816 if (item->leafid == LC_DESCRIPTOR)
817 desc = HCC_INT32(item);
821 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
825 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
839 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
841 hctransaction_t trans;
849 if (hc == NULL || hc->host == NULL)
850 return(read(fd, buf, bytes));
852 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
853 head = (void *)hc->trans.rbuf;
855 if ((offset = head->magic) != 0)
856 item = hcc_currentchaineditem(hc, head);
858 item = hcc_nextchaineditem(hc, head);
861 if (item->leafid != LC_DATA)
863 x = item->bytes - sizeof(*item) - offset;
864 if (x > (int)bytes) {
866 head->magic += x; /* leave bytes in the buffer */
869 head->magic = 0; /* all bytes used up */
870 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
871 buf = (char *)buf + x;
878 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
881 size_t limit = getiolimit();
882 int n = (bytes > limit) ? limit : bytes;
884 trans = hcc_start_command(hc, HC_READ);
885 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
886 hcc_leaf_int32(trans, LC_BYTES, n);
887 if ((head = hcc_finish_command(trans)) == NULL)
891 FOR_EACH_ITEM(item, trans, head) {
892 if (item->leafid == LC_DATA) {
893 x = item->bytes - sizeof(*item);
896 bcopy(HCC_BINARYDATA(item), buf, x);
897 buf = (char *)buf + x;
912 rc_read(hctransaction_t trans, struct HCHead *head)
920 FOR_EACH_ITEM(item, trans, head) {
921 switch(item->leafid) {
923 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
926 bytes = HCC_INT32(item);
932 if (bytes < 0 || bytes > 32768)
934 n = read(*fdp, buf, bytes);
937 hcc_leaf_data(trans, LC_DATA, buf, n);
945 rc_readfile(hctransaction_t trans, struct HCHead *head)
948 const char *path = NULL;
953 FOR_EACH_ITEM(item, trans, head) {
954 if (item->leafid == LC_PATH1)
955 path = HCC_STRING(item);
959 if ((fd = open(path, O_RDONLY)) < 0)
961 while ((n = read(fd, buf, 32768)) >= 0) {
962 if (!hcc_check_space(trans, head, 1, n)) {
966 hcc_leaf_data(trans, LC_DATA, buf, n);
981 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
983 hctransaction_t trans;
992 if (hc == NULL || hc->host == NULL)
993 return(write(fd, buf, bytes));
995 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
999 size_t limit = getiolimit();
1000 int n = (bytes > limit) ? limit : bytes;
1003 trans = hcc_start_command(hc, HC_WRITE);
1004 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1005 hcc_leaf_data(trans, LC_DATA, buf, n);
1006 if ((head = hcc_finish_command(trans)) == NULL)
1010 FOR_EACH_ITEM(item, trans, head) {
1011 if (item->leafid == LC_BYTES)
1012 x = HCC_INT32(item);
1017 buf = (const char *)buf + x;
1029 rc_write(hctransaction_t trans, struct HCHead *head)
1031 struct HCLeaf *item;
1036 FOR_EACH_ITEM(item, trans, head) {
1037 switch(item->leafid) {
1039 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1042 buf = HCC_BINARYDATA(item);
1043 n = item->bytes - sizeof(*item);
1048 head->error = EACCES;
1053 if (n < 0 || n > 32768)
1055 n = write(*fdp, buf, n);
1058 hcc_leaf_int32(trans, LC_BYTES, n);
1065 * NOTE: This function returns -errno if an error occured.
1068 hc_remove(struct HostConf *hc, const char *path)
1070 hctransaction_t trans;
1071 struct HCHead *head;
1076 if (hc == NULL || hc->host == NULL) {
1083 trans = hcc_start_command(hc, HC_REMOVE);
1084 hcc_leaf_string(trans, LC_PATH1, path);
1085 if ((head = hcc_finish_command(trans)) == NULL)
1088 return(-(int)head->error);
1093 rc_remove(hctransaction_t trans, struct HCHead *head)
1095 struct HCLeaf *item;
1096 const char *path = NULL;
1098 FOR_EACH_ITEM(item, trans, head) {
1099 if (item->leafid == LC_PATH1)
1100 path = HCC_STRING(item);
1105 head->error = EACCES;
1108 return(remove(path));
1115 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1117 hctransaction_t trans;
1118 struct HCHead *head;
1122 if (hc == NULL || hc->host == NULL)
1123 return(mkdir(path, mode));
1125 trans = hcc_start_command(hc, HC_MKDIR);
1126 hcc_leaf_string(trans, LC_PATH1, path);
1127 hcc_leaf_int32(trans, LC_MODE, mode);
1128 if ((head = hcc_finish_command(trans)) == NULL)
1136 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1138 struct HCLeaf *item;
1139 const char *path = NULL;
1142 FOR_EACH_ITEM(item, trans, head) {
1143 switch(item->leafid) {
1145 path = HCC_STRING(item);
1148 mode = HCC_INT32(item);
1153 head->error = EACCES;
1158 return(mkdir(path, mode));
1165 hc_rmdir(struct HostConf *hc, const char *path)
1167 hctransaction_t trans;
1168 struct HCHead *head;
1172 if (hc == NULL || hc->host == NULL)
1173 return(rmdir(path));
1175 trans = hcc_start_command(hc, HC_RMDIR);
1176 hcc_leaf_string(trans, LC_PATH1, path);
1177 if ((head = hcc_finish_command(trans)) == NULL)
1185 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1187 struct HCLeaf *item;
1188 const char *path = NULL;
1190 FOR_EACH_ITEM(item, trans, head) {
1191 if (item->leafid == LC_PATH1)
1192 path = HCC_STRING(item);
1195 head->error = EACCES;
1200 return(rmdir(path));
1206 * Almost silently ignore chowns that fail if we are not root.
1209 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1211 hctransaction_t trans;
1212 struct HCHead *head;
1220 if (hc == NULL || hc->host == NULL) {
1221 rc = chown(path, owner, group);
1223 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1227 trans = hcc_start_command(hc, HC_CHOWN);
1228 hcc_leaf_string(trans, LC_PATH1, path);
1229 hcc_leaf_int32(trans, LC_UID, owner);
1230 hcc_leaf_int32(trans, LC_GID, group);
1231 if ((head = hcc_finish_command(trans)) == NULL)
1239 rc_chown(hctransaction_t trans, struct HCHead *head)
1241 struct HCLeaf *item;
1242 const char *path = NULL;
1243 uid_t uid = (uid_t)-1;
1244 gid_t gid = (gid_t)-1;
1247 FOR_EACH_ITEM(item, trans, head) {
1248 switch(item->leafid) {
1250 path = HCC_STRING(item);
1253 uid = HCC_INT32(item);
1256 gid = HCC_INT32(item);
1261 head->error = EACCES;
1266 rc = chown(path, uid, gid);
1268 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1276 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1278 hctransaction_t trans;
1279 struct HCHead *head;
1287 if (hc == NULL || hc->host == NULL) {
1288 rc = lchown(path, owner, group);
1290 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1294 trans = hcc_start_command(hc, HC_LCHOWN);
1295 hcc_leaf_string(trans, LC_PATH1, path);
1296 hcc_leaf_int32(trans, LC_UID, owner);
1297 hcc_leaf_int32(trans, LC_GID, group);
1298 if ((head = hcc_finish_command(trans)) == NULL)
1306 rc_lchown(hctransaction_t trans, struct HCHead *head)
1308 struct HCLeaf *item;
1309 const char *path = NULL;
1310 uid_t uid = (uid_t)-1;
1311 gid_t gid = (gid_t)-1;
1314 FOR_EACH_ITEM(item, trans, head) {
1315 switch(item->leafid) {
1317 path = HCC_STRING(item);
1320 uid = HCC_INT32(item);
1323 gid = HCC_INT32(item);
1328 head->error = EACCES;
1333 rc = lchown(path, uid, gid);
1335 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1343 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1345 hctransaction_t trans;
1346 struct HCHead *head;
1350 if (hc == NULL || hc->host == NULL)
1351 return(chmod(path, mode));
1353 trans = hcc_start_command(hc, HC_CHMOD);
1354 hcc_leaf_string(trans, LC_PATH1, path);
1355 hcc_leaf_int32(trans, LC_MODE, mode);
1356 if ((head = hcc_finish_command(trans)) == NULL)
1364 rc_chmod(hctransaction_t trans, struct HCHead *head)
1366 struct HCLeaf *item;
1367 const char *path = NULL;
1370 FOR_EACH_ITEM(item, trans, head) {
1371 switch(item->leafid) {
1373 path = HCC_STRING(item);
1376 mode = HCC_INT32(item);
1381 head->error = EACCES;
1386 return(chmod(path, mode));
1393 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1395 hctransaction_t trans;
1396 struct HCHead *head;
1400 if (!DstRootPrivs) {
1401 /* mknod() requires root privs, so don't bother. */
1406 if (hc == NULL || hc->host == NULL)
1407 return(mknod(path, mode, rdev));
1409 trans = hcc_start_command(hc, HC_MKNOD);
1410 hcc_leaf_string(trans, LC_PATH1, path);
1411 hcc_leaf_int32(trans, LC_MODE, mode);
1412 hcc_leaf_int32(trans, LC_RDEV, rdev);
1413 if ((head = hcc_finish_command(trans)) == NULL)
1421 rc_mknod(hctransaction_t trans, struct HCHead *head)
1423 struct HCLeaf *item;
1424 const char *path = NULL;
1428 FOR_EACH_ITEM(item, trans, head) {
1429 switch(item->leafid) {
1431 path = HCC_STRING(item);
1434 mode = HCC_INT32(item);
1437 rdev = HCC_INT32(item);
1442 head->error = EACCES;
1447 return(mknod(path, mode, rdev));
1454 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1456 hctransaction_t trans;
1457 struct HCHead *head;
1461 if (hc == NULL || hc->host == NULL)
1462 return(link(name1, name2));
1464 trans = hcc_start_command(hc, HC_LINK);
1465 hcc_leaf_string(trans, LC_PATH1, name1);
1466 hcc_leaf_string(trans, LC_PATH2, name2);
1467 if ((head = hcc_finish_command(trans)) == NULL)
1475 rc_link(hctransaction_t trans, struct HCHead *head)
1477 struct HCLeaf *item;
1478 const char *name1 = NULL;
1479 const char *name2 = NULL;
1481 FOR_EACH_ITEM(item, trans, head) {
1482 switch(item->leafid) {
1484 name1 = HCC_STRING(item);
1487 name2 = HCC_STRING(item);
1492 head->error = EACCES;
1495 if (name1 == NULL || name2 == NULL)
1497 return(link(name1, name2));
1500 #ifdef _ST_FLAGS_PRESENT_
1505 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1507 hctransaction_t trans;
1508 struct HCHead *head;
1514 flags &= UF_SETTABLE;
1516 if (hc == NULL || hc->host == NULL) {
1517 if ((rc = chflags(path, flags)) < 0)
1518 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1522 trans = hcc_start_command(hc, HC_CHFLAGS);
1523 hcc_leaf_string(trans, LC_PATH1, path);
1524 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1525 if ((head = hcc_finish_command(trans)) == NULL)
1533 rc_chflags(hctransaction_t trans, struct HCHead *head)
1535 struct HCLeaf *item;
1536 const char *path = NULL;
1540 FOR_EACH_ITEM(item, trans, head) {
1541 switch(item->leafid) {
1543 path = HCC_STRING(item);
1546 flags = (u_long)HCC_INT64(item);
1551 head->error = EACCES;
1556 if ((rc = chflags(path, flags)) < 0)
1557 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1567 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1569 hctransaction_t trans;
1570 struct HCHead *head;
1571 struct HCLeaf *item;
1574 if (hc == NULL || hc->host == NULL)
1575 return(readlink(path, buf, bufsiz));
1577 trans = hcc_start_command(hc, HC_READLINK);
1578 hcc_leaf_string(trans, LC_PATH1, path);
1579 if ((head = hcc_finish_command(trans)) == NULL)
1585 FOR_EACH_ITEM(item, trans, head) {
1586 if (item->leafid == LC_DATA) {
1587 r = item->bytes - sizeof(*item);
1592 bcopy(HCC_BINARYDATA(item), buf, r);
1599 rc_readlink(hctransaction_t trans, struct HCHead *head)
1601 struct HCLeaf *item;
1602 const char *path = NULL;
1606 FOR_EACH_ITEM(item, trans, head) {
1607 if (item->leafid == LC_PATH1)
1608 path = HCC_STRING(item);
1612 r = readlink(path, buf, sizeof(buf));
1615 hcc_leaf_data(trans, LC_DATA, buf, r);
1623 hc_umask(struct HostConf *hc, mode_t numask)
1625 hctransaction_t trans;
1626 struct HCHead *head;
1627 struct HCLeaf *item;
1630 return(umask(numask));
1631 if (hc == NULL || hc->host == NULL)
1632 return(umask(numask));
1634 trans = hcc_start_command(hc, HC_UMASK);
1635 hcc_leaf_int32(trans, LC_MODE, numask);
1636 if ((head = hcc_finish_command(trans)) == NULL)
1641 numask = (mode_t) ~0666U;
1642 FOR_EACH_ITEM(item, trans, head) {
1643 if (item->leafid == LC_MODE)
1644 numask = HCC_INT32(item);
1650 rc_umask(hctransaction_t trans, struct HCHead *head)
1652 struct HCLeaf *item;
1653 mode_t numask = (mode_t) ~0666U;
1655 FOR_EACH_ITEM(item, trans, head) {
1656 if (item->leafid == LC_MODE)
1657 numask = HCC_INT32(item);
1659 numask = umask(numask);
1660 hcc_leaf_int32(trans, LC_MODE, numask);
1668 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1670 hctransaction_t trans;
1671 struct HCHead *head;
1675 if (hc == NULL || hc->host == NULL)
1676 return(symlink(name1, name2));
1678 trans = hcc_start_command(hc, HC_SYMLINK);
1679 hcc_leaf_string(trans, LC_PATH1, name1);
1680 hcc_leaf_string(trans, LC_PATH2, name2);
1681 if ((head = hcc_finish_command(trans)) == NULL)
1689 rc_symlink(hctransaction_t trans, struct HCHead *head)
1691 struct HCLeaf *item;
1692 const char *name1 = NULL;
1693 const char *name2 = NULL;
1695 FOR_EACH_ITEM(item, trans, head) {
1696 switch(item->leafid) {
1698 name1 = HCC_STRING(item);
1701 name2 = HCC_STRING(item);
1706 head->error = EACCES;
1709 if (name1 == NULL || name2 == NULL)
1711 return(symlink(name1, name2));
1718 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1720 hctransaction_t trans;
1721 struct HCHead *head;
1725 if (hc == NULL || hc->host == NULL)
1726 return(rename(name1, name2));
1728 trans = hcc_start_command(hc, HC_RENAME);
1729 hcc_leaf_string(trans, LC_PATH1, name1);
1730 hcc_leaf_string(trans, LC_PATH2, name2);
1731 if ((head = hcc_finish_command(trans)) == NULL)
1739 rc_rename(hctransaction_t trans, struct HCHead *head)
1741 struct HCLeaf *item;
1742 const char *name1 = NULL;
1743 const char *name2 = NULL;
1745 FOR_EACH_ITEM(item, trans, head) {
1746 switch(item->leafid) {
1748 name1 = HCC_STRING(item);
1751 name2 = HCC_STRING(item);
1756 head->error = EACCES;
1759 if (name1 == NULL || name2 == NULL)
1761 return(rename(name1, name2));
1768 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1770 hctransaction_t trans;
1771 struct HCHead *head;
1775 if (hc == NULL || hc->host == NULL)
1776 return(utimes(path, times));
1778 trans = hcc_start_command(hc, HC_UTIMES);
1779 hcc_leaf_string(trans, LC_PATH1, path);
1780 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1781 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1782 if ((head = hcc_finish_command(trans)) == NULL)
1790 rc_utimes(hctransaction_t trans, struct HCHead *head)
1792 struct HCLeaf *item;
1793 struct timeval times[2];
1796 bzero(times, sizeof(times));
1799 FOR_EACH_ITEM(item, trans, head) {
1800 switch(item->leafid) {
1802 path = HCC_STRING(item);
1805 times[0].tv_sec = HCC_INT64(item);
1808 times[1].tv_sec = HCC_INT64(item);
1813 head->error = EACCES;
1818 return(utimes(path, times));
1822 hc_geteuid(struct HostConf *hc)
1824 hctransaction_t trans;
1825 struct HCHead *head;
1826 struct HCLeaf *item;
1828 if (hc == NULL || hc->host == NULL)
1831 if (hc->version < 3) {
1832 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1833 /* Return 0 on error, so the caller assumes root privileges. */
1837 trans = hcc_start_command(hc, HC_GETEUID);
1838 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1840 FOR_EACH_ITEM(item, trans, head) {
1841 if (item->leafid == LC_UID)
1842 return (HCC_INT32(item));
1844 return(0); /* shouldn't happen */
1848 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1850 hcc_leaf_int32(trans, LC_UID, geteuid());
1855 getmygroups(gid_t **gidlist)
1859 if ((count = getgroups(0, *gidlist)) > 0) {
1860 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1861 if ((count = getgroups(count, *gidlist)) <= 0)
1873 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1876 hctransaction_t trans;
1877 struct HCHead *head;
1878 struct HCLeaf *item;
1880 if (hc == NULL || hc->host == NULL)
1881 return (getmygroups(gidlist));
1887 if (hc->version < 3) {
1888 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1892 trans = hcc_start_command(hc, HC_GETGROUPS);
1893 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1895 FOR_EACH_ITEM(item, trans, head) {
1896 switch(item->leafid) {
1898 count = HCC_INT32(item);
1899 if (*gidlist != NULL) { /* protocol error */
1904 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1908 if (*gidlist == NULL || i >= count) { /* protocol error */
1909 if (*gidlist != NULL)
1914 (*gidlist)[i++] = HCC_INT32(item);
1922 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1927 if ((count = getmygroups(&gidlist)) < 0)
1929 hcc_leaf_int32(trans, LC_COUNT, count);
1930 for (i = 0; i < count; i++)
1931 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1932 if (gidlist != NULL)