4 * This module implements a simple remote control protocol
11 static int hc_decode_stat(hctransaction_t trans
, struct stat
*, struct HCHead
*);
12 static int hc_decode_stat_item(struct stat
*st
, struct HCLeaf
*item
);
13 static int rc_encode_stat(hctransaction_t trans
, struct stat
*);
15 static int rc_hello(hctransaction_t trans
, struct HCHead
*);
16 static int rc_stat(hctransaction_t trans
, struct HCHead
*);
17 static int rc_lstat(hctransaction_t trans
, struct HCHead
*);
18 static int rc_opendir(hctransaction_t trans
, struct HCHead
*);
19 static int rc_readdir(hctransaction_t trans
, struct HCHead
*);
20 static int rc_closedir(hctransaction_t trans
, struct HCHead
*);
21 static int rc_scandir(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_readfile(hctransaction_t trans
, struct HCHead
*);
26 static int rc_write(hctransaction_t trans
, struct HCHead
*);
27 static int rc_remove(hctransaction_t trans
, struct HCHead
*);
28 static int rc_mkdir(hctransaction_t trans
, struct HCHead
*);
29 static int rc_rmdir(hctransaction_t trans
, struct HCHead
*);
30 static int rc_chown(hctransaction_t trans
, struct HCHead
*);
31 static int rc_lchown(hctransaction_t trans
, struct HCHead
*);
32 static int rc_chmod(hctransaction_t trans
, struct HCHead
*);
33 static int rc_mknod(hctransaction_t trans
, struct HCHead
*);
34 static int rc_link(hctransaction_t trans
, struct HCHead
*);
35 #ifdef _ST_FLAGS_PRESENT_
36 static int rc_chflags(hctransaction_t trans
, struct HCHead
*);
38 static int rc_readlink(hctransaction_t trans
, struct HCHead
*);
39 static int rc_umask(hctransaction_t trans
, struct HCHead
*);
40 static int rc_symlink(hctransaction_t trans
, struct HCHead
*);
41 static int rc_rename(hctransaction_t trans
, struct HCHead
*);
42 static int rc_utimes(hctransaction_t trans
, struct HCHead
*);
43 static int rc_geteuid(hctransaction_t trans
, struct HCHead
*);
44 static int rc_getgroups(hctransaction_t trans
, struct HCHead
*);
46 static int getmygroups(gid_t
**gidlist
);
48 static int silentwarning(int *, const char *, ...) __printflike(2, 3);
50 static struct HCDesc HCDispatchTable
[] = {
51 { HC_HELLO
, rc_hello
},
53 { HC_LSTAT
, rc_lstat
},
54 { HC_OPENDIR
, rc_opendir
},
55 { HC_READDIR
, rc_readdir
},
56 { HC_CLOSEDIR
, rc_closedir
},
58 { HC_CLOSE
, rc_close
},
60 { HC_WRITE
, rc_write
},
61 { HC_REMOVE
, rc_remove
},
62 { HC_MKDIR
, rc_mkdir
},
63 { HC_RMDIR
, rc_rmdir
},
64 { HC_CHOWN
, rc_chown
},
65 { HC_LCHOWN
, rc_lchown
},
66 { HC_CHMOD
, rc_chmod
},
67 { HC_MKNOD
, rc_mknod
},
69 #ifdef _ST_FLAGS_PRESENT_
70 { HC_CHFLAGS
, rc_chflags
},
72 { HC_READLINK
, rc_readlink
},
73 { HC_UMASK
, rc_umask
},
74 { HC_SYMLINK
, rc_symlink
},
75 { HC_RENAME
, rc_rename
},
76 { HC_UTIMES
, rc_utimes
},
77 { HC_GETEUID
, rc_geteuid
},
78 { HC_GETGROUPS
, rc_getgroups
},
79 { HC_SCANDIR
, rc_scandir
},
80 { HC_READFILE
, rc_readfile
},
81 { HC_LUTIMES
, rc_utimes
},
82 #ifdef _ST_FLAGS_PRESENT_
83 { HC_LCHFLAGS
, rc_chflags
},
85 { HC_LCHMOD
, rc_chmod
},
88 static int chown_warning
;
89 #ifdef _ST_FLAGS_PRESENT_
90 static int chflags_warning
;
94 * If not running as root generate a silent warning and return no error.
96 * If running as root return an error.
99 silentwarning(int *didwarn
, const char *ctl
, ...)
105 if (*didwarn
== 0 && QuietOpt
== 0) {
107 fprintf(stderr
, "WARNING: Not running as root, ");
109 vfprintf(stderr
, ctl
, va
);
116 hc_connect(struct HostConf
*hc
, int readonly
)
118 if (hcc_connect(hc
, readonly
) < 0) {
119 fprintf(stderr
, "Unable to connect to %s\n", hc
->host
);
122 return(hc_hello(hc
));
126 hc_slave(int fdin
, int fdout
)
128 hcc_slave(fdin
, fdout
, HCDispatchTable
,
129 sizeof(HCDispatchTable
) / sizeof(HCDispatchTable
[0]));
133 * A HELLO RPC is sent on the initial connect.
136 hc_hello(struct HostConf
*hc
)
140 hctransaction_t trans
;
144 bzero(hostbuf
, sizeof(hostbuf
));
145 if (gethostname(hostbuf
, sizeof(hostbuf
) - 1) < 0)
150 trans
= hcc_start_command(hc
, HC_HELLO
);
151 hcc_leaf_string(trans
, LC_HELLOSTR
, hostbuf
);
152 hcc_leaf_int32(trans
, LC_VERSION
, HCPROTO_VERSION
);
154 hcc_leaf_string(trans
, LC_PATH1
, UseCpFile
);
155 if ((head
= hcc_finish_command(trans
)) == NULL
) {
156 fprintf(stderr
, "Connected to %s but remote failed to complete hello\n",
162 fprintf(stderr
, "Connected to %s but remote returned error %d\n",
163 hc
->host
, head
->error
);
168 FOR_EACH_ITEM(item
, trans
, head
) {
169 switch(item
->leafid
) {
172 fprintf(stderr
, "Handshaked with %s\n", HCC_STRING(item
));
176 hc
->version
= HCC_INT32(item
);
180 if (hc
->version
< HCPROTO_VERSION_COMPAT
) {
181 fprintf(stderr
, "Remote cpdup at %s has an incompatible version\n",
184 } else if (hc
->version
< HCPROTO_VERSION
&& QuietOpt
== 0) {
186 "WARNING: Remote cpdup at %s has a lower version,\n"
187 "expect reduced speed and/or functionality\n", hc
->host
);
190 fprintf(stderr
, "Handshake failed with %s\n", hc
->host
);
195 rc_hello(hctransaction_t trans
, struct HCHead
*head
)
200 FOR_EACH_ITEM(item
, trans
, head
) {
201 if (item
->leafid
== LC_PATH1
)
202 UseCpFile
= strdup(HCC_STRING(item
));
205 bzero(hostbuf
, sizeof(hostbuf
));
206 if (gethostname(hostbuf
, sizeof(hostbuf
) - 1) < 0)
211 hcc_leaf_string(trans
, LC_HELLOSTR
, hostbuf
);
212 hcc_leaf_int32(trans
, LC_VERSION
, HCPROTO_VERSION
);
220 hc_stat(struct HostConf
*hc
, const char *path
, struct stat
*st
)
223 hctransaction_t trans
;
225 if (hc
== NULL
|| hc
->host
== NULL
)
226 return(stat(path
, st
));
228 trans
= hcc_start_command(hc
, HC_STAT
);
229 hcc_leaf_string(trans
, LC_PATH1
, path
);
230 if ((head
= hcc_finish_command(trans
)) == NULL
)
234 return(hc_decode_stat(trans
, st
, head
));
238 hc_lstat(struct HostConf
*hc
, const char *path
, struct stat
*st
)
241 hctransaction_t trans
;
243 if (hc
== NULL
|| hc
->host
== NULL
)
244 return(lstat(path
, st
));
246 trans
= hcc_start_command(hc
, HC_LSTAT
);
247 hcc_leaf_string(trans
, LC_PATH1
, path
);
248 if ((head
= hcc_finish_command(trans
)) == NULL
)
252 return(hc_decode_stat(trans
, st
, head
));
256 hc_decode_stat(hctransaction_t trans
, struct stat
*st
, struct HCHead
*head
)
260 bzero(st
, sizeof(*st
));
261 FOR_EACH_ITEM(item
, trans
, head
)
262 hc_decode_stat_item(st
, item
);
267 hc_decode_stat_item(struct stat
*st
, struct HCLeaf
*item
)
269 switch(item
->leafid
) {
271 st
->st_dev
= HCC_INT32(item
);
274 st
->st_ino
= HCC_INT64(item
);
277 st
->st_mode
= HCC_INT32(item
);
280 st
->st_nlink
= HCC_INT32(item
);
283 st
->st_uid
= HCC_INT32(item
);
286 st
->st_gid
= HCC_INT32(item
);
289 st
->st_rdev
= HCC_INT32(item
);
292 st
->st_atime
= (time_t)HCC_INT64(item
);
295 st
->st_mtime
= (time_t)HCC_INT64(item
);
298 st
->st_ctime
= (time_t)HCC_INT64(item
);
300 #if defined(st_atime) /* A macro, so very likely on modern POSIX */
302 st
->st_atim
.tv_nsec
= HCC_INT32(item
);
305 st
->st_mtim
.tv_nsec
= HCC_INT32(item
);
308 st
->st_ctim
.tv_nsec
= HCC_INT32(item
);
312 st
->st_size
= HCC_INT64(item
);
315 st
->st_blocks
= HCC_INT64(item
);
318 st
->st_blksize
= HCC_INT32(item
);
320 #ifdef _ST_FLAGS_PRESENT_
322 st
->st_flags
= (uint32_t)HCC_INT64(item
);
330 rc_stat(hctransaction_t trans
, struct HCHead
*head
)
334 const char *path
= NULL
;
336 FOR_EACH_ITEM(item
, trans
, head
) {
337 if (item
->leafid
== LC_PATH1
)
338 path
= HCC_STRING(item
);
342 if (stat(path
, &st
) < 0)
344 return (rc_encode_stat(trans
, &st
));
348 rc_lstat(hctransaction_t trans
, struct HCHead
*head
)
352 const char *path
= NULL
;
354 FOR_EACH_ITEM(item
, trans
, head
) {
355 if (item
->leafid
== LC_PATH1
)
356 path
= HCC_STRING(item
);
360 if (lstat(path
, &st
) < 0)
362 return (rc_encode_stat(trans
, &st
));
366 * Encode all entries of a stat structure.
368 * CAUTION: If you add any more entries here, be sure to
369 * increase the STAT_MAX_NUM_ENTRIES value!
371 #define STAT_MAX_NUM_ENTRIES 18
373 rc_encode_stat(hctransaction_t trans
, struct stat
*st
)
375 hcc_leaf_int32(trans
, LC_DEV
, st
->st_dev
);
376 hcc_leaf_int64(trans
, LC_INO
, st
->st_ino
);
377 hcc_leaf_int32(trans
, LC_MODE
, st
->st_mode
);
378 hcc_leaf_int32(trans
, LC_NLINK
, st
->st_nlink
);
379 hcc_leaf_int32(trans
, LC_UID
, st
->st_uid
);
380 hcc_leaf_int32(trans
, LC_GID
, st
->st_gid
);
381 hcc_leaf_int32(trans
, LC_RDEV
, st
->st_rdev
);
382 hcc_leaf_int64(trans
, LC_ATIME
, st
->st_atime
);
383 hcc_leaf_int64(trans
, LC_MTIME
, st
->st_mtime
);
384 hcc_leaf_int64(trans
, LC_CTIME
, st
->st_ctime
);
385 #if defined(st_atime)
386 hcc_leaf_int32(trans
, LC_ATIMENSEC
, st
->st_atim
.tv_nsec
);
387 hcc_leaf_int32(trans
, LC_MTIMENSEC
, st
->st_mtim
.tv_nsec
);
388 hcc_leaf_int32(trans
, LC_CTIMENSEC
, st
->st_ctim
.tv_nsec
);
390 hcc_leaf_int64(trans
, LC_FILESIZE
, st
->st_size
);
391 hcc_leaf_int64(trans
, LC_FILEBLKS
, st
->st_blocks
);
392 hcc_leaf_int32(trans
, LC_BLKSIZE
, st
->st_blksize
);
393 #ifdef _ST_FLAGS_PRESENT_
394 hcc_leaf_int64(trans
, LC_FILEFLAGS
, st
->st_flags
);
403 hc_opendir(struct HostConf
*hc
, const char *path
)
405 hctransaction_t trans
;
408 if (hc
== NULL
|| hc
->host
== NULL
)
409 return(opendir(path
));
411 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
413 struct HCDirEntry
*den
;
416 trans
= hcc_start_command(hc
, HC_OPENDIR
);
417 hcc_leaf_string(trans
, LC_PATH1
, path
);
418 if ((head
= hcc_finish_command(trans
)) == NULL
)
422 FOR_EACH_ITEM(item
, trans
, head
) {
423 if (item
->leafid
== LC_DESCRIPTOR
)
424 desc
= HCC_INT32(item
);
426 if (hcc_get_descriptor(hc
, desc
, HC_DESC_DIR
)) {
427 fprintf(stderr
, "hc_opendir: remote reused active descriptor %jd\n",
431 den
= malloc(sizeof(*den
));
432 hcc_set_descriptor(hc
, desc
, den
, HC_DESC_DIR
);
433 return ((void *)desc
);
436 /* hc->version >= 4: use HC_SCANDIR */
437 trans
= hcc_start_command(hc
, HC_SCANDIR
);
438 hcc_leaf_string(trans
, LC_PATH1
, path
);
439 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
441 return ((void *)head
);
445 rc_opendir(hctransaction_t trans
, struct HCHead
*head
)
448 const char *path
= NULL
;
452 FOR_EACH_ITEM(item
, trans
, head
) {
453 if (item
->leafid
== LC_PATH1
)
454 path
= HCC_STRING(item
);
458 if ((dir
= opendir(path
)) == NULL
) {
461 desc
= hcc_alloc_descriptor(trans
->hc
, dir
, HC_DESC_DIR
);
462 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, desc
);
471 hc_readdir(struct HostConf
*hc
, DIR *dir
, struct stat
**statpp
)
476 static struct HCDirEntry denbuf
;
479 if (hc
== NULL
|| hc
->host
== NULL
) {
480 struct dirent
*sysden
;
482 if ((sysden
= readdir(dir
)) == NULL
)
484 strlcpy(denbuf
.d_name
, sysden
->d_name
, MAXNAMLEN
+ 1);
488 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
489 hctransaction_t trans
;
490 struct HCDirEntry
*den
;
492 trans
= hcc_start_command(hc
, HC_READDIR
);
493 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, (intptr_t)dir
);
494 if ((head
= hcc_finish_command(trans
)) == NULL
)
497 return (NULL
); /* XXX errno */
498 den
= hcc_get_descriptor(hc
, (intptr_t)dir
, HC_DESC_DIR
);
500 return (NULL
); /* XXX errno */
502 FOR_EACH_ITEM(item
, trans
, head
) {
503 if (item
->leafid
== LC_PATH1
)
504 strlcpy(den
->d_name
, HCC_STRING(item
), MAXNAMLEN
+ 1);
506 return (den
->d_name
[0] ? den
: NULL
);
509 /* hc->version >= 4: using HC_SCANDIR */
510 denbuf
.d_name
[0] = 0;
512 *statpp
= malloc(sizeof(struct stat
));
513 bzero(*statpp
, sizeof(struct stat
));
514 while ((item
= hcc_nextchaineditem(hc
, head
)) != NULL
) {
515 if (item
->leafid
== LC_PATH1
) { /* this must be the last item */
516 strlcpy(denbuf
.d_name
, HCC_STRING(item
), MAXNAMLEN
+ 1);
520 hc_decode_stat_item(*statpp
, item
);
527 if (hc
->trans
.state
== HCT_FAIL
)
529 return (denbuf
.d_name
[0] ? &denbuf
: NULL
);
533 rc_readdir(hctransaction_t trans
, struct HCHead
*head
)
539 FOR_EACH_ITEM(item
, trans
, head
) {
540 if (item
->leafid
== LC_DESCRIPTOR
)
541 dir
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_DIR
);
545 if ((den
= readdir(dir
)) != NULL
)
546 hcc_leaf_string(trans
, LC_PATH1
, den
->d_name
);
553 * XXX cpdup needs to check error code to avoid truncated dirs?
556 hc_closedir(struct HostConf
*hc
, DIR *dir
)
560 if (hc
== NULL
|| hc
->host
== NULL
)
561 return(closedir(dir
));
563 if (hc
->version
<= 3) { /* compatibility: HC_SCANDIR not supported */
564 hctransaction_t trans
;
567 if ((den
= hcc_get_descriptor(hc
, (intptr_t)dir
, HC_DESC_DIR
)) != NULL
) {
569 hcc_set_descriptor(hc
, (intptr_t)dir
, NULL
, HC_DESC_DIR
);
570 trans
= hcc_start_command(hc
, HC_CLOSEDIR
);
571 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, (intptr_t)dir
);
572 if ((head
= hcc_finish_command(trans
)) == NULL
)
575 return (-1); /* XXX errno */
583 /* hc->version >= 4: using HC_SCANDIR */
585 /* skip any remaining items if the directory is closed prematurely */
586 while (hcc_nextchaineditem(hc
, head
) != NULL
)
588 if (hc
->trans
.state
== HCT_FAIL
|| head
->error
)
594 rc_closedir(hctransaction_t trans
, struct HCHead
*head
)
599 FOR_EACH_ITEM(item
, trans
, head
) {
600 if (item
->leafid
== LC_DESCRIPTOR
) {
601 dir
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_DIR
);
603 hcc_set_descriptor(trans
->hc
, HCC_INT32(item
),
610 return(closedir(dir
));
617 rc_scandir(hctransaction_t trans
, struct HCHead
*head
)
620 const char *path
= NULL
;
626 FOR_EACH_ITEM(item
, trans
, head
) {
627 if (item
->leafid
== LC_PATH1
)
628 path
= HCC_STRING(item
);
632 if ((dir
= opendir(path
)) == NULL
)
634 while ((den
= readdir(dir
)) != NULL
) {
635 if (den
->d_name
[0] == '.' && (den
->d_name
[1] == '\0' ||
636 (den
->d_name
[1] == '.' && den
->d_name
[2] == '\0')))
637 continue; /* skip "." and ".." */
639 * Check if there's enough space left in the current packet.
640 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
641 * one is a string, so we use strlen() + 1 (terminating zero).
642 * The remaining ones are numbers; we assume sizeof(int64_t) so
643 * we're on the safe side.
645 if (!hcc_check_space(trans
, head
, STAT_MAX_NUM_ENTRIES
,
646 (STAT_MAX_NUM_ENTRIES
- 1) * sizeof(int64_t) +
647 strlen(den
->d_name
) + 1)) {
651 fpath
= mprintf("%s/%s", path
, den
->d_name
);
652 if (lstat(fpath
, &st
) == 0)
653 rc_encode_stat(trans
, &st
);
654 /* The name must be the last item! */
655 hcc_leaf_string(trans
, LC_PATH1
, den
->d_name
);
658 return (closedir(dir
));
665 hc_open(struct HostConf
*hc
, const char *path
, int flags
, mode_t mode
)
667 hctransaction_t trans
;
674 if (NotForRealOpt
&& (flags
& O_CREAT
))
677 if (hc
== NULL
|| hc
->host
== NULL
) {
679 flags
|= O_LARGEFILE
;
681 return(open(path
, flags
, mode
));
684 if ((flags
& (O_WRONLY
| O_RDWR
)) == 0 && hc
->version
>= 4) {
685 trans
= hcc_start_command(hc
, HC_READFILE
);
686 hcc_leaf_string(trans
, LC_PATH1
, path
);
687 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
689 head
->magic
= 0; /* used to indicate offset within buffer */
690 return (1); /* dummy */
693 nflags
= flags
& XO_NATIVEMASK
;
701 trans
= hcc_start_command(hc
, HC_OPEN
);
702 hcc_leaf_string(trans
, LC_PATH1
, path
);
703 hcc_leaf_int32(trans
, LC_OFLAGS
, nflags
);
704 hcc_leaf_int32(trans
, LC_MODE
, mode
);
706 if ((head
= hcc_finish_command(trans
)) == NULL
)
710 FOR_EACH_ITEM(item
, trans
, head
) {
711 if (item
->leafid
== LC_DESCRIPTOR
)
712 desc
= HCC_INT32(item
);
714 if (hcc_get_descriptor(hc
, desc
, HC_DESC_FD
)) {
715 fprintf(stderr
, "hc_open: remote reused active descriptor %d\n",
719 fdp
= malloc(sizeof(int));
720 *fdp
= desc
; /* really just a dummy */
721 hcc_set_descriptor(hc
, desc
, fdp
, HC_DESC_FD
);
726 rc_open(hctransaction_t trans
, struct HCHead
*head
)
729 const char *path
= NULL
;
737 FOR_EACH_ITEM(item
, trans
, head
) {
738 switch(item
->leafid
) {
740 path
= HCC_STRING(item
);
743 nflags
= HCC_INT32(item
);
746 mode
= HCC_INT32(item
);
753 flags
= nflags
& XO_NATIVEMASK
;
754 if (nflags
& XO_CREAT
)
756 if (nflags
& XO_EXCL
)
758 if (nflags
& XO_TRUNC
)
762 if (flags
& (O_WRONLY
| O_RDWR
| O_CREAT
| O_TRUNC
)) {
763 head
->error
= EACCES
;
770 flags
|= O_LARGEFILE
;
772 if ((fd
= open(path
, flags
, mode
)) < 0)
774 fdp
= malloc(sizeof(int));
776 desc
= hcc_alloc_descriptor(trans
->hc
, fdp
, HC_DESC_FD
);
777 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, desc
);
785 hc_close(struct HostConf
*hc
, int fd
)
787 hctransaction_t trans
;
791 if (NotForRealOpt
&& fd
== 0x7FFFFFFF)
793 if (hc
== NULL
|| hc
->host
== NULL
)
796 if (fd
== 1 && hc
->version
>= 4) { /* using HC_READFILE */
797 head
= (void *)hc
->trans
.rbuf
;
798 /* skip any remaining items if the file is closed prematurely */
799 while (hcc_nextchaineditem(hc
, head
) != NULL
)
801 if (hc
->trans
.state
== HCT_FAIL
|| head
->error
)
806 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
809 hcc_set_descriptor(hc
, fd
, NULL
, HC_DESC_FD
);
811 trans
= hcc_start_command(hc
, HC_CLOSE
);
812 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
813 if ((head
= hcc_finish_command(trans
)) == NULL
)
824 rc_close(hctransaction_t trans
, struct HCHead
*head
)
831 FOR_EACH_ITEM(item
, trans
, head
) {
832 if (item
->leafid
== LC_DESCRIPTOR
)
833 desc
= HCC_INT32(item
);
837 if ((fdp
= hcc_get_descriptor(trans
->hc
, desc
, HC_DESC_FD
)) == NULL
)
841 hcc_set_descriptor(trans
->hc
, desc
, NULL
, HC_DESC_FD
);
855 hc_read(struct HostConf
*hc
, int fd
, void *buf
, size_t bytes
)
857 hctransaction_t trans
;
865 if (hc
== NULL
|| hc
->host
== NULL
)
866 return(read(fd
, buf
, bytes
));
868 if (fd
== 1 && hc
->version
>= 4) { /* using HC_READFILE */
869 head
= (void *)hc
->trans
.rbuf
;
871 if ((offset
= head
->magic
) != 0) {
872 item
= hcc_currentchaineditem(hc
, head
);
874 item
= hcc_nextchaineditem(hc
, head
);
877 if (hc
->trans
.state
== HCT_FAIL
)
881 if (item
->leafid
!= LC_DATA
)
883 x
= item
->bytes
- sizeof(*item
) - offset
;
884 if (x
> (int)bytes
) {
886 head
->magic
+= x
; /* leave bytes in the buffer */
889 head
->magic
= 0; /* all bytes used up */
890 bcopy((char *)HCC_BINARYDATA(item
) + offset
, buf
, x
);
891 buf
= (char *)buf
+ x
;
898 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
901 size_t limit
= getiolimit();
902 int n
= (bytes
> limit
) ? limit
: bytes
;
904 trans
= hcc_start_command(hc
, HC_READ
);
905 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
906 hcc_leaf_int32(trans
, LC_BYTES
, n
);
907 if ((head
= hcc_finish_command(trans
)) == NULL
)
911 FOR_EACH_ITEM(item
, trans
, head
) {
912 if (item
->leafid
== LC_DATA
) {
913 x
= item
->bytes
- sizeof(*item
);
916 bcopy(HCC_BINARYDATA(item
), buf
, x
);
917 buf
= (char *)buf
+ x
;
932 rc_read(hctransaction_t trans
, struct HCHead
*head
)
940 FOR_EACH_ITEM(item
, trans
, head
) {
941 switch(item
->leafid
) {
943 fdp
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_FD
);
946 bytes
= HCC_INT32(item
);
952 if (bytes
< 0 || bytes
> 32768)
954 n
= read(*fdp
, buf
, bytes
);
957 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
965 rc_readfile(hctransaction_t trans
, struct HCHead
*head
)
968 const char *path
= NULL
;
973 FOR_EACH_ITEM(item
, trans
, head
) {
974 if (item
->leafid
== LC_PATH1
)
975 path
= HCC_STRING(item
);
979 if ((fd
= open(path
, O_RDONLY
)) < 0)
981 while ((n
= read(fd
, buf
, 32768)) >= 0) {
982 if (!hcc_check_space(trans
, head
, 1, n
)) {
986 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
1001 hc_write(struct HostConf
*hc
, int fd
, const void *buf
, size_t bytes
)
1003 hctransaction_t trans
;
1004 struct HCHead
*head
;
1005 struct HCLeaf
*item
;
1012 if (hc
== NULL
|| hc
->host
== NULL
)
1013 return(write(fd
, buf
, bytes
));
1015 fdp
= hcc_get_descriptor(hc
, fd
, HC_DESC_FD
);
1019 size_t limit
= getiolimit();
1020 int n
= (bytes
> limit
) ? limit
: bytes
;
1023 trans
= hcc_start_command(hc
, HC_WRITE
);
1024 hcc_leaf_int32(trans
, LC_DESCRIPTOR
, fd
);
1025 hcc_leaf_data(trans
, LC_DATA
, buf
, n
);
1026 if ((head
= hcc_finish_command(trans
)) == NULL
)
1030 FOR_EACH_ITEM(item
, trans
, head
) {
1031 if (item
->leafid
== LC_BYTES
)
1032 x
= HCC_INT32(item
);
1037 buf
= (const char *)buf
+ x
;
1049 rc_write(hctransaction_t trans
, struct HCHead
*head
)
1051 struct HCLeaf
*item
;
1056 FOR_EACH_ITEM(item
, trans
, head
) {
1057 switch(item
->leafid
) {
1059 fdp
= hcc_get_descriptor(trans
->hc
, HCC_INT32(item
), HC_DESC_FD
);
1062 buf
= HCC_BINARYDATA(item
);
1063 n
= item
->bytes
- sizeof(*item
);
1068 head
->error
= EACCES
;
1073 if (n
< 0 || n
> 32768)
1075 n
= write(*fdp
, buf
, n
);
1078 hcc_leaf_int32(trans
, LC_BYTES
, n
);
1085 * NOTE: This function returns -errno if an error occured.
1088 hc_remove(struct HostConf
*hc
, const char *path
)
1090 hctransaction_t trans
;
1091 struct HCHead
*head
;
1096 if (hc
== NULL
|| hc
->host
== NULL
) {
1103 trans
= hcc_start_command(hc
, HC_REMOVE
);
1104 hcc_leaf_string(trans
, LC_PATH1
, path
);
1105 if ((head
= hcc_finish_command(trans
)) == NULL
)
1108 return(-(int)head
->error
);
1113 rc_remove(hctransaction_t trans
, struct HCHead
*head
)
1115 struct HCLeaf
*item
;
1116 const char *path
= NULL
;
1118 FOR_EACH_ITEM(item
, trans
, head
) {
1119 if (item
->leafid
== LC_PATH1
)
1120 path
= HCC_STRING(item
);
1125 head
->error
= EACCES
;
1128 return(remove(path
));
1135 hc_mkdir(struct HostConf
*hc
, const char *path
, mode_t mode
)
1137 hctransaction_t trans
;
1138 struct HCHead
*head
;
1142 if (hc
== NULL
|| hc
->host
== NULL
)
1143 return(mkdir(path
, mode
));
1145 trans
= hcc_start_command(hc
, HC_MKDIR
);
1146 hcc_leaf_string(trans
, LC_PATH1
, path
);
1147 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1148 if ((head
= hcc_finish_command(trans
)) == NULL
)
1156 rc_mkdir(hctransaction_t trans
, struct HCHead
*head
)
1158 struct HCLeaf
*item
;
1159 const char *path
= NULL
;
1162 FOR_EACH_ITEM(item
, trans
, head
) {
1163 switch(item
->leafid
) {
1165 path
= HCC_STRING(item
);
1168 mode
= HCC_INT32(item
);
1173 head
->error
= EACCES
;
1178 return(mkdir(path
, mode
));
1185 hc_rmdir(struct HostConf
*hc
, const char *path
)
1187 hctransaction_t trans
;
1188 struct HCHead
*head
;
1192 if (hc
== NULL
|| hc
->host
== NULL
)
1193 return(rmdir(path
));
1195 trans
= hcc_start_command(hc
, HC_RMDIR
);
1196 hcc_leaf_string(trans
, LC_PATH1
, path
);
1197 if ((head
= hcc_finish_command(trans
)) == NULL
)
1205 rc_rmdir(hctransaction_t trans
, struct HCHead
*head
)
1207 struct HCLeaf
*item
;
1208 const char *path
= NULL
;
1210 FOR_EACH_ITEM(item
, trans
, head
) {
1211 if (item
->leafid
== LC_PATH1
)
1212 path
= HCC_STRING(item
);
1215 head
->error
= EACCES
;
1220 return(rmdir(path
));
1226 * Almost silently ignore chowns that fail if we are not root.
1229 hc_chown(struct HostConf
*hc
, const char *path
, uid_t owner
, gid_t group
)
1231 hctransaction_t trans
;
1232 struct HCHead
*head
;
1240 if (hc
== NULL
|| hc
->host
== NULL
) {
1241 rc
= chown(path
, owner
, group
);
1243 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1247 trans
= hcc_start_command(hc
, HC_CHOWN
);
1248 hcc_leaf_string(trans
, LC_PATH1
, path
);
1249 hcc_leaf_int32(trans
, LC_UID
, owner
);
1250 hcc_leaf_int32(trans
, LC_GID
, group
);
1251 if ((head
= hcc_finish_command(trans
)) == NULL
)
1259 rc_chown(hctransaction_t trans
, struct HCHead
*head
)
1261 struct HCLeaf
*item
;
1262 const char *path
= NULL
;
1263 uid_t uid
= (uid_t
)-1;
1264 gid_t gid
= (gid_t
)-1;
1267 FOR_EACH_ITEM(item
, trans
, head
) {
1268 switch(item
->leafid
) {
1270 path
= HCC_STRING(item
);
1273 uid
= HCC_INT32(item
);
1276 gid
= HCC_INT32(item
);
1281 head
->error
= EACCES
;
1286 rc
= chown(path
, uid
, gid
);
1288 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1296 hc_lchown(struct HostConf
*hc
, const char *path
, uid_t owner
, gid_t group
)
1298 hctransaction_t trans
;
1299 struct HCHead
*head
;
1307 if (hc
== NULL
|| hc
->host
== NULL
) {
1308 rc
= lchown(path
, owner
, group
);
1310 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1314 trans
= hcc_start_command(hc
, HC_LCHOWN
);
1315 hcc_leaf_string(trans
, LC_PATH1
, path
);
1316 hcc_leaf_int32(trans
, LC_UID
, owner
);
1317 hcc_leaf_int32(trans
, LC_GID
, group
);
1318 if ((head
= hcc_finish_command(trans
)) == NULL
)
1326 rc_lchown(hctransaction_t trans
, struct HCHead
*head
)
1328 struct HCLeaf
*item
;
1329 const char *path
= NULL
;
1330 uid_t uid
= (uid_t
)-1;
1331 gid_t gid
= (gid_t
)-1;
1334 FOR_EACH_ITEM(item
, trans
, head
) {
1335 switch(item
->leafid
) {
1337 path
= HCC_STRING(item
);
1340 uid
= HCC_INT32(item
);
1343 gid
= HCC_INT32(item
);
1348 head
->error
= EACCES
;
1353 rc
= lchown(path
, uid
, gid
);
1355 rc
= silentwarning(&chown_warning
, "file ownership may differ\n");
1363 hc_chmod(struct HostConf
*hc
, const char *path
, mode_t mode
)
1365 hctransaction_t trans
;
1366 struct HCHead
*head
;
1370 if (hc
== NULL
|| hc
->host
== NULL
)
1371 return(chmod(path
, mode
));
1373 trans
= hcc_start_command(hc
, HC_CHMOD
);
1374 hcc_leaf_string(trans
, LC_PATH1
, path
);
1375 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1376 if ((head
= hcc_finish_command(trans
)) == NULL
)
1384 hc_lchmod(struct HostConf
*hc
, const char *path
, mode_t mode
)
1386 hctransaction_t trans
;
1387 struct HCHead
*head
;
1391 if (hc
== NULL
|| hc
->host
== NULL
)
1392 return(lchmod(path
, mode
));
1394 trans
= hcc_start_command(hc
, HC_LCHMOD
);
1395 hcc_leaf_string(trans
, LC_PATH1
, path
);
1396 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1397 if ((head
= hcc_finish_command(trans
)) == NULL
)
1405 rc_chmod(hctransaction_t trans
, struct HCHead
*head
)
1407 struct HCLeaf
*item
;
1408 const char *path
= NULL
;
1411 FOR_EACH_ITEM(item
, trans
, head
) {
1412 switch(item
->leafid
) {
1414 path
= HCC_STRING(item
);
1417 mode
= HCC_INT32(item
);
1422 head
->error
= EACCES
;
1427 if (head
->cmd
== HC_LCHMOD
)
1428 return(lchmod(path
, mode
));
1430 return(chmod(path
, mode
));
1437 hc_mknod(struct HostConf
*hc
, const char *path
, mode_t mode
, dev_t rdev
)
1439 hctransaction_t trans
;
1440 struct HCHead
*head
;
1444 if (!DstRootPrivs
) {
1445 /* mknod() requires root privs, so don't bother. */
1450 if (hc
== NULL
|| hc
->host
== NULL
)
1451 return(mknod(path
, mode
, rdev
));
1453 trans
= hcc_start_command(hc
, HC_MKNOD
);
1454 hcc_leaf_string(trans
, LC_PATH1
, path
);
1455 hcc_leaf_int32(trans
, LC_MODE
, mode
);
1456 hcc_leaf_int32(trans
, LC_RDEV
, rdev
);
1457 if ((head
= hcc_finish_command(trans
)) == NULL
)
1465 rc_mknod(hctransaction_t trans
, struct HCHead
*head
)
1467 struct HCLeaf
*item
;
1468 const char *path
= NULL
;
1472 FOR_EACH_ITEM(item
, trans
, head
) {
1473 switch(item
->leafid
) {
1475 path
= HCC_STRING(item
);
1478 mode
= HCC_INT32(item
);
1481 rdev
= HCC_INT32(item
);
1486 head
->error
= EACCES
;
1491 return(mknod(path
, mode
, rdev
));
1498 hc_link(struct HostConf
*hc
, const char *name1
, const char *name2
)
1500 hctransaction_t trans
;
1501 struct HCHead
*head
;
1505 if (hc
== NULL
|| hc
->host
== NULL
)
1506 return(link(name1
, name2
));
1508 trans
= hcc_start_command(hc
, HC_LINK
);
1509 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1510 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1511 if ((head
= hcc_finish_command(trans
)) == NULL
)
1519 rc_link(hctransaction_t trans
, struct HCHead
*head
)
1521 struct HCLeaf
*item
;
1522 const char *name1
= NULL
;
1523 const char *name2
= NULL
;
1525 FOR_EACH_ITEM(item
, trans
, head
) {
1526 switch(item
->leafid
) {
1528 name1
= HCC_STRING(item
);
1531 name2
= HCC_STRING(item
);
1536 head
->error
= EACCES
;
1539 if (name1
== NULL
|| name2
== NULL
)
1541 return(link(name1
, name2
));
1544 #ifdef _ST_FLAGS_PRESENT_
1549 hc_chflags(struct HostConf
*hc
, const char *path
, u_long flags
)
1551 hctransaction_t trans
;
1552 struct HCHead
*head
;
1558 flags
&= UF_SETTABLE
;
1560 if (hc
== NULL
|| hc
->host
== NULL
) {
1561 if ((rc
= chflags(path
, flags
)) < 0)
1562 rc
= silentwarning(&chflags_warning
, "file flags may differ\n");
1566 trans
= hcc_start_command(hc
, HC_CHFLAGS
);
1567 hcc_leaf_string(trans
, LC_PATH1
, path
);
1568 hcc_leaf_int64(trans
, LC_FILEFLAGS
, flags
);
1569 if ((head
= hcc_finish_command(trans
)) == NULL
)
1577 hc_lchflags(struct HostConf
*hc
, const char *path
, u_long flags
)
1579 hctransaction_t trans
;
1580 struct HCHead
*head
;
1586 flags
&= UF_SETTABLE
;
1588 if (hc
== NULL
|| hc
->host
== NULL
) {
1589 if ((rc
= lchflags(path
, flags
)) < 0)
1590 rc
= silentwarning(&chflags_warning
, "file flags may differ\n");
1594 trans
= hcc_start_command(hc
, HC_LCHFLAGS
);
1595 hcc_leaf_string(trans
, LC_PATH1
, path
);
1596 hcc_leaf_int64(trans
, LC_FILEFLAGS
, flags
);
1597 if ((head
= hcc_finish_command(trans
)) == NULL
)
1605 rc_chflags(hctransaction_t trans
, struct HCHead
*head
)
1607 struct HCLeaf
*item
;
1608 const char *path
= NULL
;
1612 FOR_EACH_ITEM(item
, trans
, head
) {
1613 switch(item
->leafid
) {
1615 path
= HCC_STRING(item
);
1618 flags
= (u_long
)HCC_INT64(item
);
1623 head
->error
= EACCES
;
1628 if (head
->cmd
== HC_LCHFLAGS
)
1629 rc
= lchflags(path
, flags
);
1631 rc
= chflags(path
, flags
);
1633 rc
= silentwarning(&chflags_warning
, "file flags may differ\n");
1643 hc_readlink(struct HostConf
*hc
, const char *path
, char *buf
, int bufsiz
)
1645 hctransaction_t trans
;
1646 struct HCHead
*head
;
1647 struct HCLeaf
*item
;
1650 if (hc
== NULL
|| hc
->host
== NULL
)
1651 return(readlink(path
, buf
, bufsiz
));
1653 trans
= hcc_start_command(hc
, HC_READLINK
);
1654 hcc_leaf_string(trans
, LC_PATH1
, path
);
1655 if ((head
= hcc_finish_command(trans
)) == NULL
)
1661 FOR_EACH_ITEM(item
, trans
, head
) {
1662 if (item
->leafid
== LC_DATA
) {
1663 r
= item
->bytes
- sizeof(*item
);
1668 bcopy(HCC_BINARYDATA(item
), buf
, r
);
1675 rc_readlink(hctransaction_t trans
, struct HCHead
*head
)
1677 struct HCLeaf
*item
;
1678 const char *path
= NULL
;
1682 FOR_EACH_ITEM(item
, trans
, head
) {
1683 if (item
->leafid
== LC_PATH1
)
1684 path
= HCC_STRING(item
);
1688 r
= readlink(path
, buf
, sizeof(buf
));
1691 hcc_leaf_data(trans
, LC_DATA
, buf
, r
);
1699 hc_umask(struct HostConf
*hc
, mode_t numask
)
1701 hctransaction_t trans
;
1702 struct HCHead
*head
;
1703 struct HCLeaf
*item
;
1706 return(umask(numask
));
1707 if (hc
== NULL
|| hc
->host
== NULL
)
1708 return(umask(numask
));
1710 trans
= hcc_start_command(hc
, HC_UMASK
);
1711 hcc_leaf_int32(trans
, LC_MODE
, numask
);
1712 if ((head
= hcc_finish_command(trans
)) == NULL
)
1717 numask
= (mode_t
) ~0666U;
1718 FOR_EACH_ITEM(item
, trans
, head
) {
1719 if (item
->leafid
== LC_MODE
)
1720 numask
= HCC_INT32(item
);
1726 rc_umask(hctransaction_t trans
, struct HCHead
*head
)
1728 struct HCLeaf
*item
;
1729 mode_t numask
= (mode_t
) ~0666U;
1731 FOR_EACH_ITEM(item
, trans
, head
) {
1732 if (item
->leafid
== LC_MODE
)
1733 numask
= HCC_INT32(item
);
1735 numask
= umask(numask
);
1736 hcc_leaf_int32(trans
, LC_MODE
, numask
);
1744 hc_symlink(struct HostConf
*hc
, const char *name1
, const char *name2
)
1746 hctransaction_t trans
;
1747 struct HCHead
*head
;
1751 if (hc
== NULL
|| hc
->host
== NULL
)
1752 return(symlink(name1
, name2
));
1754 trans
= hcc_start_command(hc
, HC_SYMLINK
);
1755 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1756 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1757 if ((head
= hcc_finish_command(trans
)) == NULL
)
1765 rc_symlink(hctransaction_t trans
, struct HCHead
*head
)
1767 struct HCLeaf
*item
;
1768 const char *name1
= NULL
;
1769 const char *name2
= NULL
;
1771 FOR_EACH_ITEM(item
, trans
, head
) {
1772 switch(item
->leafid
) {
1774 name1
= HCC_STRING(item
);
1777 name2
= HCC_STRING(item
);
1782 head
->error
= EACCES
;
1785 if (name1
== NULL
|| name2
== NULL
)
1787 return(symlink(name1
, name2
));
1794 hc_rename(struct HostConf
*hc
, const char *name1
, const char *name2
)
1796 hctransaction_t trans
;
1797 struct HCHead
*head
;
1801 if (hc
== NULL
|| hc
->host
== NULL
)
1802 return(rename(name1
, name2
));
1804 trans
= hcc_start_command(hc
, HC_RENAME
);
1805 hcc_leaf_string(trans
, LC_PATH1
, name1
);
1806 hcc_leaf_string(trans
, LC_PATH2
, name2
);
1807 if ((head
= hcc_finish_command(trans
)) == NULL
)
1815 rc_rename(hctransaction_t trans
, struct HCHead
*head
)
1817 struct HCLeaf
*item
;
1818 const char *name1
= NULL
;
1819 const char *name2
= NULL
;
1821 FOR_EACH_ITEM(item
, trans
, head
) {
1822 switch(item
->leafid
) {
1824 name1
= HCC_STRING(item
);
1827 name2
= HCC_STRING(item
);
1832 head
->error
= EACCES
;
1835 if (name1
== NULL
|| name2
== NULL
)
1837 return(rename(name1
, name2
));
1844 hc_utimes(struct HostConf
*hc
, const char *path
, const struct timeval
*times
)
1846 hctransaction_t trans
;
1847 struct HCHead
*head
;
1851 if (hc
== NULL
|| hc
->host
== NULL
) {
1852 return(utimes(path
, times
));
1855 trans
= hcc_start_command(hc
, HC_UTIMES
);
1856 hcc_leaf_string(trans
, LC_PATH1
, path
);
1857 hcc_leaf_int64(trans
, LC_ATIME
, times
[0].tv_sec
);
1858 hcc_leaf_int64(trans
, LC_MTIME
, times
[1].tv_sec
);
1859 #if defined(st_atime)
1860 hcc_leaf_int32(trans
, LC_ATIMENSEC
, times
[0].tv_usec
* 1000);
1861 hcc_leaf_int32(trans
, LC_MTIMENSEC
, times
[1].tv_usec
* 1000);
1863 if ((head
= hcc_finish_command(trans
)) == NULL
)
1871 hc_lutimes(struct HostConf
*hc
, const char *path
, const struct timeval
*times
)
1873 hctransaction_t trans
;
1874 struct HCHead
*head
;
1878 if (hc
== NULL
|| hc
->host
== NULL
) {
1879 return(lutimes(path
, times
));
1882 trans
= hcc_start_command(hc
, HC_LUTIMES
);
1883 hcc_leaf_string(trans
, LC_PATH1
, path
);
1884 hcc_leaf_int64(trans
, LC_ATIME
, times
[0].tv_sec
);
1885 hcc_leaf_int64(trans
, LC_MTIME
, times
[1].tv_sec
);
1886 #if defined(st_atime)
1887 hcc_leaf_int32(trans
, LC_ATIMENSEC
, times
[0].tv_usec
* 1000);
1888 hcc_leaf_int32(trans
, LC_MTIMENSEC
, times
[1].tv_usec
* 1000);
1890 if ((head
= hcc_finish_command(trans
)) == NULL
)
1898 rc_utimes(hctransaction_t trans
, struct HCHead
*head
)
1900 struct HCLeaf
*item
;
1901 struct timeval times
[2];
1904 bzero(times
, sizeof(times
));
1907 FOR_EACH_ITEM(item
, trans
, head
) {
1908 switch(item
->leafid
) {
1910 path
= HCC_STRING(item
);
1913 times
[0].tv_sec
= HCC_INT64(item
);
1916 times
[1].tv_sec
= HCC_INT64(item
);
1918 #if defined(st_atimespec) || defined(_STATBUF_ST_NSEC)
1920 times
[0].tv_usec
= HCC_INT32(item
) / 1000;
1923 times
[1].tv_usec
= HCC_INT32(item
) / 1000;
1929 head
->error
= EACCES
;
1934 if (head
->cmd
== HC_LUTIMES
)
1935 return(lutimes(path
, times
));
1937 return(utimes(path
, times
));
1941 hc_geteuid(struct HostConf
*hc
)
1943 hctransaction_t trans
;
1944 struct HCHead
*head
;
1945 struct HCLeaf
*item
;
1947 if (hc
== NULL
|| hc
->host
== NULL
)
1950 if (hc
->version
< 3) {
1951 fprintf(stderr
, "WARNING: Remote client uses old protocol version\n");
1952 /* Return 0 on error, so the caller assumes root privileges. */
1956 trans
= hcc_start_command(hc
, HC_GETEUID
);
1957 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
1959 FOR_EACH_ITEM(item
, trans
, head
) {
1960 if (item
->leafid
== LC_UID
)
1961 return (HCC_INT32(item
));
1963 return(0); /* shouldn't happen */
1967 rc_geteuid(hctransaction_t trans
, struct HCHead
*head __unused
)
1969 hcc_leaf_int32(trans
, LC_UID
, geteuid());
1974 getmygroups(gid_t
**gidlist
)
1978 if ((count
= getgroups(0, *gidlist
)) > 0) {
1979 if ((*gidlist
= malloc(count
* sizeof(gid_t
))) != NULL
) {
1980 if ((count
= getgroups(count
, *gidlist
)) <= 0)
1992 hc_getgroups(struct HostConf
*hc
, gid_t
**gidlist
)
1995 hctransaction_t trans
;
1996 struct HCHead
*head
;
1997 struct HCLeaf
*item
;
1999 if (hc
== NULL
|| hc
->host
== NULL
)
2000 return (getmygroups(gidlist
));
2006 if (hc
->version
< 3) {
2007 fprintf(stderr
, "WARNING: Remote client uses old protocol version\n");
2011 trans
= hcc_start_command(hc
, HC_GETGROUPS
);
2012 if ((head
= hcc_finish_command(trans
)) == NULL
|| head
->error
)
2014 FOR_EACH_ITEM(item
, trans
, head
) {
2015 switch(item
->leafid
) {
2017 count
= HCC_INT32(item
);
2018 if (*gidlist
!= NULL
) { /* protocol error */
2023 if ((*gidlist
= malloc(count
* sizeof(gid_t
))) == NULL
)
2027 if (*gidlist
== NULL
|| i
>= count
) { /* protocol error */
2028 if (*gidlist
!= NULL
)
2033 (*gidlist
)[i
++] = HCC_INT32(item
);
2041 rc_getgroups(hctransaction_t trans
, struct HCHead
*head __unused
)
2046 if ((count
= getmygroups(&gidlist
)) < 0)
2048 hcc_leaf_int32(trans
, LC_COUNT
, count
);
2049 for (i
= 0; i
< count
; i
++)
2050 hcc_leaf_int32(trans
, LC_GID
, gidlist
[i
]);
2051 if (gidlist
!= NULL
)