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
)