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]));
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 (NotForRealOpt && (flags & O_CREAT))
662 if (hc == NULL || hc->host == NULL) {
664 flags |= O_LARGEFILE;
666 return(open(path, flags, mode));
669 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
670 trans = hcc_start_command(hc, HC_READFILE);
671 hcc_leaf_string(trans, LC_PATH1, path);
672 if ((head = hcc_finish_command(trans)) == NULL || head->error)
674 head->magic = 0; /* used to indicate offset within buffer */
675 return (1); /* dummy */
678 nflags = flags & XO_NATIVEMASK;
686 trans = hcc_start_command(hc, HC_OPEN);
687 hcc_leaf_string(trans, LC_PATH1, path);
688 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
689 hcc_leaf_int32(trans, LC_MODE, mode);
691 if ((head = hcc_finish_command(trans)) == NULL)
695 FOR_EACH_ITEM(item, trans, head) {
696 if (item->leafid == LC_DESCRIPTOR)
697 desc = HCC_INT32(item);
699 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
700 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
704 fdp = malloc(sizeof(int));
705 *fdp = desc; /* really just a dummy */
706 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
711 rc_open(hctransaction_t trans, struct HCHead *head)
714 const char *path = NULL;
722 FOR_EACH_ITEM(item, trans, head) {
723 switch(item->leafid) {
725 path = HCC_STRING(item);
728 nflags = HCC_INT32(item);
731 mode = HCC_INT32(item);
738 flags = nflags & XO_NATIVEMASK;
739 if (nflags & XO_CREAT)
741 if (nflags & XO_EXCL)
743 if (nflags & XO_TRUNC)
747 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
748 head->error = EACCES;
755 flags |= O_LARGEFILE;
757 if ((fd = open(path, flags, mode)) < 0)
759 fdp = malloc(sizeof(int));
761 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
762 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
770 hc_close(struct HostConf *hc, int fd)
772 hctransaction_t trans;
776 if (NotForRealOpt && fd == 0x7FFFFFFF)
778 if (hc == NULL || hc->host == NULL)
781 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
782 head = (void *)hc->trans.rbuf;
783 /* skip any remaining items if the file is closed prematurely */
784 while (hcc_nextchaineditem(hc, head) != NULL)
791 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
794 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
796 trans = hcc_start_command(hc, HC_CLOSE);
797 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
798 if ((head = hcc_finish_command(trans)) == NULL)
809 rc_close(hctransaction_t trans, struct HCHead *head)
816 FOR_EACH_ITEM(item, trans, head) {
817 if (item->leafid == LC_DESCRIPTOR)
818 desc = HCC_INT32(item);
822 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
826 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
840 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
842 hctransaction_t trans;
850 if (hc == NULL || hc->host == NULL)
851 return(read(fd, buf, bytes));
853 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
854 head = (void *)hc->trans.rbuf;
856 if ((offset = head->magic) != 0)
857 item = hcc_currentchaineditem(hc, head);
859 item = hcc_nextchaineditem(hc, head);
862 if (item->leafid != LC_DATA)
864 x = item->bytes - sizeof(*item) - offset;
865 if (x > (int)bytes) {
867 head->magic += x; /* leave bytes in the buffer */
870 head->magic = 0; /* all bytes used up */
871 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
872 buf = (char *)buf + x;
879 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
882 size_t limit = getiolimit();
883 int n = (bytes > limit) ? limit : bytes;
885 trans = hcc_start_command(hc, HC_READ);
886 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
887 hcc_leaf_int32(trans, LC_BYTES, n);
888 if ((head = hcc_finish_command(trans)) == NULL)
892 FOR_EACH_ITEM(item, trans, head) {
893 if (item->leafid == LC_DATA) {
894 x = item->bytes - sizeof(*item);
897 bcopy(HCC_BINARYDATA(item), buf, x);
898 buf = (char *)buf + x;
913 rc_read(hctransaction_t trans, struct HCHead *head)
921 FOR_EACH_ITEM(item, trans, head) {
922 switch(item->leafid) {
924 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
927 bytes = HCC_INT32(item);
933 if (bytes < 0 || bytes > 32768)
935 n = read(*fdp, buf, bytes);
938 hcc_leaf_data(trans, LC_DATA, buf, n);
946 rc_readfile(hctransaction_t trans, struct HCHead *head)
949 const char *path = NULL;
954 FOR_EACH_ITEM(item, trans, head) {
955 if (item->leafid == LC_PATH1)
956 path = HCC_STRING(item);
960 if ((fd = open(path, O_RDONLY)) < 0)
962 while ((n = read(fd, buf, 32768)) >= 0) {
963 if (!hcc_check_space(trans, head, 1, n)) {
967 hcc_leaf_data(trans, LC_DATA, buf, n);
982 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
984 hctransaction_t trans;
993 if (hc == NULL || hc->host == NULL)
994 return(write(fd, buf, bytes));
996 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1000 size_t limit = getiolimit();
1001 int n = (bytes > limit) ? limit : bytes;
1004 trans = hcc_start_command(hc, HC_WRITE);
1005 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1006 hcc_leaf_data(trans, LC_DATA, buf, n);
1007 if ((head = hcc_finish_command(trans)) == NULL)
1011 FOR_EACH_ITEM(item, trans, head) {
1012 if (item->leafid == LC_BYTES)
1013 x = HCC_INT32(item);
1018 buf = (const char *)buf + x;
1030 rc_write(hctransaction_t trans, struct HCHead *head)
1032 struct HCLeaf *item;
1037 FOR_EACH_ITEM(item, trans, head) {
1038 switch(item->leafid) {
1040 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1043 buf = HCC_BINARYDATA(item);
1044 n = item->bytes - sizeof(*item);
1049 head->error = EACCES;
1054 if (n < 0 || n > 32768)
1056 n = write(*fdp, buf, n);
1059 hcc_leaf_int32(trans, LC_BYTES, n);
1066 * NOTE: This function returns -errno if an error occured.
1069 hc_remove(struct HostConf *hc, const char *path)
1071 hctransaction_t trans;
1072 struct HCHead *head;
1077 if (hc == NULL || hc->host == NULL) {
1084 trans = hcc_start_command(hc, HC_REMOVE);
1085 hcc_leaf_string(trans, LC_PATH1, path);
1086 if ((head = hcc_finish_command(trans)) == NULL)
1089 return(-(int)head->error);
1094 rc_remove(hctransaction_t trans, struct HCHead *head)
1096 struct HCLeaf *item;
1097 const char *path = NULL;
1099 FOR_EACH_ITEM(item, trans, head) {
1100 if (item->leafid == LC_PATH1)
1101 path = HCC_STRING(item);
1106 head->error = EACCES;
1109 return(remove(path));
1116 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1118 hctransaction_t trans;
1119 struct HCHead *head;
1123 if (hc == NULL || hc->host == NULL)
1124 return(mkdir(path, mode));
1126 trans = hcc_start_command(hc, HC_MKDIR);
1127 hcc_leaf_string(trans, LC_PATH1, path);
1128 hcc_leaf_int32(trans, LC_MODE, mode);
1129 if ((head = hcc_finish_command(trans)) == NULL)
1137 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1139 struct HCLeaf *item;
1140 const char *path = NULL;
1143 FOR_EACH_ITEM(item, trans, head) {
1144 switch(item->leafid) {
1146 path = HCC_STRING(item);
1149 mode = HCC_INT32(item);
1154 head->error = EACCES;
1159 return(mkdir(path, mode));
1166 hc_rmdir(struct HostConf *hc, const char *path)
1168 hctransaction_t trans;
1169 struct HCHead *head;
1173 if (hc == NULL || hc->host == NULL)
1174 return(rmdir(path));
1176 trans = hcc_start_command(hc, HC_RMDIR);
1177 hcc_leaf_string(trans, LC_PATH1, path);
1178 if ((head = hcc_finish_command(trans)) == NULL)
1186 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1188 struct HCLeaf *item;
1189 const char *path = NULL;
1191 FOR_EACH_ITEM(item, trans, head) {
1192 if (item->leafid == LC_PATH1)
1193 path = HCC_STRING(item);
1196 head->error = EACCES;
1201 return(rmdir(path));
1207 * Almost silently ignore chowns that fail if we are not root.
1210 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1212 hctransaction_t trans;
1213 struct HCHead *head;
1221 if (hc == NULL || hc->host == NULL) {
1222 rc = chown(path, owner, group);
1224 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1228 trans = hcc_start_command(hc, HC_CHOWN);
1229 hcc_leaf_string(trans, LC_PATH1, path);
1230 hcc_leaf_int32(trans, LC_UID, owner);
1231 hcc_leaf_int32(trans, LC_GID, group);
1232 if ((head = hcc_finish_command(trans)) == NULL)
1240 rc_chown(hctransaction_t trans, struct HCHead *head)
1242 struct HCLeaf *item;
1243 const char *path = NULL;
1244 uid_t uid = (uid_t)-1;
1245 gid_t gid = (gid_t)-1;
1248 FOR_EACH_ITEM(item, trans, head) {
1249 switch(item->leafid) {
1251 path = HCC_STRING(item);
1254 uid = HCC_INT32(item);
1257 gid = HCC_INT32(item);
1262 head->error = EACCES;
1267 rc = chown(path, uid, gid);
1269 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1277 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1279 hctransaction_t trans;
1280 struct HCHead *head;
1288 if (hc == NULL || hc->host == NULL) {
1289 rc = lchown(path, owner, group);
1291 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1295 trans = hcc_start_command(hc, HC_LCHOWN);
1296 hcc_leaf_string(trans, LC_PATH1, path);
1297 hcc_leaf_int32(trans, LC_UID, owner);
1298 hcc_leaf_int32(trans, LC_GID, group);
1299 if ((head = hcc_finish_command(trans)) == NULL)
1307 rc_lchown(hctransaction_t trans, struct HCHead *head)
1309 struct HCLeaf *item;
1310 const char *path = NULL;
1311 uid_t uid = (uid_t)-1;
1312 gid_t gid = (gid_t)-1;
1315 FOR_EACH_ITEM(item, trans, head) {
1316 switch(item->leafid) {
1318 path = HCC_STRING(item);
1321 uid = HCC_INT32(item);
1324 gid = HCC_INT32(item);
1329 head->error = EACCES;
1334 rc = lchown(path, uid, gid);
1336 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1344 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1346 hctransaction_t trans;
1347 struct HCHead *head;
1351 if (hc == NULL || hc->host == NULL)
1352 return(chmod(path, mode));
1354 trans = hcc_start_command(hc, HC_CHMOD);
1355 hcc_leaf_string(trans, LC_PATH1, path);
1356 hcc_leaf_int32(trans, LC_MODE, mode);
1357 if ((head = hcc_finish_command(trans)) == NULL)
1365 rc_chmod(hctransaction_t trans, struct HCHead *head)
1367 struct HCLeaf *item;
1368 const char *path = NULL;
1371 FOR_EACH_ITEM(item, trans, head) {
1372 switch(item->leafid) {
1374 path = HCC_STRING(item);
1377 mode = HCC_INT32(item);
1382 head->error = EACCES;
1387 return(chmod(path, mode));
1394 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1396 hctransaction_t trans;
1397 struct HCHead *head;
1401 if (!DstRootPrivs) {
1402 /* mknod() requires root privs, so don't bother. */
1407 if (hc == NULL || hc->host == NULL)
1408 return(mknod(path, mode, rdev));
1410 trans = hcc_start_command(hc, HC_MKNOD);
1411 hcc_leaf_string(trans, LC_PATH1, path);
1412 hcc_leaf_int32(trans, LC_MODE, mode);
1413 hcc_leaf_int32(trans, LC_RDEV, rdev);
1414 if ((head = hcc_finish_command(trans)) == NULL)
1422 rc_mknod(hctransaction_t trans, struct HCHead *head)
1424 struct HCLeaf *item;
1425 const char *path = NULL;
1429 FOR_EACH_ITEM(item, trans, head) {
1430 switch(item->leafid) {
1432 path = HCC_STRING(item);
1435 mode = HCC_INT32(item);
1438 rdev = HCC_INT32(item);
1443 head->error = EACCES;
1448 return(mknod(path, mode, rdev));
1455 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1457 hctransaction_t trans;
1458 struct HCHead *head;
1462 if (hc == NULL || hc->host == NULL)
1463 return(link(name1, name2));
1465 trans = hcc_start_command(hc, HC_LINK);
1466 hcc_leaf_string(trans, LC_PATH1, name1);
1467 hcc_leaf_string(trans, LC_PATH2, name2);
1468 if ((head = hcc_finish_command(trans)) == NULL)
1476 rc_link(hctransaction_t trans, struct HCHead *head)
1478 struct HCLeaf *item;
1479 const char *name1 = NULL;
1480 const char *name2 = NULL;
1482 FOR_EACH_ITEM(item, trans, head) {
1483 switch(item->leafid) {
1485 name1 = HCC_STRING(item);
1488 name2 = HCC_STRING(item);
1493 head->error = EACCES;
1496 if (name1 == NULL || name2 == NULL)
1498 return(link(name1, name2));
1501 #ifdef _ST_FLAGS_PRESENT_
1506 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1508 hctransaction_t trans;
1509 struct HCHead *head;
1515 flags &= UF_SETTABLE;
1517 if (hc == NULL || hc->host == NULL) {
1518 if ((rc = chflags(path, flags)) < 0)
1519 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1523 trans = hcc_start_command(hc, HC_CHFLAGS);
1524 hcc_leaf_string(trans, LC_PATH1, path);
1525 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1526 if ((head = hcc_finish_command(trans)) == NULL)
1534 rc_chflags(hctransaction_t trans, struct HCHead *head)
1536 struct HCLeaf *item;
1537 const char *path = NULL;
1541 FOR_EACH_ITEM(item, trans, head) {
1542 switch(item->leafid) {
1544 path = HCC_STRING(item);
1547 flags = (u_long)HCC_INT64(item);
1552 head->error = EACCES;
1557 if ((rc = chflags(path, flags)) < 0)
1558 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1568 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1570 hctransaction_t trans;
1571 struct HCHead *head;
1572 struct HCLeaf *item;
1575 if (hc == NULL || hc->host == NULL)
1576 return(readlink(path, buf, bufsiz));
1578 trans = hcc_start_command(hc, HC_READLINK);
1579 hcc_leaf_string(trans, LC_PATH1, path);
1580 if ((head = hcc_finish_command(trans)) == NULL)
1586 FOR_EACH_ITEM(item, trans, head) {
1587 if (item->leafid == LC_DATA) {
1588 r = item->bytes - sizeof(*item);
1593 bcopy(HCC_BINARYDATA(item), buf, r);
1600 rc_readlink(hctransaction_t trans, struct HCHead *head)
1602 struct HCLeaf *item;
1603 const char *path = NULL;
1607 FOR_EACH_ITEM(item, trans, head) {
1608 if (item->leafid == LC_PATH1)
1609 path = HCC_STRING(item);
1613 r = readlink(path, buf, sizeof(buf));
1616 hcc_leaf_data(trans, LC_DATA, buf, r);
1624 hc_umask(struct HostConf *hc, mode_t numask)
1626 hctransaction_t trans;
1627 struct HCHead *head;
1628 struct HCLeaf *item;
1631 return(umask(numask));
1632 if (hc == NULL || hc->host == NULL)
1633 return(umask(numask));
1635 trans = hcc_start_command(hc, HC_UMASK);
1636 hcc_leaf_int32(trans, LC_MODE, numask);
1637 if ((head = hcc_finish_command(trans)) == NULL)
1642 numask = (mode_t) ~0666U;
1643 FOR_EACH_ITEM(item, trans, head) {
1644 if (item->leafid == LC_MODE)
1645 numask = HCC_INT32(item);
1651 rc_umask(hctransaction_t trans, struct HCHead *head)
1653 struct HCLeaf *item;
1654 mode_t numask = (mode_t) ~0666U;
1656 FOR_EACH_ITEM(item, trans, head) {
1657 if (item->leafid == LC_MODE)
1658 numask = HCC_INT32(item);
1660 numask = umask(numask);
1661 hcc_leaf_int32(trans, LC_MODE, numask);
1669 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1671 hctransaction_t trans;
1672 struct HCHead *head;
1676 if (hc == NULL || hc->host == NULL)
1677 return(symlink(name1, name2));
1679 trans = hcc_start_command(hc, HC_SYMLINK);
1680 hcc_leaf_string(trans, LC_PATH1, name1);
1681 hcc_leaf_string(trans, LC_PATH2, name2);
1682 if ((head = hcc_finish_command(trans)) == NULL)
1690 rc_symlink(hctransaction_t trans, struct HCHead *head)
1692 struct HCLeaf *item;
1693 const char *name1 = NULL;
1694 const char *name2 = NULL;
1696 FOR_EACH_ITEM(item, trans, head) {
1697 switch(item->leafid) {
1699 name1 = HCC_STRING(item);
1702 name2 = HCC_STRING(item);
1707 head->error = EACCES;
1710 if (name1 == NULL || name2 == NULL)
1712 return(symlink(name1, name2));
1719 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1721 hctransaction_t trans;
1722 struct HCHead *head;
1726 if (hc == NULL || hc->host == NULL)
1727 return(rename(name1, name2));
1729 trans = hcc_start_command(hc, HC_RENAME);
1730 hcc_leaf_string(trans, LC_PATH1, name1);
1731 hcc_leaf_string(trans, LC_PATH2, name2);
1732 if ((head = hcc_finish_command(trans)) == NULL)
1740 rc_rename(hctransaction_t trans, struct HCHead *head)
1742 struct HCLeaf *item;
1743 const char *name1 = NULL;
1744 const char *name2 = NULL;
1746 FOR_EACH_ITEM(item, trans, head) {
1747 switch(item->leafid) {
1749 name1 = HCC_STRING(item);
1752 name2 = HCC_STRING(item);
1757 head->error = EACCES;
1760 if (name1 == NULL || name2 == NULL)
1762 return(rename(name1, name2));
1769 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1771 hctransaction_t trans;
1772 struct HCHead *head;
1776 if (hc == NULL || hc->host == NULL)
1777 return(utimes(path, times));
1779 trans = hcc_start_command(hc, HC_UTIMES);
1780 hcc_leaf_string(trans, LC_PATH1, path);
1781 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1782 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1783 if ((head = hcc_finish_command(trans)) == NULL)
1791 rc_utimes(hctransaction_t trans, struct HCHead *head)
1793 struct HCLeaf *item;
1794 struct timeval times[2];
1797 bzero(times, sizeof(times));
1800 FOR_EACH_ITEM(item, trans, head) {
1801 switch(item->leafid) {
1803 path = HCC_STRING(item);
1806 times[0].tv_sec = HCC_INT64(item);
1809 times[1].tv_sec = HCC_INT64(item);
1814 head->error = EACCES;
1819 return(utimes(path, times));
1823 hc_geteuid(struct HostConf *hc)
1825 hctransaction_t trans;
1826 struct HCHead *head;
1827 struct HCLeaf *item;
1829 if (hc == NULL || hc->host == NULL)
1832 if (hc->version < 3) {
1833 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1834 /* Return 0 on error, so the caller assumes root privileges. */
1838 trans = hcc_start_command(hc, HC_GETEUID);
1839 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1841 FOR_EACH_ITEM(item, trans, head) {
1842 if (item->leafid == LC_UID)
1843 return (HCC_INT32(item));
1845 return(0); /* shouldn't happen */
1849 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1851 hcc_leaf_int32(trans, LC_UID, geteuid());
1856 getmygroups(gid_t **gidlist)
1860 if ((count = getgroups(0, *gidlist)) > 0) {
1861 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1862 if ((count = getgroups(count, *gidlist)) <= 0)
1874 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1877 hctransaction_t trans;
1878 struct HCHead *head;
1879 struct HCLeaf *item;
1881 if (hc == NULL || hc->host == NULL)
1882 return (getmygroups(gidlist));
1888 if (hc->version < 3) {
1889 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1893 trans = hcc_start_command(hc, HC_GETGROUPS);
1894 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1896 FOR_EACH_ITEM(item, trans, head) {
1897 switch(item->leafid) {
1899 count = HCC_INT32(item);
1900 if (*gidlist != NULL) { /* protocol error */
1905 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1909 if (*gidlist == NULL || i >= count) { /* protocol error */
1910 if (*gidlist != NULL)
1915 (*gidlist)[i++] = HCC_INT32(item);
1923 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1928 if ((count = getmygroups(&gidlist)) < 0)
1930 hcc_leaf_int32(trans, LC_COUNT, count);
1931 for (i = 0; i < count; i++)
1932 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1933 if (gidlist != NULL)