hack(6): Update gethdate().
[dragonfly.git] / bin / cpdup / hcproto.c
blobb52ef337ba0e89d8b7f3a3813fe1bc14fc123e9f
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]));
129 * A HELLO RPC is sent on the initial connect.
132 hc_hello(struct HostConf *hc)
134 struct HCHead *head;
135 struct HCLeaf *item;
136 hctransaction_t trans;
137 char hostbuf[256];
138 int error;
140 bzero(hostbuf, sizeof(hostbuf));
141 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
142 return(-1);
143 if (hostbuf[0] == 0)
144 hostbuf[0] = '?';
146 trans = hcc_start_command(hc, HC_HELLO);
147 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
148 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
149 if (UseCpFile)
150 hcc_leaf_string(trans, LC_PATH1, UseCpFile);
151 if ((head = hcc_finish_command(trans)) == NULL) {
152 fprintf(stderr, "Connected to %s but remote failed to complete hello\n",
153 hc->host);
154 return(-1);
157 if (head->error) {
158 fprintf(stderr, "Connected to %s but remote returned error %d\n",
159 hc->host, head->error);
160 return(-1);
163 error = -1;
164 FOR_EACH_ITEM(item, trans, head) {
165 switch(item->leafid) {
166 case LC_HELLOSTR:
167 if (QuietOpt == 0)
168 fprintf(stderr, "Handshaked with %s\n", HCC_STRING(item));
169 error = 0;
170 break;
171 case LC_VERSION:
172 hc->version = HCC_INT32(item);
173 break;
176 if (hc->version < HCPROTO_VERSION_COMPAT) {
177 fprintf(stderr, "Remote cpdup at %s has an incompatible version\n",
178 hc->host);
179 error = -1;
180 } else if (hc->version < HCPROTO_VERSION && QuietOpt == 0) {
181 fprintf(stderr, "WARNING: Remote cpdup at %s has a lower version, "
182 "expect reduced speed\n", hc->host);
184 if (error < 0)
185 fprintf(stderr, "Handshake failed with %s\n", hc->host);
186 return (error);
189 static int
190 rc_hello(hctransaction_t trans, struct HCHead *head)
192 struct HCLeaf *item;
193 char hostbuf[256];
195 FOR_EACH_ITEM(item, trans, head) {
196 if (item->leafid == LC_PATH1)
197 UseCpFile = strdup(HCC_STRING(item));
200 bzero(hostbuf, sizeof(hostbuf));
201 if (gethostname(hostbuf, sizeof(hostbuf) - 1) < 0)
202 return(-1);
203 if (hostbuf[0] == 0)
204 hostbuf[0] = '?';
206 hcc_leaf_string(trans, LC_HELLOSTR, hostbuf);
207 hcc_leaf_int32(trans, LC_VERSION, HCPROTO_VERSION);
208 return(0);
212 * STAT, LSTAT
215 hc_stat(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(stat(path, st));
223 trans = hcc_start_command(hc, HC_STAT);
224 hcc_leaf_string(trans, LC_PATH1, path);
225 if ((head = hcc_finish_command(trans)) == NULL)
226 return(-1);
227 if (head->error)
228 return(-1);
229 return(hc_decode_stat(trans, st, head));
233 hc_lstat(struct HostConf *hc, const char *path, struct stat *st)
235 struct HCHead *head;
236 hctransaction_t trans;
238 if (hc == NULL || hc->host == NULL)
239 return(lstat(path, st));
241 trans = hcc_start_command(hc, HC_LSTAT);
242 hcc_leaf_string(trans, LC_PATH1, path);
243 if ((head = hcc_finish_command(trans)) == NULL)
244 return(-1);
245 if (head->error)
246 return(-1);
247 return(hc_decode_stat(trans, st, head));
250 static int
251 hc_decode_stat(hctransaction_t trans, struct stat *st, struct HCHead *head)
253 struct HCLeaf *item;
255 bzero(st, sizeof(*st));
256 FOR_EACH_ITEM(item, trans, head)
257 hc_decode_stat_item(st, item);
258 return(0);
261 static int
262 hc_decode_stat_item(struct stat *st, struct HCLeaf *item)
264 switch(item->leafid) {
265 case LC_DEV:
266 st->st_dev = HCC_INT32(item);
267 break;
268 case LC_INO:
269 st->st_ino = HCC_INT64(item);
270 break;
271 case LC_MODE:
272 st->st_mode = HCC_INT32(item);
273 break;
274 case LC_NLINK:
275 st->st_nlink = HCC_INT32(item);
276 break;
277 case LC_UID:
278 st->st_uid = HCC_INT32(item);
279 break;
280 case LC_GID:
281 st->st_gid = HCC_INT32(item);
282 break;
283 case LC_RDEV:
284 st->st_rdev = HCC_INT32(item);
285 break;
286 case LC_ATIME:
287 st->st_atime = (time_t)HCC_INT64(item);
288 break;
289 case LC_MTIME:
290 st->st_mtime = (time_t)HCC_INT64(item);
291 break;
292 case LC_CTIME:
293 st->st_ctime = (time_t)HCC_INT64(item);
294 break;
295 case LC_FILESIZE:
296 st->st_size = HCC_INT64(item);
297 break;
298 case LC_FILEBLKS:
299 st->st_blocks = HCC_INT64(item);
300 break;
301 case LC_BLKSIZE:
302 st->st_blksize = HCC_INT32(item);
303 break;
304 #ifdef _ST_FSMID_PRESENT_
305 case LC_FSMID:
306 st->st_fsmid = HCC_INT64(item);
307 break;
308 #endif
309 #ifdef _ST_FLAGS_PRESENT_
310 case LC_FILEFLAGS:
311 st->st_flags = (uint32_t)HCC_INT64(item);
312 break;
313 #endif
315 return(0);
318 static int
319 rc_stat(hctransaction_t trans, struct HCHead *head)
321 struct HCLeaf *item;
322 struct stat st;
323 const char *path = NULL;
325 FOR_EACH_ITEM(item, trans, head) {
326 if (item->leafid == LC_PATH1)
327 path = HCC_STRING(item);
329 if (path == NULL)
330 return(-2);
331 if (stat(path, &st) < 0)
332 return(-1);
333 return (rc_encode_stat(trans, &st));
336 static int
337 rc_lstat(hctransaction_t trans, struct HCHead *head)
339 struct HCLeaf *item;
340 struct stat st;
341 const char *path = NULL;
343 FOR_EACH_ITEM(item, trans, head) {
344 if (item->leafid == LC_PATH1)
345 path = HCC_STRING(item);
347 if (path == NULL)
348 return(-2);
349 if (lstat(path, &st) < 0)
350 return(-1);
351 return (rc_encode_stat(trans, &st));
355 * Encode all entries of a stat structure.
357 * CAUTION: If you add any more entries here, be sure to
358 * increase the STAT_MAX_NUM_ENTRIES value!
360 #define STAT_MAX_NUM_ENTRIES 18
361 static int
362 rc_encode_stat(hctransaction_t trans, struct stat *st)
364 hcc_leaf_int32(trans, LC_DEV, st->st_dev);
365 hcc_leaf_int64(trans, LC_INO, st->st_ino);
366 hcc_leaf_int32(trans, LC_MODE, st->st_mode);
367 hcc_leaf_int32(trans, LC_NLINK, st->st_nlink);
368 hcc_leaf_int32(trans, LC_UID, st->st_uid);
369 hcc_leaf_int32(trans, LC_GID, st->st_gid);
370 hcc_leaf_int32(trans, LC_RDEV, st->st_rdev);
371 hcc_leaf_int64(trans, LC_ATIME, st->st_atime);
372 hcc_leaf_int64(trans, LC_MTIME, st->st_mtime);
373 hcc_leaf_int64(trans, LC_CTIME, st->st_ctime);
374 hcc_leaf_int64(trans, LC_FILESIZE, st->st_size);
375 hcc_leaf_int64(trans, LC_FILEBLKS, st->st_blocks);
376 hcc_leaf_int32(trans, LC_BLKSIZE, st->st_blksize);
377 #ifdef _ST_FSMID_PRESENT_
378 hcc_leaf_int64(trans, LC_FSMID, st->st_fsmid);
379 #endif
380 #ifdef _ST_FLAGS_PRESENT_
381 hcc_leaf_int64(trans, LC_FILEFLAGS, st->st_flags);
382 #endif
383 return(0);
387 * OPENDIR
389 DIR *
390 hc_opendir(struct HostConf *hc, const char *path)
392 hctransaction_t trans;
393 struct HCHead *head;
395 if (hc == NULL || hc->host == NULL)
396 return(opendir(path));
398 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
399 struct HCLeaf *item;
400 struct HCDirEntry *den;
401 intptr_t desc = 0;
403 trans = hcc_start_command(hc, HC_OPENDIR);
404 hcc_leaf_string(trans, LC_PATH1, path);
405 if ((head = hcc_finish_command(trans)) == NULL)
406 return (NULL);
407 if (head->error)
408 return (NULL);
409 FOR_EACH_ITEM(item, trans, head) {
410 if (item->leafid == LC_DESCRIPTOR)
411 desc = HCC_INT32(item);
413 if (hcc_get_descriptor(hc, desc, HC_DESC_DIR)) {
414 fprintf(stderr, "hc_opendir: remote reused active descriptor %jd\n",
415 (intmax_t)desc);
416 return (NULL);
418 den = malloc(sizeof(*den));
419 hcc_set_descriptor(hc, desc, den, HC_DESC_DIR);
420 return ((void *)desc);
423 /* hc->version >= 4: use HC_SCANDIR */
424 trans = hcc_start_command(hc, HC_SCANDIR);
425 hcc_leaf_string(trans, LC_PATH1, path);
426 if ((head = hcc_finish_command(trans)) == NULL || head->error)
427 return (NULL);
428 return ((void *)head);
431 static int
432 rc_opendir(hctransaction_t trans, struct HCHead *head)
434 struct HCLeaf *item;
435 const char *path = NULL;
436 DIR *dir;
437 int desc;
439 FOR_EACH_ITEM(item, trans, head) {
440 if (item->leafid == LC_PATH1)
441 path = HCC_STRING(item);
443 if (path == NULL)
444 return(-2);
445 if ((dir = opendir(path)) == NULL) {
446 head->error = errno;
447 } else {
448 desc = hcc_alloc_descriptor(trans->hc, dir, HC_DESC_DIR);
449 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
451 return(0);
455 * READDIR
457 struct HCDirEntry *
458 hc_readdir(struct HostConf *hc, DIR *dir, struct stat **statpp)
460 int stat_ok = 0;
461 struct HCHead *head;
462 struct HCLeaf *item;
463 static struct HCDirEntry denbuf;
465 *statpp = NULL;
466 if (hc == NULL || hc->host == NULL) {
467 struct dirent *sysden;
469 if ((sysden = readdir(dir)) == NULL)
470 return (NULL);
471 strlcpy(denbuf.d_name, sysden->d_name, MAXNAMLEN + 1);
472 return (&denbuf);
475 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
476 hctransaction_t trans;
477 struct HCDirEntry *den;
479 trans = hcc_start_command(hc, HC_READDIR);
480 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
481 if ((head = hcc_finish_command(trans)) == NULL)
482 return (NULL);
483 if (head->error)
484 return (NULL); /* XXX errno */
485 den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR);
486 if (den == NULL)
487 return (NULL); /* XXX errno */
488 den->d_name[0] = 0;
489 FOR_EACH_ITEM(item, trans, head) {
490 if (item->leafid == LC_PATH1)
491 strlcpy(den->d_name, HCC_STRING(item), MAXNAMLEN + 1);
493 return (den->d_name[0] ? den : NULL);
496 /* hc->version >= 4: using HC_SCANDIR */
497 denbuf.d_name[0] = 0;
498 head = (void *)dir;
499 *statpp = malloc(sizeof(struct stat));
500 bzero(*statpp, sizeof(struct stat));
501 while ((item = hcc_nextchaineditem(hc, head)) != NULL) {
502 if (item->leafid == LC_PATH1) { /* this must be the last item */
503 strlcpy(denbuf.d_name, HCC_STRING(item), MAXNAMLEN + 1);
504 break;
505 } else {
506 stat_ok = 1;
507 hc_decode_stat_item(*statpp, item);
510 if (!stat_ok) {
511 free(*statpp);
512 *statpp = NULL;
514 return (denbuf.d_name[0] ? &denbuf : NULL);
517 static int
518 rc_readdir(hctransaction_t trans, struct HCHead *head)
520 struct HCLeaf *item;
521 struct dirent *den;
522 DIR *dir = NULL;
524 FOR_EACH_ITEM(item, trans, head) {
525 if (item->leafid == LC_DESCRIPTOR)
526 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
528 if (dir == NULL)
529 return(-2);
530 if ((den = readdir(dir)) != NULL)
531 hcc_leaf_string(trans, LC_PATH1, den->d_name);
532 return(0);
536 * CLOSEDIR
538 * XXX cpdup needs to check error code to avoid truncated dirs?
541 hc_closedir(struct HostConf *hc, DIR *dir)
543 struct HCHead *head;
545 if (hc == NULL || hc->host == NULL)
546 return(closedir(dir));
548 if (hc->version <= 3) { /* compatibility: HC_SCANDIR not supported */
549 hctransaction_t trans;
550 struct dirent *den;
552 if ((den = hcc_get_descriptor(hc, (intptr_t)dir, HC_DESC_DIR)) != NULL) {
553 free(den);
554 hcc_set_descriptor(hc, (intptr_t)dir, NULL, HC_DESC_DIR);
555 trans = hcc_start_command(hc, HC_CLOSEDIR);
556 hcc_leaf_int32(trans, LC_DESCRIPTOR, (intptr_t)dir);
557 if ((head = hcc_finish_command(trans)) == NULL)
558 return (-1);
559 if (head->error)
560 return (-1); /* XXX errno */
561 return (0);
562 } else {
563 /* errno */
564 return(-1);
568 /* hc->version >= 4: using HC_SCANDIR */
569 head = (void *)dir;
570 /* skip any remaining items if the directory is closed prematurely */
571 while (hcc_nextchaineditem(hc, head) != NULL)
572 /*nothing*/ ;
573 if (head->error)
574 return (-1);
575 return (0);
578 static int
579 rc_closedir(hctransaction_t trans, struct HCHead *head)
581 struct HCLeaf *item;
582 DIR *dir = NULL;
584 FOR_EACH_ITEM(item, trans, head) {
585 if (item->leafid == LC_DESCRIPTOR) {
586 dir = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_DIR);
587 if (dir != NULL) {
588 hcc_set_descriptor(trans->hc, HCC_INT32(item),
589 NULL, HC_DESC_DIR);
593 if (dir == NULL)
594 return(-2);
595 return(closedir(dir));
599 * SCANDIR
601 static int
602 rc_scandir(hctransaction_t trans, struct HCHead *head)
604 struct HCLeaf *item;
605 const char *path = NULL;
606 struct dirent *den;
607 DIR *dir;
608 char *fpath;
609 struct stat st;
611 FOR_EACH_ITEM(item, trans, head) {
612 if (item->leafid == LC_PATH1)
613 path = HCC_STRING(item);
615 if (path == NULL)
616 return (-2);
617 if ((dir = opendir(path)) == NULL)
618 return (-1);
619 while ((den = readdir(dir)) != NULL) {
620 if (den->d_name[0] == '.' && (den->d_name[1] == '\0' ||
621 (den->d_name[1] == '.' && den->d_name[2] == '\0')))
622 continue; /* skip "." and ".." */
624 * Check if there's enough space left in the current packet.
625 * We have at most STAT_MAX_NUM_ENTRIES pieces of data, of which
626 * one is a string, so we use strlen() + 1 (terminating zero).
627 * The remaining ones are numbers; we assume sizeof(int64_t) so
628 * we're on the safe side.
630 if (!hcc_check_space(trans, head, STAT_MAX_NUM_ENTRIES,
631 (STAT_MAX_NUM_ENTRIES - 1) * sizeof(int64_t) +
632 strlen(den->d_name) + 1)) {
633 closedir(dir);
634 return (-1);
636 fpath = mprintf("%s/%s", path, den->d_name);
637 if (lstat(fpath, &st) == 0)
638 rc_encode_stat(trans, &st);
639 /* The name must be the last item! */
640 hcc_leaf_string(trans, LC_PATH1, den->d_name);
641 free(fpath);
643 return (closedir(dir));
647 * OPEN
650 hc_open(struct HostConf *hc, const char *path, int flags, mode_t mode)
652 hctransaction_t trans;
653 struct HCHead *head;
654 struct HCLeaf *item;
655 int *fdp;
656 int desc = 0;
657 int nflags;
659 if (NotForRealOpt && (flags & O_CREAT))
660 return(0x7FFFFFFF);
662 if (hc == NULL || hc->host == NULL) {
663 #ifdef O_LARGEFILE
664 flags |= O_LARGEFILE;
665 #endif
666 return(open(path, flags, mode));
669 if ((flags & (O_WRONLY | O_RDWR)) == 0 && hc->version >= 4) {
670 trans = hcc_start_command(hc, HC_READFILE);
671 hcc_leaf_string(trans, LC_PATH1, path);
672 if ((head = hcc_finish_command(trans)) == NULL || head->error)
673 return (-1);
674 head->magic = 0; /* used to indicate offset within buffer */
675 return (1); /* dummy */
678 nflags = flags & XO_NATIVEMASK;
679 if (flags & O_CREAT)
680 nflags |= XO_CREAT;
681 if (flags & O_EXCL)
682 nflags |= XO_EXCL;
683 if (flags & O_TRUNC)
684 nflags |= XO_TRUNC;
686 trans = hcc_start_command(hc, HC_OPEN);
687 hcc_leaf_string(trans, LC_PATH1, path);
688 hcc_leaf_int32(trans, LC_OFLAGS, nflags);
689 hcc_leaf_int32(trans, LC_MODE, mode);
691 if ((head = hcc_finish_command(trans)) == NULL)
692 return(-1);
693 if (head->error)
694 return(-1);
695 FOR_EACH_ITEM(item, trans, head) {
696 if (item->leafid == LC_DESCRIPTOR)
697 desc = HCC_INT32(item);
699 if (hcc_get_descriptor(hc, desc, HC_DESC_FD)) {
700 fprintf(stderr, "hc_open: remote reused active descriptor %d\n",
701 desc);
702 return(-1);
704 fdp = malloc(sizeof(int));
705 *fdp = desc; /* really just a dummy */
706 hcc_set_descriptor(hc, desc, fdp, HC_DESC_FD);
707 return(desc);
710 static int
711 rc_open(hctransaction_t trans, struct HCHead *head)
713 struct HCLeaf *item;
714 const char *path = NULL;
715 int nflags = 0;
716 int flags;
717 mode_t mode = 0666;
718 int desc;
719 int *fdp;
720 int fd;
722 FOR_EACH_ITEM(item, trans, head) {
723 switch(item->leafid) {
724 case LC_PATH1:
725 path = HCC_STRING(item);
726 break;
727 case LC_OFLAGS:
728 nflags = HCC_INT32(item);
729 break;
730 case LC_MODE:
731 mode = HCC_INT32(item);
732 break;
735 if (path == NULL)
736 return(-2);
738 flags = nflags & XO_NATIVEMASK;
739 if (nflags & XO_CREAT)
740 flags |= O_CREAT;
741 if (nflags & XO_EXCL)
742 flags |= O_EXCL;
743 if (nflags & XO_TRUNC)
744 flags |= O_TRUNC;
746 if (ReadOnlyOpt) {
747 if (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC)) {
748 head->error = EACCES;
749 return (0);
751 flags |= O_RDONLY;
754 #ifdef O_LARGEFILE
755 flags |= O_LARGEFILE;
756 #endif
757 if ((fd = open(path, flags, mode)) < 0)
758 return(-1);
759 fdp = malloc(sizeof(int));
760 *fdp = fd;
761 desc = hcc_alloc_descriptor(trans->hc, fdp, HC_DESC_FD);
762 hcc_leaf_int32(trans, LC_DESCRIPTOR, desc);
763 return(0);
767 * CLOSE
770 hc_close(struct HostConf *hc, int fd)
772 hctransaction_t trans;
773 struct HCHead *head;
774 int *fdp;
776 if (NotForRealOpt && fd == 0x7FFFFFFF)
777 return(0);
778 if (hc == NULL || hc->host == NULL)
779 return(close(fd));
781 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
782 head = (void *)hc->trans.rbuf;
783 /* skip any remaining items if the file is closed prematurely */
784 while (hcc_nextchaineditem(hc, head) != NULL)
785 /*nothing*/ ;
786 if (head->error)
787 return (-1);
788 return (0);
791 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
792 if (fdp) {
793 free(fdp);
794 hcc_set_descriptor(hc, fd, NULL, HC_DESC_FD);
796 trans = hcc_start_command(hc, HC_CLOSE);
797 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
798 if ((head = hcc_finish_command(trans)) == NULL)
799 return(-1);
800 if (head->error)
801 return(-1);
802 return(0);
803 } else {
804 return(-1);
808 static int
809 rc_close(hctransaction_t trans, struct HCHead *head)
811 struct HCLeaf *item;
812 int *fdp = NULL;
813 int fd;
814 int desc = -1;
816 FOR_EACH_ITEM(item, trans, head) {
817 if (item->leafid == LC_DESCRIPTOR)
818 desc = HCC_INT32(item);
820 if (desc < 0)
821 return(-2);
822 if ((fdp = hcc_get_descriptor(trans->hc, desc, HC_DESC_FD)) == NULL)
823 return(-2);
824 fd = *fdp;
825 free(fdp);
826 hcc_set_descriptor(trans->hc, desc, NULL, HC_DESC_FD);
827 return(close(fd));
830 static int
831 getiolimit(void)
833 return(32768);
837 * READ
839 ssize_t
840 hc_read(struct HostConf *hc, int fd, void *buf, size_t bytes)
842 hctransaction_t trans;
843 struct HCHead *head;
844 struct HCLeaf *item;
845 int *fdp;
846 int offset;
847 int r = 0;
848 int x = 0;
850 if (hc == NULL || hc->host == NULL)
851 return(read(fd, buf, bytes));
853 if (fd == 1 && hc->version >= 4) { /* using HC_READFILE */
854 head = (void *)hc->trans.rbuf;
855 while (bytes) {
856 if ((offset = head->magic) != 0)
857 item = hcc_currentchaineditem(hc, head);
858 else
859 item = hcc_nextchaineditem(hc, head);
860 if (item == NULL)
861 return (r);
862 if (item->leafid != LC_DATA)
863 return (-1);
864 x = item->bytes - sizeof(*item) - offset;
865 if (x > (int)bytes) {
866 x = (int)bytes;
867 head->magic += x; /* leave bytes in the buffer */
869 else
870 head->magic = 0; /* all bytes used up */
871 bcopy((char *)HCC_BINARYDATA(item) + offset, buf, x);
872 buf = (char *)buf + x;
873 bytes -= (size_t)x;
874 r += x;
876 return (r);
879 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
880 if (fdp) {
881 while (bytes) {
882 size_t limit = getiolimit();
883 int n = (bytes > limit) ? limit : bytes;
885 trans = hcc_start_command(hc, HC_READ);
886 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
887 hcc_leaf_int32(trans, LC_BYTES, n);
888 if ((head = hcc_finish_command(trans)) == NULL)
889 return(-1);
890 if (head->error)
891 return(-1);
892 FOR_EACH_ITEM(item, trans, head) {
893 if (item->leafid == LC_DATA) {
894 x = item->bytes - sizeof(*item);
895 if (x > (int)bytes)
896 x = (int)bytes;
897 bcopy(HCC_BINARYDATA(item), buf, x);
898 buf = (char *)buf + x;
899 bytes -= (size_t)x;
900 r += x;
903 if (x < n)
904 break;
906 return(r);
907 } else {
908 return(-1);
912 static int
913 rc_read(hctransaction_t trans, struct HCHead *head)
915 struct HCLeaf *item;
916 int *fdp = NULL;
917 char buf[32768];
918 int bytes = -1;
919 int n;
921 FOR_EACH_ITEM(item, trans, head) {
922 switch(item->leafid) {
923 case LC_DESCRIPTOR:
924 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
925 break;
926 case LC_BYTES:
927 bytes = HCC_INT32(item);
928 break;
931 if (fdp == NULL)
932 return(-2);
933 if (bytes < 0 || bytes > 32768)
934 return(-2);
935 n = read(*fdp, buf, bytes);
936 if (n < 0)
937 return(-1);
938 hcc_leaf_data(trans, LC_DATA, buf, n);
939 return(0);
943 * READFILE
945 static int
946 rc_readfile(hctransaction_t trans, struct HCHead *head)
948 struct HCLeaf *item;
949 const char *path = NULL;
950 char buf[32768];
951 int n;
952 int fd;
954 FOR_EACH_ITEM(item, trans, head) {
955 if (item->leafid == LC_PATH1)
956 path = HCC_STRING(item);
958 if (path == NULL)
959 return (-2);
960 if ((fd = open(path, O_RDONLY)) < 0)
961 return(-1);
962 while ((n = read(fd, buf, 32768)) >= 0) {
963 if (!hcc_check_space(trans, head, 1, n)) {
964 close(fd);
965 return (-1);
967 hcc_leaf_data(trans, LC_DATA, buf, n);
968 if (n == 0)
969 break;
971 if (n < 0) {
972 close(fd);
973 return (-1);
975 return (close(fd));
979 * WRITE
981 ssize_t
982 hc_write(struct HostConf *hc, int fd, const void *buf, size_t bytes)
984 hctransaction_t trans;
985 struct HCHead *head;
986 struct HCLeaf *item;
987 int *fdp;
988 int r;
990 if (NotForRealOpt)
991 return(bytes);
993 if (hc == NULL || hc->host == NULL)
994 return(write(fd, buf, bytes));
996 fdp = hcc_get_descriptor(hc, fd, HC_DESC_FD);
997 if (fdp) {
998 r = 0;
999 while (bytes) {
1000 size_t limit = getiolimit();
1001 int n = (bytes > limit) ? limit : bytes;
1002 int x = 0;
1004 trans = hcc_start_command(hc, HC_WRITE);
1005 hcc_leaf_int32(trans, LC_DESCRIPTOR, fd);
1006 hcc_leaf_data(trans, LC_DATA, buf, n);
1007 if ((head = hcc_finish_command(trans)) == NULL)
1008 return(-1);
1009 if (head->error)
1010 return(-1);
1011 FOR_EACH_ITEM(item, trans, head) {
1012 if (item->leafid == LC_BYTES)
1013 x = HCC_INT32(item);
1015 if (x < 0 || x > n)
1016 return(-1);
1017 r += x;
1018 buf = (const char *)buf + x;
1019 bytes -= x;
1020 if (x < n)
1021 break;
1023 return(r);
1024 } else {
1025 return(-1);
1029 static int
1030 rc_write(hctransaction_t trans, struct HCHead *head)
1032 struct HCLeaf *item;
1033 int *fdp = NULL;
1034 void *buf = NULL;
1035 int n = -1;
1037 FOR_EACH_ITEM(item, trans, head) {
1038 switch(item->leafid) {
1039 case LC_DESCRIPTOR:
1040 fdp = hcc_get_descriptor(trans->hc, HCC_INT32(item), HC_DESC_FD);
1041 break;
1042 case LC_DATA:
1043 buf = HCC_BINARYDATA(item);
1044 n = item->bytes - sizeof(*item);
1045 break;
1048 if (ReadOnlyOpt) {
1049 head->error = EACCES;
1050 return (0);
1052 if (fdp == NULL)
1053 return(-2);
1054 if (n < 0 || n > 32768)
1055 return(-2);
1056 n = write(*fdp, buf, n);
1057 if (n < 0)
1058 return (-1);
1059 hcc_leaf_int32(trans, LC_BYTES, n);
1060 return(0);
1064 * REMOVE
1066 * NOTE: This function returns -errno if an error occured.
1069 hc_remove(struct HostConf *hc, const char *path)
1071 hctransaction_t trans;
1072 struct HCHead *head;
1073 int res;
1075 if (NotForRealOpt)
1076 return(0);
1077 if (hc == NULL || hc->host == NULL) {
1078 res = remove(path);
1079 if (res < 0)
1080 res = -errno;
1081 return(res);
1084 trans = hcc_start_command(hc, HC_REMOVE);
1085 hcc_leaf_string(trans, LC_PATH1, path);
1086 if ((head = hcc_finish_command(trans)) == NULL)
1087 return(-EIO);
1088 if (head->error)
1089 return(-(int)head->error);
1090 return(0);
1093 static int
1094 rc_remove(hctransaction_t trans, struct HCHead *head)
1096 struct HCLeaf *item;
1097 const char *path = NULL;
1099 FOR_EACH_ITEM(item, trans, head) {
1100 if (item->leafid == LC_PATH1)
1101 path = HCC_STRING(item);
1103 if (path == NULL)
1104 return(-2);
1105 if (ReadOnlyOpt) {
1106 head->error = EACCES;
1107 return (0);
1109 return(remove(path));
1113 * MKDIR
1116 hc_mkdir(struct HostConf *hc, const char *path, mode_t mode)
1118 hctransaction_t trans;
1119 struct HCHead *head;
1121 if (NotForRealOpt)
1122 return(0);
1123 if (hc == NULL || hc->host == NULL)
1124 return(mkdir(path, mode));
1126 trans = hcc_start_command(hc, HC_MKDIR);
1127 hcc_leaf_string(trans, LC_PATH1, path);
1128 hcc_leaf_int32(trans, LC_MODE, mode);
1129 if ((head = hcc_finish_command(trans)) == NULL)
1130 return(-1);
1131 if (head->error)
1132 return(-1);
1133 return(0);
1136 static int
1137 rc_mkdir(hctransaction_t trans, struct HCHead *head)
1139 struct HCLeaf *item;
1140 const char *path = NULL;
1141 mode_t mode = 0777;
1143 FOR_EACH_ITEM(item, trans, head) {
1144 switch(item->leafid) {
1145 case LC_PATH1:
1146 path = HCC_STRING(item);
1147 break;
1148 case LC_MODE:
1149 mode = HCC_INT32(item);
1150 break;
1153 if (ReadOnlyOpt) {
1154 head->error = EACCES;
1155 return (0);
1157 if (path == NULL)
1158 return(-2);
1159 return(mkdir(path, mode));
1163 * RMDIR
1166 hc_rmdir(struct HostConf *hc, const char *path)
1168 hctransaction_t trans;
1169 struct HCHead *head;
1171 if (NotForRealOpt)
1172 return(0);
1173 if (hc == NULL || hc->host == NULL)
1174 return(rmdir(path));
1176 trans = hcc_start_command(hc, HC_RMDIR);
1177 hcc_leaf_string(trans, LC_PATH1, path);
1178 if ((head = hcc_finish_command(trans)) == NULL)
1179 return(-1);
1180 if (head->error)
1181 return(-1);
1182 return(0);
1185 static int
1186 rc_rmdir(hctransaction_t trans, struct HCHead *head)
1188 struct HCLeaf *item;
1189 const char *path = NULL;
1191 FOR_EACH_ITEM(item, trans, head) {
1192 if (item->leafid == LC_PATH1)
1193 path = HCC_STRING(item);
1195 if (ReadOnlyOpt) {
1196 head->error = EACCES;
1197 return (0);
1199 if (path == NULL)
1200 return(-2);
1201 return(rmdir(path));
1205 * CHOWN
1207 * Almost silently ignore chowns that fail if we are not root.
1210 hc_chown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1212 hctransaction_t trans;
1213 struct HCHead *head;
1214 int rc;
1216 if (NotForRealOpt)
1217 return(0);
1218 if (!DstRootPrivs)
1219 owner = -1;
1221 if (hc == NULL || hc->host == NULL) {
1222 rc = chown(path, owner, group);
1223 if (rc < 0)
1224 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1225 return(rc);
1228 trans = hcc_start_command(hc, HC_CHOWN);
1229 hcc_leaf_string(trans, LC_PATH1, path);
1230 hcc_leaf_int32(trans, LC_UID, owner);
1231 hcc_leaf_int32(trans, LC_GID, group);
1232 if ((head = hcc_finish_command(trans)) == NULL)
1233 return(-1);
1234 if (head->error)
1235 return(-1);
1236 return(0);
1239 static int
1240 rc_chown(hctransaction_t trans, struct HCHead *head)
1242 struct HCLeaf *item;
1243 const char *path = NULL;
1244 uid_t uid = (uid_t)-1;
1245 gid_t gid = (gid_t)-1;
1246 int rc;
1248 FOR_EACH_ITEM(item, trans, head) {
1249 switch(item->leafid) {
1250 case LC_PATH1:
1251 path = HCC_STRING(item);
1252 break;
1253 case LC_UID:
1254 uid = HCC_INT32(item);
1255 break;
1256 case LC_GID:
1257 gid = HCC_INT32(item);
1258 break;
1261 if (ReadOnlyOpt) {
1262 head->error = EACCES;
1263 return (0);
1265 if (path == NULL)
1266 return(-2);
1267 rc = chown(path, uid, gid);
1268 if (rc < 0)
1269 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1270 return(rc);
1274 * LCHOWN
1277 hc_lchown(struct HostConf *hc, const char *path, uid_t owner, gid_t group)
1279 hctransaction_t trans;
1280 struct HCHead *head;
1281 int rc;
1283 if (NotForRealOpt)
1284 return(0);
1285 if (!DstRootPrivs)
1286 owner = -1;
1288 if (hc == NULL || hc->host == NULL) {
1289 rc = lchown(path, owner, group);
1290 if (rc < 0)
1291 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1292 return(rc);
1295 trans = hcc_start_command(hc, HC_LCHOWN);
1296 hcc_leaf_string(trans, LC_PATH1, path);
1297 hcc_leaf_int32(trans, LC_UID, owner);
1298 hcc_leaf_int32(trans, LC_GID, group);
1299 if ((head = hcc_finish_command(trans)) == NULL)
1300 return(-1);
1301 if (head->error)
1302 return(-1);
1303 return(0);
1306 static int
1307 rc_lchown(hctransaction_t trans, struct HCHead *head)
1309 struct HCLeaf *item;
1310 const char *path = NULL;
1311 uid_t uid = (uid_t)-1;
1312 gid_t gid = (gid_t)-1;
1313 int rc;
1315 FOR_EACH_ITEM(item, trans, head) {
1316 switch(item->leafid) {
1317 case LC_PATH1:
1318 path = HCC_STRING(item);
1319 break;
1320 case LC_UID:
1321 uid = HCC_INT32(item);
1322 break;
1323 case LC_GID:
1324 gid = HCC_INT32(item);
1325 break;
1328 if (ReadOnlyOpt) {
1329 head->error = EACCES;
1330 return (0);
1332 if (path == NULL)
1333 return(-2);
1334 rc = lchown(path, uid, gid);
1335 if (rc < 0)
1336 rc = silentwarning(&chown_warning, "file ownership may differ\n");
1337 return(rc);
1341 * CHMOD
1344 hc_chmod(struct HostConf *hc, const char *path, mode_t mode)
1346 hctransaction_t trans;
1347 struct HCHead *head;
1349 if (NotForRealOpt)
1350 return(0);
1351 if (hc == NULL || hc->host == NULL)
1352 return(chmod(path, mode));
1354 trans = hcc_start_command(hc, HC_CHMOD);
1355 hcc_leaf_string(trans, LC_PATH1, path);
1356 hcc_leaf_int32(trans, LC_MODE, mode);
1357 if ((head = hcc_finish_command(trans)) == NULL)
1358 return(-1);
1359 if (head->error)
1360 return(-1);
1361 return(0);
1364 static int
1365 rc_chmod(hctransaction_t trans, struct HCHead *head)
1367 struct HCLeaf *item;
1368 const char *path = NULL;
1369 mode_t mode = 0666;
1371 FOR_EACH_ITEM(item, trans, head) {
1372 switch(item->leafid) {
1373 case LC_PATH1:
1374 path = HCC_STRING(item);
1375 break;
1376 case LC_MODE:
1377 mode = HCC_INT32(item);
1378 break;
1381 if (ReadOnlyOpt) {
1382 head->error = EACCES;
1383 return (0);
1385 if (path == NULL)
1386 return(-2);
1387 return(chmod(path, mode));
1391 * MKNOD
1394 hc_mknod(struct HostConf *hc, const char *path, mode_t mode, dev_t rdev)
1396 hctransaction_t trans;
1397 struct HCHead *head;
1399 if (NotForRealOpt)
1400 return(0);
1401 if (!DstRootPrivs) {
1402 /* mknod() requires root privs, so don't bother. */
1403 errno = EPERM;
1404 return (-1);
1407 if (hc == NULL || hc->host == NULL)
1408 return(mknod(path, mode, rdev));
1410 trans = hcc_start_command(hc, HC_MKNOD);
1411 hcc_leaf_string(trans, LC_PATH1, path);
1412 hcc_leaf_int32(trans, LC_MODE, mode);
1413 hcc_leaf_int32(trans, LC_RDEV, rdev);
1414 if ((head = hcc_finish_command(trans)) == NULL)
1415 return(-1);
1416 if (head->error)
1417 return(-1);
1418 return(0);
1421 static int
1422 rc_mknod(hctransaction_t trans, struct HCHead *head)
1424 struct HCLeaf *item;
1425 const char *path = NULL;
1426 mode_t mode = 0666;
1427 dev_t rdev = 0;
1429 FOR_EACH_ITEM(item, trans, head) {
1430 switch(item->leafid) {
1431 case LC_PATH1:
1432 path = HCC_STRING(item);
1433 break;
1434 case LC_MODE:
1435 mode = HCC_INT32(item);
1436 break;
1437 case LC_RDEV:
1438 rdev = HCC_INT32(item);
1439 break;
1442 if (ReadOnlyOpt) {
1443 head->error = EACCES;
1444 return (0);
1446 if (path == NULL)
1447 return(-2);
1448 return(mknod(path, mode, rdev));
1452 * LINK
1455 hc_link(struct HostConf *hc, const char *name1, const char *name2)
1457 hctransaction_t trans;
1458 struct HCHead *head;
1460 if (NotForRealOpt)
1461 return(0);
1462 if (hc == NULL || hc->host == NULL)
1463 return(link(name1, name2));
1465 trans = hcc_start_command(hc, HC_LINK);
1466 hcc_leaf_string(trans, LC_PATH1, name1);
1467 hcc_leaf_string(trans, LC_PATH2, name2);
1468 if ((head = hcc_finish_command(trans)) == NULL)
1469 return(-1);
1470 if (head->error)
1471 return(-1);
1472 return(0);
1475 static int
1476 rc_link(hctransaction_t trans, struct HCHead *head)
1478 struct HCLeaf *item;
1479 const char *name1 = NULL;
1480 const char *name2 = NULL;
1482 FOR_EACH_ITEM(item, trans, head) {
1483 switch(item->leafid) {
1484 case LC_PATH1:
1485 name1 = HCC_STRING(item);
1486 break;
1487 case LC_PATH2:
1488 name2 = HCC_STRING(item);
1489 break;
1492 if (ReadOnlyOpt) {
1493 head->error = EACCES;
1494 return (-0);
1496 if (name1 == NULL || name2 == NULL)
1497 return(-2);
1498 return(link(name1, name2));
1501 #ifdef _ST_FLAGS_PRESENT_
1503 * CHFLAGS
1506 hc_chflags(struct HostConf *hc, const char *path, u_long flags)
1508 hctransaction_t trans;
1509 struct HCHead *head;
1510 int rc;
1512 if (NotForRealOpt)
1513 return(0);
1514 if (!DstRootPrivs)
1515 flags &= UF_SETTABLE;
1517 if (hc == NULL || hc->host == NULL) {
1518 if ((rc = chflags(path, flags)) < 0)
1519 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1520 return (rc);
1523 trans = hcc_start_command(hc, HC_CHFLAGS);
1524 hcc_leaf_string(trans, LC_PATH1, path);
1525 hcc_leaf_int64(trans, LC_FILEFLAGS, flags);
1526 if ((head = hcc_finish_command(trans)) == NULL)
1527 return(-1);
1528 if (head->error)
1529 return(-1);
1530 return(0);
1533 static int
1534 rc_chflags(hctransaction_t trans, struct HCHead *head)
1536 struct HCLeaf *item;
1537 const char *path = NULL;
1538 u_long flags = 0;
1539 int rc;
1541 FOR_EACH_ITEM(item, trans, head) {
1542 switch(item->leafid) {
1543 case LC_PATH1:
1544 path = HCC_STRING(item);
1545 break;
1546 case LC_FILEFLAGS:
1547 flags = (u_long)HCC_INT64(item);
1548 break;
1551 if (ReadOnlyOpt) {
1552 head->error = EACCES;
1553 return (0);
1555 if (path == NULL)
1556 return(-2);
1557 if ((rc = chflags(path, flags)) < 0)
1558 rc = silentwarning(&chflags_warning, "file flags may differ\n");
1559 return(rc);
1562 #endif
1565 * READLINK
1568 hc_readlink(struct HostConf *hc, const char *path, char *buf, int bufsiz)
1570 hctransaction_t trans;
1571 struct HCHead *head;
1572 struct HCLeaf *item;
1573 int r;
1575 if (hc == NULL || hc->host == NULL)
1576 return(readlink(path, buf, bufsiz));
1578 trans = hcc_start_command(hc, HC_READLINK);
1579 hcc_leaf_string(trans, LC_PATH1, path);
1580 if ((head = hcc_finish_command(trans)) == NULL)
1581 return(-1);
1582 if (head->error)
1583 return(-1);
1585 r = 0;
1586 FOR_EACH_ITEM(item, trans, head) {
1587 if (item->leafid == LC_DATA) {
1588 r = item->bytes - sizeof(*item);
1589 if (r < 0)
1590 r = 0;
1591 if (r > bufsiz)
1592 r = bufsiz;
1593 bcopy(HCC_BINARYDATA(item), buf, r);
1596 return(r);
1599 static int
1600 rc_readlink(hctransaction_t trans, struct HCHead *head)
1602 struct HCLeaf *item;
1603 const char *path = NULL;
1604 char buf[1024];
1605 int r;
1607 FOR_EACH_ITEM(item, trans, head) {
1608 if (item->leafid == LC_PATH1)
1609 path = HCC_STRING(item);
1611 if (path == NULL)
1612 return(-2);
1613 r = readlink(path, buf, sizeof(buf));
1614 if (r < 0)
1615 return(-1);
1616 hcc_leaf_data(trans, LC_DATA, buf, r);
1617 return(0);
1621 * UMASK
1623 mode_t
1624 hc_umask(struct HostConf *hc, mode_t numask)
1626 hctransaction_t trans;
1627 struct HCHead *head;
1628 struct HCLeaf *item;
1630 if (NotForRealOpt)
1631 return(umask(numask));
1632 if (hc == NULL || hc->host == NULL)
1633 return(umask(numask));
1635 trans = hcc_start_command(hc, HC_UMASK);
1636 hcc_leaf_int32(trans, LC_MODE, numask);
1637 if ((head = hcc_finish_command(trans)) == NULL)
1638 return((mode_t)-1);
1639 if (head->error)
1640 return((mode_t)-1);
1642 numask = (mode_t) ~0666U;
1643 FOR_EACH_ITEM(item, trans, head) {
1644 if (item->leafid == LC_MODE)
1645 numask = HCC_INT32(item);
1647 return(numask);
1650 static int
1651 rc_umask(hctransaction_t trans, struct HCHead *head)
1653 struct HCLeaf *item;
1654 mode_t numask = (mode_t) ~0666U;
1656 FOR_EACH_ITEM(item, trans, head) {
1657 if (item->leafid == LC_MODE)
1658 numask = HCC_INT32(item);
1660 numask = umask(numask);
1661 hcc_leaf_int32(trans, LC_MODE, numask);
1662 return(0);
1666 * SYMLINK
1669 hc_symlink(struct HostConf *hc, const char *name1, const char *name2)
1671 hctransaction_t trans;
1672 struct HCHead *head;
1674 if (NotForRealOpt)
1675 return(0);
1676 if (hc == NULL || hc->host == NULL)
1677 return(symlink(name1, name2));
1679 trans = hcc_start_command(hc, HC_SYMLINK);
1680 hcc_leaf_string(trans, LC_PATH1, name1);
1681 hcc_leaf_string(trans, LC_PATH2, name2);
1682 if ((head = hcc_finish_command(trans)) == NULL)
1683 return(-1);
1684 if (head->error)
1685 return(-1);
1686 return(0);
1689 static int
1690 rc_symlink(hctransaction_t trans, struct HCHead *head)
1692 struct HCLeaf *item;
1693 const char *name1 = NULL;
1694 const char *name2 = NULL;
1696 FOR_EACH_ITEM(item, trans, head) {
1697 switch(item->leafid) {
1698 case LC_PATH1:
1699 name1 = HCC_STRING(item);
1700 break;
1701 case LC_PATH2:
1702 name2 = HCC_STRING(item);
1703 break;
1706 if (ReadOnlyOpt) {
1707 head->error = EACCES;
1708 return (0);
1710 if (name1 == NULL || name2 == NULL)
1711 return(-2);
1712 return(symlink(name1, name2));
1716 * RENAME
1719 hc_rename(struct HostConf *hc, const char *name1, const char *name2)
1721 hctransaction_t trans;
1722 struct HCHead *head;
1724 if (NotForRealOpt)
1725 return(0);
1726 if (hc == NULL || hc->host == NULL)
1727 return(rename(name1, name2));
1729 trans = hcc_start_command(hc, HC_RENAME);
1730 hcc_leaf_string(trans, LC_PATH1, name1);
1731 hcc_leaf_string(trans, LC_PATH2, name2);
1732 if ((head = hcc_finish_command(trans)) == NULL)
1733 return(-1);
1734 if (head->error)
1735 return(-1);
1736 return(0);
1739 static int
1740 rc_rename(hctransaction_t trans, struct HCHead *head)
1742 struct HCLeaf *item;
1743 const char *name1 = NULL;
1744 const char *name2 = NULL;
1746 FOR_EACH_ITEM(item, trans, head) {
1747 switch(item->leafid) {
1748 case LC_PATH1:
1749 name1 = HCC_STRING(item);
1750 break;
1751 case LC_PATH2:
1752 name2 = HCC_STRING(item);
1753 break;
1756 if (ReadOnlyOpt) {
1757 head->error = EACCES;
1758 return (0);
1760 if (name1 == NULL || name2 == NULL)
1761 return(-2);
1762 return(rename(name1, name2));
1766 * UTIMES
1769 hc_utimes(struct HostConf *hc, const char *path, const struct timeval *times)
1771 hctransaction_t trans;
1772 struct HCHead *head;
1774 if (NotForRealOpt)
1775 return(0);
1776 if (hc == NULL || hc->host == NULL)
1777 return(utimes(path, times));
1779 trans = hcc_start_command(hc, HC_UTIMES);
1780 hcc_leaf_string(trans, LC_PATH1, path);
1781 hcc_leaf_int64(trans, LC_ATIME, times[0].tv_sec);
1782 hcc_leaf_int64(trans, LC_MTIME, times[1].tv_sec);
1783 if ((head = hcc_finish_command(trans)) == NULL)
1784 return(-1);
1785 if (head->error)
1786 return(-1);
1787 return(0);
1790 static int
1791 rc_utimes(hctransaction_t trans, struct HCHead *head)
1793 struct HCLeaf *item;
1794 struct timeval times[2];
1795 const char *path;
1797 bzero(times, sizeof(times));
1798 path = NULL;
1800 FOR_EACH_ITEM(item, trans, head) {
1801 switch(item->leafid) {
1802 case LC_PATH1:
1803 path = HCC_STRING(item);
1804 break;
1805 case LC_ATIME:
1806 times[0].tv_sec = HCC_INT64(item);
1807 break;
1808 case LC_MTIME:
1809 times[1].tv_sec = HCC_INT64(item);
1810 break;
1813 if (ReadOnlyOpt) {
1814 head->error = EACCES;
1815 return (0);
1817 if (path == NULL)
1818 return(-2);
1819 return(utimes(path, times));
1822 uid_t
1823 hc_geteuid(struct HostConf *hc)
1825 hctransaction_t trans;
1826 struct HCHead *head;
1827 struct HCLeaf *item;
1829 if (hc == NULL || hc->host == NULL)
1830 return (geteuid());
1832 if (hc->version < 3) {
1833 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1834 /* Return 0 on error, so the caller assumes root privileges. */
1835 return (0);
1838 trans = hcc_start_command(hc, HC_GETEUID);
1839 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1840 return(0);
1841 FOR_EACH_ITEM(item, trans, head) {
1842 if (item->leafid == LC_UID)
1843 return (HCC_INT32(item));
1845 return(0); /* shouldn't happen */
1848 static int
1849 rc_geteuid(hctransaction_t trans, struct HCHead *head __unused)
1851 hcc_leaf_int32(trans, LC_UID, geteuid());
1852 return (0);
1855 static int
1856 getmygroups(gid_t **gidlist)
1858 int count;
1860 if ((count = getgroups(0, *gidlist)) > 0) {
1861 if ((*gidlist = malloc(count * sizeof(gid_t))) != NULL) {
1862 if ((count = getgroups(count, *gidlist)) <= 0)
1863 free(*gidlist);
1865 else
1866 count = -1;
1868 else
1869 *gidlist = NULL;
1870 return (count);
1874 hc_getgroups(struct HostConf *hc, gid_t **gidlist)
1876 int count, i;
1877 hctransaction_t trans;
1878 struct HCHead *head;
1879 struct HCLeaf *item;
1881 if (hc == NULL || hc->host == NULL)
1882 return (getmygroups(gidlist));
1884 i = 0;
1885 count = 0;
1886 *gidlist = NULL;
1888 if (hc->version < 3) {
1889 fprintf(stderr, "WARNING: Remote client uses old protocol version\n");
1890 return (-1);
1893 trans = hcc_start_command(hc, HC_GETGROUPS);
1894 if ((head = hcc_finish_command(trans)) == NULL || head->error)
1895 return(-1);
1896 FOR_EACH_ITEM(item, trans, head) {
1897 switch(item->leafid) {
1898 case LC_COUNT:
1899 count = HCC_INT32(item);
1900 if (*gidlist != NULL) { /* protocol error */
1901 free(*gidlist);
1902 *gidlist = NULL;
1903 return (-1);
1905 if ((*gidlist = malloc(count * sizeof(gid_t))) == NULL)
1906 return (-1);
1907 break;
1908 case LC_GID:
1909 if (*gidlist == NULL || i >= count) { /* protocol error */
1910 if (*gidlist != NULL)
1911 free(*gidlist);
1912 *gidlist = NULL;
1913 return (-1);
1915 (*gidlist)[i++] = HCC_INT32(item);
1916 break;
1919 return (count);
1922 static int
1923 rc_getgroups(hctransaction_t trans, struct HCHead *head __unused)
1925 int count, i;
1926 gid_t *gidlist;
1928 if ((count = getmygroups(&gidlist)) < 0)
1929 return (-1);
1930 hcc_leaf_int32(trans, LC_COUNT, count);
1931 for (i = 0; i < count; i++)
1932 hcc_leaf_int32(trans, LC_GID, gidlist[i]);
1933 if (gidlist != NULL)
1934 free(gidlist);
1935 return (0);