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(struct stat *, struct HCHead *);
14 static int rc_encode_stat(hctransaction_t trans, struct stat *);
16 static int rc_hello(hctransaction_t trans, struct HCHead *);
17 static int rc_stat(hctransaction_t trans, struct HCHead *);
18 static int rc_lstat(hctransaction_t trans, struct HCHead *);
19 static int rc_opendir(hctransaction_t trans, struct HCHead *);
20 static int rc_readdir(hctransaction_t trans, struct HCHead *);
21 static int rc_closedir(hctransaction_t trans, struct HCHead *);
22 static int rc_open(hctransaction_t trans, struct HCHead *);
23 static int rc_close(hctransaction_t trans, struct HCHead *);
24 static int rc_read(hctransaction_t trans, struct HCHead *);
25 static int rc_write(hctransaction_t trans, struct HCHead *);
26 static int rc_remove(hctransaction_t trans, struct HCHead *);
27 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
28 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
29 static int rc_chown(hctransaction_t trans, struct HCHead *);
30 static int rc_lchown(hctransaction_t trans, struct HCHead *);
31 static int rc_chmod(hctransaction_t trans, struct HCHead *);
32 static int rc_mknod(hctransaction_t trans, struct HCHead *);
33 static int rc_link(hctransaction_t trans, struct HCHead *);
34 #ifdef _ST_FLAGS_PRESENT_
35 static int rc_chflags(hctransaction_t trans, struct HCHead *);
37 static int rc_readlink(hctransaction_t trans, struct HCHead *);
38 static int rc_umask(hctransaction_t trans, struct HCHead *);
39 static int rc_symlink(hctransaction_t trans, struct HCHead *);
40 static int rc_rename(hctransaction_t trans, struct HCHead *);
41 static int rc_utimes(hctransaction_t trans, struct HCHead *);
42 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
43 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
45 static int getmygroups(gid_t **gidlist);
47 struct HCDesc HCDispatchTable[] = {
48 { HC_HELLO, rc_hello },
50 { HC_LSTAT, rc_lstat },
51 { HC_OPENDIR, rc_opendir },
52 { HC_READDIR, rc_readdir },
53 { HC_CLOSEDIR, rc_closedir },
55 { HC_CLOSE, rc_close },
57 { HC_WRITE, rc_write },
58 { HC_REMOVE, rc_remove },
59 { HC_MKDIR, rc_mkdir },
60 { HC_RMDIR, rc_rmdir },
61 { HC_CHOWN, rc_chown },
62 { HC_LCHOWN, rc_lchown },
63 { HC_CHMOD, rc_chmod },
64 { HC_MKNOD, rc_mknod },
66 #ifdef _ST_FLAGS_PRESENT_
67 { HC_CHFLAGS, rc_chflags },
69 { HC_READLINK, rc_readlink },
70 { HC_UMASK, rc_umask },
71 { HC_SYMLINK, rc_symlink },
72 { HC_RENAME, rc_rename },
73 { HC_UTIMES, rc_utimes },
74 { HC_GETEUID, rc_geteuid },
75 { HC_GETGROUPS, rc_getgroups },
78 static int chown_warning;
79 static int chflags_warning;
82 * If not running as root generate a silent warning and return no error.
84 * If running as root return an error.
87 silentwarning(int *didwarn, const char *ctl, ...)
93 if (*didwarn == 0 && QuietOpt == 0) {
95 fprintf(stderr, "WARNING: Not running as root, ");
97 vfprintf(stderr, ctl, va);
104 hc_connect(struct HostConf *hc)
106 if (hcc_connect(hc) < 0) {
107 fprintf(stderr, "Unable to connect to %s\n", hc->host);
110 return(hc_hello(hc));
114 hc_slave(int fdin, int fdout)
116 hcc_slave(fdin, fdout, HCDispatchTable,
117 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
122 * A HELLO RPC is sent on the initial connect.
125 hc_hello(struct HostConf *hc)
129 hctransaction_t trans;
133 bzero(hostbuf, sizeof(hostbuf));
134 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
139 trans = hcc_start_command(hc, HC_HELLO);
140 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
141 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
142 if ((head = hcc_finish_command(trans)) == NULL) {
143 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
149 fprintf(stderr, "Connected to %s but remote returned error %d\n",
150 hc->host, head->error);
155 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
156 switch(item->leafid) {
159 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
163 hc->version = HCC_INT32(item);
167 if (hc->version < HCPROTO_VERSION_COMPAT) {
168 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
173 fprintf(stderr, "Handshake failed with %s\n", hc->host);
178 rc_hello(hctransaction_t trans, struct HCHead *head __unused)
182 bzero(hostbuf, sizeof(hostbuf));
183 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
188 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
189 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
197 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
200 hctransaction_t trans;
202 if (hc == NULL || hc->host == NULL)
203 return(stat(path, st));
205 trans = hcc_start_command(hc, HC_STAT);
206 hcc_leaf_string(trans, LC_PATH1, path);
207 if ((head = hcc_finish_command(trans)) == NULL)
211 return(hc_decode_stat(st, head));
215 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
218 hctransaction_t trans;
220 if (hc == NULL || hc->host == NULL)
221 return(lstat(path, st));
223 trans = hcc_start_command(hc, HC_LSTAT);
224 hcc_leaf_string(trans, LC_PATH1, path);
225 if ((head = hcc_finish_command(trans)) == NULL)
229 return(hc_decode_stat(st, head));
233 hc_decode_stat(struct stat *st, struct HCHead *head)
237 bzero(st, sizeof(*st));
238 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
239 switch(item->leafid) {
241 st->st_dev = HCC_INT32(item);
244 st->st_ino = HCC_INT64(item);
247 st->st_mode = HCC_INT32(item);
250 st->st_nlink = HCC_INT32(item);
253 st->st_uid = HCC_INT32(item);
256 st->st_gid = HCC_INT32(item);
259 st->st_rdev = HCC_INT32(item);
262 st->st_atime = (time_t)HCC_INT64(item);
265 st->st_mtime = (time_t)HCC_INT64(item);
268 st->st_ctime = (time_t)HCC_INT64(item);
271 st->st_size = HCC_INT64(item);
274 st->st_blocks = HCC_INT64(item);
277 st->st_blksize = HCC_INT32(item);
279 #ifdef _ST_FSMID_PRESENT_
281 st->st_fsmid = HCC_INT64(item);
284 #ifdef _ST_FLAGS_PRESENT_
286 st->st_flags = (u_int32_t)HCC_INT64(item);
295 rc_stat(hctransaction_t trans, struct HCHead *head)
299 const char *path = NULL;
301 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
302 switch(item->leafid) {
304 path = HCC_STRING(item);
310 if (stat(path, &st) < 0)
312 return (rc_encode_stat(trans, &st));
316 rc_lstat(hctransaction_t trans, struct HCHead *head)
320 const char *path = NULL;
322 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
323 switch(item->leafid) {
325 path = HCC_STRING(item);
331 if (lstat(path, &st) < 0)
333 return (rc_encode_stat(trans, &st));
337 rc_encode_stat(hctransaction_t trans, struct stat *st)
339 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
340 hcc_leaf_int64(trans, LC_INO, st->st_ino);
341 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
342 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
343 hcc_leaf_int32(trans, LC_UID, st->st_uid);
344 hcc_leaf_int32(trans, LC_GID, st->st_gid);
345 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
346 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
347 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
348 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
349 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
350 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
351 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
352 #ifdef _ST_FSMID_PRESENT_
353 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
355 #ifdef _ST_FLAGS_PRESENT_
356 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
365 hc_opendir(struct HostConf *hc, const char *path)
367 hctransaction_t trans;
373 if (hc == NULL || hc->host == NULL)
374 return(opendir(path));
376 trans = hcc_start_command(hc, HC_OPENDIR);
377 hcc_leaf_string(trans, LC_PATH1, path);
378 if ((head = hcc_finish_command(trans)) == NULL)
382 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
383 switch(item->leafid) {
385 desc = HCC_INT32(item);
389 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
390 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
394 den = malloc(sizeof(*den));
395 bzero(den, sizeof(*den));
396 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
397 return((void *)desc);
401 rc_opendir(hctransaction_t trans, struct HCHead *head)
404 const char *path = NULL;
408 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
409 switch(item->leafid) {
411 path = HCC_STRING(item);
417 if ((dir = opendir(path)) == NULL) {
420 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
421 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
430 hc_readdir(struct HostConf *hc, DIR *dir)
432 hctransaction_t trans;
437 if (hc == NULL || hc->host == NULL)
438 return(readdir(dir));
440 trans = hcc_start_command(hc, HC_READDIR);
441 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
442 if ((head = hcc_finish_command(trans)) == NULL)
445 return(NULL); /* XXX errno */
446 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
448 return(NULL); /* XXX errno */
451 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
452 switch(item->leafid) {
454 snprintf(den->d_name, sizeof(den->d_name), "%s", HCC_STRING(item));
457 den->d_fileno = HCC_INT64(item);
460 den->d_type = HCC_INT32(item);
464 if (den->d_name[0]) {
465 #ifdef _DIRENT_HAVE_D_NAMLEN
466 den->d_namlen = strlen(den->d_name);
470 return(NULL); /* XXX errno */
474 rc_readdir(hctransaction_t trans, struct HCHead *head)
480 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
481 switch(item->leafid) {
483 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
489 if ((den = readdir(dir)) != NULL) {
490 hcc_leaf_string(trans, LC_PATH1, den->d_name);
491 hcc_leaf_int64(trans, LC_INO, den->d_fileno);
492 hcc_leaf_int32(trans, LC_TYPE, den->d_type);
500 * XXX cpdup needs to check error code to avoid truncated dirs?
503 hc_closedir(struct HostConf *hc, DIR *dir)
505 hctransaction_t trans;
509 if (hc == NULL || hc->host == NULL)
510 return(closedir(dir));
511 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
514 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
516 trans = hcc_start_command(hc, HC_CLOSEDIR);
517 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
518 if ((head = hcc_finish_command(trans)) == NULL)
521 return(-1); /* XXX errno */
530 rc_closedir(hctransaction_t trans, struct HCHead *head)
535 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
536 switch(item->leafid) {
538 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
540 hcc_set_descriptor(trans->hc, HCC_INT32(item), NULL, HC_DESC_DIR);
546 return(closedir(dir));
553 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
555 hctransaction_t trans;
562 if (hc == NULL || hc->host == NULL) {
564 flags |= O_LARGEFILE;
566 return(open(path, flags, mode));
569 nflags = flags & XO_NATIVEMASK;
577 trans = hcc_start_command(hc, HC_OPEN);
578 hcc_leaf_string(trans, LC_PATH1, path);
579 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
580 hcc_leaf_int32(trans, LC_MODE, mode);
582 if ((head = hcc_finish_command(trans)) == NULL)
586 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
587 switch(item->leafid) {
589 desc = HCC_INT32(item);
593 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
594 fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
598 fdp = malloc(sizeof(int));
599 *fdp = desc; /* really just a dummy */
600 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
605 rc_open(hctransaction_t trans, struct HCHead *head)
608 const char *path = NULL;
616 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
617 switch(item->leafid) {
619 path = HCC_STRING(item);
622 nflags = HCC_INT32(item);
625 mode = HCC_INT32(item);
632 flags = nflags & XO_NATIVEMASK;
633 if (nflags & XO_CREAT)
635 if (nflags & XO_EXCL)
637 if (nflags & XO_TRUNC)
641 flags |= O_LARGEFILE;
643 if ((fd = open(path, flags, mode)) < 0) {
647 fdp = malloc(sizeof(int));
649 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
650 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
658 hc_close(struct HostConf *hc, int fd)
660 hctransaction_t trans;
664 if (hc == NULL || hc->host == NULL)
667 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
670 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
672 trans = hcc_start_command(hc, HC_CLOSE);
673 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
674 if ((head = hcc_finish_command(trans)) == NULL)
685 rc_close(hctransaction_t trans, struct HCHead *head)
692 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
693 switch(item->leafid) {
695 desc = HCC_INT32(item);
701 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
705 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
719 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
721 hctransaction_t trans;
727 if (hc == NULL || hc->host == NULL)
728 return(read(fd, buf, bytes));
730 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
734 size_t limit = getiolimit();
735 int n = (bytes > limit) ? limit : bytes;
738 trans = hcc_start_command(hc, HC_READ);
739 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
740 hcc_leaf_int32(trans, LC_BYTES, n);
741 if ((head = hcc_finish_command(trans)) == NULL)
745 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
746 switch(item->leafid) {
748 x = item->bytes - sizeof(*item);
751 bcopy(HCC_BINARYDATA(item), buf, x);
752 buf = (char *)buf + x;
768 rc_read(hctransaction_t trans, struct HCHead *head)
776 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
777 switch(item->leafid) {
779 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
782 bytes = HCC_INT32(item);
788 if (bytes < 0 || bytes > 32768)
790 n = read(*fdp, buf, bytes);
795 hcc_leaf_data(trans, LC_DATA, buf, n);
803 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
805 hctransaction_t trans;
811 if (hc == NULL || hc->host == NULL)
812 return(write(fd, buf, bytes));
814 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
818 size_t limit = getiolimit();
819 int n = (bytes > limit) ? limit : bytes;
822 trans = hcc_start_command(hc, HC_WRITE);
823 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
824 hcc_leaf_data(trans, LC_DATA, buf, n);
825 if ((head = hcc_finish_command(trans)) == NULL)
829 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
830 switch(item->leafid) {
839 buf = (const char *)buf + x;
851 rc_write(hctransaction_t trans, struct HCHead *head)
858 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
859 switch(item->leafid) {
861 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
864 buf = HCC_BINARYDATA(item);
865 n = item->bytes - sizeof(*item);
871 if (n < 0 || n > 32768)
873 n = write(*fdp, buf, n);
877 hcc_leaf_int32(trans, LC_BYTES, n);
885 * NOTE: This function returns -errno if an error occured.
888 hc_remove(struct HostConf *hc, const char *path)
890 hctransaction_t trans;
894 if (hc == NULL || hc->host == NULL) {
901 trans = hcc_start_command(hc, HC_REMOVE);
902 hcc_leaf_string(trans, LC_PATH1, path);
903 if ((head = hcc_finish_command(trans)) == NULL)
906 return(-(int)head->error);
911 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
914 const char *path = NULL;
916 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
917 switch(item->leafid) {
919 path = HCC_STRING(item);
925 return(remove(path));
932 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
934 hctransaction_t trans;
937 if (hc == NULL || hc->host == NULL)
938 return(mkdir(path, mode));
940 trans = hcc_start_command(hc, HC_MKDIR);
941 hcc_leaf_string(trans, LC_PATH1, path);
942 hcc_leaf_int32(trans, LC_MODE, mode);
943 if ((head = hcc_finish_command(trans)) == NULL)
951 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
954 const char *path = NULL;
957 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
958 switch(item->leafid) {
960 path = HCC_STRING(item);
963 mode = HCC_INT32(item);
969 return(mkdir(path, mode));
976 hc_rmdir(struct HostConf *hc, const char *path)
978 hctransaction_t trans;
981 if (hc == NULL || hc->host == NULL)
984 trans = hcc_start_command(hc, HC_RMDIR);
985 hcc_leaf_string(trans, LC_PATH1, path);
986 if ((head = hcc_finish_command(trans)) == NULL)
994 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
997 const char *path = NULL;
999 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1000 switch(item->leafid) {
1002 path = HCC_STRING(item);
1008 return(rmdir(path));
1014 * Almost silently ignore chowns that fail if we are not root.
1017 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1019 hctransaction_t trans;
1020 struct HCHead *head;
1026 if (hc == NULL || hc->host == NULL) {
1027 rc = chown(path, owner, group);
1029 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1033 trans = hcc_start_command(hc, HC_CHOWN);
1034 hcc_leaf_string(trans, LC_PATH1, path);
1035 hcc_leaf_int32(trans, LC_UID, owner);
1036 hcc_leaf_int32(trans, LC_GID, group);
1037 if ((head = hcc_finish_command(trans)) == NULL)
1045 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1047 struct HCLeaf *item;
1048 const char *path = NULL;
1049 uid_t uid = (uid_t)-1;
1050 gid_t gid = (gid_t)-1;
1053 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1054 switch(item->leafid) {
1056 path = HCC_STRING(item);
1059 uid = HCC_INT32(item);
1062 gid = HCC_INT32(item);
1068 rc = chown(path, uid, gid);
1070 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1078 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1080 hctransaction_t trans;
1081 struct HCHead *head;
1087 if (hc == NULL || hc->host == NULL) {
1088 rc = lchown(path, owner, group);
1090 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1094 trans = hcc_start_command(hc, HC_LCHOWN);
1095 hcc_leaf_string(trans, LC_PATH1, path);
1096 hcc_leaf_int32(trans, LC_UID, owner);
1097 hcc_leaf_int32(trans, LC_GID, group);
1098 if ((head = hcc_finish_command(trans)) == NULL)
1106 rc_lchown(hctransaction_t trans __unused, struct HCHead *head)
1108 struct HCLeaf *item;
1109 const char *path = NULL;
1110 uid_t uid = (uid_t)-1;
1111 gid_t gid = (gid_t)-1;
1114 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1115 switch(item->leafid) {
1117 path = HCC_STRING(item);
1120 uid = HCC_INT32(item);
1123 gid = HCC_INT32(item);
1129 rc = lchown(path, uid, gid);
1131 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1139 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1141 hctransaction_t trans;
1142 struct HCHead *head;
1144 if (hc == NULL || hc->host == NULL)
1145 return(chmod(path, mode));
1147 trans = hcc_start_command(hc, HC_CHMOD);
1148 hcc_leaf_string(trans, LC_PATH1, path);
1149 hcc_leaf_int32(trans, LC_MODE, mode);
1150 if ((head = hcc_finish_command(trans)) == NULL)
1158 rc_chmod(hctransaction_t trans __unused, struct HCHead *head)
1160 struct HCLeaf *item;
1161 const char *path = NULL;
1164 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1165 switch(item->leafid) {
1167 path = HCC_STRING(item);
1170 mode = HCC_INT32(item);
1176 return(chmod(path, mode));
1183 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1185 hctransaction_t trans;
1186 struct HCHead *head;
1188 if (!DstRootPrivs) {
1189 /* mknod() requires root privs, so don't bother. */
1194 if (hc == NULL || hc->host == NULL)
1195 return(mknod(path, mode, rdev));
1197 trans = hcc_start_command(hc, HC_MKNOD);
1198 hcc_leaf_string(trans, LC_PATH1, path);
1199 hcc_leaf_int32(trans, LC_MODE, mode);
1200 hcc_leaf_int32(trans, LC_RDEV, rdev);
1201 if ((head = hcc_finish_command(trans)) == NULL)
1209 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1211 struct HCLeaf *item;
1212 const char *path = NULL;
1216 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1217 switch(item->leafid) {
1219 path = HCC_STRING(item);
1222 mode = HCC_INT32(item);
1225 rdev = HCC_INT32(item);
1231 return(mknod(path, mode, rdev));
1238 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1240 hctransaction_t trans;
1241 struct HCHead *head;
1243 if (hc == NULL || hc->host == NULL)
1244 return(link(name1, name2));
1246 trans = hcc_start_command(hc, HC_LINK);
1247 hcc_leaf_string(trans, LC_PATH1, name1);
1248 hcc_leaf_string(trans, LC_PATH2, name2);
1249 if ((head = hcc_finish_command(trans)) == NULL)
1257 rc_link(hctransaction_t trans __unused, struct HCHead *head)
1259 struct HCLeaf *item;
1260 const char *name1 = NULL;
1261 const char *name2 = NULL;
1263 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1264 switch(item->leafid) {
1266 name1 = HCC_STRING(item);
1269 name2 = HCC_STRING(item);
1273 if (name1 == NULL || name2 == NULL)
1275 return(link(name1, name2));
1278 #ifdef _ST_FLAGS_PRESENT_
1283 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1285 hctransaction_t trans;
1286 struct HCHead *head;
1290 flags &= UF_SETTABLE;
1292 if (hc == NULL || hc->host == NULL) {
1293 if ((rc = chflags(path, flags)) < 0)
1294 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1298 trans = hcc_start_command(hc, HC_CHFLAGS);
1299 hcc_leaf_string(trans, LC_PATH1, path);
1300 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1301 if ((head = hcc_finish_command(trans)) == NULL)
1309 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1311 struct HCLeaf *item;
1312 const char *path = NULL;
1316 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1317 switch(item->leafid) {
1319 path = HCC_STRING(item);
1322 flags = (u_long)HCC_INT64(item);
1328 if ((rc = chflags(path, flags)) < 0)
1329 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1339 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1341 hctransaction_t trans;
1342 struct HCHead *head;
1343 struct HCLeaf *item;
1346 if (hc == NULL || hc->host == NULL)
1347 return(readlink(path, buf, bufsiz));
1349 trans = hcc_start_command(hc, HC_READLINK);
1350 hcc_leaf_string(trans, LC_PATH1, path);
1351 if ((head = hcc_finish_command(trans)) == NULL)
1357 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1358 switch(item->leafid) {
1360 r = item->bytes - sizeof(*item);
1365 bcopy(HCC_BINARYDATA(item), buf, r);
1373 rc_readlink(hctransaction_t trans, struct HCHead *head)
1375 struct HCLeaf *item;
1376 const char *path = NULL;
1380 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1381 switch(item->leafid) {
1383 path = HCC_STRING(item);
1389 r = readlink(path, buf, sizeof(buf));
1392 hcc_leaf_data(trans, LC_DATA, buf, r);
1400 hc_umask(struct HostConf *hc, mode_t numask)
1402 hctransaction_t trans;
1403 struct HCHead *head;
1404 struct HCLeaf *item;
1406 if (hc == NULL || hc->host == NULL)
1407 return(umask(numask));
1409 trans = hcc_start_command(hc, HC_UMASK);
1410 hcc_leaf_int32(trans, LC_MODE, numask);
1411 if ((head = hcc_finish_command(trans)) == NULL)
1417 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1418 switch(item->leafid) {
1420 numask = HCC_INT32(item);
1428 rc_umask(hctransaction_t trans, struct HCHead *head)
1430 struct HCLeaf *item;
1431 mode_t numask = ~0666;
1433 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1434 switch(item->leafid) {
1436 numask = HCC_INT32(item);
1440 numask = umask(numask);
1441 hcc_leaf_int32(trans, LC_MODE, numask);
1449 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1451 hctransaction_t trans;
1452 struct HCHead *head;
1454 if (hc == NULL || hc->host == NULL)
1455 return(symlink(name1, name2));
1457 trans = hcc_start_command(hc, HC_SYMLINK);
1458 hcc_leaf_string(trans, LC_PATH1, name1);
1459 hcc_leaf_string(trans, LC_PATH2, name2);
1460 if ((head = hcc_finish_command(trans)) == NULL)
1468 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1470 struct HCLeaf *item;
1471 const char *name1 = NULL;
1472 const char *name2 = NULL;
1474 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1475 switch(item->leafid) {
1477 name1 = HCC_STRING(item);
1480 name2 = HCC_STRING(item);
1484 if (name1 == NULL || name2 == NULL)
1486 return(symlink(name1, name2));
1493 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1495 hctransaction_t trans;
1496 struct HCHead *head;
1498 if (hc == NULL || hc->host == NULL)
1499 return(rename(name1, name2));
1501 trans = hcc_start_command(hc, HC_RENAME);
1502 hcc_leaf_string(trans, LC_PATH1, name1);
1503 hcc_leaf_string(trans, LC_PATH2, name2);
1504 if ((head = hcc_finish_command(trans)) == NULL)
1512 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1514 struct HCLeaf *item;
1515 const char *name1 = NULL;
1516 const char *name2 = NULL;
1518 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1519 switch(item->leafid) {
1521 name1 = HCC_STRING(item);
1524 name2 = HCC_STRING(item);
1528 if (name1 == NULL || name2 == NULL)
1530 return(rename(name1, name2));
1537 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1539 hctransaction_t trans;
1540 struct HCHead *head;
1542 if (hc == NULL || hc->host == NULL)
1543 return(utimes(path, times));
1545 trans = hcc_start_command(hc, HC_UTIMES);
1546 hcc_leaf_string(trans, LC_PATH1, path);
1547 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1548 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1549 if ((head = hcc_finish_command(trans)) == NULL)
1557 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1559 struct HCLeaf *item;
1560 struct timeval times[2];
1563 bzero(times, sizeof(times));
1566 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1567 switch(item->leafid) {
1569 path = HCC_STRING(item);
1572 times[0].tv_sec = HCC_INT64(item);
1575 times[1].tv_sec = HCC_INT64(item);
1581 return(utimes(path, times));
1585 hc_geteuid(struct HostConf *hc)
1587 hctransaction_t trans;
1588 struct HCHead *head;
1589 struct HCLeaf *item;
1591 if (hc == NULL || hc->host == NULL)
1594 if (hc->version < 3) {
1595 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1596 /* Return 0 on error, so the caller assumes root privileges. */
1600 trans = hcc_start_command(hc, HC_GETEUID);
1601 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1603 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1604 if (item->leafid == LC_UID)
1605 return (HCC_INT32(item));
1607 return(0); /* shouldn't happen */
1611 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1613 hcc_leaf_int32(trans, LC_UID, geteuid());
1618 getmygroups(gid_t **gidlist)
1622 if ((count = getgroups(0, *gidlist)) > 0) {
1623 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1624 if ((count = getgroups(count, *gidlist)) <= 0)
1636 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1639 hctransaction_t trans;
1640 struct HCHead *head;
1641 struct HCLeaf *item;
1643 if (hc == NULL || hc->host == NULL)
1644 return (getmygroups(gidlist));
1650 if (hc->version < 3) {
1651 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1655 trans = hcc_start_command(hc, HC_GETGROUPS);
1656 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1658 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1659 switch(item->leafid) {
1661 count = HCC_INT32(item);
1662 if (*gidlist != NULL) { /* protocol error */
1667 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1671 if (*gidlist == NULL || i >= count) { /* protocol error */
1672 if (*gidlist != NULL)
1677 (*gidlist)[i++] = HCC_INT32(item);
1685 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1690 if ((count = getmygroups(&gidlist)) < 0)
1692 hcc_leaf_int32(trans, LC_COUNT, count);
1693 for (i = 0; i < count; i++)
1694 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1695 if (gidlist != NULL)