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 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]));
129 * A HELLO RPC is sent on the initial connect.
132 hc_hello(struct HostConf *hc)
136 hctransaction_t trans;
140 bzero(hostbuf, sizeof(hostbuf));
141 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
146 trans = hcc_start_command(hc, HC_HELLO);
147 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
148 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
150 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
151 if ((head = hcc_finish_command(trans)) == NULL) {
152 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
158 fprintf(stderr, "Connected to %s but remote returned error %d\n",
159 hc->host, head->error);
164 FOR_EACH_ITEM(item, trans, head) {
165 switch(item->leafid) {
168 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
172 hc->version = HCC_INT32(item);
176 if (hc->version < HCPROTO_VERSION_COMPAT) {
177 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
180 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
181 fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
182 "expect reduced speed\n", hc->host);
185 fprintf(stderr, "Handshake failed with %s\n", hc->host);
190 rc_hello(hctransaction_t trans, struct HCHead *head)
195 FOR_EACH_ITEM(item, trans, head) {
196 if (item->leafid == LC_PATH1)
197 UseCpFile = strdup(HCC_STRING(item));
200 bzero(hostbuf, sizeof(hostbuf));
201 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
206 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
207 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
215 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
218 hctransaction_t trans;
220 if (hc == NULL || hc->host == NULL)
221 return(stat(path, st));
223 trans = hcc_start_command(hc, HC_STAT);
224 hcc_leaf_string(trans, LC_PATH1, path);
225 if ((head = hcc_finish_command(trans)) == NULL)
229 return(hc_decode_stat(trans, st, head));
233 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
236 hctransaction_t trans;
238 if (hc == NULL || hc->host == NULL)
239 return(lstat(path, st));
241 trans = hcc_start_command(hc, HC_LSTAT);
242 hcc_leaf_string(trans, LC_PATH1, path);
243 if ((head = hcc_finish_command(trans)) == NULL)
247 return(hc_decode_stat(trans, st, head));
251 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
255 bzero(st, sizeof(*st));
256 FOR_EACH_ITEM(item, trans, head)
257 hc_decode_stat_item(st, item);
262 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
264 switch(item->leafid) {
266 st->st_dev = HCC_INT32(item);
269 st->st_ino = HCC_INT64(item);
272 st->st_mode = HCC_INT32(item);
275 st->st_nlink = HCC_INT32(item);
278 st->st_uid = HCC_INT32(item);
281 st->st_gid = HCC_INT32(item);
284 st->st_rdev = HCC_INT32(item);
287 st->st_atime = (time_t)HCC_INT64(item);
290 st->st_mtime = (time_t)HCC_INT64(item);
293 st->st_ctime = (time_t)HCC_INT64(item);
296 st->st_size = HCC_INT64(item);
299 st->st_blocks = HCC_INT64(item);
302 st->st_blksize = HCC_INT32(item);
304 #ifdef _ST_FSMID_PRESENT_
306 st->st_fsmid = HCC_INT64(item);
309 #ifdef _ST_FLAGS_PRESENT_
311 st->st_flags = (uint32_t)HCC_INT64(item);
319 rc_stat(hctransaction_t trans, struct HCHead *head)
323 const char *path = NULL;
325 FOR_EACH_ITEM(item, trans, head) {
326 if (item->leafid == LC_PATH1)
327 path = HCC_STRING(item);
331 if (stat(path, &st) < 0)
333 return (rc_encode_stat(trans, &st));
337 rc_lstat(hctransaction_t trans, struct HCHead *head)
341 const char *path = NULL;
343 FOR_EACH_ITEM(item, trans, head) {
344 if (item->leafid == LC_PATH1)
345 path = HCC_STRING(item);
349 if (lstat(path, &st) < 0)
351 return (rc_encode_stat(trans, &st));
355 * Encode all entries of a stat structure.
357 * CAUTION: If you add any more entries here, be sure to
358 * increase the STAT_MAX_NUM_ENTRIES value!
360 #define STAT_MAX_NUM_ENTRIES 18
362 rc_encode_stat(hctransaction_t trans, struct stat *st)
364 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
365 hcc_leaf_int64(trans, LC_INO, st->st_ino);
366 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
367 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
368 hcc_leaf_int32(trans, LC_UID, st->st_uid);
369 hcc_leaf_int32(trans, LC_GID, st->st_gid);
370 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
371 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
372 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
373 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
374 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
375 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
376 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
377 #ifdef _ST_FSMID_PRESENT_
378 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
380 #ifdef _ST_FLAGS_PRESENT_
381 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
390 hc_opendir(struct HostConf *hc, const char *path)
392 hctransaction_t trans;
395 if (hc == NULL || hc->host == NULL)
396 return(opendir(path));
398 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
400 struct HCDirEntry *den;
403 trans = hcc_start_command(hc, HC_OPENDIR);
404 hcc_leaf_string(trans, LC_PATH1, path);
405 if ((head = hcc_finish_command(trans)) == NULL)
409 FOR_EACH_ITEM(item, trans, head) {
410 if (item->leafid == LC_DESCRIPTOR)
411 desc = HCC_INT32(item);
413 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
414 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
418 den = malloc(sizeof(*den));
419 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
420 return ((void *)desc);
423 /* hc->version >= 4: use HC_SCANDIR */
424 trans = hcc_start_command(hc, HC_SCANDIR);
425 hcc_leaf_string(trans, LC_PATH1, path);
426 if ((head = hcc_finish_command(trans)) == NULL || head->error)
428 return ((void *)head);
432 rc_opendir(hctransaction_t trans, struct HCHead *head)
435 const char *path = NULL;
439 FOR_EACH_ITEM(item, trans, head) {
440 if (item->leafid == LC_PATH1)
441 path = HCC_STRING(item);
445 if ((dir = opendir(path)) == NULL) {
448 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
449 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
458 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
463 static struct HCDirEntry denbuf;
466 if (hc == NULL || hc->host == NULL) {
467 struct dirent *sysden;
469 if ((sysden = readdir(dir)) == NULL)
471 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
475 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
476 hctransaction_t trans;
477 struct HCDirEntry *den;
479 trans = hcc_start_command(hc, HC_READDIR);
480 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
481 if ((head = hcc_finish_command(trans)) == NULL)
484 return (NULL); /* XXX errno */
485 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
487 return (NULL); /* XXX errno */
489 FOR_EACH_ITEM(item, trans, head) {
490 if (item->leafid == LC_PATH1)
491 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
493 return (den->d_name[0] ? den : NULL);
496 /* hc->version >= 4: using HC_SCANDIR */
497 denbuf.d_name[0] = 0;
499 *statpp = malloc(sizeof(struct stat));
500 bzero(*statpp, sizeof(struct stat));
501 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
502 if (item->leafid == LC_PATH1) { /* this must be the last item */
503 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
507 hc_decode_stat_item(*statpp, item);
514 return (denbuf.d_name[0] ? &denbuf : NULL);
518 rc_readdir(hctransaction_t trans, struct HCHead *head)
524 FOR_EACH_ITEM(item, trans, head) {
525 if (item->leafid == LC_DESCRIPTOR)
526 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
530 if ((den = readdir(dir)) != NULL)
531 hcc_leaf_string(trans, LC_PATH1, den->d_name);
538 * XXX cpdup needs to check error code to avoid truncated dirs?
541 hc_closedir(struct HostConf *hc, DIR *dir)
545 if (hc == NULL || hc->host == NULL)
546 return(closedir(dir));
548 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
549 hctransaction_t trans;
552 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
554 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
555 trans = hcc_start_command(hc, HC_CLOSEDIR);
556 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
557 if ((head = hcc_finish_command(trans)) == NULL)
560 return (-1); /* XXX errno */
568 /* hc->version >= 4: using HC_SCANDIR */
570 /* skip any remaining items if the directory is closed prematurely */
571 while (hcc_nextchaineditem(hc, head) != NULL)
579 rc_closedir(hctransaction_t trans, struct HCHead *head)
584 FOR_EACH_ITEM(item, trans, head) {
585 if (item->leafid == LC_DESCRIPTOR) {
586 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
588 hcc_set_descriptor(trans->hc, HCC_INT32(item),
595 return(closedir(dir));
602 rc_scandir(hctransaction_t trans, struct HCHead *head)
605 const char *path = NULL;
611 FOR_EACH_ITEM(item, trans, head) {
612 if (item->leafid == LC_PATH1)
613 path = HCC_STRING(item);
617 if ((dir = opendir(path)) == NULL)
619 while ((den = readdir(dir)) != NULL) {
620 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
621 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
622 continue; /* skip "." and ".." */
624 * Check if there's enough space left in the current packet.
625 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
626 * one is a string, so we use strlen() + 1 (terminating zero).
627 * The remaining ones are numbers; we assume sizeof(int64_t) so
628 * we're on the safe side.
630 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
631 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
632 strlen(den->d_name) + 1)) {
636 fpath = mprintf("%s/%s", path, den->d_name);
637 if (lstat(fpath, &st) == 0)
638 rc_encode_stat(trans, &st);
639 /* The name must be the last item! */
640 hcc_leaf_string(trans, LC_PATH1, den->d_name);
643 return (closedir(dir));
650 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
652 hctransaction_t trans;
659 if (hc == NULL || hc->host == NULL) {
661 flags |= O_LARGEFILE;
663 return(open(path, flags, mode));
666 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
667 trans = hcc_start_command(hc, HC_READFILE);
668 hcc_leaf_string(trans, LC_PATH1, path);
669 if ((head = hcc_finish_command(trans)) == NULL || head->error)
671 head->magic = 0; /* used to indicate offset within buffer */
672 return (1); /* dummy */
675 nflags = flags & XO_NATIVEMASK;
683 trans = hcc_start_command(hc, HC_OPEN);
684 hcc_leaf_string(trans, LC_PATH1, path);
685 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
686 hcc_leaf_int32(trans, LC_MODE, mode);
688 if ((head = hcc_finish_command(trans)) == NULL)
692 FOR_EACH_ITEM(item, trans, head) {
693 if (item->leafid == LC_DESCRIPTOR)
694 desc = HCC_INT32(item);
696 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
697 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
701 fdp = malloc(sizeof(int));
702 *fdp = desc; /* really just a dummy */
703 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
708 rc_open(hctransaction_t trans, struct HCHead *head)
711 const char *path = NULL;
719 FOR_EACH_ITEM(item, trans, head) {
720 switch(item->leafid) {
722 path = HCC_STRING(item);
725 nflags = HCC_INT32(item);
728 mode = HCC_INT32(item);
735 flags = nflags & XO_NATIVEMASK;
736 if (nflags & XO_CREAT)
738 if (nflags & XO_EXCL)
740 if (nflags & XO_TRUNC)
744 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
745 head->error = EACCES;
752 flags |= O_LARGEFILE;
754 if ((fd = open(path, flags, mode)) < 0)
756 fdp = malloc(sizeof(int));
758 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
759 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
767 hc_close(struct HostConf *hc, int fd)
769 hctransaction_t trans;
773 if (hc == NULL || hc->host == NULL)
776 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
777 head = (void *)hc->trans.rbuf;
778 /* skip any remaining items if the file is closed prematurely */
779 while (hcc_nextchaineditem(hc, head) != NULL)
786 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
789 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
791 trans = hcc_start_command(hc, HC_CLOSE);
792 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
793 if ((head = hcc_finish_command(trans)) == NULL)
804 rc_close(hctransaction_t trans, struct HCHead *head)
811 FOR_EACH_ITEM(item, trans, head) {
812 if (item->leafid == LC_DESCRIPTOR)
813 desc = HCC_INT32(item);
817 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
821 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
835 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
837 hctransaction_t trans;
845 if (hc == NULL || hc->host == NULL)
846 return(read(fd, buf, bytes));
848 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
849 head = (void *)hc->trans.rbuf;
851 if ((offset = head->magic) != 0)
852 item = hcc_currentchaineditem(hc, head);
854 item = hcc_nextchaineditem(hc, head);
857 if (item->leafid != LC_DATA)
859 x = item->bytes - sizeof(*item) - offset;
860 if (x > (int)bytes) {
862 head->magic += x; /* leave bytes in the buffer */
865 head->magic = 0; /* all bytes used up */
866 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
867 buf = (char *)buf + x;
874 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
877 size_t limit = getiolimit();
878 int n = (bytes > limit) ? limit : bytes;
880 trans = hcc_start_command(hc, HC_READ);
881 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
882 hcc_leaf_int32(trans, LC_BYTES, n);
883 if ((head = hcc_finish_command(trans)) == NULL)
887 FOR_EACH_ITEM(item, trans, head) {
888 if (item->leafid == LC_DATA) {
889 x = item->bytes - sizeof(*item);
892 bcopy(HCC_BINARYDATA(item), buf, x);
893 buf = (char *)buf + x;
908 rc_read(hctransaction_t trans, struct HCHead *head)
916 FOR_EACH_ITEM(item, trans, head) {
917 switch(item->leafid) {
919 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
922 bytes = HCC_INT32(item);
928 if (bytes < 0 || bytes > 32768)
930 n = read(*fdp, buf, bytes);
933 hcc_leaf_data(trans, LC_DATA, buf, n);
941 rc_readfile(hctransaction_t trans, struct HCHead *head)
944 const char *path = NULL;
949 FOR_EACH_ITEM(item, trans, head) {
950 if (item->leafid == LC_PATH1)
951 path = HCC_STRING(item);
955 if ((fd = open(path, O_RDONLY)) < 0)
957 while ((n = read(fd, buf, 32768)) >= 0) {
958 if (!hcc_check_space(trans, head, 1, n)) {
962 hcc_leaf_data(trans, LC_DATA, buf, n);
977 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
979 hctransaction_t trans;
985 if (hc == NULL || hc->host == NULL)
986 return(write(fd, buf, bytes));
988 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
992 size_t limit = getiolimit();
993 int n = (bytes > limit) ? limit : bytes;
996 trans = hcc_start_command(hc, HC_WRITE);
997 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
998 hcc_leaf_data(trans, LC_DATA, buf, n);
999 if ((head = hcc_finish_command(trans)) == NULL)
1003 FOR_EACH_ITEM(item, trans, head) {
1004 if (item->leafid == LC_BYTES)
1005 x = HCC_INT32(item);
1010 buf = (const char *)buf + x;
1022 rc_write(hctransaction_t trans, struct HCHead *head)
1024 struct HCLeaf *item;
1029 FOR_EACH_ITEM(item, trans, head) {
1030 switch(item->leafid) {
1032 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1035 buf = HCC_BINARYDATA(item);
1036 n = item->bytes - sizeof(*item);
1041 head->error = EACCES;
1046 if (n < 0 || n > 32768)
1048 n = write(*fdp, buf, n);
1051 hcc_leaf_int32(trans, LC_BYTES, n);
1058 * NOTE: This function returns -errno if an error occured.
1061 hc_remove(struct HostConf *hc, const char *path)
1063 hctransaction_t trans;
1064 struct HCHead *head;
1067 if (hc == NULL || hc->host == NULL) {
1074 trans = hcc_start_command(hc, HC_REMOVE);
1075 hcc_leaf_string(trans, LC_PATH1, path);
1076 if ((head = hcc_finish_command(trans)) == NULL)
1079 return(-(int)head->error);
1084 rc_remove(hctransaction_t trans, struct HCHead *head)
1086 struct HCLeaf *item;
1087 const char *path = NULL;
1089 FOR_EACH_ITEM(item, trans, head) {
1090 if (item->leafid == LC_PATH1)
1091 path = HCC_STRING(item);
1096 head->error = EACCES;
1099 return(remove(path));
1106 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1108 hctransaction_t trans;
1109 struct HCHead *head;
1111 if (hc == NULL || hc->host == NULL)
1112 return(mkdir(path, mode));
1114 trans = hcc_start_command(hc, HC_MKDIR);
1115 hcc_leaf_string(trans, LC_PATH1, path);
1116 hcc_leaf_int32(trans, LC_MODE, mode);
1117 if ((head = hcc_finish_command(trans)) == NULL)
1125 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1127 struct HCLeaf *item;
1128 const char *path = NULL;
1131 FOR_EACH_ITEM(item, trans, head) {
1132 switch(item->leafid) {
1134 path = HCC_STRING(item);
1137 mode = HCC_INT32(item);
1142 head->error = EACCES;
1147 return(mkdir(path, mode));
1154 hc_rmdir(struct HostConf *hc, const char *path)
1156 hctransaction_t trans;
1157 struct HCHead *head;
1159 if (hc == NULL || hc->host == NULL)
1160 return(rmdir(path));
1162 trans = hcc_start_command(hc, HC_RMDIR);
1163 hcc_leaf_string(trans, LC_PATH1, path);
1164 if ((head = hcc_finish_command(trans)) == NULL)
1172 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1174 struct HCLeaf *item;
1175 const char *path = NULL;
1177 FOR_EACH_ITEM(item, trans, head) {
1178 if (item->leafid == LC_PATH1)
1179 path = HCC_STRING(item);
1182 head->error = EACCES;
1187 return(rmdir(path));
1193 * Almost silently ignore chowns that fail if we are not root.
1196 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1198 hctransaction_t trans;
1199 struct HCHead *head;
1205 if (hc == NULL || hc->host == NULL) {
1206 rc = chown(path, owner, group);
1208 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1212 trans = hcc_start_command(hc, HC_CHOWN);
1213 hcc_leaf_string(trans, LC_PATH1, path);
1214 hcc_leaf_int32(trans, LC_UID, owner);
1215 hcc_leaf_int32(trans, LC_GID, group);
1216 if ((head = hcc_finish_command(trans)) == NULL)
1224 rc_chown(hctransaction_t trans, struct HCHead *head)
1226 struct HCLeaf *item;
1227 const char *path = NULL;
1228 uid_t uid = (uid_t)-1;
1229 gid_t gid = (gid_t)-1;
1232 FOR_EACH_ITEM(item, trans, head) {
1233 switch(item->leafid) {
1235 path = HCC_STRING(item);
1238 uid = HCC_INT32(item);
1241 gid = HCC_INT32(item);
1246 head->error = EACCES;
1251 rc = chown(path, uid, gid);
1253 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1261 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1263 hctransaction_t trans;
1264 struct HCHead *head;
1270 if (hc == NULL || hc->host == NULL) {
1271 rc = lchown(path, owner, group);
1273 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1277 trans = hcc_start_command(hc, HC_LCHOWN);
1278 hcc_leaf_string(trans, LC_PATH1, path);
1279 hcc_leaf_int32(trans, LC_UID, owner);
1280 hcc_leaf_int32(trans, LC_GID, group);
1281 if ((head = hcc_finish_command(trans)) == NULL)
1289 rc_lchown(hctransaction_t trans, struct HCHead *head)
1291 struct HCLeaf *item;
1292 const char *path = NULL;
1293 uid_t uid = (uid_t)-1;
1294 gid_t gid = (gid_t)-1;
1297 FOR_EACH_ITEM(item, trans, head) {
1298 switch(item->leafid) {
1300 path = HCC_STRING(item);
1303 uid = HCC_INT32(item);
1306 gid = HCC_INT32(item);
1311 head->error = EACCES;
1316 rc = lchown(path, uid, gid);
1318 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1326 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1328 hctransaction_t trans;
1329 struct HCHead *head;
1331 if (hc == NULL || hc->host == NULL)
1332 return(chmod(path, mode));
1334 trans = hcc_start_command(hc, HC_CHMOD);
1335 hcc_leaf_string(trans, LC_PATH1, path);
1336 hcc_leaf_int32(trans, LC_MODE, mode);
1337 if ((head = hcc_finish_command(trans)) == NULL)
1345 rc_chmod(hctransaction_t trans, struct HCHead *head)
1347 struct HCLeaf *item;
1348 const char *path = NULL;
1351 FOR_EACH_ITEM(item, trans, head) {
1352 switch(item->leafid) {
1354 path = HCC_STRING(item);
1357 mode = HCC_INT32(item);
1362 head->error = EACCES;
1367 return(chmod(path, mode));
1374 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1376 hctransaction_t trans;
1377 struct HCHead *head;
1379 if (!DstRootPrivs) {
1380 /* mknod() requires root privs, so don't bother. */
1385 if (hc == NULL || hc->host == NULL)
1386 return(mknod(path, mode, rdev));
1388 trans = hcc_start_command(hc, HC_MKNOD);
1389 hcc_leaf_string(trans, LC_PATH1, path);
1390 hcc_leaf_int32(trans, LC_MODE, mode);
1391 hcc_leaf_int32(trans, LC_RDEV, rdev);
1392 if ((head = hcc_finish_command(trans)) == NULL)
1400 rc_mknod(hctransaction_t trans, struct HCHead *head)
1402 struct HCLeaf *item;
1403 const char *path = NULL;
1407 FOR_EACH_ITEM(item, trans, head) {
1408 switch(item->leafid) {
1410 path = HCC_STRING(item);
1413 mode = HCC_INT32(item);
1416 rdev = HCC_INT32(item);
1421 head->error = EACCES;
1426 return(mknod(path, mode, rdev));
1433 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1435 hctransaction_t trans;
1436 struct HCHead *head;
1438 if (hc == NULL || hc->host == NULL)
1439 return(link(name1, name2));
1441 trans = hcc_start_command(hc, HC_LINK);
1442 hcc_leaf_string(trans, LC_PATH1, name1);
1443 hcc_leaf_string(trans, LC_PATH2, name2);
1444 if ((head = hcc_finish_command(trans)) == NULL)
1452 rc_link(hctransaction_t trans, struct HCHead *head)
1454 struct HCLeaf *item;
1455 const char *name1 = NULL;
1456 const char *name2 = NULL;
1458 FOR_EACH_ITEM(item, trans, head) {
1459 switch(item->leafid) {
1461 name1 = HCC_STRING(item);
1464 name2 = HCC_STRING(item);
1469 head->error = EACCES;
1472 if (name1 == NULL || name2 == NULL)
1474 return(link(name1, name2));
1477 #ifdef _ST_FLAGS_PRESENT_
1482 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1484 hctransaction_t trans;
1485 struct HCHead *head;
1489 flags &= UF_SETTABLE;
1491 if (hc == NULL || hc->host == NULL) {
1492 if ((rc = chflags(path, flags)) < 0)
1493 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1497 trans = hcc_start_command(hc, HC_CHFLAGS);
1498 hcc_leaf_string(trans, LC_PATH1, path);
1499 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1500 if ((head = hcc_finish_command(trans)) == NULL)
1508 rc_chflags(hctransaction_t trans, struct HCHead *head)
1510 struct HCLeaf *item;
1511 const char *path = NULL;
1515 FOR_EACH_ITEM(item, trans, head) {
1516 switch(item->leafid) {
1518 path = HCC_STRING(item);
1521 flags = (u_long)HCC_INT64(item);
1526 head->error = EACCES;
1531 if ((rc = chflags(path, flags)) < 0)
1532 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1542 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1544 hctransaction_t trans;
1545 struct HCHead *head;
1546 struct HCLeaf *item;
1549 if (hc == NULL || hc->host == NULL)
1550 return(readlink(path, buf, bufsiz));
1552 trans = hcc_start_command(hc, HC_READLINK);
1553 hcc_leaf_string(trans, LC_PATH1, path);
1554 if ((head = hcc_finish_command(trans)) == NULL)
1560 FOR_EACH_ITEM(item, trans, head) {
1561 if (item->leafid == LC_DATA) {
1562 r = item->bytes - sizeof(*item);
1567 bcopy(HCC_BINARYDATA(item), buf, r);
1574 rc_readlink(hctransaction_t trans, struct HCHead *head)
1576 struct HCLeaf *item;
1577 const char *path = NULL;
1581 FOR_EACH_ITEM(item, trans, head) {
1582 if (item->leafid == LC_PATH1)
1583 path = HCC_STRING(item);
1587 r = readlink(path, buf, sizeof(buf));
1590 hcc_leaf_data(trans, LC_DATA, buf, r);
1598 hc_umask(struct HostConf *hc, mode_t numask)
1600 hctransaction_t trans;
1601 struct HCHead *head;
1602 struct HCLeaf *item;
1604 if (hc == NULL || hc->host == NULL)
1605 return(umask(numask));
1607 trans = hcc_start_command(hc, HC_UMASK);
1608 hcc_leaf_int32(trans, LC_MODE, numask);
1609 if ((head = hcc_finish_command(trans)) == NULL)
1614 numask = (mode_t) ~0666U;
1615 FOR_EACH_ITEM(item, trans, head) {
1616 if (item->leafid == LC_MODE)
1617 numask = HCC_INT32(item);
1623 rc_umask(hctransaction_t trans, struct HCHead *head)
1625 struct HCLeaf *item;
1626 mode_t numask = (mode_t) ~0666U;
1628 FOR_EACH_ITEM(item, trans, head) {
1629 if (item->leafid == LC_MODE)
1630 numask = HCC_INT32(item);
1632 numask = umask(numask);
1633 hcc_leaf_int32(trans, LC_MODE, numask);
1641 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1643 hctransaction_t trans;
1644 struct HCHead *head;
1646 if (hc == NULL || hc->host == NULL)
1647 return(symlink(name1, name2));
1649 trans = hcc_start_command(hc, HC_SYMLINK);
1650 hcc_leaf_string(trans, LC_PATH1, name1);
1651 hcc_leaf_string(trans, LC_PATH2, name2);
1652 if ((head = hcc_finish_command(trans)) == NULL)
1660 rc_symlink(hctransaction_t trans, struct HCHead *head)
1662 struct HCLeaf *item;
1663 const char *name1 = NULL;
1664 const char *name2 = NULL;
1666 FOR_EACH_ITEM(item, trans, head) {
1667 switch(item->leafid) {
1669 name1 = HCC_STRING(item);
1672 name2 = HCC_STRING(item);
1677 head->error = EACCES;
1680 if (name1 == NULL || name2 == NULL)
1682 return(symlink(name1, name2));
1689 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1691 hctransaction_t trans;
1692 struct HCHead *head;
1694 if (hc == NULL || hc->host == NULL)
1695 return(rename(name1, name2));
1697 trans = hcc_start_command(hc, HC_RENAME);
1698 hcc_leaf_string(trans, LC_PATH1, name1);
1699 hcc_leaf_string(trans, LC_PATH2, name2);
1700 if ((head = hcc_finish_command(trans)) == NULL)
1708 rc_rename(hctransaction_t trans, struct HCHead *head)
1710 struct HCLeaf *item;
1711 const char *name1 = NULL;
1712 const char *name2 = NULL;
1714 FOR_EACH_ITEM(item, trans, head) {
1715 switch(item->leafid) {
1717 name1 = HCC_STRING(item);
1720 name2 = HCC_STRING(item);
1725 head->error = EACCES;
1728 if (name1 == NULL || name2 == NULL)
1730 return(rename(name1, name2));
1737 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1739 hctransaction_t trans;
1740 struct HCHead *head;
1742 if (hc == NULL || hc->host == NULL)
1743 return(utimes(path, times));
1745 trans = hcc_start_command(hc, HC_UTIMES);
1746 hcc_leaf_string(trans, LC_PATH1, path);
1747 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1748 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1749 if ((head = hcc_finish_command(trans)) == NULL)
1757 rc_utimes(hctransaction_t trans, struct HCHead *head)
1759 struct HCLeaf *item;
1760 struct timeval times[2];
1763 bzero(times, sizeof(times));
1766 FOR_EACH_ITEM(item, trans, head) {
1767 switch(item->leafid) {
1769 path = HCC_STRING(item);
1772 times[0].tv_sec = HCC_INT64(item);
1775 times[1].tv_sec = HCC_INT64(item);
1780 head->error = EACCES;
1785 return(utimes(path, times));
1789 hc_geteuid(struct HostConf *hc)
1791 hctransaction_t trans;
1792 struct HCHead *head;
1793 struct HCLeaf *item;
1795 if (hc == NULL || hc->host == NULL)
1798 if (hc->version < 3) {
1799 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1800 /* Return 0 on error, so the caller assumes root privileges. */
1804 trans = hcc_start_command(hc, HC_GETEUID);
1805 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1807 FOR_EACH_ITEM(item, trans, head) {
1808 if (item->leafid == LC_UID)
1809 return (HCC_INT32(item));
1811 return(0); /* shouldn't happen */
1815 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1817 hcc_leaf_int32(trans, LC_UID, geteuid());
1822 getmygroups(gid_t **gidlist)
1826 if ((count = getgroups(0, *gidlist)) > 0) {
1827 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1828 if ((count = getgroups(count, *gidlist)) <= 0)
1840 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1843 hctransaction_t trans;
1844 struct HCHead *head;
1845 struct HCLeaf *item;
1847 if (hc == NULL || hc->host == NULL)
1848 return (getmygroups(gidlist));
1854 if (hc->version < 3) {
1855 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1859 trans = hcc_start_command(hc, HC_GETGROUPS);
1860 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1862 FOR_EACH_ITEM(item, trans, head) {
1863 switch(item->leafid) {
1865 count = HCC_INT32(item);
1866 if (*gidlist != NULL) { /* protocol error */
1871 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1875 if (*gidlist == NULL || i >= count) { /* protocol error */
1876 if (*gidlist != NULL)
1881 (*gidlist)[i++] = HCC_INT32(item);
1889 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1894 if ((count = getmygroups(&gidlist)) < 0)
1896 hcc_leaf_int32(trans, LC_COUNT, count);
1897 for (i = 0; i < count; i++)
1898 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1899 if (gidlist != NULL)