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]));
128 * A HELLO RPC is sent on the initial connect.
131 hc_hello(struct HostConf
*hc
)
135 hctransaction_t trans
;
139 bzero(hostbuf
, sizeof(hostbuf
));
140 if (gethostname(hostbuf
, sizeof(hostbuf
) - 1) < 0)
145 trans
= hcc_start_command(hc
, HC_HELLO
);
146 hcc_leaf_string(trans
, LC_HELLOSTR
, hostbuf
);
147 hcc_leaf_int32(trans
, LC_VERSION
, HCPROTO_VERSION
);
149 hcc_leaf_string(trans
, LC_PATH1
, UseCpFile
);
150 if ((head
= hcc_finish_command(trans
)) == NULL
) {
151 fprintf(stderr
, "Connected to %s but remote failed to complete hello\n",
157 fprintf(stderr
, "Connected to %s but remote returned error %d\n",
158 hc
->host
, head
->error
);
163 FOR_EACH_ITEM(item
, trans
, head
) {
164 switch(item
->leafid
) {
167 fprintf(stderr
, "Handshaked with %s\n", HCC_STRING(item
));
171 hc
->version
= HCC_INT32(item
);
175 if (hc
->version
< HCPROTO_VERSION_COMPAT
) {
176 fprintf(stderr
, "Remote cpdup at %s has an incompatible version\n",
179 } else if (hc
->version
< HCPROTO_VERSION
&& QuietOpt
== 0) {
180 fprintf(stderr
, "WARNING: Remote cpdup at %s has a lower version, "
181 "expect reduced speed\n", hc
->host
);
184 fprintf(stderr
, "Handshake failed with %s\n", hc
->host
);
189 rc_hello(hctransaction_t trans
, struct HCHead
*head
)
194 FOR_EACH_ITEM(item
, trans
, head
) {
195 if (item
->leafid
== LC_PATH1
)
196 UseCpFile
= strdup(HCC_STRING(item
));
199 bzero(hostbuf
, sizeof(hostbuf
));
200 if (gethostname(hostbuf
, sizeof(hostbuf
) - 1) < 0)
205 hcc_leaf_string(trans
, LC_HELLOSTR
, hostbuf
);
206 hcc_leaf_int32(trans
, LC_VERSION
, HCPROTO_VERSION
);
214 hc_stat(struct HostConf
*hc
, const char *path
, struct stat
*st
)
217 hctransaction_t trans
;
219 if (hc
== NULL
|| hc
->host
== NULL
)
220 return(stat(path
, st
));
222 trans
= hcc_start_command(hc
, HC_STAT
);
223 hcc_leaf_string(trans
, LC_PATH1
, path
);
224 if ((head
= hcc_finish_command(trans
)) == NULL
)
228 return(hc_decode_stat(trans
, st
, head
));
232 hc_lstat(struct HostConf
*hc
, const char *path
, struct stat
*st
)
235 hctransaction_t trans
;
237 if (hc
== NULL
|| hc
->host
== NULL
)
238 return(lstat(path
, st
));
240 trans
= hcc_start_command(hc
, HC_LSTAT
);
241 hcc_leaf_string(trans
, LC_PATH1
, path
);
242 if ((head
= hcc_finish_command(trans
)) == NULL
)
246 return(hc_decode_stat(trans
, st
, head
));
250 hc_decode_stat(hctransaction_t trans
, struct stat
*st
, struct HCHead
*head
)
254 bzero(st
, sizeof(*st
));
255 FOR_EACH_ITEM(item
, trans
, head
)
256 hc_decode_stat_item(st
, item
);
261 hc_decode_stat_item(struct stat
*st
, struct HCLeaf
*item
)
263 switch(item
->leafid
) {
265 st
->st_dev
= HCC_INT32(item
);
268 st
->st_ino
= HCC_INT64(item
);
271 st
->st_mode
= HCC_INT32(item
);
274 st
->st_nlink
= HCC_INT32(item
);
277 st
->st_uid
= HCC_INT32(item
);
280 st
->st_gid
= HCC_INT32(item
);
283 st
->st_rdev
= HCC_INT32(item
);
286 st
->st_atime
= (time_t)HCC_INT64(item
);
289 st
->st_mtime
= (time_t)HCC_INT64(item
);
292 st
->st_ctime
= (time_t)HCC_INT64(item
);
295 st
->st_size
= HCC_INT64(item
);
298 st
->st_blocks
= HCC_INT64(item
);
301 st
->st_blksize
= HCC_INT32(item
);
303 #ifdef _ST_FSMID_PRESENT_
305 st
->st_fsmid
= HCC_INT64(item
);
308 #ifdef _ST_FLAGS_PRESENT_
310 st
->st_flags
= (uint32_t)HCC_INT64(item
);
318 rc_stat(hctransaction_t trans
, struct HCHead
*head
)
322 const char *path
= NULL
;
324 FOR_EACH_ITEM(item
, trans
, head
) {
325 if (item
->leafid
== LC_PATH1
)
326 path
= HCC_STRING(item
);
330 if (stat(path
, &st
) < 0)
332 return (rc_encode_stat(trans
, &st
));
336 rc_lstat(hctransaction_t trans
, struct HCHead
*head
)
340 const char *path
= NULL
;
342 FOR_EACH_ITEM(item
, trans
, head
) {
343 if (item
->leafid
== LC_PATH1
)
344 path
= HCC_STRING(item
);
348 if (lstat(path
, &st
) < 0)
350 return (rc_encode_stat(trans
, &st
));
354 * Encode all entries of a stat structure.
356 * CAUTION: If you add any more entries here, be sure to
357 * increase the STAT_MAX_NUM_ENTRIES value!
359 #define STAT_MAX_NUM_ENTRIES 18
361 rc_encode_stat(hctransaction_t trans
, struct stat
*st
)
363 hcc_leaf_int32(trans
, LC_DEV
, st
->st_dev
);
364 hcc_leaf_int64(trans
, LC_INO
, st
->st_ino
);
365 hcc_leaf_int32(trans
, LC_MODE
, st
->st_mode
);
366 hcc_leaf_int32(trans
, LC_NLINK
, st
->st_nlink
);
367 hcc_leaf_int32(trans
, LC_UID
, st
->st_uid
);
368 hcc_leaf_int32(trans
, LC_GID
, st
->st_gid
);
369 hcc_leaf_int32(trans
, LC_RDEV
, st
->st_rdev
);
370 hcc_leaf_int64(trans
, LC_ATIME
, st
->st_atime
);
371 hcc_leaf_int64(trans
, LC_MTIME
, st
->st_mtime
);
372 hcc_leaf_int64(trans
, LC_CTIME
, st
->st_ctime
);
373 hcc_leaf_int64(trans
, LC_FILESIZE
, st
->st_size
);
374 hcc_leaf_int64(trans
, LC_FILEBLKS
, st
->st_blocks
);
375 hcc_leaf_int32(trans
, LC_BLKSIZE
, st
->st_blksize
);
376 #ifdef _ST_FSMID_PRESENT_
377 hcc_leaf_int64(trans
, LC_FSMID
, st
->st_fsmid
);
379 #ifdef _ST_FLAGS_PRESENT_
380 hcc_leaf_int64(trans
, LC_FILEFLAGS
, st
->st_flags
);
389 hc_opendir(struct HostConf
*hc
, const char *path
)
391 hctransaction_t trans
;
394 if (hc
== NULL
|| hc
->host
== NULL
)
395 return(opendir(path
));
397 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
399 struct HCDirEntry
*den
;
402 trans
= hcc_start_command(hc
, HC_OPENDIR
);
403 hcc_leaf_string(trans
, LC_PATH1
, path
);
404 if ((head
= hcc_finish_command(trans
)) == NULL
)
408 FOR_EACH_ITEM(item
, trans
, head
) {
409 if (item
->leafid
== LC_DESCRIPTOR
)
410 desc
= HCC_INT32(item
);
412 if (hcc_get_descriptor(hc
, desc
, HC_DESC_DIR
)) {
413 fprintf(stderr
, "hc_opendir: remote reused active descriptor %jd\n",
417 den
= malloc(sizeof(*den
));
418 hcc_set_descriptor(hc
, desc
, den
, HC_DESC_DIR
);
419 return ((void *)desc
);
422 /* hc->version >= 4: use HC_SCANDIR */
423 trans
= hcc_start_command(hc
, HC_SCANDIR
);
424 hcc_leaf_string(trans
, LC_PATH1
, path
);
425 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
427 return ((void *)head
);
431 rc_opendir(hctransaction_t trans
, struct HCHead
*head
)
434 const char *path
= NULL
;
438 FOR_EACH_ITEM(item
, trans
, head
) {
439 if (item
->leafid
== LC_PATH1
)
440 path
= HCC_STRING(item
);
444 if ((dir
= opendir(path
)) == NULL
) {
447 desc
= hcc_alloc_descriptor(trans
->hc
, dir
, HC_DESC_DIR
);
448 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, desc
);
457 hc_readdir(struct HostConf
*hc
, DIR *dir
, struct stat
**statpp
)
462 static struct HCDirEntry denbuf
;
465 if (hc
== NULL
|| hc
->host
== NULL
) {
466 struct dirent
*sysden
;
468 if ((sysden
= readdir(dir
)) == NULL
)
470 strlcpy(denbuf
.d_name
, sysden
->d_name
, MAXNAMLEN
+ 1);
474 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
475 hctransaction_t trans
;
476 struct HCDirEntry
*den
;
478 trans
= hcc_start_command(hc
, HC_READDIR
);
479 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, (intptr_t)dir
);
480 if ((head
= hcc_finish_command(trans
)) == NULL
)
483 return (NULL
); /* XXX errno */
484 den
= hcc_get_descriptor(hc
, (intptr_t)dir
, HC_DESC_DIR
);
486 return (NULL
); /* XXX errno */
488 FOR_EACH_ITEM(item
, trans
, head
) {
489 if (item
->leafid
== LC_PATH1
)
490 strlcpy(den
->d_name
, HCC_STRING(item
), MAXNAMLEN
+ 1);
492 return (den
->d_name
[0] ? den
: NULL
);
495 /* hc->version >= 4: using HC_SCANDIR */
496 denbuf
.d_name
[0] = 0;
498 *statpp
= malloc(sizeof(struct stat
));
499 bzero(*statpp
, sizeof(struct stat
));
500 while ((item
= hcc_nextchaineditem(hc
, head
)) != NULL
) {
501 if (item
->leafid
== LC_PATH1
) { /* this must be the last item */
502 strlcpy(denbuf
.d_name
, HCC_STRING(item
), MAXNAMLEN
+ 1);
506 hc_decode_stat_item(*statpp
, item
);
513 return (denbuf
.d_name
[0] ? &denbuf
: NULL
);
517 rc_readdir(hctransaction_t trans
, struct HCHead
*head
)
523 FOR_EACH_ITEM(item
, trans
, head
) {
524 if (item
->leafid
== LC_DESCRIPTOR
)
525 dir
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_DIR
);
529 if ((den
= readdir(dir
)) != NULL
)
530 hcc_leaf_string(trans
, LC_PATH1
, den
->d_name
);
537 * XXX cpdup needs to check error code to avoid truncated dirs?
540 hc_closedir(struct HostConf
*hc
, DIR *dir
)
544 if (hc
== NULL
|| hc
->host
== NULL
)
545 return(closedir(dir
));
547 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
548 hctransaction_t trans
;
551 if ((den
= hcc_get_descriptor(hc
, (intptr_t)dir
, HC_DESC_DIR
)) != NULL
) {
553 hcc_set_descriptor(hc
, (intptr_t)dir
, NULL
, HC_DESC_DIR
);
554 trans
= hcc_start_command(hc
, HC_CLOSEDIR
);
555 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, (intptr_t)dir
);
556 if ((head
= hcc_finish_command(trans
)) == NULL
)
559 return (-1); /* XXX errno */
567 /* hc->version >= 4: using HC_SCANDIR */
569 /* skip any remaining items if the directory is closed prematurely */
570 while (hcc_nextchaineditem(hc
, head
) != NULL
)
578 rc_closedir(hctransaction_t trans
, struct HCHead
*head
)
583 FOR_EACH_ITEM(item
, trans
, head
) {
584 if (item
->leafid
== LC_DESCRIPTOR
) {
585 dir
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_DIR
);
587 hcc_set_descriptor(trans
->hc
, HCC_INT32(item
),
594 return(closedir(dir
));
601 rc_scandir(hctransaction_t trans
, struct HCHead
*head
)
604 const char *path
= NULL
;
610 FOR_EACH_ITEM(item
, trans
, head
) {
611 if (item
->leafid
== LC_PATH1
)
612 path
= HCC_STRING(item
);
616 if ((dir
= opendir(path
)) == NULL
)
618 while ((den
= readdir(dir
)) != NULL
) {
619 if (den
->d_name
[0] == '.' && (den
->d_name
[1] == '\0' ||
620 (den
->d_name
[1] == '.' && den
->d_name
[2] == '\0')))
621 continue; /* skip "." and ".." */
623 * Check if there's enough space left in the current packet.
624 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
625 * one is a string, so we use strlen() + 1 (terminating zero).
626 * The remaining ones are numbers; we assume sizeof(int64_t) so
627 * we're on the safe side.
629 if (!hcc_check_space(trans
, head
, STAT_MAX_NUM_ENTRIES
,
630 (STAT_MAX_NUM_ENTRIES
- 1) * sizeof(int64_t) +
631 strlen(den
->d_name
) + 1)) {
635 fpath
= mprintf("%s/%s", path
, den
->d_name
);
636 if (lstat(fpath
, &st
) == 0)
637 rc_encode_stat(trans
, &st
);
638 /* The name must be the last item! */
639 hcc_leaf_string(trans
, LC_PATH1
, den
->d_name
);
642 return (closedir(dir
));
649 hc_open(struct HostConf
*hc
, const char *path
, int flags
, mode_t mode
)
651 hctransaction_t trans
;
658 if (NotForRealOpt
&& (flags
& O_CREAT
))
661 if (hc
== NULL
|| hc
->host
== NULL
) {
663 flags
|= O_LARGEFILE
;
665 return(open(path
, flags
, mode
));
668 if ((flags
& (O_WRONLY
| O_RDWR
)) == 0 && hc
->version
>= 4) {
669 trans
= hcc_start_command(hc
, HC_READFILE
);
670 hcc_leaf_string(trans
, LC_PATH1
, path
);
671 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
673 head
->magic
= 0; /* used to indicate offset within buffer */
674 return (1); /* dummy */
677 nflags
= flags
& XO_NATIVEMASK
;
685 trans
= hcc_start_command(hc
, HC_OPEN
);
686 hcc_leaf_string(trans
, LC_PATH1
, path
);
687 hcc_leaf_int32(trans
, LC_OFLAGS
, nflags
);
688 hcc_leaf_int32(trans
, LC_MODE
, mode
);
690 if ((head
= hcc_finish_command(trans
)) == NULL
)
694 FOR_EACH_ITEM(item
, trans
, head
) {
695 if (item
->leafid
== LC_DESCRIPTOR
)
696 desc
= HCC_INT32(item
);
698 if (hcc_get_descriptor(hc
, desc
, HC_DESC_FD
)) {
699 fprintf(stderr
, "hc_open: remote reused active descriptor %d\n",
703 fdp
= malloc(sizeof(int));
704 *fdp
= desc
; /* really just a dummy */
705 hcc_set_descriptor(hc
, desc
, fdp
, HC_DESC_FD
);
710 rc_open(hctransaction_t trans
, struct HCHead
*head
)
713 const char *path
= NULL
;
721 FOR_EACH_ITEM(item
, trans
, head
) {
722 switch(item
->leafid
) {
724 path
= HCC_STRING(item
);
727 nflags
= HCC_INT32(item
);
730 mode
= HCC_INT32(item
);
737 flags
= nflags
& XO_NATIVEMASK
;
738 if (nflags
& XO_CREAT
)
740 if (nflags
& XO_EXCL
)
742 if (nflags
& XO_TRUNC
)
746 if (flags
& (O_WRONLY
| O_RDWR
| O_CREAT
| O_TRUNC
)) {
747 head
->error
= EACCES
;
754 flags
|= O_LARGEFILE
;
756 if ((fd
= open(path
, flags
, mode
)) < 0)
758 fdp
= malloc(sizeof(int));
760 desc
= hcc_alloc_descriptor(trans
->hc
, fdp
, HC_DESC_FD
);
761 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, desc
);
769 hc_close(struct HostConf
*hc
, int fd
)
771 hctransaction_t trans
;
775 if (NotForRealOpt
&& fd
== 0x7FFFFFFF)
777 if (hc
== NULL
|| hc
->host
== NULL
)
780 if (fd
== 1 && hc
->version
>= 4) { /* using HC_READFILE */
781 head
= (void *)hc
->trans
.rbuf
;
782 /* skip any remaining items if the file is closed prematurely */
783 while (hcc_nextchaineditem(hc
, head
) != NULL
)
790 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
793 hcc_set_descriptor(hc
, fd
, NULL
, HC_DESC_FD
);
795 trans
= hcc_start_command(hc
, HC_CLOSE
);
796 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
797 if ((head
= hcc_finish_command(trans
)) == NULL
)
808 rc_close(hctransaction_t trans
, struct HCHead
*head
)
815 FOR_EACH_ITEM(item
, trans
, head
) {
816 if (item
->leafid
== LC_DESCRIPTOR
)
817 desc
= HCC_INT32(item
);
821 if ((fdp
= hcc_get_descriptor(trans
->hc
, desc
, HC_DESC_FD
)) == NULL
)
825 hcc_set_descriptor(trans
->hc
, desc
, NULL
, HC_DESC_FD
);
839 hc_read(struct HostConf
*hc
, int fd
, void *buf
, size_t bytes
)
841 hctransaction_t trans
;
849 if (hc
== NULL
|| hc
->host
== NULL
)
850 return(read(fd
, buf
, bytes
));
852 if (fd
== 1 && hc
->version
>= 4) { /* using HC_READFILE */
853 head
= (void *)hc
->trans
.rbuf
;
855 if ((offset
= head
->magic
) != 0)
856 item
= hcc_currentchaineditem(hc
, head
);
858 item
= hcc_nextchaineditem(hc
, head
);
861 if (item
->leafid
!= LC_DATA
)
863 x
= item
->bytes
- sizeof(*item
) - offset
;
864 if (x
> (int)bytes
) {
866 head
->magic
+= x
; /* leave bytes in the buffer */
869 head
->magic
= 0; /* all bytes used up */
870 bcopy((char *)HCC_BINARYDATA(item
) + offset
, buf
, x
);
871 buf
= (char *)buf
+ x
;
878 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
881 size_t limit
= getiolimit();
882 int n
= (bytes
> limit
) ? limit
: bytes
;
884 trans
= hcc_start_command(hc
, HC_READ
);
885 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
886 hcc_leaf_int32(trans
, LC_BYTES
, n
);
887 if ((head
= hcc_finish_command(trans
)) == NULL
)
891 FOR_EACH_ITEM(item
, trans
, head
) {
892 if (item
->leafid
== LC_DATA
) {
893 x
= item
->bytes
- sizeof(*item
);
896 bcopy(HCC_BINARYDATA(item
), buf
, x
);
897 buf
= (char *)buf
+ x
;
912 rc_read(hctransaction_t trans
, struct HCHead
*head
)
920 FOR_EACH_ITEM(item
, trans
, head
) {
921 switch(item
->leafid
) {
923 fdp
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_FD
);
926 bytes
= HCC_INT32(item
);
932 if (bytes
< 0 || bytes
> 32768)
934 n
= read(*fdp
, buf
, bytes
);
937 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
945 rc_readfile(hctransaction_t trans
, struct HCHead
*head
)
948 const char *path
= NULL
;
953 FOR_EACH_ITEM(item
, trans
, head
) {
954 if (item
->leafid
== LC_PATH1
)
955 path
= HCC_STRING(item
);
959 if ((fd
= open(path
, O_RDONLY
)) < 0)
961 while ((n
= read(fd
, buf
, 32768)) >= 0) {
962 if (!hcc_check_space(trans
, head
, 1, n
)) {
966 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
981 hc_write(struct HostConf
*hc
, int fd
, const void *buf
, size_t bytes
)
983 hctransaction_t trans
;
992 if (hc
== NULL
|| hc
->host
== NULL
)
993 return(write(fd
, buf
, bytes
));
995 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
999 size_t limit
= getiolimit();
1000 int n
= (bytes
> limit
) ? limit
: bytes
;
1003 trans
= hcc_start_command(hc
, HC_WRITE
);
1004 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
1005 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
1006 if ((head
= hcc_finish_command(trans
)) == NULL
)
1010 FOR_EACH_ITEM(item
, trans
, head
) {
1011 if (item
->leafid
== LC_BYTES
)
1012 x
= HCC_INT32(item
);
1017 buf
= (const char *)buf
+ x
;
1029 rc_write(hctransaction_t trans
, struct HCHead
*head
)
1031 struct HCLeaf
*item
;
1036 FOR_EACH_ITEM(item
, trans
, head
) {
1037 switch(item
->leafid
) {
1039 fdp
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_FD
);
1042 buf
= HCC_BINARYDATA(item
);
1043 n
= item
->bytes
- sizeof(*item
);
1048 head
->error
= EACCES
;
1053 if (n
< 0 || n
> 32768)
1055 n
= write(*fdp
, buf
, n
);
1058 hcc_leaf_int32(trans
, LC_BYTES
, n
);
1065 * NOTE: This function returns -errno if an error occured.
1068 hc_remove(struct HostConf
*hc
, const char *path
)
1070 hctransaction_t trans
;
1071 struct HCHead
*head
;
1076 if (hc
== NULL
|| hc
->host
== NULL
) {
1083 trans
= hcc_start_command(hc
, HC_REMOVE
);
1084 hcc_leaf_string(trans
, LC_PATH1
, path
);
1085 if ((head
= hcc_finish_command(trans
)) == NULL
)
1088 return(-(int)head
->error
);
1093 rc_remove(hctransaction_t trans
, struct HCHead
*head
)
1095 struct HCLeaf
*item
;
1096 const char *path
= NULL
;
1098 FOR_EACH_ITEM(item
, trans
, head
) {
1099 if (item
->leafid
== LC_PATH1
)
1100 path
= HCC_STRING(item
);
1105 head
->error
= EACCES
;
1108 return(remove(path
));
1115 hc_mkdir(struct HostConf
*hc
, const char *path
, mode_t mode
)
1117 hctransaction_t trans
;
1118 struct HCHead
*head
;
1122 if (hc
== NULL
|| hc
->host
== NULL
)
1123 return(mkdir(path
, mode
));
1125 trans
= hcc_start_command(hc
, HC_MKDIR
);
1126 hcc_leaf_string(trans
, LC_PATH1
, path
);
1127 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1128 if ((head
= hcc_finish_command(trans
)) == NULL
)
1136 rc_mkdir(hctransaction_t trans
, struct HCHead
*head
)
1138 struct HCLeaf
*item
;
1139 const char *path
= NULL
;
1142 FOR_EACH_ITEM(item
, trans
, head
) {
1143 switch(item
->leafid
) {
1145 path
= HCC_STRING(item
);
1148 mode
= HCC_INT32(item
);
1153 head
->error
= EACCES
;
1158 return(mkdir(path
, mode
));
1165 hc_rmdir(struct HostConf
*hc
, const char *path
)
1167 hctransaction_t trans
;
1168 struct HCHead
*head
;
1172 if (hc
== NULL
|| hc
->host
== NULL
)
1173 return(rmdir(path
));
1175 trans
= hcc_start_command(hc
, HC_RMDIR
);
1176 hcc_leaf_string(trans
, LC_PATH1
, path
);
1177 if ((head
= hcc_finish_command(trans
)) == NULL
)
1185 rc_rmdir(hctransaction_t trans
, struct HCHead
*head
)
1187 struct HCLeaf
*item
;
1188 const char *path
= NULL
;
1190 FOR_EACH_ITEM(item
, trans
, head
) {
1191 if (item
->leafid
== LC_PATH1
)
1192 path
= HCC_STRING(item
);
1195 head
->error
= EACCES
;
1200 return(rmdir(path
));
1206 * Almost silently ignore chowns that fail if we are not root.
1209 hc_chown(struct HostConf
*hc
, const char *path
, uid_t owner
, gid_t group
)
1211 hctransaction_t trans
;
1212 struct HCHead
*head
;
1220 if (hc
== NULL
|| hc
->host
== NULL
) {
1221 rc
= chown(path
, owner
, group
);
1223 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1227 trans
= hcc_start_command(hc
, HC_CHOWN
);
1228 hcc_leaf_string(trans
, LC_PATH1
, path
);
1229 hcc_leaf_int32(trans
, LC_UID
, owner
);
1230 hcc_leaf_int32(trans
, LC_GID
, group
);
1231 if ((head
= hcc_finish_command(trans
)) == NULL
)
1239 rc_chown(hctransaction_t trans
, struct HCHead
*head
)
1241 struct HCLeaf
*item
;
1242 const char *path
= NULL
;
1243 uid_t uid
= (uid_t
)-1;
1244 gid_t gid
= (gid_t
)-1;
1247 FOR_EACH_ITEM(item
, trans
, head
) {
1248 switch(item
->leafid
) {
1250 path
= HCC_STRING(item
);
1253 uid
= HCC_INT32(item
);
1256 gid
= HCC_INT32(item
);
1261 head
->error
= EACCES
;
1266 rc
= chown(path
, uid
, gid
);
1268 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1276 hc_lchown(struct HostConf
*hc
, const char *path
, uid_t owner
, gid_t group
)
1278 hctransaction_t trans
;
1279 struct HCHead
*head
;
1287 if (hc
== NULL
|| hc
->host
== NULL
) {
1288 rc
= lchown(path
, owner
, group
);
1290 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1294 trans
= hcc_start_command(hc
, HC_LCHOWN
);
1295 hcc_leaf_string(trans
, LC_PATH1
, path
);
1296 hcc_leaf_int32(trans
, LC_UID
, owner
);
1297 hcc_leaf_int32(trans
, LC_GID
, group
);
1298 if ((head
= hcc_finish_command(trans
)) == NULL
)
1306 rc_lchown(hctransaction_t trans
, struct HCHead
*head
)
1308 struct HCLeaf
*item
;
1309 const char *path
= NULL
;
1310 uid_t uid
= (uid_t
)-1;
1311 gid_t gid
= (gid_t
)-1;
1314 FOR_EACH_ITEM(item
, trans
, head
) {
1315 switch(item
->leafid
) {
1317 path
= HCC_STRING(item
);
1320 uid
= HCC_INT32(item
);
1323 gid
= HCC_INT32(item
);
1328 head
->error
= EACCES
;
1333 rc
= lchown(path
, uid
, gid
);
1335 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1343 hc_chmod(struct HostConf
*hc
, const char *path
, mode_t mode
)
1345 hctransaction_t trans
;
1346 struct HCHead
*head
;
1350 if (hc
== NULL
|| hc
->host
== NULL
)
1351 return(chmod(path
, mode
));
1353 trans
= hcc_start_command(hc
, HC_CHMOD
);
1354 hcc_leaf_string(trans
, LC_PATH1
, path
);
1355 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1356 if ((head
= hcc_finish_command(trans
)) == NULL
)
1364 rc_chmod(hctransaction_t trans
, struct HCHead
*head
)
1366 struct HCLeaf
*item
;
1367 const char *path
= NULL
;
1370 FOR_EACH_ITEM(item
, trans
, head
) {
1371 switch(item
->leafid
) {
1373 path
= HCC_STRING(item
);
1376 mode
= HCC_INT32(item
);
1381 head
->error
= EACCES
;
1386 return(chmod(path
, mode
));
1393 hc_mknod(struct HostConf
*hc
, const char *path
, mode_t mode
, dev_t rdev
)
1395 hctransaction_t trans
;
1396 struct HCHead
*head
;
1400 if (!DstRootPrivs
) {
1401 /* mknod() requires root privs, so don't bother. */
1406 if (hc
== NULL
|| hc
->host
== NULL
)
1407 return(mknod(path
, mode
, rdev
));
1409 trans
= hcc_start_command(hc
, HC_MKNOD
);
1410 hcc_leaf_string(trans
, LC_PATH1
, path
);
1411 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1412 hcc_leaf_int32(trans
, LC_RDEV
, rdev
);
1413 if ((head
= hcc_finish_command(trans
)) == NULL
)
1421 rc_mknod(hctransaction_t trans
, struct HCHead
*head
)
1423 struct HCLeaf
*item
;
1424 const char *path
= NULL
;
1428 FOR_EACH_ITEM(item
, trans
, head
) {
1429 switch(item
->leafid
) {
1431 path
= HCC_STRING(item
);
1434 mode
= HCC_INT32(item
);
1437 rdev
= HCC_INT32(item
);
1442 head
->error
= EACCES
;
1447 return(mknod(path
, mode
, rdev
));
1454 hc_link(struct HostConf
*hc
, const char *name1
, const char *name2
)
1456 hctransaction_t trans
;
1457 struct HCHead
*head
;
1461 if (hc
== NULL
|| hc
->host
== NULL
)
1462 return(link(name1
, name2
));
1464 trans
= hcc_start_command(hc
, HC_LINK
);
1465 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1466 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1467 if ((head
= hcc_finish_command(trans
)) == NULL
)
1475 rc_link(hctransaction_t trans
, struct HCHead
*head
)
1477 struct HCLeaf
*item
;
1478 const char *name1
= NULL
;
1479 const char *name2
= NULL
;
1481 FOR_EACH_ITEM(item
, trans
, head
) {
1482 switch(item
->leafid
) {
1484 name1
= HCC_STRING(item
);
1487 name2
= HCC_STRING(item
);
1492 head
->error
= EACCES
;
1495 if (name1
== NULL
|| name2
== NULL
)
1497 return(link(name1
, name2
));
1500 #ifdef _ST_FLAGS_PRESENT_
1505 hc_chflags(struct HostConf
*hc
, const char *path
, u_long flags
)
1507 hctransaction_t trans
;
1508 struct HCHead
*head
;
1514 flags
&= UF_SETTABLE
;
1516 if (hc
== NULL
|| hc
->host
== NULL
) {
1517 if ((rc
= chflags(path
, flags
)) < 0)
1518 rc
= silentwarning(&chflags_warning
, "file flags may differ\n");
1522 trans
= hcc_start_command(hc
, HC_CHFLAGS
);
1523 hcc_leaf_string(trans
, LC_PATH1
, path
);
1524 hcc_leaf_int64(trans
, LC_FILEFLAGS
, flags
);
1525 if ((head
= hcc_finish_command(trans
)) == NULL
)
1533 rc_chflags(hctransaction_t trans
, struct HCHead
*head
)
1535 struct HCLeaf
*item
;
1536 const char *path
= NULL
;
1540 FOR_EACH_ITEM(item
, trans
, head
) {
1541 switch(item
->leafid
) {
1543 path
= HCC_STRING(item
);
1546 flags
= (u_long
)HCC_INT64(item
);
1551 head
->error
= EACCES
;
1556 if ((rc
= chflags(path
, flags
)) < 0)
1557 rc
= silentwarning(&chflags_warning
, "file flags may differ\n");
1567 hc_readlink(struct HostConf
*hc
, const char *path
, char *buf
, int bufsiz
)
1569 hctransaction_t trans
;
1570 struct HCHead
*head
;
1571 struct HCLeaf
*item
;
1574 if (hc
== NULL
|| hc
->host
== NULL
)
1575 return(readlink(path
, buf
, bufsiz
));
1577 trans
= hcc_start_command(hc
, HC_READLINK
);
1578 hcc_leaf_string(trans
, LC_PATH1
, path
);
1579 if ((head
= hcc_finish_command(trans
)) == NULL
)
1585 FOR_EACH_ITEM(item
, trans
, head
) {
1586 if (item
->leafid
== LC_DATA
) {
1587 r
= item
->bytes
- sizeof(*item
);
1592 bcopy(HCC_BINARYDATA(item
), buf
, r
);
1599 rc_readlink(hctransaction_t trans
, struct HCHead
*head
)
1601 struct HCLeaf
*item
;
1602 const char *path
= NULL
;
1606 FOR_EACH_ITEM(item
, trans
, head
) {
1607 if (item
->leafid
== LC_PATH1
)
1608 path
= HCC_STRING(item
);
1612 r
= readlink(path
, buf
, sizeof(buf
));
1615 hcc_leaf_data(trans
, LC_DATA
, buf
, r
);
1623 hc_umask(struct HostConf
*hc
, mode_t numask
)
1625 hctransaction_t trans
;
1626 struct HCHead
*head
;
1627 struct HCLeaf
*item
;
1630 return(umask(numask
));
1631 if (hc
== NULL
|| hc
->host
== NULL
)
1632 return(umask(numask
));
1634 trans
= hcc_start_command(hc
, HC_UMASK
);
1635 hcc_leaf_int32(trans
, LC_MODE
, numask
);
1636 if ((head
= hcc_finish_command(trans
)) == NULL
)
1641 numask
= (mode_t
) ~0666U;
1642 FOR_EACH_ITEM(item
, trans
, head
) {
1643 if (item
->leafid
== LC_MODE
)
1644 numask
= HCC_INT32(item
);
1650 rc_umask(hctransaction_t trans
, struct HCHead
*head
)
1652 struct HCLeaf
*item
;
1653 mode_t numask
= (mode_t
) ~0666U;
1655 FOR_EACH_ITEM(item
, trans
, head
) {
1656 if (item
->leafid
== LC_MODE
)
1657 numask
= HCC_INT32(item
);
1659 numask
= umask(numask
);
1660 hcc_leaf_int32(trans
, LC_MODE
, numask
);
1668 hc_symlink(struct HostConf
*hc
, const char *name1
, const char *name2
)
1670 hctransaction_t trans
;
1671 struct HCHead
*head
;
1675 if (hc
== NULL
|| hc
->host
== NULL
)
1676 return(symlink(name1
, name2
));
1678 trans
= hcc_start_command(hc
, HC_SYMLINK
);
1679 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1680 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1681 if ((head
= hcc_finish_command(trans
)) == NULL
)
1689 rc_symlink(hctransaction_t trans
, struct HCHead
*head
)
1691 struct HCLeaf
*item
;
1692 const char *name1
= NULL
;
1693 const char *name2
= NULL
;
1695 FOR_EACH_ITEM(item
, trans
, head
) {
1696 switch(item
->leafid
) {
1698 name1
= HCC_STRING(item
);
1701 name2
= HCC_STRING(item
);
1706 head
->error
= EACCES
;
1709 if (name1
== NULL
|| name2
== NULL
)
1711 return(symlink(name1
, name2
));
1718 hc_rename(struct HostConf
*hc
, const char *name1
, const char *name2
)
1720 hctransaction_t trans
;
1721 struct HCHead
*head
;
1725 if (hc
== NULL
|| hc
->host
== NULL
)
1726 return(rename(name1
, name2
));
1728 trans
= hcc_start_command(hc
, HC_RENAME
);
1729 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1730 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1731 if ((head
= hcc_finish_command(trans
)) == NULL
)
1739 rc_rename(hctransaction_t trans
, struct HCHead
*head
)
1741 struct HCLeaf
*item
;
1742 const char *name1
= NULL
;
1743 const char *name2
= NULL
;
1745 FOR_EACH_ITEM(item
, trans
, head
) {
1746 switch(item
->leafid
) {
1748 name1
= HCC_STRING(item
);
1751 name2
= HCC_STRING(item
);
1756 head
->error
= EACCES
;
1759 if (name1
== NULL
|| name2
== NULL
)
1761 return(rename(name1
, name2
));
1768 hc_utimes(struct HostConf
*hc
, const char *path
, const struct timeval
*times
)
1770 hctransaction_t trans
;
1771 struct HCHead
*head
;
1775 if (hc
== NULL
|| hc
->host
== NULL
)
1776 return(utimes(path
, times
));
1778 trans
= hcc_start_command(hc
, HC_UTIMES
);
1779 hcc_leaf_string(trans
, LC_PATH1
, path
);
1780 hcc_leaf_int64(trans
, LC_ATIME
, times
[0].tv_sec
);
1781 hcc_leaf_int64(trans
, LC_MTIME
, times
[1].tv_sec
);
1782 if ((head
= hcc_finish_command(trans
)) == NULL
)
1790 rc_utimes(hctransaction_t trans
, struct HCHead
*head
)
1792 struct HCLeaf
*item
;
1793 struct timeval times
[2];
1796 bzero(times
, sizeof(times
));
1799 FOR_EACH_ITEM(item
, trans
, head
) {
1800 switch(item
->leafid
) {
1802 path
= HCC_STRING(item
);
1805 times
[0].tv_sec
= HCC_INT64(item
);
1808 times
[1].tv_sec
= HCC_INT64(item
);
1813 head
->error
= EACCES
;
1818 return(utimes(path
, times
));
1822 hc_geteuid(struct HostConf
*hc
)
1824 hctransaction_t trans
;
1825 struct HCHead
*head
;
1826 struct HCLeaf
*item
;
1828 if (hc
== NULL
|| hc
->host
== NULL
)
1831 if (hc
->version
< 3) {
1832 fprintf(stderr
, "WARNING: Remote client uses old protocol version\n");
1833 /* Return 0 on error, so the caller assumes root privileges. */
1837 trans
= hcc_start_command(hc
, HC_GETEUID
);
1838 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
1840 FOR_EACH_ITEM(item
, trans
, head
) {
1841 if (item
->leafid
== LC_UID
)
1842 return (HCC_INT32(item
));
1844 return(0); /* shouldn't happen */
1848 rc_geteuid(hctransaction_t trans
, struct HCHead
*head __unused
)
1850 hcc_leaf_int32(trans
, LC_UID
, geteuid());
1855 getmygroups(gid_t
**gidlist
)
1859 if ((count
= getgroups(0, *gidlist
)) > 0) {
1860 if ((*gidlist
= malloc(count
* sizeof(gid_t
))) != NULL
) {
1861 if ((count
= getgroups(count
, *gidlist
)) <= 0)
1873 hc_getgroups(struct HostConf
*hc
, gid_t
**gidlist
)
1876 hctransaction_t trans
;
1877 struct HCHead
*head
;
1878 struct HCLeaf
*item
;
1880 if (hc
== NULL
|| hc
->host
== NULL
)
1881 return (getmygroups(gidlist
));
1887 if (hc
->version
< 3) {
1888 fprintf(stderr
, "WARNING: Remote client uses old protocol version\n");
1892 trans
= hcc_start_command(hc
, HC_GETGROUPS
);
1893 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
1895 FOR_EACH_ITEM(item
, trans
, head
) {
1896 switch(item
->leafid
) {
1898 count
= HCC_INT32(item
);
1899 if (*gidlist
!= NULL
) { /* protocol error */
1904 if ((*gidlist
= malloc(count
* sizeof(gid_t
))) == NULL
)
1908 if (*gidlist
== NULL
|| i
>= count
) { /* protocol error */
1909 if (*gidlist
!= NULL
)
1914 (*gidlist
)[i
++] = HCC_INT32(item
);
1922 rc_getgroups(hctransaction_t trans
, struct HCHead
*head __unused
)
1927 if ((count
= getmygroups(&gidlist
)) < 0)
1929 hcc_leaf_int32(trans
, LC_COUNT
, count
);
1930 for (i
= 0; i
< count
; i
++)
1931 hcc_leaf_int32(trans
, LC_GID
, gidlist
[i
]);
1932 if (gidlist
!= NULL
)