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 #ifdef _ST_FLAGS_PRESENT_
87 static int chflags_warning;
91 * If not running as root generate a silent warning and return no error.
93 * If running as root return an error.
96 silentwarning(int *didwarn, const char *ctl, ...)
102 if (*didwarn == 0 && QuietOpt == 0) {
104 fprintf(stderr, "WARNING: Not running as root, ");
106 vfprintf(stderr, ctl, va);
113 hc_connect(struct HostConf *hc, int readonly)
115 if (hcc_connect(hc, readonly) < 0) {
116 fprintf(stderr, "Unable to connect to %s\n", hc->host);
119 return(hc_hello(hc));
123 hc_slave(int fdin, int fdout)
125 hcc_slave(fdin, fdout, HCDispatchTable,
126 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
130 * A HELLO RPC is sent on the initial connect.
133 hc_hello(struct HostConf *hc)
137 hctransaction_t trans;
141 bzero(hostbuf, sizeof(hostbuf));
142 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
147 trans = hcc_start_command(hc, HC_HELLO);
148 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
149 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
151 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
152 if ((head = hcc_finish_command(trans)) == NULL) {
153 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
159 fprintf(stderr, "Connected to %s but remote returned error %d\n",
160 hc->host, head->error);
165 FOR_EACH_ITEM(item, trans, head) {
166 switch(item->leafid) {
169 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
173 hc->version = HCC_INT32(item);
177 if (hc->version < HCPROTO_VERSION_COMPAT) {
178 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
181 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
183 "WARNING: Remote cpdup at %s has a lower version,\n"
184 "expect reduced speed and/or functionality\n", hc->host);
187 fprintf(stderr, "Handshake failed with %s\n", hc->host);
192 rc_hello(hctransaction_t trans, struct HCHead *head)
197 FOR_EACH_ITEM(item, trans, head) {
198 if (item->leafid == LC_PATH1)
199 UseCpFile = strdup(HCC_STRING(item));
202 bzero(hostbuf, sizeof(hostbuf));
203 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
208 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
209 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
217 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
220 hctransaction_t trans;
222 if (hc == NULL || hc->host == NULL)
223 return(stat(path, st));
225 trans = hcc_start_command(hc, HC_STAT);
226 hcc_leaf_string(trans, LC_PATH1, path);
227 if ((head = hcc_finish_command(trans)) == NULL)
231 return(hc_decode_stat(trans, st, head));
235 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
238 hctransaction_t trans;
240 if (hc == NULL || hc->host == NULL)
241 return(lstat(path, st));
243 trans = hcc_start_command(hc, HC_LSTAT);
244 hcc_leaf_string(trans, LC_PATH1, path);
245 if ((head = hcc_finish_command(trans)) == NULL)
249 return(hc_decode_stat(trans, st, head));
253 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
257 bzero(st, sizeof(*st));
258 FOR_EACH_ITEM(item, trans, head)
259 hc_decode_stat_item(st, item);
264 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
266 switch(item->leafid) {
268 st->st_dev = HCC_INT32(item);
271 st->st_ino = HCC_INT64(item);
274 st->st_mode = HCC_INT32(item);
277 st->st_nlink = HCC_INT32(item);
280 st->st_uid = HCC_INT32(item);
283 st->st_gid = HCC_INT32(item);
286 st->st_rdev = HCC_INT32(item);
289 st->st_atime = (time_t)HCC_INT64(item);
292 st->st_mtime = (time_t)HCC_INT64(item);
295 st->st_ctime = (time_t)HCC_INT64(item);
297 #if defined(st_atime) /* A macro, so very likely on modern POSIX */
299 st->st_atim.tv_nsec = HCC_INT32(item);
302 st->st_mtim.tv_nsec = HCC_INT32(item);
305 st->st_ctim.tv_nsec = HCC_INT32(item);
309 st->st_size = HCC_INT64(item);
312 st->st_blocks = HCC_INT64(item);
315 st->st_blksize = HCC_INT32(item);
317 #ifdef _ST_FSMID_PRESENT_
319 st->st_fsmid = HCC_INT64(item);
322 #ifdef _ST_FLAGS_PRESENT_
324 st->st_flags = (uint32_t)HCC_INT64(item);
332 rc_stat(hctransaction_t trans, struct HCHead *head)
336 const char *path = NULL;
338 FOR_EACH_ITEM(item, trans, head) {
339 if (item->leafid == LC_PATH1)
340 path = HCC_STRING(item);
344 if (stat(path, &st) < 0)
346 return (rc_encode_stat(trans, &st));
350 rc_lstat(hctransaction_t trans, struct HCHead *head)
354 const char *path = NULL;
356 FOR_EACH_ITEM(item, trans, head) {
357 if (item->leafid == LC_PATH1)
358 path = HCC_STRING(item);
362 if (lstat(path, &st) < 0)
364 return (rc_encode_stat(trans, &st));
368 * Encode all entries of a stat structure.
370 * CAUTION: If you add any more entries here, be sure to
371 * increase the STAT_MAX_NUM_ENTRIES value!
373 #define STAT_MAX_NUM_ENTRIES 18
375 rc_encode_stat(hctransaction_t trans, struct stat *st)
377 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
378 hcc_leaf_int64(trans, LC_INO, st->st_ino);
379 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
380 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
381 hcc_leaf_int32(trans, LC_UID, st->st_uid);
382 hcc_leaf_int32(trans, LC_GID, st->st_gid);
383 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
384 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
385 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
386 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
387 #if defined(st_atime)
388 hcc_leaf_int32(trans, LC_ATIMENSEC, st->st_atim.tv_nsec);
389 hcc_leaf_int32(trans, LC_MTIMENSEC, st->st_mtim.tv_nsec);
390 hcc_leaf_int32(trans, LC_CTIMENSEC, st->st_ctim.tv_nsec);
392 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
393 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
394 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
395 #ifdef _ST_FSMID_PRESENT_
396 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
398 #ifdef _ST_FLAGS_PRESENT_
399 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
408 hc_opendir(struct HostConf *hc, const char *path)
410 hctransaction_t trans;
413 if (hc == NULL || hc->host == NULL)
414 return(opendir(path));
416 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
418 struct HCDirEntry *den;
421 trans = hcc_start_command(hc, HC_OPENDIR);
422 hcc_leaf_string(trans, LC_PATH1, path);
423 if ((head = hcc_finish_command(trans)) == NULL)
427 FOR_EACH_ITEM(item, trans, head) {
428 if (item->leafid == LC_DESCRIPTOR)
429 desc = HCC_INT32(item);
431 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
432 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
436 den = malloc(sizeof(*den));
437 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
438 return ((void *)desc);
441 /* hc->version >= 4: use HC_SCANDIR */
442 trans = hcc_start_command(hc, HC_SCANDIR);
443 hcc_leaf_string(trans, LC_PATH1, path);
444 if ((head = hcc_finish_command(trans)) == NULL || head->error)
446 return ((void *)head);
450 rc_opendir(hctransaction_t trans, struct HCHead *head)
453 const char *path = NULL;
457 FOR_EACH_ITEM(item, trans, head) {
458 if (item->leafid == LC_PATH1)
459 path = HCC_STRING(item);
463 if ((dir = opendir(path)) == NULL) {
466 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
467 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
476 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
481 static struct HCDirEntry denbuf;
484 if (hc == NULL || hc->host == NULL) {
485 struct dirent *sysden;
487 if ((sysden = readdir(dir)) == NULL)
489 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
493 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
494 hctransaction_t trans;
495 struct HCDirEntry *den;
497 trans = hcc_start_command(hc, HC_READDIR);
498 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
499 if ((head = hcc_finish_command(trans)) == NULL)
502 return (NULL); /* XXX errno */
503 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
505 return (NULL); /* XXX errno */
507 FOR_EACH_ITEM(item, trans, head) {
508 if (item->leafid == LC_PATH1)
509 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
511 return (den->d_name[0] ? den : NULL);
514 /* hc->version >= 4: using HC_SCANDIR */
515 denbuf.d_name[0] = 0;
517 *statpp = malloc(sizeof(struct stat));
518 bzero(*statpp, sizeof(struct stat));
519 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
520 if (item->leafid == LC_PATH1) { /* this must be the last item */
521 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
525 hc_decode_stat_item(*statpp, item);
532 if (hc->trans.state == HCT_FAIL)
534 return (denbuf.d_name[0] ? &denbuf : NULL);
538 rc_readdir(hctransaction_t trans, struct HCHead *head)
544 FOR_EACH_ITEM(item, trans, head) {
545 if (item->leafid == LC_DESCRIPTOR)
546 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
550 if ((den = readdir(dir)) != NULL)
551 hcc_leaf_string(trans, LC_PATH1, den->d_name);
558 * XXX cpdup needs to check error code to avoid truncated dirs?
561 hc_closedir(struct HostConf *hc, DIR *dir)
565 if (hc == NULL || hc->host == NULL)
566 return(closedir(dir));
568 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
569 hctransaction_t trans;
572 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
574 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
575 trans = hcc_start_command(hc, HC_CLOSEDIR);
576 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
577 if ((head = hcc_finish_command(trans)) == NULL)
580 return (-1); /* XXX errno */
588 /* hc->version >= 4: using HC_SCANDIR */
590 /* skip any remaining items if the directory is closed prematurely */
591 while (hcc_nextchaineditem(hc, head) != NULL)
593 if (hc->trans.state == HCT_FAIL || head->error)
599 rc_closedir(hctransaction_t trans, struct HCHead *head)
604 FOR_EACH_ITEM(item, trans, head) {
605 if (item->leafid == LC_DESCRIPTOR) {
606 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
608 hcc_set_descriptor(trans->hc, HCC_INT32(item),
615 return(closedir(dir));
622 rc_scandir(hctransaction_t trans, struct HCHead *head)
625 const char *path = NULL;
631 FOR_EACH_ITEM(item, trans, head) {
632 if (item->leafid == LC_PATH1)
633 path = HCC_STRING(item);
637 if ((dir = opendir(path)) == NULL)
639 while ((den = readdir(dir)) != NULL) {
640 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
641 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
642 continue; /* skip "." and ".." */
644 * Check if there's enough space left in the current packet.
645 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
646 * one is a string, so we use strlen() + 1 (terminating zero).
647 * The remaining ones are numbers; we assume sizeof(int64_t) so
648 * we're on the safe side.
650 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
651 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
652 strlen(den->d_name) + 1)) {
656 fpath = mprintf("%s/%s", path, den->d_name);
657 if (lstat(fpath, &st) == 0)
658 rc_encode_stat(trans, &st);
659 /* The name must be the last item! */
660 hcc_leaf_string(trans, LC_PATH1, den->d_name);
663 return (closedir(dir));
670 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
672 hctransaction_t trans;
679 if (NotForRealOpt && (flags & O_CREAT))
682 if (hc == NULL || hc->host == NULL) {
684 flags |= O_LARGEFILE;
686 return(open(path, flags, mode));
689 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
690 trans = hcc_start_command(hc, HC_READFILE);
691 hcc_leaf_string(trans, LC_PATH1, path);
692 if ((head = hcc_finish_command(trans)) == NULL || head->error)
694 head->magic = 0; /* used to indicate offset within buffer */
695 return (1); /* dummy */
698 nflags = flags & XO_NATIVEMASK;
706 trans = hcc_start_command(hc, HC_OPEN);
707 hcc_leaf_string(trans, LC_PATH1, path);
708 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
709 hcc_leaf_int32(trans, LC_MODE, mode);
711 if ((head = hcc_finish_command(trans)) == NULL)
715 FOR_EACH_ITEM(item, trans, head) {
716 if (item->leafid == LC_DESCRIPTOR)
717 desc = HCC_INT32(item);
719 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
720 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
724 fdp = malloc(sizeof(int));
725 *fdp = desc; /* really just a dummy */
726 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
731 rc_open(hctransaction_t trans, struct HCHead *head)
734 const char *path = NULL;
742 FOR_EACH_ITEM(item, trans, head) {
743 switch(item->leafid) {
745 path = HCC_STRING(item);
748 nflags = HCC_INT32(item);
751 mode = HCC_INT32(item);
758 flags = nflags & XO_NATIVEMASK;
759 if (nflags & XO_CREAT)
761 if (nflags & XO_EXCL)
763 if (nflags & XO_TRUNC)
767 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
768 head->error = EACCES;
775 flags |= O_LARGEFILE;
777 if ((fd = open(path, flags, mode)) < 0)
779 fdp = malloc(sizeof(int));
781 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
782 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
790 hc_close(struct HostConf *hc, int fd)
792 hctransaction_t trans;
796 if (NotForRealOpt && fd == 0x7FFFFFFF)
798 if (hc == NULL || hc->host == NULL)
801 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
802 head = (void *)hc->trans.rbuf;
803 /* skip any remaining items if the file is closed prematurely */
804 while (hcc_nextchaineditem(hc, head) != NULL)
806 if (hc->trans.state == HCT_FAIL || head->error)
811 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
814 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
816 trans = hcc_start_command(hc, HC_CLOSE);
817 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
818 if ((head = hcc_finish_command(trans)) == NULL)
829 rc_close(hctransaction_t trans, struct HCHead *head)
836 FOR_EACH_ITEM(item, trans, head) {
837 if (item->leafid == LC_DESCRIPTOR)
838 desc = HCC_INT32(item);
842 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
846 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
860 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
862 hctransaction_t trans;
870 if (hc == NULL || hc->host == NULL)
871 return(read(fd, buf, bytes));
873 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
874 head = (void *)hc->trans.rbuf;
876 if ((offset = head->magic) != 0) {
877 item = hcc_currentchaineditem(hc, head);
879 item = hcc_nextchaineditem(hc, head);
882 if (hc->trans.state == HCT_FAIL)
886 if (item->leafid != LC_DATA)
888 x = item->bytes - sizeof(*item) - offset;
889 if (x > (int)bytes) {
891 head->magic += x; /* leave bytes in the buffer */
894 head->magic = 0; /* all bytes used up */
895 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
896 buf = (char *)buf + x;
903 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
906 size_t limit = getiolimit();
907 int n = (bytes > limit) ? limit : bytes;
909 trans = hcc_start_command(hc, HC_READ);
910 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
911 hcc_leaf_int32(trans, LC_BYTES, n);
912 if ((head = hcc_finish_command(trans)) == NULL)
916 FOR_EACH_ITEM(item, trans, head) {
917 if (item->leafid == LC_DATA) {
918 x = item->bytes - sizeof(*item);
921 bcopy(HCC_BINARYDATA(item), buf, x);
922 buf = (char *)buf + x;
937 rc_read(hctransaction_t trans, struct HCHead *head)
945 FOR_EACH_ITEM(item, trans, head) {
946 switch(item->leafid) {
948 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
951 bytes = HCC_INT32(item);
957 if (bytes < 0 || bytes > 32768)
959 n = read(*fdp, buf, bytes);
962 hcc_leaf_data(trans, LC_DATA, buf, n);
970 rc_readfile(hctransaction_t trans, struct HCHead *head)
973 const char *path = NULL;
978 FOR_EACH_ITEM(item, trans, head) {
979 if (item->leafid == LC_PATH1)
980 path = HCC_STRING(item);
984 if ((fd = open(path, O_RDONLY)) < 0)
986 while ((n = read(fd, buf, 32768)) >= 0) {
987 if (!hcc_check_space(trans, head, 1, n)) {
991 hcc_leaf_data(trans, LC_DATA, buf, n);
1006 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
1008 hctransaction_t trans;
1009 struct HCHead *head;
1010 struct HCLeaf *item;
1017 if (hc == NULL || hc->host == NULL)
1018 return(write(fd, buf, bytes));
1020 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
1024 size_t limit = getiolimit();
1025 int n = (bytes > limit) ? limit : bytes;
1028 trans = hcc_start_command(hc, HC_WRITE);
1029 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1030 hcc_leaf_data(trans, LC_DATA, buf, n);
1031 if ((head = hcc_finish_command(trans)) == NULL)
1035 FOR_EACH_ITEM(item, trans, head) {
1036 if (item->leafid == LC_BYTES)
1037 x = HCC_INT32(item);
1042 buf = (const char *)buf + x;
1054 rc_write(hctransaction_t trans, struct HCHead *head)
1056 struct HCLeaf *item;
1061 FOR_EACH_ITEM(item, trans, head) {
1062 switch(item->leafid) {
1064 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1067 buf = HCC_BINARYDATA(item);
1068 n = item->bytes - sizeof(*item);
1073 head->error = EACCES;
1078 if (n < 0 || n > 32768)
1080 n = write(*fdp, buf, n);
1083 hcc_leaf_int32(trans, LC_BYTES, n);
1090 * NOTE: This function returns -errno if an error occured.
1093 hc_remove(struct HostConf *hc, const char *path)
1095 hctransaction_t trans;
1096 struct HCHead *head;
1101 if (hc == NULL || hc->host == NULL) {
1108 trans = hcc_start_command(hc, HC_REMOVE);
1109 hcc_leaf_string(trans, LC_PATH1, path);
1110 if ((head = hcc_finish_command(trans)) == NULL)
1113 return(-(int)head->error);
1118 rc_remove(hctransaction_t trans, struct HCHead *head)
1120 struct HCLeaf *item;
1121 const char *path = NULL;
1123 FOR_EACH_ITEM(item, trans, head) {
1124 if (item->leafid == LC_PATH1)
1125 path = HCC_STRING(item);
1130 head->error = EACCES;
1133 return(remove(path));
1140 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1142 hctransaction_t trans;
1143 struct HCHead *head;
1147 if (hc == NULL || hc->host == NULL)
1148 return(mkdir(path, mode));
1150 trans = hcc_start_command(hc, HC_MKDIR);
1151 hcc_leaf_string(trans, LC_PATH1, path);
1152 hcc_leaf_int32(trans, LC_MODE, mode);
1153 if ((head = hcc_finish_command(trans)) == NULL)
1161 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1163 struct HCLeaf *item;
1164 const char *path = NULL;
1167 FOR_EACH_ITEM(item, trans, head) {
1168 switch(item->leafid) {
1170 path = HCC_STRING(item);
1173 mode = HCC_INT32(item);
1178 head->error = EACCES;
1183 return(mkdir(path, mode));
1190 hc_rmdir(struct HostConf *hc, const char *path)
1192 hctransaction_t trans;
1193 struct HCHead *head;
1197 if (hc == NULL || hc->host == NULL)
1198 return(rmdir(path));
1200 trans = hcc_start_command(hc, HC_RMDIR);
1201 hcc_leaf_string(trans, LC_PATH1, path);
1202 if ((head = hcc_finish_command(trans)) == NULL)
1210 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1212 struct HCLeaf *item;
1213 const char *path = NULL;
1215 FOR_EACH_ITEM(item, trans, head) {
1216 if (item->leafid == LC_PATH1)
1217 path = HCC_STRING(item);
1220 head->error = EACCES;
1225 return(rmdir(path));
1231 * Almost silently ignore chowns that fail if we are not root.
1234 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1236 hctransaction_t trans;
1237 struct HCHead *head;
1245 if (hc == NULL || hc->host == NULL) {
1246 rc = chown(path, owner, group);
1248 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1252 trans = hcc_start_command(hc, HC_CHOWN);
1253 hcc_leaf_string(trans, LC_PATH1, path);
1254 hcc_leaf_int32(trans, LC_UID, owner);
1255 hcc_leaf_int32(trans, LC_GID, group);
1256 if ((head = hcc_finish_command(trans)) == NULL)
1264 rc_chown(hctransaction_t trans, struct HCHead *head)
1266 struct HCLeaf *item;
1267 const char *path = NULL;
1268 uid_t uid = (uid_t)-1;
1269 gid_t gid = (gid_t)-1;
1272 FOR_EACH_ITEM(item, trans, head) {
1273 switch(item->leafid) {
1275 path = HCC_STRING(item);
1278 uid = HCC_INT32(item);
1281 gid = HCC_INT32(item);
1286 head->error = EACCES;
1291 rc = chown(path, uid, gid);
1293 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1301 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1303 hctransaction_t trans;
1304 struct HCHead *head;
1312 if (hc == NULL || hc->host == NULL) {
1313 rc = lchown(path, owner, group);
1315 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1319 trans = hcc_start_command(hc, HC_LCHOWN);
1320 hcc_leaf_string(trans, LC_PATH1, path);
1321 hcc_leaf_int32(trans, LC_UID, owner);
1322 hcc_leaf_int32(trans, LC_GID, group);
1323 if ((head = hcc_finish_command(trans)) == NULL)
1331 rc_lchown(hctransaction_t trans, struct HCHead *head)
1333 struct HCLeaf *item;
1334 const char *path = NULL;
1335 uid_t uid = (uid_t)-1;
1336 gid_t gid = (gid_t)-1;
1339 FOR_EACH_ITEM(item, trans, head) {
1340 switch(item->leafid) {
1342 path = HCC_STRING(item);
1345 uid = HCC_INT32(item);
1348 gid = HCC_INT32(item);
1353 head->error = EACCES;
1358 rc = lchown(path, uid, gid);
1360 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1368 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1370 hctransaction_t trans;
1371 struct HCHead *head;
1375 if (hc == NULL || hc->host == NULL)
1376 return(chmod(path, mode));
1378 trans = hcc_start_command(hc, HC_CHMOD);
1379 hcc_leaf_string(trans, LC_PATH1, path);
1380 hcc_leaf_int32(trans, LC_MODE, mode);
1381 if ((head = hcc_finish_command(trans)) == NULL)
1389 rc_chmod(hctransaction_t trans, struct HCHead *head)
1391 struct HCLeaf *item;
1392 const char *path = NULL;
1395 FOR_EACH_ITEM(item, trans, head) {
1396 switch(item->leafid) {
1398 path = HCC_STRING(item);
1401 mode = HCC_INT32(item);
1406 head->error = EACCES;
1411 return(chmod(path, mode));
1418 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1420 hctransaction_t trans;
1421 struct HCHead *head;
1425 if (!DstRootPrivs) {
1426 /* mknod() requires root privs, so don't bother. */
1431 if (hc == NULL || hc->host == NULL)
1432 return(mknod(path, mode, rdev));
1434 trans = hcc_start_command(hc, HC_MKNOD);
1435 hcc_leaf_string(trans, LC_PATH1, path);
1436 hcc_leaf_int32(trans, LC_MODE, mode);
1437 hcc_leaf_int32(trans, LC_RDEV, rdev);
1438 if ((head = hcc_finish_command(trans)) == NULL)
1446 rc_mknod(hctransaction_t trans, struct HCHead *head)
1448 struct HCLeaf *item;
1449 const char *path = NULL;
1453 FOR_EACH_ITEM(item, trans, head) {
1454 switch(item->leafid) {
1456 path = HCC_STRING(item);
1459 mode = HCC_INT32(item);
1462 rdev = HCC_INT32(item);
1467 head->error = EACCES;
1472 return(mknod(path, mode, rdev));
1479 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1481 hctransaction_t trans;
1482 struct HCHead *head;
1486 if (hc == NULL || hc->host == NULL)
1487 return(link(name1, name2));
1489 trans = hcc_start_command(hc, HC_LINK);
1490 hcc_leaf_string(trans, LC_PATH1, name1);
1491 hcc_leaf_string(trans, LC_PATH2, name2);
1492 if ((head = hcc_finish_command(trans)) == NULL)
1500 rc_link(hctransaction_t trans, struct HCHead *head)
1502 struct HCLeaf *item;
1503 const char *name1 = NULL;
1504 const char *name2 = NULL;
1506 FOR_EACH_ITEM(item, trans, head) {
1507 switch(item->leafid) {
1509 name1 = HCC_STRING(item);
1512 name2 = HCC_STRING(item);
1517 head->error = EACCES;
1520 if (name1 == NULL || name2 == NULL)
1522 return(link(name1, name2));
1525 #ifdef _ST_FLAGS_PRESENT_
1530 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1532 hctransaction_t trans;
1533 struct HCHead *head;
1539 flags &= UF_SETTABLE;
1541 if (hc == NULL || hc->host == NULL) {
1542 if ((rc = chflags(path, flags)) < 0)
1543 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1547 trans = hcc_start_command(hc, HC_CHFLAGS);
1548 hcc_leaf_string(trans, LC_PATH1, path);
1549 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1550 if ((head = hcc_finish_command(trans)) == NULL)
1558 rc_chflags(hctransaction_t trans, struct HCHead *head)
1560 struct HCLeaf *item;
1561 const char *path = NULL;
1565 FOR_EACH_ITEM(item, trans, head) {
1566 switch(item->leafid) {
1568 path = HCC_STRING(item);
1571 flags = (u_long)HCC_INT64(item);
1576 head->error = EACCES;
1581 if ((rc = chflags(path, flags)) < 0)
1582 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1592 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1594 hctransaction_t trans;
1595 struct HCHead *head;
1596 struct HCLeaf *item;
1599 if (hc == NULL || hc->host == NULL)
1600 return(readlink(path, buf, bufsiz));
1602 trans = hcc_start_command(hc, HC_READLINK);
1603 hcc_leaf_string(trans, LC_PATH1, path);
1604 if ((head = hcc_finish_command(trans)) == NULL)
1610 FOR_EACH_ITEM(item, trans, head) {
1611 if (item->leafid == LC_DATA) {
1612 r = item->bytes - sizeof(*item);
1617 bcopy(HCC_BINARYDATA(item), buf, r);
1624 rc_readlink(hctransaction_t trans, struct HCHead *head)
1626 struct HCLeaf *item;
1627 const char *path = NULL;
1631 FOR_EACH_ITEM(item, trans, head) {
1632 if (item->leafid == LC_PATH1)
1633 path = HCC_STRING(item);
1637 r = readlink(path, buf, sizeof(buf));
1640 hcc_leaf_data(trans, LC_DATA, buf, r);
1648 hc_umask(struct HostConf *hc, mode_t numask)
1650 hctransaction_t trans;
1651 struct HCHead *head;
1652 struct HCLeaf *item;
1655 return(umask(numask));
1656 if (hc == NULL || hc->host == NULL)
1657 return(umask(numask));
1659 trans = hcc_start_command(hc, HC_UMASK);
1660 hcc_leaf_int32(trans, LC_MODE, numask);
1661 if ((head = hcc_finish_command(trans)) == NULL)
1666 numask = (mode_t) ~0666U;
1667 FOR_EACH_ITEM(item, trans, head) {
1668 if (item->leafid == LC_MODE)
1669 numask = HCC_INT32(item);
1675 rc_umask(hctransaction_t trans, struct HCHead *head)
1677 struct HCLeaf *item;
1678 mode_t numask = (mode_t) ~0666U;
1680 FOR_EACH_ITEM(item, trans, head) {
1681 if (item->leafid == LC_MODE)
1682 numask = HCC_INT32(item);
1684 numask = umask(numask);
1685 hcc_leaf_int32(trans, LC_MODE, numask);
1693 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1695 hctransaction_t trans;
1696 struct HCHead *head;
1700 if (hc == NULL || hc->host == NULL)
1701 return(symlink(name1, name2));
1703 trans = hcc_start_command(hc, HC_SYMLINK);
1704 hcc_leaf_string(trans, LC_PATH1, name1);
1705 hcc_leaf_string(trans, LC_PATH2, name2);
1706 if ((head = hcc_finish_command(trans)) == NULL)
1714 rc_symlink(hctransaction_t trans, struct HCHead *head)
1716 struct HCLeaf *item;
1717 const char *name1 = NULL;
1718 const char *name2 = NULL;
1720 FOR_EACH_ITEM(item, trans, head) {
1721 switch(item->leafid) {
1723 name1 = HCC_STRING(item);
1726 name2 = HCC_STRING(item);
1731 head->error = EACCES;
1734 if (name1 == NULL || name2 == NULL)
1736 return(symlink(name1, name2));
1743 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1745 hctransaction_t trans;
1746 struct HCHead *head;
1750 if (hc == NULL || hc->host == NULL)
1751 return(rename(name1, name2));
1753 trans = hcc_start_command(hc, HC_RENAME);
1754 hcc_leaf_string(trans, LC_PATH1, name1);
1755 hcc_leaf_string(trans, LC_PATH2, name2);
1756 if ((head = hcc_finish_command(trans)) == NULL)
1764 rc_rename(hctransaction_t trans, struct HCHead *head)
1766 struct HCLeaf *item;
1767 const char *name1 = NULL;
1768 const char *name2 = NULL;
1770 FOR_EACH_ITEM(item, trans, head) {
1771 switch(item->leafid) {
1773 name1 = HCC_STRING(item);
1776 name2 = HCC_STRING(item);
1781 head->error = EACCES;
1784 if (name1 == NULL || name2 == NULL)
1786 return(rename(name1, name2));
1793 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1795 hctransaction_t trans;
1796 struct HCHead *head;
1800 if (hc == NULL || hc->host == NULL)
1801 return(utimes(path, times));
1803 trans = hcc_start_command(hc, HC_UTIMES);
1804 hcc_leaf_string(trans, LC_PATH1, path);
1805 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1806 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1807 #if defined(st_atime)
1808 hcc_leaf_int32(trans, LC_ATIMENSEC, times[0].tv_usec * 1000);
1809 hcc_leaf_int32(trans, LC_MTIMENSEC, times[1].tv_usec * 1000);
1811 if ((head = hcc_finish_command(trans)) == NULL)
1819 rc_utimes(hctransaction_t trans, struct HCHead *head)
1821 struct HCLeaf *item;
1822 struct timeval times[2];
1825 bzero(times, sizeof(times));
1828 FOR_EACH_ITEM(item, trans, head) {
1829 switch(item->leafid) {
1831 path = HCC_STRING(item);
1834 times[0].tv_sec = HCC_INT64(item);
1837 times[1].tv_sec = HCC_INT64(item);
1839 #if defined(st_atimespec) || defined(_STATBUF_ST_NSEC)
1841 times[0].tv_usec = HCC_INT32(item) / 1000;
1844 times[1].tv_usec = HCC_INT32(item) / 1000;
1850 head->error = EACCES;
1855 return(utimes(path, times));
1859 hc_geteuid(struct HostConf *hc)
1861 hctransaction_t trans;
1862 struct HCHead *head;
1863 struct HCLeaf *item;
1865 if (hc == NULL || hc->host == NULL)
1868 if (hc->version < 3) {
1869 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1870 /* Return 0 on error, so the caller assumes root privileges. */
1874 trans = hcc_start_command(hc, HC_GETEUID);
1875 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1877 FOR_EACH_ITEM(item, trans, head) {
1878 if (item->leafid == LC_UID)
1879 return (HCC_INT32(item));
1881 return(0); /* shouldn't happen */
1885 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1887 hcc_leaf_int32(trans, LC_UID, geteuid());
1892 getmygroups(gid_t **gidlist)
1896 if ((count = getgroups(0, *gidlist)) > 0) {
1897 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1898 if ((count = getgroups(count, *gidlist)) <= 0)
1910 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1913 hctransaction_t trans;
1914 struct HCHead *head;
1915 struct HCLeaf *item;
1917 if (hc == NULL || hc->host == NULL)
1918 return (getmygroups(gidlist));
1924 if (hc->version < 3) {
1925 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1929 trans = hcc_start_command(hc, HC_GETGROUPS);
1930 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1932 FOR_EACH_ITEM(item, trans, head) {
1933 switch(item->leafid) {
1935 count = HCC_INT32(item);
1936 if (*gidlist != NULL) { /* protocol error */
1941 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1945 if (*gidlist == NULL || i >= count) { /* protocol error */
1946 if (*gidlist != NULL)
1951 (*gidlist)[i++] = HCC_INT32(item);
1959 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1964 if ((count = getmygroups(&gidlist)) < 0)
1966 hcc_leaf_int32(trans, LC_COUNT, count);
1967 for (i = 0; i < count; i++)
1968 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1969 if (gidlist != NULL)