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
)