Fix typo in MLINK name.
[dragonfly.git] / bin / cpdup / hcproto.c
blob6424074ad6681b6af1537326f2e673b0d2baf652
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(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 *);
39 #endif
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 },
54 { HC_STAT, rc_stat },
55 { HC_LSTAT, rc_lstat },
56 { HC_OPENDIR, rc_opendir },
57 { HC_READDIR, rc_readdir },
58 { HC_CLOSEDIR, rc_closedir },
59 { HC_OPEN, rc_open },
60 { HC_CLOSE, rc_close },
61 { HC_READ, rc_read },
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 },
70 { HC_LINK, rc_link },
71 #ifdef _ST_FLAGS_PRESENT_
72 { HC_CHFLAGS, rc_chflags },
73 #endif
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.
93 static int
94 silentwarning(int *didwarn, const char *ctl, ...)
96 va_list va;
98 if (DstRootPrivs)
99 return(-1);
100 if (*didwarn == 0 && QuietOpt == 0) {
101 *didwarn = 1;
102 fprintf(stderr, "WARNING: Not running as root, ");
103 va_start(va, ctl);
104 vfprintf(stderr, ctl, va);
105 va_end(va);
107 return(0);
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);
115 return(-1);
117 return(hc_hello(hc));
120 void
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)
133 struct HCHead *head;
134 struct HCLeaf *item;
135 hctransaction_t trans;
136 char hostbuf[256];
137 int error;
139 bzero(hostbuf, sizeof(hostbuf));
140 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
141 return(-1);
142 if (hostbuf[0] == 0)
143 hostbuf[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);
148 if (UseCpFile)
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",
152 hc->host);
153 return(-1);
156 if (head->error) {
157 fprintf(stderr, "Connected to %s but remote returned error %d\n",
158 hc->host, head->error);
159 return(-1);
162 error = -1;
163 FOR_EACH_ITEM(item, trans, head) {
164 switch(item->leafid) {
165 case LC_HELLOSTR:
166 if (QuietOpt == 0)
167 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
168 error = 0;
169 break;
170 case LC_VERSION:
171 hc->version = HCC_INT32(item);
172 break;
175 if (hc->version < HCPROTO_VERSION_COMPAT) {
176 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
177 hc->host);
178 error = -1;
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);
183 if (error < 0)
184 fprintf(stderr, "Handshake failed with %s\n", hc->host);
185 return (error);
188 static int
189 rc_hello(hctransaction_t trans, struct HCHead *head)
191 struct HCLeaf *item;
192 char hostbuf[256];
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)
201 return(-1);
202 if (hostbuf[0] == 0)
203 hostbuf[0] = '?';
205 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
206 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
207 return(0);
211 * STAT, LSTAT
214 hc_stat(struct HostConf *hc, const char *path, struct stat *st)
216 struct HCHead *head;
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)
225 return(-1);
226 if (head->error)
227 return(-1);
228 return(hc_decode_stat(trans, st, head));
232 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
234 struct HCHead *head;
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)
243 return(-1);
244 if (head->error)
245 return(-1);
246 return(hc_decode_stat(trans, st, head));
249 static int
250 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
252 struct HCLeaf *item;
254 bzero(st, sizeof(*st));
255 FOR_EACH_ITEM(item, trans, head)
256 hc_decode_stat_item(st, item);
257 return(0);
260 static int
261 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
263 switch(item->leafid) {
264 case LC_DEV:
265 st->st_dev = HCC_INT32(item);
266 break;
267 case LC_INO:
268 st->st_ino = HCC_INT64(item);
269 break;
270 case LC_MODE:
271 st->st_mode = HCC_INT32(item);
272 break;
273 case LC_NLINK:
274 st->st_nlink = HCC_INT32(item);
275 break;
276 case LC_UID:
277 st->st_uid = HCC_INT32(item);
278 break;
279 case LC_GID:
280 st->st_gid = HCC_INT32(item);
281 break;
282 case LC_RDEV:
283 st->st_rdev = HCC_INT32(item);
284 break;
285 case LC_ATIME:
286 st->st_atime = (time_t)HCC_INT64(item);
287 break;
288 case LC_MTIME:
289 st->st_mtime = (time_t)HCC_INT64(item);
290 break;
291 case LC_CTIME:
292 st->st_ctime = (time_t)HCC_INT64(item);
293 break;
294 case LC_FILESIZE:
295 st->st_size = HCC_INT64(item);
296 break;
297 case LC_FILEBLKS:
298 st->st_blocks = HCC_INT64(item);
299 break;
300 case LC_BLKSIZE:
301 st->st_blksize = HCC_INT32(item);
302 break;
303 #ifdef _ST_FSMID_PRESENT_
304 case LC_FSMID:
305 st->st_fsmid = HCC_INT64(item);
306 break;
307 #endif
308 #ifdef _ST_FLAGS_PRESENT_
309 case LC_FILEFLAGS:
310 st->st_flags = (uint32_t)HCC_INT64(item);
311 break;
312 #endif
314 return(0);
317 static int
318 rc_stat(hctransaction_t trans, struct HCHead *head)
320 struct HCLeaf *item;
321 struct stat st;
322 const char *path = NULL;
324 FOR_EACH_ITEM(item, trans, head) {
325 if (item->leafid == LC_PATH1)
326 path = HCC_STRING(item);
328 if (path == NULL)
329 return(-2);
330 if (stat(path, &st) < 0)
331 return(-1);
332 return (rc_encode_stat(trans, &st));
335 static int
336 rc_lstat(hctransaction_t trans, struct HCHead *head)
338 struct HCLeaf *item;
339 struct stat st;
340 const char *path = NULL;
342 FOR_EACH_ITEM(item, trans, head) {
343 if (item->leafid == LC_PATH1)
344 path = HCC_STRING(item);
346 if (path == NULL)
347 return(-2);
348 if (lstat(path, &st) < 0)
349 return(-1);
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
360 static int
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);
378 #endif
379 #ifdef _ST_FLAGS_PRESENT_
380 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
381 #endif
382 return(0);
386 * OPENDIR
388 DIR *
389 hc_opendir(struct HostConf *hc, const char *path)
391 hctransaction_t trans;
392 struct HCHead *head;
394 if (hc == NULL || hc->host == NULL)
395 return(opendir(path));
397 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
398 struct HCLeaf *item;
399 struct HCDirEntry *den;
400 intptr_t desc = 0;
402 trans = hcc_start_command(hc, HC_OPENDIR);
403 hcc_leaf_string(trans, LC_PATH1, path);
404 if ((head = hcc_finish_command(trans)) == NULL)
405 return (NULL);
406 if (head->error)
407 return (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",
414 (intmax_t)desc);
415 return (NULL);
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)
426 return (NULL);
427 return ((void *)head);
430 static int
431 rc_opendir(hctransaction_t trans, struct HCHead *head)
433 struct HCLeaf *item;
434 const char *path = NULL;
435 DIR *dir;
436 int desc;
438 FOR_EACH_ITEM(item, trans, head) {
439 if (item->leafid == LC_PATH1)
440 path = HCC_STRING(item);
442 if (path == NULL)
443 return(-2);
444 if ((dir = opendir(path)) == NULL) {
445 head->error = errno;
446 } else {
447 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
448 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
450 return(0);
454 * READDIR
456 struct HCDirEntry *
457 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
459 int stat_ok = 0;
460 struct HCHead *head;
461 struct HCLeaf *item;
462 static struct HCDirEntry denbuf;
464 *statpp = NULL;
465 if (hc == NULL || hc->host == NULL) {
466 struct dirent *sysden;
468 if ((sysden = readdir(dir)) == NULL)
469 return (NULL);
470 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
471 return (&denbuf);
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)
481 return (NULL);
482 if (head->error)
483 return (NULL); /* XXX errno */
484 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
485 if (den == NULL)
486 return (NULL); /* XXX errno */
487 den->d_name[0] = 0;
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;
497 head = (void *)dir;
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);
503 break;
504 } else {
505 stat_ok = 1;
506 hc_decode_stat_item(*statpp, item);
509 if (!stat_ok) {
510 free(*statpp);
511 *statpp = NULL;
513 return (denbuf.d_name[0] ? &denbuf : NULL);
516 static int
517 rc_readdir(hctransaction_t trans, struct HCHead *head)
519 struct HCLeaf *item;
520 struct dirent *den;
521 DIR *dir = NULL;
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);
527 if (dir == NULL)
528 return(-2);
529 if ((den = readdir(dir)) != NULL)
530 hcc_leaf_string(trans, LC_PATH1, den->d_name);
531 return(0);
535 * CLOSEDIR
537 * XXX cpdup needs to check error code to avoid truncated dirs?
540 hc_closedir(struct HostConf *hc, DIR *dir)
542 struct HCHead *head;
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;
549 struct dirent *den;
551 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
552 free(den);
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)
557 return (-1);
558 if (head->error)
559 return (-1); /* XXX errno */
560 return (0);
561 } else {
562 /* errno */
563 return(-1);
567 /* hc->version >= 4: using HC_SCANDIR */
568 head = (void *)dir;
569 /* skip any remaining items if the directory is closed prematurely */
570 while (hcc_nextchaineditem(hc, head) != NULL)
571 /*nothing*/ ;
572 if (head->error)
573 return (-1);
574 return (0);
577 static int
578 rc_closedir(hctransaction_t trans, struct HCHead *head)
580 struct HCLeaf *item;
581 DIR *dir = NULL;
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);
586 if (dir != NULL) {
587 hcc_set_descriptor(trans->hc, HCC_INT32(item),
588 NULL, HC_DESC_DIR);
592 if (dir == NULL)
593 return(-2);
594 return(closedir(dir));
598 * SCANDIR
600 static int
601 rc_scandir(hctransaction_t trans, struct HCHead *head)
603 struct HCLeaf *item;
604 const char *path = NULL;
605 struct dirent *den;
606 DIR *dir;
607 char *fpath;
608 struct stat st;
610 FOR_EACH_ITEM(item, trans, head) {
611 if (item->leafid == LC_PATH1)
612 path = HCC_STRING(item);
614 if (path == NULL)
615 return (-2);
616 if ((dir = opendir(path)) == NULL)
617 return (-1);
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)) {
632 closedir(dir);
633 return (-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);
640 free(fpath);
642 return (closedir(dir));
646 * OPEN
649 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
651 hctransaction_t trans;
652 struct HCHead *head;
653 struct HCLeaf *item;
654 int *fdp;
655 int desc = 0;
656 int nflags;
658 if (NotForRealOpt && (flags & O_CREAT))
659 return(0x7FFFFFFF);
661 if (hc == NULL || hc->host == NULL) {
662 #ifdef O_LARGEFILE
663 flags |= O_LARGEFILE;
664 #endif
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)
672 return (-1);
673 head->magic = 0; /* used to indicate offset within buffer */
674 return (1); /* dummy */
677 nflags = flags & XO_NATIVEMASK;
678 if (flags & O_CREAT)
679 nflags |= XO_CREAT;
680 if (flags & O_EXCL)
681 nflags |= XO_EXCL;
682 if (flags & O_TRUNC)
683 nflags |= XO_TRUNC;
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)
691 return(-1);
692 if (head->error)
693 return(-1);
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",
700 desc);
701 return(-1);
703 fdp = malloc(sizeof(int));
704 *fdp = desc; /* really just a dummy */
705 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
706 return(desc);
709 static int
710 rc_open(hctransaction_t trans, struct HCHead *head)
712 struct HCLeaf *item;
713 const char *path = NULL;
714 int nflags = 0;
715 int flags;
716 mode_t mode = 0666;
717 int desc;
718 int *fdp;
719 int fd;
721 FOR_EACH_ITEM(item, trans, head) {
722 switch(item->leafid) {
723 case LC_PATH1:
724 path = HCC_STRING(item);
725 break;
726 case LC_OFLAGS:
727 nflags = HCC_INT32(item);
728 break;
729 case LC_MODE:
730 mode = HCC_INT32(item);
731 break;
734 if (path == NULL)
735 return(-2);
737 flags = nflags & XO_NATIVEMASK;
738 if (nflags & XO_CREAT)
739 flags |= O_CREAT;
740 if (nflags & XO_EXCL)
741 flags |= O_EXCL;
742 if (nflags & XO_TRUNC)
743 flags |= O_TRUNC;
745 if (ReadOnlyOpt) {
746 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
747 head->error = EACCES;
748 return (0);
750 flags |= O_RDONLY;
753 #ifdef O_LARGEFILE
754 flags |= O_LARGEFILE;
755 #endif
756 if ((fd = open(path, flags, mode)) < 0)
757 return(-1);
758 fdp = malloc(sizeof(int));
759 *fdp = fd;
760 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
761 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
762 return(0);
766 * CLOSE
769 hc_close(struct HostConf *hc, int fd)
771 hctransaction_t trans;
772 struct HCHead *head;
773 int *fdp;
775 if (NotForRealOpt && fd == 0x7FFFFFFF)
776 return(0);
777 if (hc == NULL || hc->host == NULL)
778 return(close(fd));
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)
784 /*nothing*/ ;
785 if (head->error)
786 return (-1);
787 return (0);
790 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
791 if (fdp) {
792 free(fdp);
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)
798 return(-1);
799 if (head->error)
800 return(-1);
801 return(0);
802 } else {
803 return(-1);
807 static int
808 rc_close(hctransaction_t trans, struct HCHead *head)
810 struct HCLeaf *item;
811 int *fdp = NULL;
812 int fd;
813 int desc = -1;
815 FOR_EACH_ITEM(item, trans, head) {
816 if (item->leafid == LC_DESCRIPTOR)
817 desc = HCC_INT32(item);
819 if (desc < 0)
820 return(-2);
821 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
822 return(-2);
823 fd = *fdp;
824 free(fdp);
825 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
826 return(close(fd));
829 static int
830 getiolimit(void)
832 return(32768);
836 * READ
838 ssize_t
839 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
841 hctransaction_t trans;
842 struct HCHead *head;
843 struct HCLeaf *item;
844 int *fdp;
845 int offset;
846 int r = 0;
847 int x = 0;
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;
854 while (bytes) {
855 if ((offset = head->magic) != 0)
856 item = hcc_currentchaineditem(hc, head);
857 else
858 item = hcc_nextchaineditem(hc, head);
859 if (item == NULL)
860 return (r);
861 if (item->leafid != LC_DATA)
862 return (-1);
863 x = item->bytes - sizeof(*item) - offset;
864 if (x > (int)bytes) {
865 x = (int)bytes;
866 head->magic += x; /* leave bytes in the buffer */
868 else
869 head->magic = 0; /* all bytes used up */
870 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
871 buf = (char *)buf + x;
872 bytes -= (size_t)x;
873 r += x;
875 return (r);
878 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
879 if (fdp) {
880 while (bytes) {
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)
888 return(-1);
889 if (head->error)
890 return(-1);
891 FOR_EACH_ITEM(item, trans, head) {
892 if (item->leafid == LC_DATA) {
893 x = item->bytes - sizeof(*item);
894 if (x > (int)bytes)
895 x = (int)bytes;
896 bcopy(HCC_BINARYDATA(item), buf, x);
897 buf = (char *)buf + x;
898 bytes -= (size_t)x;
899 r += x;
902 if (x < n)
903 break;
905 return(r);
906 } else {
907 return(-1);
911 static int
912 rc_read(hctransaction_t trans, struct HCHead *head)
914 struct HCLeaf *item;
915 int *fdp = NULL;
916 char buf[32768];
917 int bytes = -1;
918 int n;
920 FOR_EACH_ITEM(item, trans, head) {
921 switch(item->leafid) {
922 case LC_DESCRIPTOR:
923 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
924 break;
925 case LC_BYTES:
926 bytes = HCC_INT32(item);
927 break;
930 if (fdp == NULL)
931 return(-2);
932 if (bytes < 0 || bytes > 32768)
933 return(-2);
934 n = read(*fdp, buf, bytes);
935 if (n < 0)
936 return(-1);
937 hcc_leaf_data(trans, LC_DATA, buf, n);
938 return(0);
942 * READFILE
944 static int
945 rc_readfile(hctransaction_t trans, struct HCHead *head)
947 struct HCLeaf *item;
948 const char *path = NULL;
949 char buf[32768];
950 int n;
951 int fd;
953 FOR_EACH_ITEM(item, trans, head) {
954 if (item->leafid == LC_PATH1)
955 path = HCC_STRING(item);
957 if (path == NULL)
958 return (-2);
959 if ((fd = open(path, O_RDONLY)) < 0)
960 return(-1);
961 while ((n = read(fd, buf, 32768)) >= 0) {
962 if (!hcc_check_space(trans, head, 1, n)) {
963 close(fd);
964 return (-1);
966 hcc_leaf_data(trans, LC_DATA, buf, n);
967 if (n == 0)
968 break;
970 if (n < 0) {
971 close(fd);
972 return (-1);
974 return (close(fd));
978 * WRITE
980 ssize_t
981 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
983 hctransaction_t trans;
984 struct HCHead *head;
985 struct HCLeaf *item;
986 int *fdp;
987 int r;
989 if (NotForRealOpt)
990 return(bytes);
992 if (hc == NULL || hc->host == NULL)
993 return(write(fd, buf, bytes));
995 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
996 if (fdp) {
997 r = 0;
998 while (bytes) {
999 size_t limit = getiolimit();
1000 int n = (bytes > limit) ? limit : bytes;
1001 int x = 0;
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)
1007 return(-1);
1008 if (head->error)
1009 return(-1);
1010 FOR_EACH_ITEM(item, trans, head) {
1011 if (item->leafid == LC_BYTES)
1012 x = HCC_INT32(item);
1014 if (x < 0 || x > n)
1015 return(-1);
1016 r += x;
1017 buf = (const char *)buf + x;
1018 bytes -= x;
1019 if (x < n)
1020 break;
1022 return(r);
1023 } else {
1024 return(-1);
1028 static int
1029 rc_write(hctransaction_t trans, struct HCHead *head)
1031 struct HCLeaf *item;
1032 int *fdp = NULL;
1033 void *buf = NULL;
1034 int n = -1;
1036 FOR_EACH_ITEM(item, trans, head) {
1037 switch(item->leafid) {
1038 case LC_DESCRIPTOR:
1039 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1040 break;
1041 case LC_DATA:
1042 buf = HCC_BINARYDATA(item);
1043 n = item->bytes - sizeof(*item);
1044 break;
1047 if (ReadOnlyOpt) {
1048 head->error = EACCES;
1049 return (0);
1051 if (fdp == NULL)
1052 return(-2);
1053 if (n < 0 || n > 32768)
1054 return(-2);
1055 n = write(*fdp, buf, n);
1056 if (n < 0)
1057 return (-1);
1058 hcc_leaf_int32(trans, LC_BYTES, n);
1059 return(0);
1063 * REMOVE
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;
1072 int res;
1074 if (NotForRealOpt)
1075 return(0);
1076 if (hc == NULL || hc->host == NULL) {
1077 res = remove(path);
1078 if (res < 0)
1079 res = -errno;
1080 return(res);
1083 trans = hcc_start_command(hc, HC_REMOVE);
1084 hcc_leaf_string(trans, LC_PATH1, path);
1085 if ((head = hcc_finish_command(trans)) == NULL)
1086 return(-EIO);
1087 if (head->error)
1088 return(-(int)head->error);
1089 return(0);
1092 static int
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);
1102 if (path == NULL)
1103 return(-2);
1104 if (ReadOnlyOpt) {
1105 head->error = EACCES;
1106 return (0);
1108 return(remove(path));
1112 * MKDIR
1115 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1117 hctransaction_t trans;
1118 struct HCHead *head;
1120 if (NotForRealOpt)
1121 return(0);
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)
1129 return(-1);
1130 if (head->error)
1131 return(-1);
1132 return(0);
1135 static int
1136 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1138 struct HCLeaf *item;
1139 const char *path = NULL;
1140 mode_t mode = 0777;
1142 FOR_EACH_ITEM(item, trans, head) {
1143 switch(item->leafid) {
1144 case LC_PATH1:
1145 path = HCC_STRING(item);
1146 break;
1147 case LC_MODE:
1148 mode = HCC_INT32(item);
1149 break;
1152 if (ReadOnlyOpt) {
1153 head->error = EACCES;
1154 return (0);
1156 if (path == NULL)
1157 return(-2);
1158 return(mkdir(path, mode));
1162 * RMDIR
1165 hc_rmdir(struct HostConf *hc, const char *path)
1167 hctransaction_t trans;
1168 struct HCHead *head;
1170 if (NotForRealOpt)
1171 return(0);
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)
1178 return(-1);
1179 if (head->error)
1180 return(-1);
1181 return(0);
1184 static int
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);
1194 if (ReadOnlyOpt) {
1195 head->error = EACCES;
1196 return (0);
1198 if (path == NULL)
1199 return(-2);
1200 return(rmdir(path));
1204 * CHOWN
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;
1213 int rc;
1215 if (NotForRealOpt)
1216 return(0);
1217 if (!DstRootPrivs)
1218 owner = -1;
1220 if (hc == NULL || hc->host == NULL) {
1221 rc = chown(path, owner, group);
1222 if (rc < 0)
1223 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1224 return(rc);
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)
1232 return(-1);
1233 if (head->error)
1234 return(-1);
1235 return(0);
1238 static int
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;
1245 int rc;
1247 FOR_EACH_ITEM(item, trans, head) {
1248 switch(item->leafid) {
1249 case LC_PATH1:
1250 path = HCC_STRING(item);
1251 break;
1252 case LC_UID:
1253 uid = HCC_INT32(item);
1254 break;
1255 case LC_GID:
1256 gid = HCC_INT32(item);
1257 break;
1260 if (ReadOnlyOpt) {
1261 head->error = EACCES;
1262 return (0);
1264 if (path == NULL)
1265 return(-2);
1266 rc = chown(path, uid, gid);
1267 if (rc < 0)
1268 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1269 return(rc);
1273 * LCHOWN
1276 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1278 hctransaction_t trans;
1279 struct HCHead *head;
1280 int rc;
1282 if (NotForRealOpt)
1283 return(0);
1284 if (!DstRootPrivs)
1285 owner = -1;
1287 if (hc == NULL || hc->host == NULL) {
1288 rc = lchown(path, owner, group);
1289 if (rc < 0)
1290 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1291 return(rc);
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)
1299 return(-1);
1300 if (head->error)
1301 return(-1);
1302 return(0);
1305 static int
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;
1312 int rc;
1314 FOR_EACH_ITEM(item, trans, head) {
1315 switch(item->leafid) {
1316 case LC_PATH1:
1317 path = HCC_STRING(item);
1318 break;
1319 case LC_UID:
1320 uid = HCC_INT32(item);
1321 break;
1322 case LC_GID:
1323 gid = HCC_INT32(item);
1324 break;
1327 if (ReadOnlyOpt) {
1328 head->error = EACCES;
1329 return (0);
1331 if (path == NULL)
1332 return(-2);
1333 rc = lchown(path, uid, gid);
1334 if (rc < 0)
1335 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1336 return(rc);
1340 * CHMOD
1343 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1345 hctransaction_t trans;
1346 struct HCHead *head;
1348 if (NotForRealOpt)
1349 return(0);
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)
1357 return(-1);
1358 if (head->error)
1359 return(-1);
1360 return(0);
1363 static int
1364 rc_chmod(hctransaction_t trans, struct HCHead *head)
1366 struct HCLeaf *item;
1367 const char *path = NULL;
1368 mode_t mode = 0666;
1370 FOR_EACH_ITEM(item, trans, head) {
1371 switch(item->leafid) {
1372 case LC_PATH1:
1373 path = HCC_STRING(item);
1374 break;
1375 case LC_MODE:
1376 mode = HCC_INT32(item);
1377 break;
1380 if (ReadOnlyOpt) {
1381 head->error = EACCES;
1382 return (0);
1384 if (path == NULL)
1385 return(-2);
1386 return(chmod(path, mode));
1390 * MKNOD
1393 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1395 hctransaction_t trans;
1396 struct HCHead *head;
1398 if (NotForRealOpt)
1399 return(0);
1400 if (!DstRootPrivs) {
1401 /* mknod() requires root privs, so don't bother. */
1402 errno = EPERM;
1403 return (-1);
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)
1414 return(-1);
1415 if (head->error)
1416 return(-1);
1417 return(0);
1420 static int
1421 rc_mknod(hctransaction_t trans, struct HCHead *head)
1423 struct HCLeaf *item;
1424 const char *path = NULL;
1425 mode_t mode = 0666;
1426 dev_t rdev = 0;
1428 FOR_EACH_ITEM(item, trans, head) {
1429 switch(item->leafid) {
1430 case LC_PATH1:
1431 path = HCC_STRING(item);
1432 break;
1433 case LC_MODE:
1434 mode = HCC_INT32(item);
1435 break;
1436 case LC_RDEV:
1437 rdev = HCC_INT32(item);
1438 break;
1441 if (ReadOnlyOpt) {
1442 head->error = EACCES;
1443 return (0);
1445 if (path == NULL)
1446 return(-2);
1447 return(mknod(path, mode, rdev));
1451 * LINK
1454 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1456 hctransaction_t trans;
1457 struct HCHead *head;
1459 if (NotForRealOpt)
1460 return(0);
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)
1468 return(-1);
1469 if (head->error)
1470 return(-1);
1471 return(0);
1474 static int
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) {
1483 case LC_PATH1:
1484 name1 = HCC_STRING(item);
1485 break;
1486 case LC_PATH2:
1487 name2 = HCC_STRING(item);
1488 break;
1491 if (ReadOnlyOpt) {
1492 head->error = EACCES;
1493 return (-0);
1495 if (name1 == NULL || name2 == NULL)
1496 return(-2);
1497 return(link(name1, name2));
1500 #ifdef _ST_FLAGS_PRESENT_
1502 * CHFLAGS
1505 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1507 hctransaction_t trans;
1508 struct HCHead *head;
1509 int rc;
1511 if (NotForRealOpt)
1512 return(0);
1513 if (!DstRootPrivs)
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");
1519 return (rc);
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)
1526 return(-1);
1527 if (head->error)
1528 return(-1);
1529 return(0);
1532 static int
1533 rc_chflags(hctransaction_t trans, struct HCHead *head)
1535 struct HCLeaf *item;
1536 const char *path = NULL;
1537 u_long flags = 0;
1538 int rc;
1540 FOR_EACH_ITEM(item, trans, head) {
1541 switch(item->leafid) {
1542 case LC_PATH1:
1543 path = HCC_STRING(item);
1544 break;
1545 case LC_FILEFLAGS:
1546 flags = (u_long)HCC_INT64(item);
1547 break;
1550 if (ReadOnlyOpt) {
1551 head->error = EACCES;
1552 return (0);
1554 if (path == NULL)
1555 return(-2);
1556 if ((rc = chflags(path, flags)) < 0)
1557 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1558 return(rc);
1561 #endif
1564 * READLINK
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;
1572 int r;
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)
1580 return(-1);
1581 if (head->error)
1582 return(-1);
1584 r = 0;
1585 FOR_EACH_ITEM(item, trans, head) {
1586 if (item->leafid == LC_DATA) {
1587 r = item->bytes - sizeof(*item);
1588 if (r < 0)
1589 r = 0;
1590 if (r > bufsiz)
1591 r = bufsiz;
1592 bcopy(HCC_BINARYDATA(item), buf, r);
1595 return(r);
1598 static int
1599 rc_readlink(hctransaction_t trans, struct HCHead *head)
1601 struct HCLeaf *item;
1602 const char *path = NULL;
1603 char buf[1024];
1604 int r;
1606 FOR_EACH_ITEM(item, trans, head) {
1607 if (item->leafid == LC_PATH1)
1608 path = HCC_STRING(item);
1610 if (path == NULL)
1611 return(-2);
1612 r = readlink(path, buf, sizeof(buf));
1613 if (r < 0)
1614 return(-1);
1615 hcc_leaf_data(trans, LC_DATA, buf, r);
1616 return(0);
1620 * UMASK
1622 mode_t
1623 hc_umask(struct HostConf *hc, mode_t numask)
1625 hctransaction_t trans;
1626 struct HCHead *head;
1627 struct HCLeaf *item;
1629 if (NotForRealOpt)
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)
1637 return((mode_t)-1);
1638 if (head->error)
1639 return((mode_t)-1);
1641 numask = (mode_t) ~0666U;
1642 FOR_EACH_ITEM(item, trans, head) {
1643 if (item->leafid == LC_MODE)
1644 numask = HCC_INT32(item);
1646 return(numask);
1649 static int
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);
1661 return(0);
1665 * SYMLINK
1668 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1670 hctransaction_t trans;
1671 struct HCHead *head;
1673 if (NotForRealOpt)
1674 return(0);
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)
1682 return(-1);
1683 if (head->error)
1684 return(-1);
1685 return(0);
1688 static int
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) {
1697 case LC_PATH1:
1698 name1 = HCC_STRING(item);
1699 break;
1700 case LC_PATH2:
1701 name2 = HCC_STRING(item);
1702 break;
1705 if (ReadOnlyOpt) {
1706 head->error = EACCES;
1707 return (0);
1709 if (name1 == NULL || name2 == NULL)
1710 return(-2);
1711 return(symlink(name1, name2));
1715 * RENAME
1718 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1720 hctransaction_t trans;
1721 struct HCHead *head;
1723 if (NotForRealOpt)
1724 return(0);
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)
1732 return(-1);
1733 if (head->error)
1734 return(-1);
1735 return(0);
1738 static int
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) {
1747 case LC_PATH1:
1748 name1 = HCC_STRING(item);
1749 break;
1750 case LC_PATH2:
1751 name2 = HCC_STRING(item);
1752 break;
1755 if (ReadOnlyOpt) {
1756 head->error = EACCES;
1757 return (0);
1759 if (name1 == NULL || name2 == NULL)
1760 return(-2);
1761 return(rename(name1, name2));
1765 * UTIMES
1768 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1770 hctransaction_t trans;
1771 struct HCHead *head;
1773 if (NotForRealOpt)
1774 return(0);
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)
1783 return(-1);
1784 if (head->error)
1785 return(-1);
1786 return(0);
1789 static int
1790 rc_utimes(hctransaction_t trans, struct HCHead *head)
1792 struct HCLeaf *item;
1793 struct timeval times[2];
1794 const char *path;
1796 bzero(times, sizeof(times));
1797 path = NULL;
1799 FOR_EACH_ITEM(item, trans, head) {
1800 switch(item->leafid) {
1801 case LC_PATH1:
1802 path = HCC_STRING(item);
1803 break;
1804 case LC_ATIME:
1805 times[0].tv_sec = HCC_INT64(item);
1806 break;
1807 case LC_MTIME:
1808 times[1].tv_sec = HCC_INT64(item);
1809 break;
1812 if (ReadOnlyOpt) {
1813 head->error = EACCES;
1814 return (0);
1816 if (path == NULL)
1817 return(-2);
1818 return(utimes(path, times));
1821 uid_t
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)
1829 return (geteuid());
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. */
1834 return (0);
1837 trans = hcc_start_command(hc, HC_GETEUID);
1838 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1839 return(0);
1840 FOR_EACH_ITEM(item, trans, head) {
1841 if (item->leafid == LC_UID)
1842 return (HCC_INT32(item));
1844 return(0); /* shouldn't happen */
1847 static int
1848 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1850 hcc_leaf_int32(trans, LC_UID, geteuid());
1851 return (0);
1854 static int
1855 getmygroups(gid_t **gidlist)
1857 int count;
1859 if ((count = getgroups(0, *gidlist)) > 0) {
1860 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1861 if ((count = getgroups(count, *gidlist)) <= 0)
1862 free(*gidlist);
1864 else
1865 count = -1;
1867 else
1868 *gidlist = NULL;
1869 return (count);
1873 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1875 int count, i;
1876 hctransaction_t trans;
1877 struct HCHead *head;
1878 struct HCLeaf *item;
1880 if (hc == NULL || hc->host == NULL)
1881 return (getmygroups(gidlist));
1883 i = 0;
1884 count = 0;
1885 *gidlist = NULL;
1887 if (hc->version < 3) {
1888 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1889 return (-1);
1892 trans = hcc_start_command(hc, HC_GETGROUPS);
1893 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1894 return(-1);
1895 FOR_EACH_ITEM(item, trans, head) {
1896 switch(item->leafid) {
1897 case LC_COUNT:
1898 count = HCC_INT32(item);
1899 if (*gidlist != NULL) { /* protocol error */
1900 free(*gidlist);
1901 *gidlist = NULL;
1902 return (-1);
1904 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1905 return (-1);
1906 break;
1907 case LC_GID:
1908 if (*gidlist == NULL || i >= count) { /* protocol error */
1909 if (*gidlist != NULL)
1910 free(*gidlist);
1911 *gidlist = NULL;
1912 return (-1);
1914 (*gidlist)[i++] = HCC_INT32(item);
1915 break;
1918 return (count);
1921 static int
1922 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1924 int count, i;
1925 gid_t *gidlist;
1927 if ((count = getmygroups(&gidlist)) < 0)
1928 return (-1);
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)
1933 free(gidlist);
1934 return (0);