HAMMER VFS - Major retooling of the refcount mechanics, and fix a deadlock
[dragonfly.git] / bin / cpdup / hcproto.c
blob5acb6ddb0047ca0e1514982152a7f65e772d574a
1 /*
2 * HCPROTO.C
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 $
7 */
9 #include "cpdup.h"
10 #include "hclink.h"
11 #include "hcproto.h"
13 static int hc_decode_stat(struct stat *, struct HCHead *);
14 static int rc_encode_stat(hctransaction_t trans, struct stat *);
16 static int rc_hello(hctransaction_t trans, struct HCHead *);
17 static int rc_stat(hctransaction_t trans, struct HCHead *);
18 static int rc_lstat(hctransaction_t trans, struct HCHead *);
19 static int rc_opendir(hctransaction_t trans, struct HCHead *);
20 static int rc_readdir(hctransaction_t trans, struct HCHead *);
21 static int rc_closedir(hctransaction_t trans, struct HCHead *);
22 static int rc_open(hctransaction_t trans, struct HCHead *);
23 static int rc_close(hctransaction_t trans, struct HCHead *);
24 static int rc_read(hctransaction_t trans, struct HCHead *);
25 static int rc_write(hctransaction_t trans, struct HCHead *);
26 static int rc_remove(hctransaction_t trans, struct HCHead *);
27 static int rc_mkdir(hctransaction_t trans, struct HCHead *);
28 static int rc_rmdir(hctransaction_t trans, struct HCHead *);
29 static int rc_chown(hctransaction_t trans, struct HCHead *);
30 static int rc_lchown(hctransaction_t trans, struct HCHead *);
31 static int rc_chmod(hctransaction_t trans, struct HCHead *);
32 static int rc_mknod(hctransaction_t trans, struct HCHead *);
33 static int rc_link(hctransaction_t trans, struct HCHead *);
34 #ifdef _ST_FLAGS_PRESENT_
35 static int rc_chflags(hctransaction_t trans, struct HCHead *);
36 #endif
37 static int rc_readlink(hctransaction_t trans, struct HCHead *);
38 static int rc_umask(hctransaction_t trans, struct HCHead *);
39 static int rc_symlink(hctransaction_t trans, struct HCHead *);
40 static int rc_rename(hctransaction_t trans, struct HCHead *);
41 static int rc_utimes(hctransaction_t trans, struct HCHead *);
42 static int rc_geteuid(hctransaction_t trans, struct HCHead *);
43 static int rc_getgroups(hctransaction_t trans, struct HCHead *);
45 static int getmygroups(gid_t **gidlist);
47 struct HCDesc HCDispatchTable[] = {
48 { HC_HELLO, rc_hello },
49 { HC_STAT, rc_stat },
50 { HC_LSTAT, rc_lstat },
51 { HC_OPENDIR, rc_opendir },
52 { HC_READDIR, rc_readdir },
53 { HC_CLOSEDIR, rc_closedir },
54 { HC_OPEN, rc_open },
55 { HC_CLOSE, rc_close },
56 { HC_READ, rc_read },
57 { HC_WRITE, rc_write },
58 { HC_REMOVE, rc_remove },
59 { HC_MKDIR, rc_mkdir },
60 { HC_RMDIR, rc_rmdir },
61 { HC_CHOWN, rc_chown },
62 { HC_LCHOWN, rc_lchown },
63 { HC_CHMOD, rc_chmod },
64 { HC_MKNOD, rc_mknod },
65 { HC_LINK, rc_link },
66 #ifdef _ST_FLAGS_PRESENT_
67 { HC_CHFLAGS, rc_chflags },
68 #endif
69 { HC_READLINK, rc_readlink },
70 { HC_UMASK, rc_umask },
71 { HC_SYMLINK, rc_symlink },
72 { HC_RENAME, rc_rename },
73 { HC_UTIMES, rc_utimes },
74 { HC_GETEUID, rc_geteuid },
75 { HC_GETGROUPS, rc_getgroups },
78 static int chown_warning;
79 static int chflags_warning;
82 * If not running as root generate a silent warning and return no error.
84 * If running as root return an error.
86 static int
87 silentwarning(int *didwarn, const char *ctl, ...)
89 va_list va;
91 if (DstRootPrivs)
92 return(-1);
93 if (*didwarn == 0 && QuietOpt == 0) {
94 *didwarn = 1;
95 fprintf(stderr, "WARNING: Not running as root, ");
96 va_start(va, ctl);
97 vfprintf(stderr, ctl, va);
98 va_end(va);
100 return(0);
104 hc_connect(struct HostConf *hc)
106 if (hcc_connect(hc) < 0) {
107 fprintf(stderr, "Unable to connect to %s\n", hc->host);
108 return(-1);
110 return(hc_hello(hc));
113 void
114 hc_slave(int fdin, int fdout)
116 hcc_slave(fdin, fdout, HCDispatchTable,
117 sizeof(HCDispatchTable) / sizeof(HCDispatchTable[0]));
122 * A HELLO RPC is sent on the initial connect.
125 hc_hello(struct HostConf *hc)
127 struct HCHead *head;
128 struct HCLeaf *item;
129 hctransaction_t trans;
130 char hostbuf[256];
131 int error;
133 bzero(hostbuf, sizeof(hostbuf));
134 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
135 return(-1);
136 if (hostbuf[0] == 0)
137 hostbuf[0] = '?';
139 trans = hcc_start_command(hc, HC_HELLO);
140 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
141 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
142 if ((head = hcc_finish_command(trans)) == NULL) {
143 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
144 hc->host);
145 return(-1);
148 if (head->error) {
149 fprintf(stderr, "Connected to %s but remote returned error %d\n",
150 hc->host, head->error);
151 return(-1);
154 error = -1;
155 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
156 switch(item->leafid) {
157 case LC_HELLOSTR:
158 if (QuietOpt == 0)
159 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
160 error = 0;
161 break;
162 case LC_VERSION:
163 hc->version = HCC_INT32(item);
164 break;
167 if (hc->version < HCPROTO_VERSION_COMPAT) {
168 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
169 hc->host);
170 error = -1;
172 if (error < 0)
173 fprintf(stderr, "Handshake failed with %s\n", hc->host);
174 return (error);
177 static int
178 rc_hello(hctransaction_t trans, struct HCHead *head __unused)
180 char hostbuf[256];
182 bzero(hostbuf, sizeof(hostbuf));
183 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
184 return(-1);
185 if (hostbuf[0] == 0)
186 hostbuf[0] = '?';
188 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
189 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
190 return(0);
194 * STAT, LSTAT
197 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
199 struct HCHead *head;
200 hctransaction_t trans;
202 if (hc == NULL || hc->host == NULL)
203 return(stat(path, st));
205 trans = hcc_start_command(hc, HC_STAT);
206 hcc_leaf_string(trans, LC_PATH1, path);
207 if ((head = hcc_finish_command(trans)) == NULL)
208 return(-1);
209 if (head->error)
210 return(-1);
211 return(hc_decode_stat(st, head));
215 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
217 struct HCHead *head;
218 hctransaction_t trans;
220 if (hc == NULL || hc->host == NULL)
221 return(lstat(path, st));
223 trans = hcc_start_command(hc, HC_LSTAT);
224 hcc_leaf_string(trans, LC_PATH1, path);
225 if ((head = hcc_finish_command(trans)) == NULL)
226 return(-1);
227 if (head->error)
228 return(-1);
229 return(hc_decode_stat(st, head));
232 static int
233 hc_decode_stat(struct stat *st, struct HCHead *head)
235 struct HCLeaf *item;
237 bzero(st, sizeof(*st));
238 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
239 switch(item->leafid) {
240 case LC_DEV:
241 st->st_dev = HCC_INT32(item);
242 break;
243 case LC_INO:
244 st->st_ino = HCC_INT64(item);
245 break;
246 case LC_MODE:
247 st->st_mode = HCC_INT32(item);
248 break;
249 case LC_NLINK:
250 st->st_nlink = HCC_INT32(item);
251 break;
252 case LC_UID:
253 st->st_uid = HCC_INT32(item);
254 break;
255 case LC_GID:
256 st->st_gid = HCC_INT32(item);
257 break;
258 case LC_RDEV:
259 st->st_rdev = HCC_INT32(item);
260 break;
261 case LC_ATIME:
262 st->st_atime = (time_t)HCC_INT64(item);
263 break;
264 case LC_MTIME:
265 st->st_mtime = (time_t)HCC_INT64(item);
266 break;
267 case LC_CTIME:
268 st->st_ctime = (time_t)HCC_INT64(item);
269 break;
270 case LC_FILESIZE:
271 st->st_size = HCC_INT64(item);
272 break;
273 case LC_FILEBLKS:
274 st->st_blocks = HCC_INT64(item);
275 break;
276 case LC_BLKSIZE:
277 st->st_blksize = HCC_INT32(item);
278 break;
279 #ifdef _ST_FSMID_PRESENT_
280 case LC_FSMID:
281 st->st_fsmid = HCC_INT64(item);
282 break;
283 #endif
284 #ifdef _ST_FLAGS_PRESENT_
285 case LC_FILEFLAGS:
286 st->st_flags = (u_int32_t)HCC_INT64(item);
287 break;
288 #endif
291 return(0);
294 static int
295 rc_stat(hctransaction_t trans, struct HCHead *head)
297 struct HCLeaf *item;
298 struct stat st;
299 const char *path = NULL;
301 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
302 switch(item->leafid) {
303 case LC_PATH1:
304 path = HCC_STRING(item);
305 break;
308 if (path == NULL)
309 return(-2);
310 if (stat(path, &st) < 0)
311 return(-1);
312 return (rc_encode_stat(trans, &st));
315 static int
316 rc_lstat(hctransaction_t trans, struct HCHead *head)
318 struct HCLeaf *item;
319 struct stat st;
320 const char *path = NULL;
322 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
323 switch(item->leafid) {
324 case LC_PATH1:
325 path = HCC_STRING(item);
326 break;
329 if (path == NULL)
330 return(-2);
331 if (lstat(path, &st) < 0)
332 return(-1);
333 return (rc_encode_stat(trans, &st));
336 static int
337 rc_encode_stat(hctransaction_t trans, struct stat *st)
339 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
340 hcc_leaf_int64(trans, LC_INO, st->st_ino);
341 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
342 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
343 hcc_leaf_int32(trans, LC_UID, st->st_uid);
344 hcc_leaf_int32(trans, LC_GID, st->st_gid);
345 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
346 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
347 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
348 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
349 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
350 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
351 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
352 #ifdef _ST_FSMID_PRESENT_
353 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
354 #endif
355 #ifdef _ST_FLAGS_PRESENT_
356 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
357 #endif
358 return(0);
362 * OPENDIR
364 DIR *
365 hc_opendir(struct HostConf *hc, const char *path)
367 hctransaction_t trans;
368 struct HCHead *head;
369 struct HCLeaf *item;
370 struct dirent *den;
371 intptr_t desc = 0;
373 if (hc == NULL || hc->host == NULL)
374 return(opendir(path));
376 trans = hcc_start_command(hc, HC_OPENDIR);
377 hcc_leaf_string(trans, LC_PATH1, path);
378 if ((head = hcc_finish_command(trans)) == NULL)
379 return(NULL);
380 if (head->error)
381 return(NULL);
382 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
383 switch(item->leafid) {
384 case LC_DESCRIPTOR:
385 desc = HCC_INT32(item);
386 break;
389 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
390 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
391 (intmax_t)desc);
392 return(NULL);
394 den = malloc(sizeof(*den));
395 bzero(den, sizeof(*den));
396 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
397 return((void *)desc);
400 static int
401 rc_opendir(hctransaction_t trans, struct HCHead *head)
403 struct HCLeaf *item;
404 const char *path = NULL;
405 DIR *dir;
406 int desc;
408 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
409 switch(item->leafid) {
410 case LC_PATH1:
411 path = HCC_STRING(item);
412 break;
415 if (path == NULL)
416 return(-2);
417 if ((dir = opendir(path)) == NULL) {
418 head->error = errno;
419 } else {
420 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
421 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
423 return(0);
427 * READDIR
429 struct dirent *
430 hc_readdir(struct HostConf *hc, DIR *dir)
432 hctransaction_t trans;
433 struct HCHead *head;
434 struct HCLeaf *item;
435 struct dirent *den;
437 if (hc == NULL || hc->host == NULL)
438 return(readdir(dir));
440 trans = hcc_start_command(hc, HC_READDIR);
441 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
442 if ((head = hcc_finish_command(trans)) == NULL)
443 return(NULL);
444 if (head->error)
445 return(NULL); /* XXX errno */
446 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
447 if (den == NULL)
448 return(NULL); /* XXX errno */
449 if (den->d_name)
450 den->d_name[0] = 0;
451 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
452 switch(item->leafid) {
453 case LC_PATH1:
454 snprintf(den->d_name, sizeof(den->d_name), "%s", HCC_STRING(item));
455 break;
456 case LC_INO:
457 den->d_fileno = HCC_INT64(item);
458 break;
459 case LC_TYPE:
460 den->d_type = HCC_INT32(item);
461 break;
464 if (den->d_name[0]) {
465 #ifdef _DIRENT_HAVE_D_NAMLEN
466 den->d_namlen = strlen(den->d_name);
467 #endif
468 return(den);
470 return(NULL); /* XXX errno */
473 static int
474 rc_readdir(hctransaction_t trans, struct HCHead *head)
476 struct HCLeaf *item;
477 struct dirent *den;
478 DIR *dir = NULL;
480 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
481 switch(item->leafid) {
482 case LC_DESCRIPTOR:
483 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
484 break;
487 if (dir == NULL)
488 return(-2);
489 if ((den = readdir(dir)) != NULL) {
490 hcc_leaf_string(trans, LC_PATH1, den->d_name);
491 hcc_leaf_int64(trans, LC_INO, den->d_fileno);
492 hcc_leaf_int32(trans, LC_TYPE, den->d_type);
494 return(0);
498 * CLOSEDIR
500 * XXX cpdup needs to check error code to avoid truncated dirs?
503 hc_closedir(struct HostConf *hc, DIR *dir)
505 hctransaction_t trans;
506 struct HCHead *head;
507 struct dirent *den;
509 if (hc == NULL || hc->host == NULL)
510 return(closedir(dir));
511 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
512 if (den) {
513 free(den);
514 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
516 trans = hcc_start_command(hc, HC_CLOSEDIR);
517 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
518 if ((head = hcc_finish_command(trans)) == NULL)
519 return(-1);
520 if (head->error)
521 return(-1); /* XXX errno */
522 return(0);
523 } else {
524 /* errno */
525 return(-1);
529 static int
530 rc_closedir(hctransaction_t trans, struct HCHead *head)
532 struct HCLeaf *item;
533 DIR *dir = NULL;
535 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
536 switch(item->leafid) {
537 case LC_DESCRIPTOR:
538 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
539 if (dir != NULL)
540 hcc_set_descriptor(trans->hc, HCC_INT32(item), NULL, HC_DESC_DIR);
541 break;
544 if (dir == NULL)
545 return(-2);
546 return(closedir(dir));
550 * OPEN
553 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
555 hctransaction_t trans;
556 struct HCHead *head;
557 struct HCLeaf *item;
558 int *fdp;
559 int desc = 0;
560 int nflags;
562 if (hc == NULL || hc->host == NULL) {
563 #ifdef O_LARGEFILE
564 flags |= O_LARGEFILE;
565 #endif
566 return(open(path, flags, mode));
569 nflags = flags & XO_NATIVEMASK;
570 if (flags & O_CREAT)
571 nflags |= XO_CREAT;
572 if (flags & O_EXCL)
573 nflags |= XO_EXCL;
574 if (flags & O_TRUNC)
575 nflags |= XO_TRUNC;
577 trans = hcc_start_command(hc, HC_OPEN);
578 hcc_leaf_string(trans, LC_PATH1, path);
579 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
580 hcc_leaf_int32(trans, LC_MODE, mode);
582 if ((head = hcc_finish_command(trans)) == NULL)
583 return(-1);
584 if (head->error)
585 return(-1);
586 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
587 switch(item->leafid) {
588 case LC_DESCRIPTOR:
589 desc = HCC_INT32(item);
590 break;
593 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
594 fprintf(stderr, "hc_opendir: remote reused active descriptor %d\n",
595 desc);
596 return(-1);
598 fdp = malloc(sizeof(int));
599 *fdp = desc; /* really just a dummy */
600 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
601 return(desc);
604 static int
605 rc_open(hctransaction_t trans, struct HCHead *head)
607 struct HCLeaf *item;
608 const char *path = NULL;
609 int nflags = 0;
610 int flags;
611 mode_t mode = 0666;
612 int desc;
613 int *fdp;
614 int fd;
616 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
617 switch(item->leafid) {
618 case LC_PATH1:
619 path = HCC_STRING(item);
620 break;
621 case LC_OFLAGS:
622 nflags = HCC_INT32(item);
623 break;
624 case LC_MODE:
625 mode = HCC_INT32(item);
626 break;
629 if (path == NULL)
630 return(-2);
632 flags = nflags & XO_NATIVEMASK;
633 if (nflags & XO_CREAT)
634 flags |= O_CREAT;
635 if (nflags & XO_EXCL)
636 flags |= O_EXCL;
637 if (nflags & XO_TRUNC)
638 flags |= O_TRUNC;
640 #ifdef O_LARGEFILE
641 flags |= O_LARGEFILE;
642 #endif
643 if ((fd = open(path, flags, mode)) < 0) {
644 head->error = errno;
645 return(0);
647 fdp = malloc(sizeof(int));
648 *fdp = fd;
649 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
650 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
651 return(0);
655 * CLOSE
658 hc_close(struct HostConf *hc, int fd)
660 hctransaction_t trans;
661 struct HCHead *head;
662 int *fdp;
664 if (hc == NULL || hc->host == NULL)
665 return(close(fd));
667 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
668 if (fdp) {
669 free(fdp);
670 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
672 trans = hcc_start_command(hc, HC_CLOSE);
673 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
674 if ((head = hcc_finish_command(trans)) == NULL)
675 return(-1);
676 if (head->error)
677 return(-1);
678 return(0);
679 } else {
680 return(-1);
684 static int
685 rc_close(hctransaction_t trans, struct HCHead *head)
687 struct HCLeaf *item;
688 int *fdp = NULL;
689 int fd;
690 int desc = -1;
692 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
693 switch(item->leafid) {
694 case LC_DESCRIPTOR:
695 desc = HCC_INT32(item);
696 break;
699 if (desc < 0)
700 return(-2);
701 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
702 return(-2);
703 fd = *fdp;
704 free(fdp);
705 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
706 return(close(fd));
709 static int
710 getiolimit(void)
712 return(32768);
716 * READ
718 ssize_t
719 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
721 hctransaction_t trans;
722 struct HCHead *head;
723 struct HCLeaf *item;
724 int *fdp;
725 int r;
727 if (hc == NULL || hc->host == NULL)
728 return(read(fd, buf, bytes));
730 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
731 if (fdp) {
732 r = 0;
733 while (bytes) {
734 size_t limit = getiolimit();
735 int n = (bytes > limit) ? limit : bytes;
736 int x = 0;
738 trans = hcc_start_command(hc, HC_READ);
739 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
740 hcc_leaf_int32(trans, LC_BYTES, n);
741 if ((head = hcc_finish_command(trans)) == NULL)
742 return(-1);
743 if (head->error)
744 return(-1);
745 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
746 switch(item->leafid) {
747 case LC_DATA:
748 x = item->bytes - sizeof(*item);
749 if (x > (int)bytes)
750 x = (int)bytes;
751 bcopy(HCC_BINARYDATA(item), buf, x);
752 buf = (char *)buf + x;
753 bytes -= (size_t)x;
754 r += x;
755 break;
758 if (x < n)
759 break;
761 return(r);
762 } else {
763 return(-1);
767 static int
768 rc_read(hctransaction_t trans, struct HCHead *head)
770 struct HCLeaf *item;
771 int *fdp = NULL;
772 char buf[32768];
773 int bytes = -1;
774 int n;
776 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
777 switch(item->leafid) {
778 case LC_DESCRIPTOR:
779 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
780 break;
781 case LC_BYTES:
782 bytes = HCC_INT32(item);
783 break;
786 if (fdp == NULL)
787 return(-2);
788 if (bytes < 0 || bytes > 32768)
789 return(-2);
790 n = read(*fdp, buf, bytes);
791 if (n < 0) {
792 head->error = errno;
793 return(0);
795 hcc_leaf_data(trans, LC_DATA, buf, n);
796 return(0);
800 * WRITE
802 ssize_t
803 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
805 hctransaction_t trans;
806 struct HCHead *head;
807 struct HCLeaf *item;
808 int *fdp;
809 int r;
811 if (hc == NULL || hc->host == NULL)
812 return(write(fd, buf, bytes));
814 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
815 if (fdp) {
816 r = 0;
817 while (bytes) {
818 size_t limit = getiolimit();
819 int n = (bytes > limit) ? limit : bytes;
820 int x = 0;
822 trans = hcc_start_command(hc, HC_WRITE);
823 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
824 hcc_leaf_data(trans, LC_DATA, buf, n);
825 if ((head = hcc_finish_command(trans)) == NULL)
826 return(-1);
827 if (head->error)
828 return(-1);
829 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
830 switch(item->leafid) {
831 case LC_BYTES:
832 x = HCC_INT32(item);
833 break;
836 if (x < 0 || x > n)
837 return(-1);
838 r += x;
839 buf = (const char *)buf + x;
840 bytes -= x;
841 if (x < n)
842 break;
844 return(r);
845 } else {
846 return(-1);
850 static int
851 rc_write(hctransaction_t trans, struct HCHead *head)
853 struct HCLeaf *item;
854 int *fdp = NULL;
855 void *buf = NULL;
856 int n = -1;
858 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
859 switch(item->leafid) {
860 case LC_DESCRIPTOR:
861 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
862 break;
863 case LC_DATA:
864 buf = HCC_BINARYDATA(item);
865 n = item->bytes - sizeof(*item);
866 break;
869 if (fdp == NULL)
870 return(-2);
871 if (n < 0 || n > 32768)
872 return(-2);
873 n = write(*fdp, buf, n);
874 if (n < 0) {
875 head->error = errno;
876 } else {
877 hcc_leaf_int32(trans, LC_BYTES, n);
879 return(0);
883 * REMOVE
885 * NOTE: This function returns -errno if an error occured.
888 hc_remove(struct HostConf *hc, const char *path)
890 hctransaction_t trans;
891 struct HCHead *head;
892 int res;
894 if (hc == NULL || hc->host == NULL) {
895 res = remove(path);
896 if (res < 0)
897 res = -errno;
898 return(res);
901 trans = hcc_start_command(hc, HC_REMOVE);
902 hcc_leaf_string(trans, LC_PATH1, path);
903 if ((head = hcc_finish_command(trans)) == NULL)
904 return(-EIO);
905 if (head->error)
906 return(-(int)head->error);
907 return(0);
910 static int
911 rc_remove(hctransaction_t trans __unused, struct HCHead *head)
913 struct HCLeaf *item;
914 const char *path = NULL;
916 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
917 switch(item->leafid) {
918 case LC_PATH1:
919 path = HCC_STRING(item);
920 break;
923 if (path == NULL)
924 return(-2);
925 return(remove(path));
929 * MKDIR
932 hc_mkdir(struct HostConf *hc __unused, const char *path, mode_t mode)
934 hctransaction_t trans;
935 struct HCHead *head;
937 if (hc == NULL || hc->host == NULL)
938 return(mkdir(path, mode));
940 trans = hcc_start_command(hc, HC_MKDIR);
941 hcc_leaf_string(trans, LC_PATH1, path);
942 hcc_leaf_int32(trans, LC_MODE, mode);
943 if ((head = hcc_finish_command(trans)) == NULL)
944 return(-1);
945 if (head->error)
946 return(-1);
947 return(0);
950 static int
951 rc_mkdir(hctransaction_t trans __unused, struct HCHead *head)
953 struct HCLeaf *item;
954 const char *path = NULL;
955 mode_t mode = 0777;
957 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
958 switch(item->leafid) {
959 case LC_PATH1:
960 path = HCC_STRING(item);
961 break;
962 case LC_MODE:
963 mode = HCC_INT32(item);
964 break;
967 if (path == NULL)
968 return(-1);
969 return(mkdir(path, mode));
973 * RMDIR
976 hc_rmdir(struct HostConf *hc, const char *path)
978 hctransaction_t trans;
979 struct HCHead *head;
981 if (hc == NULL || hc->host == NULL)
982 return(rmdir(path));
984 trans = hcc_start_command(hc, HC_RMDIR);
985 hcc_leaf_string(trans, LC_PATH1, path);
986 if ((head = hcc_finish_command(trans)) == NULL)
987 return(-1);
988 if (head->error)
989 return(-1);
990 return(0);
993 static int
994 rc_rmdir(hctransaction_t trans __unused, struct HCHead *head)
996 struct HCLeaf *item;
997 const char *path = NULL;
999 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1000 switch(item->leafid) {
1001 case LC_PATH1:
1002 path = HCC_STRING(item);
1003 break;
1006 if (path == NULL)
1007 return(-1);
1008 return(rmdir(path));
1012 * CHOWN
1014 * Almost silently ignore chowns that fail if we are not root.
1017 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1019 hctransaction_t trans;
1020 struct HCHead *head;
1021 int rc;
1023 if (!DstRootPrivs)
1024 owner = -1;
1026 if (hc == NULL || hc->host == NULL) {
1027 rc = chown(path, owner, group);
1028 if (rc < 0)
1029 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1030 return(rc);
1033 trans = hcc_start_command(hc, HC_CHOWN);
1034 hcc_leaf_string(trans, LC_PATH1, path);
1035 hcc_leaf_int32(trans, LC_UID, owner);
1036 hcc_leaf_int32(trans, LC_GID, group);
1037 if ((head = hcc_finish_command(trans)) == NULL)
1038 return(-1);
1039 if (head->error)
1040 return(-1);
1041 return(0);
1044 static int
1045 rc_chown(hctransaction_t trans __unused, struct HCHead *head)
1047 struct HCLeaf *item;
1048 const char *path = NULL;
1049 uid_t uid = (uid_t)-1;
1050 gid_t gid = (gid_t)-1;
1051 int rc;
1053 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1054 switch(item->leafid) {
1055 case LC_PATH1:
1056 path = HCC_STRING(item);
1057 break;
1058 case LC_UID:
1059 uid = HCC_INT32(item);
1060 break;
1061 case LC_GID:
1062 gid = HCC_INT32(item);
1063 break;
1066 if (path == NULL)
1067 return(-1);
1068 rc = chown(path, uid, gid);
1069 if (rc < 0)
1070 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1071 return(rc);
1075 * LCHOWN
1078 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1080 hctransaction_t trans;
1081 struct HCHead *head;
1082 int rc;
1084 if (!DstRootPrivs)
1085 owner = -1;
1087 if (hc == NULL || hc->host == NULL) {
1088 rc = lchown(path, owner, group);
1089 if (rc < 0)
1090 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1091 return(rc);
1094 trans = hcc_start_command(hc, HC_LCHOWN);
1095 hcc_leaf_string(trans, LC_PATH1, path);
1096 hcc_leaf_int32(trans, LC_UID, owner);
1097 hcc_leaf_int32(trans, LC_GID, group);
1098 if ((head = hcc_finish_command(trans)) == NULL)
1099 return(-1);
1100 if (head->error)
1101 return(-1);
1102 return(0);
1105 static int
1106 rc_lchown(hctransaction_t trans __unused, struct HCHead *head)
1108 struct HCLeaf *item;
1109 const char *path = NULL;
1110 uid_t uid = (uid_t)-1;
1111 gid_t gid = (gid_t)-1;
1112 int rc;
1114 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1115 switch(item->leafid) {
1116 case LC_PATH1:
1117 path = HCC_STRING(item);
1118 break;
1119 case LC_UID:
1120 uid = HCC_INT32(item);
1121 break;
1122 case LC_GID:
1123 gid = HCC_INT32(item);
1124 break;
1127 if (path == NULL)
1128 return(-1);
1129 rc = lchown(path, uid, gid);
1130 if (rc < 0)
1131 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1132 return(rc);
1136 * CHMOD
1139 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1141 hctransaction_t trans;
1142 struct HCHead *head;
1144 if (hc == NULL || hc->host == NULL)
1145 return(chmod(path, mode));
1147 trans = hcc_start_command(hc, HC_CHMOD);
1148 hcc_leaf_string(trans, LC_PATH1, path);
1149 hcc_leaf_int32(trans, LC_MODE, mode);
1150 if ((head = hcc_finish_command(trans)) == NULL)
1151 return(-1);
1152 if (head->error)
1153 return(-1);
1154 return(0);
1157 static int
1158 rc_chmod(hctransaction_t trans __unused, struct HCHead *head)
1160 struct HCLeaf *item;
1161 const char *path = NULL;
1162 mode_t mode = 0666;
1164 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1165 switch(item->leafid) {
1166 case LC_PATH1:
1167 path = HCC_STRING(item);
1168 break;
1169 case LC_MODE:
1170 mode = HCC_INT32(item);
1171 break;
1174 if (path == NULL)
1175 return(-1);
1176 return(chmod(path, mode));
1180 * MKNOD
1183 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1185 hctransaction_t trans;
1186 struct HCHead *head;
1188 if (!DstRootPrivs) {
1189 /* mknod() requires root privs, so don't bother. */
1190 errno = EPERM;
1191 return (-1);
1194 if (hc == NULL || hc->host == NULL)
1195 return(mknod(path, mode, rdev));
1197 trans = hcc_start_command(hc, HC_MKNOD);
1198 hcc_leaf_string(trans, LC_PATH1, path);
1199 hcc_leaf_int32(trans, LC_MODE, mode);
1200 hcc_leaf_int32(trans, LC_RDEV, rdev);
1201 if ((head = hcc_finish_command(trans)) == NULL)
1202 return(-1);
1203 if (head->error)
1204 return(-1);
1205 return(0);
1208 static int
1209 rc_mknod(hctransaction_t trans __unused, struct HCHead *head)
1211 struct HCLeaf *item;
1212 const char *path = NULL;
1213 mode_t mode = 0666;
1214 dev_t rdev = 0;
1216 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1217 switch(item->leafid) {
1218 case LC_PATH1:
1219 path = HCC_STRING(item);
1220 break;
1221 case LC_MODE:
1222 mode = HCC_INT32(item);
1223 break;
1224 case LC_RDEV:
1225 rdev = HCC_INT32(item);
1226 break;
1229 if (path == NULL)
1230 return(-1);
1231 return(mknod(path, mode, rdev));
1235 * LINK
1238 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1240 hctransaction_t trans;
1241 struct HCHead *head;
1243 if (hc == NULL || hc->host == NULL)
1244 return(link(name1, name2));
1246 trans = hcc_start_command(hc, HC_LINK);
1247 hcc_leaf_string(trans, LC_PATH1, name1);
1248 hcc_leaf_string(trans, LC_PATH2, name2);
1249 if ((head = hcc_finish_command(trans)) == NULL)
1250 return(-1);
1251 if (head->error)
1252 return(-1);
1253 return(0);
1256 static int
1257 rc_link(hctransaction_t trans __unused, struct HCHead *head)
1259 struct HCLeaf *item;
1260 const char *name1 = NULL;
1261 const char *name2 = NULL;
1263 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1264 switch(item->leafid) {
1265 case LC_PATH1:
1266 name1 = HCC_STRING(item);
1267 break;
1268 case LC_PATH2:
1269 name2 = HCC_STRING(item);
1270 break;
1273 if (name1 == NULL || name2 == NULL)
1274 return(-2);
1275 return(link(name1, name2));
1278 #ifdef _ST_FLAGS_PRESENT_
1280 * CHFLAGS
1283 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1285 hctransaction_t trans;
1286 struct HCHead *head;
1287 int rc;
1289 if (!DstRootPrivs)
1290 flags &= UF_SETTABLE;
1292 if (hc == NULL || hc->host == NULL) {
1293 if ((rc = chflags(path, flags)) < 0)
1294 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1295 return (rc);
1298 trans = hcc_start_command(hc, HC_CHFLAGS);
1299 hcc_leaf_string(trans, LC_PATH1, path);
1300 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1301 if ((head = hcc_finish_command(trans)) == NULL)
1302 return(-1);
1303 if (head->error)
1304 return(-1);
1305 return(0);
1308 static int
1309 rc_chflags(hctransaction_t trans __unused, struct HCHead *head)
1311 struct HCLeaf *item;
1312 const char *path = NULL;
1313 u_long flags = 0;
1314 int rc;
1316 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1317 switch(item->leafid) {
1318 case LC_PATH1:
1319 path = HCC_STRING(item);
1320 break;
1321 case LC_FILEFLAGS:
1322 flags = (u_long)HCC_INT64(item);
1323 break;
1326 if (path == NULL)
1327 return(-2);
1328 if ((rc = chflags(path, flags)) < 0)
1329 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1330 return(rc);
1333 #endif
1336 * READLINK
1339 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1341 hctransaction_t trans;
1342 struct HCHead *head;
1343 struct HCLeaf *item;
1344 int r;
1346 if (hc == NULL || hc->host == NULL)
1347 return(readlink(path, buf, bufsiz));
1349 trans = hcc_start_command(hc, HC_READLINK);
1350 hcc_leaf_string(trans, LC_PATH1, path);
1351 if ((head = hcc_finish_command(trans)) == NULL)
1352 return(-1);
1353 if (head->error)
1354 return(-1);
1356 r = 0;
1357 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1358 switch(item->leafid) {
1359 case LC_DATA:
1360 r = item->bytes - sizeof(*item);
1361 if (r < 0)
1362 r = 0;
1363 if (r > bufsiz)
1364 r = bufsiz;
1365 bcopy(HCC_BINARYDATA(item), buf, r);
1366 break;
1369 return(r);
1372 static int
1373 rc_readlink(hctransaction_t trans, struct HCHead *head)
1375 struct HCLeaf *item;
1376 const char *path = NULL;
1377 char buf[1024];
1378 int r;
1380 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1381 switch(item->leafid) {
1382 case LC_PATH1:
1383 path = HCC_STRING(item);
1384 break;
1387 if (path == NULL)
1388 return(-2);
1389 r = readlink(path, buf, sizeof(buf));
1390 if (r < 0)
1391 return(-1);
1392 hcc_leaf_data(trans, LC_DATA, buf, r);
1393 return(0);
1397 * UMASK
1399 mode_t
1400 hc_umask(struct HostConf *hc, mode_t numask)
1402 hctransaction_t trans;
1403 struct HCHead *head;
1404 struct HCLeaf *item;
1406 if (hc == NULL || hc->host == NULL)
1407 return(umask(numask));
1409 trans = hcc_start_command(hc, HC_UMASK);
1410 hcc_leaf_int32(trans, LC_MODE, numask);
1411 if ((head = hcc_finish_command(trans)) == NULL)
1412 return((mode_t)-1);
1413 if (head->error)
1414 return((mode_t)-1);
1416 numask = ~0666;
1417 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1418 switch(item->leafid) {
1419 case LC_MODE:
1420 numask = HCC_INT32(item);
1421 break;
1424 return(numask);
1427 static int
1428 rc_umask(hctransaction_t trans, struct HCHead *head)
1430 struct HCLeaf *item;
1431 mode_t numask = ~0666;
1433 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1434 switch(item->leafid) {
1435 case LC_MODE:
1436 numask = HCC_INT32(item);
1437 break;
1440 numask = umask(numask);
1441 hcc_leaf_int32(trans, LC_MODE, numask);
1442 return(0);
1446 * SYMLINK
1449 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1451 hctransaction_t trans;
1452 struct HCHead *head;
1454 if (hc == NULL || hc->host == NULL)
1455 return(symlink(name1, name2));
1457 trans = hcc_start_command(hc, HC_SYMLINK);
1458 hcc_leaf_string(trans, LC_PATH1, name1);
1459 hcc_leaf_string(trans, LC_PATH2, name2);
1460 if ((head = hcc_finish_command(trans)) == NULL)
1461 return(-1);
1462 if (head->error)
1463 return(-1);
1464 return(0);
1467 static int
1468 rc_symlink(hctransaction_t trans __unused, struct HCHead *head)
1470 struct HCLeaf *item;
1471 const char *name1 = NULL;
1472 const char *name2 = NULL;
1474 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1475 switch(item->leafid) {
1476 case LC_PATH1:
1477 name1 = HCC_STRING(item);
1478 break;
1479 case LC_PATH2:
1480 name2 = HCC_STRING(item);
1481 break;
1484 if (name1 == NULL || name2 == NULL)
1485 return(-2);
1486 return(symlink(name1, name2));
1490 * RENAME
1493 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1495 hctransaction_t trans;
1496 struct HCHead *head;
1498 if (hc == NULL || hc->host == NULL)
1499 return(rename(name1, name2));
1501 trans = hcc_start_command(hc, HC_RENAME);
1502 hcc_leaf_string(trans, LC_PATH1, name1);
1503 hcc_leaf_string(trans, LC_PATH2, name2);
1504 if ((head = hcc_finish_command(trans)) == NULL)
1505 return(-1);
1506 if (head->error)
1507 return(-1);
1508 return(0);
1511 static int
1512 rc_rename(hctransaction_t trans __unused, struct HCHead *head)
1514 struct HCLeaf *item;
1515 const char *name1 = NULL;
1516 const char *name2 = NULL;
1518 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1519 switch(item->leafid) {
1520 case LC_PATH1:
1521 name1 = HCC_STRING(item);
1522 break;
1523 case LC_PATH2:
1524 name2 = HCC_STRING(item);
1525 break;
1528 if (name1 == NULL || name2 == NULL)
1529 return(-2);
1530 return(rename(name1, name2));
1534 * UTIMES
1537 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1539 hctransaction_t trans;
1540 struct HCHead *head;
1542 if (hc == NULL || hc->host == NULL)
1543 return(utimes(path, times));
1545 trans = hcc_start_command(hc, HC_UTIMES);
1546 hcc_leaf_string(trans, LC_PATH1, path);
1547 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1548 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1549 if ((head = hcc_finish_command(trans)) == NULL)
1550 return(-1);
1551 if (head->error)
1552 return(-1);
1553 return(0);
1556 static int
1557 rc_utimes(hctransaction_t trans __unused, struct HCHead *head)
1559 struct HCLeaf *item;
1560 struct timeval times[2];
1561 const char *path;
1563 bzero(times, sizeof(times));
1564 path = NULL;
1566 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1567 switch(item->leafid) {
1568 case LC_PATH1:
1569 path = HCC_STRING(item);
1570 break;
1571 case LC_ATIME:
1572 times[0].tv_sec = HCC_INT64(item);
1573 break;
1574 case LC_MTIME:
1575 times[1].tv_sec = HCC_INT64(item);
1576 break;
1579 if (path == NULL)
1580 return(-2);
1581 return(utimes(path, times));
1584 uid_t
1585 hc_geteuid(struct HostConf *hc)
1587 hctransaction_t trans;
1588 struct HCHead *head;
1589 struct HCLeaf *item;
1591 if (hc == NULL || hc->host == NULL)
1592 return (geteuid());
1594 if (hc->version < 3) {
1595 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1596 /* Return 0 on error, so the caller assumes root privileges. */
1597 return (0);
1600 trans = hcc_start_command(hc, HC_GETEUID);
1601 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1602 return(0);
1603 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1604 if (item->leafid == LC_UID)
1605 return (HCC_INT32(item));
1607 return(0); /* shouldn't happen */
1610 static int
1611 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1613 hcc_leaf_int32(trans, LC_UID, geteuid());
1614 return (0);
1617 static int
1618 getmygroups(gid_t **gidlist)
1620 int count;
1622 if ((count = getgroups(0, *gidlist)) > 0) {
1623 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1624 if ((count = getgroups(count, *gidlist)) <= 0)
1625 free(*gidlist);
1627 else
1628 count = -1;
1630 else
1631 *gidlist = NULL;
1632 return (count);
1636 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1638 int count, i;
1639 hctransaction_t trans;
1640 struct HCHead *head;
1641 struct HCLeaf *item;
1643 if (hc == NULL || hc->host == NULL)
1644 return (getmygroups(gidlist));
1646 i = 0;
1647 count = 0;
1648 *gidlist = NULL;
1650 if (hc->version < 3) {
1651 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1652 return (-1);
1655 trans = hcc_start_command(hc, HC_GETGROUPS);
1656 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1657 return(-1);
1658 for (item = hcc_firstitem(head); item; item = hcc_nextitem(head, item)) {
1659 switch(item->leafid) {
1660 case LC_COUNT:
1661 count = HCC_INT32(item);
1662 if (*gidlist != NULL) { /* protocol error */
1663 free(*gidlist);
1664 *gidlist = NULL;
1665 return (-1);
1667 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1668 return (-1);
1669 break;
1670 case LC_GID:
1671 if (*gidlist == NULL || i >= count) { /* protocol error */
1672 if (*gidlist != NULL)
1673 free(*gidlist);
1674 *gidlist = NULL;
1675 return (-1);
1677 (*gidlist)[i++] = HCC_INT32(item);
1678 break;
1681 return (count);
1684 static int
1685 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1687 int count, i;
1688 gid_t *gidlist;
1690 if ((count = getmygroups(&gidlist)) < 0)
1691 return (-1);
1692 hcc_leaf_int32(trans, LC_COUNT, count);
1693 for (i = 0; i < count; i++)
1694 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1695 if (gidlist != NULL)
1696 free(gidlist);
1697 return (0);