1 /* $NetBSD: server.c,v 1.30 2006/12/18 15:14:42 christos Exp $ */
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)server.c 8.1 (Berkeley) 6/9/93";
37 __RCSID("$NetBSD: server.c,v 1.30 2006/12/18 15:14:42 christos Exp $");
41 #include <sys/types.h>
52 #define ack() do { if (write(rem, "\0\n", 2) < 0) error("ack failed: %s\n", strerror(errno)); } while (0)
53 #define err() do { if (write(rem, "\1\n", 2) < 0) error("err failed: %s\n", strerror(errno)); } while (0)
55 struct linkbuf
*ihead
; /* list of files with more than one link */
56 char buf
[BUFSIZ
]; /* general purpose buffer */
57 char target
[BUFSIZ
]; /* target/source directory name */
58 char *tp
; /* pointer to end of target name */
59 char *Tdest
; /* pointer to last T dest*/
60 char *Destcopy
; /* pointer to current dest */
61 int Destcopylen
; /* length of destination directory name */
62 int Sourcelen
; /* length of source directory name */
63 int catname
; /* cat name to target name */
64 char *stp
[32]; /* stack of saved tp's for directories */
65 int oumask
; /* old umask for creating files */
67 extern FILE *lfp
; /* log file for mailing changes */
69 static int chkparent(char *);
70 static void clean(char *);
71 static void comment(char *);
72 static void dospecial(char *);
73 static int fchtogm(int, char *, time_t, char *, char *, mode_t
);
74 static void hardlink(char *);
75 static void note(const char *, ...)
76 __attribute__((__format__(__printf__
, 1, 2)));
77 static void query(char *);
78 static void recvf(char *, int);
79 static void removeit(struct stat
*);
80 static int response(void);
81 static void rmchk(int);
82 static struct linkbuf
*
83 savelink(struct stat
*);
84 static void sendf(char *, int);
85 static int update(char *, int, struct stat
*);
88 * Server routine to read requests and process them.
90 * Tname - Transmit file if out of date
91 * Vname - Verify if file out of date or not
92 * Qname - Query if file exists. Return mtime & size if it does.
100 signal(SIGHUP
, cleanup
);
101 signal(SIGINT
, cleanup
);
102 signal(SIGQUIT
, cleanup
);
103 signal(SIGTERM
, cleanup
);
104 signal(SIGPIPE
, cleanup
);
108 (void) snprintf(buf
, sizeof(buf
), "V%d\n", VERSION
);
109 if (write(rem
, buf
, strlen(buf
)) < 0)
110 error("server: could not write remote end: %s\n",
115 if (read(rem
, cp
, 1) <= 0)
118 error("server: expected control record\n");
122 if (read(rem
, cp
, 1) != 1)
124 } while (*cp
++ != '\n' && cp
< &cmdbuf
[BUFSIZ
]);
128 case 'T': /* init target file/directory name */
129 catname
= 1; /* target should be directory */
132 case 't': /* init target file/directory name */
135 if (exptilde(target
, cp
) == NULL
)
143 case 'R': /* Transfer a regular file. */
147 case 'D': /* Transfer a directory. */
151 case 'K': /* Transfer symbolic link. */
155 case 'k': /* Transfer hard link. */
159 case 'E': /* End. (of directory) */
162 error("server: too many 'E's\n");
170 case 'C': /* Clean. Cleanup a directory */
174 case 'Q': /* Query. Does the file/directory exist? */
178 case 'S': /* Special. Execute commands */
184 * These entries are reserved but not currently used.
185 * The intent is to allow remote hosts to have master copies.
186 * Currently, only the host rdist runs on can have masters.
188 case 'X': /* start a new list of files to exclude */
190 case 'x': /* add name to list of files to exclude */
196 if (exptilde(buf
, cp
) == NULL
)
201 except
= bp
= expand(makeblock(NAME
, cp
), E_VARS
);
203 bp
->b_next
= expand(makeblock(NAME
, cp
), E_VARS
);
204 while (bp
->b_next
!= NULL
)
209 case 'I': /* Install. Transfer file if out of date. */
211 while (*cp
>= '0' && *cp
<= '7')
212 opts
= (opts
<< 3) | (*cp
++ - '0');
214 error("server: options not delimited\n");
220 case 'L': /* Log. save message in log file */
233 error("server: unknown command '%s'\n", cp
);
241 * Update the file(s) if they are different.
242 * destdir = 1 if destination should be a directory
243 * (i.e., more than one source is being copied to the same destination).
246 install(char *src
, char *dest
, int destdir
, int opts
)
249 char destcopy
[BUFSIZ
];
252 opts
&= ~WHOLE
; /* WHOLE mode only useful if renaming */
254 } else if (!(opts
& WHOLE
)) {
255 /* prepare for proper renaming of directory trees */
257 Destcopylen
= strlen(dest
);
258 while (Destcopylen
> 0 && dest
[Destcopylen
] == '/')
261 strlcpy(destcopy
, dest
, sizeof(destcopy
));
263 if (nflag
|| debug
) {
264 printf("%s%s%s%s%s %s %s\n", opts
& VERIFY
? "verify":"install",
265 opts
& WHOLE
? " -w" : "",
266 opts
& YOUNGER
? " -y" : "",
267 opts
& COMPARE
? " -b" : "",
268 opts
& REMOVE
? " -R" : "", src
, dest
);
273 rname
= exptilde(target
, src
);
280 /* We can only do this after expansion of src */
281 Sourcelen
= strlen(target
);
282 while (Sourcelen
> 0 && target
[Sourcelen
] == '/')
286 * If we are renaming a directory and we want to preserve
287 * the directory hierarchy (-w), we must strip off the leading
288 * directory name and preserve the rest.
291 while (*rname
== '/')
295 rname
= strrchr(target
, '/');
302 printf("target = %s, rname = %s\n", target
, rname
);
304 * Pass the destination file/directory name to remote.
306 (void) snprintf(buf
, sizeof(buf
), "%c%s\n", destdir
? 'T' : 't', dest
);
308 printf("buf = %s", buf
);
309 if (write(rem
, buf
, strlen(buf
)) < 0)
310 error("could not pass filename to remote: %s\n",
322 #define protoname() (pw ? pw->pw_name : user)
323 #define protogroup() (gr ? gr->gr_name : group)
325 * Transfer the file or directory in target[].
326 * rname is the name of the file on the remote host.
329 sendf(char *rname
, int opts
)
333 int sizerr
, f
, u
, len
;
338 extern struct subcmd
*subcmds
;
339 static char user
[15], group
[15];
342 printf("sendf(%s, %x)\n", rname
, opts
);
346 if ((opts
& FOLLOW
? stat(target
, &stb
) : lstat(target
, &stb
)) < 0) {
347 error("%s: %s\n", target
, strerror(errno
));
350 if ((u
= update(rname
, opts
, &stb
)) == 0) {
351 if (S_ISREG(stb
.st_mode
) && stb
.st_nlink
> 1)
352 (void) savelink(&stb
);
356 if (pw
== NULL
|| pw
->pw_uid
!= stb
.st_uid
)
357 if ((pw
= getpwuid(stb
.st_uid
)) == NULL
) {
358 dolog(lfp
, "%s: no password entry for uid %d \n",
361 (void)snprintf(user
, sizeof(user
), ":%lu",
364 if (gr
== NULL
|| gr
->gr_gid
!= stb
.st_gid
)
365 if ((gr
= getgrgid(stb
.st_gid
)) == NULL
) {
366 dolog(lfp
, "%s: no name for group %d\n",
369 (void)snprintf(group
, sizeof(group
), ":%lu",
374 dolog(lfp
, "need to install: %s\n", target
);
377 dolog(lfp
, "installing: %s\n", target
);
378 opts
&= ~(COMPARE
|REMOVE
);
381 switch (stb
.st_mode
& S_IFMT
) {
383 if ((d
= opendir(target
)) == NULL
) {
384 error("%s: %s\n", target
, strerror(errno
));
387 (void) snprintf(buf
, sizeof(buf
), "D%o %04o 0 0 %s %s %s\n",
388 opts
, stb
.st_mode
& 07777, protoname(), protogroup(),
391 printf("buf = %s", buf
);
392 if (write(rem
, buf
, strlen(buf
)) < 0)
393 error("can not write dir spec to remote: %s\n",
396 if (response() < 0) {
406 while ((dp
= readdir(d
)) != NULL
) {
407 if (!strcmp(dp
->d_name
, ".") ||
408 !strcmp(dp
->d_name
, ".."))
410 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
411 error("%s/%s: Name too long\n", target
,
418 while ((*tp
++ = *cp
++) != 0)
421 sendf(dp
->d_name
, opts
);
424 if (write(rem
, "E\n", 2) < 0)
425 error("can not write E to remote: %s\n",
435 if (stb
.st_nlink
> 1) {
438 if ((lp
= savelink(&stb
)) != NULL
) {
440 if (*lp
->target
== 0)
441 (void) snprintf(buf
, sizeof(buf
),
442 "k%o %s %s\n", opts
, lp
->pathname
, rname
);
444 (void) snprintf(buf
, sizeof(buf
),
445 "k%o %s/%s %s\n", opts
, lp
->target
,
446 lp
->pathname
, rname
);
448 printf("buf = %s", buf
);
449 if (write(rem
, buf
, strlen(buf
)) < 0)
450 error("can not write link spec to remote: %s\n",
456 (void) snprintf(buf
, sizeof(buf
), "K%o %o %lld %ld %s %s %s\n",
457 opts
, stb
.st_mode
& 07777, (unsigned long long)stb
.st_size
,
458 (u_long
)stb
.st_mtime
, protoname(), protogroup(), rname
);
460 printf("buf = %s", buf
);
461 if (write(rem
, buf
, strlen(buf
)) < 0)
462 error("can not write link spec to remote: %s\n",
466 sizerr
= (readlink(target
, buf
, BUFSIZ
) != stb
.st_size
);
467 if (write(rem
, buf
, stb
.st_size
) < 0)
468 error("can not write link name to remote: %s\n",
471 printf("readlink = %.*s\n", (int)stb
.st_size
, buf
);
478 error("%s: not a file or directory\n", target
);
484 dolog(lfp
, "need to update: %s\n", target
);
487 dolog(lfp
, "updating: %s\n", target
);
490 if (stb
.st_nlink
> 1) {
493 if ((lp
= savelink(&stb
)) != NULL
) {
495 if (*lp
->target
== 0)
496 (void) snprintf(buf
, sizeof(buf
), "k%o %s %s\n", opts
,
497 lp
->pathname
, rname
);
499 (void) snprintf(buf
, sizeof(buf
), "k%o %s/%s %s\n",
500 opts
, lp
->target
, lp
->pathname
, rname
);
502 printf("buf = %s", buf
);
503 if (write(rem
, buf
, strlen(buf
)) <0)
504 error("write of file name failed: %s\n",
511 if ((f
= open(target
, O_RDONLY
, 0)) < 0) {
512 error("%s: %s\n", target
, strerror(errno
));
515 (void)snprintf(buf
, sizeof(buf
), "R%o %o %lld %lu %s %s %s\n", opts
,
516 stb
.st_mode
& 07777, (unsigned long long)stb
.st_size
,
517 (u_long
)stb
.st_mtime
, protoname(), protogroup(), rname
);
519 printf("buf = %s", buf
);
520 if (write(rem
, buf
, strlen(buf
)) < 0)
521 error("write of file name failed: %s\n", strerror(errno
));
522 if (response() < 0) {
527 for (i
= 0; i
< stb
.st_size
; i
+= BUFSIZ
) {
529 if (i
+ amt
> stb
.st_size
)
530 amt
= stb
.st_size
- i
;
531 if (sizerr
== 0 && read(f
, buf
, amt
) != amt
)
533 if (write(rem
, buf
, amt
) < 0)
534 error("write of file data failed: %s\n", strerror(errno
));
539 error("%s: file changed size\n", target
);
544 if (f
< 0 || (f
== 0 && (opts
& COMPARE
)))
547 for (sc
= subcmds
; sc
!= NULL
; sc
= sc
->sc_next
) {
548 if (sc
->sc_type
!= SPECIAL
)
550 if (sc
->sc_args
!= NULL
&& !inlist(sc
->sc_args
, target
))
552 dolog(lfp
, "special \"%s\"\n", sc
->sc_name
);
555 (void) snprintf(buf
, sizeof(buf
), "SFILE=%s;%s\n", target
,
558 printf("buf = %s", buf
);
559 if (write(rem
, buf
, strlen(buf
)) < 0)
560 error("write of special failed: %s\n", strerror(errno
));
561 while (response() > 0)
566 static struct linkbuf
*
567 savelink(struct stat
*st
)
571 for (lp
= ihead
; lp
!= NULL
; lp
= lp
->nextp
)
572 if (lp
->inum
== st
->st_ino
&& lp
->devnum
== st
->st_dev
) {
576 lp
= (struct linkbuf
*) malloc(sizeof(*lp
));
578 dolog(lfp
, "out of memory, link information lost\n");
582 lp
->inum
= st
->st_ino
;
583 lp
->devnum
= st
->st_dev
;
584 lp
->count
= st
->st_nlink
- 1;
587 * Change the starting directory of target
588 * into the destination directory
590 strncpy(lp
->pathname
, Destcopy
, Destcopylen
);
591 strlcpy(lp
->pathname
+ Destcopylen
, target
+ Sourcelen
, sizeof(lp
->pathname
) - Destcopylen
);
593 strlcpy(lp
->pathname
, target
, sizeof(lp
->pathname
));
595 strlcpy(lp
->target
, Tdest
, sizeof(lp
->target
));
603 * Check to see if file needs to be updated on the remote machine.
604 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
605 * and 3 if comparing binaries to determine if out of date.
608 update(char *rname
, int opts
, struct stat
*st
)
615 printf("update(%s, %lx, %lx)\n", rname
, (long)opts
, (long)st
);
618 * Check to see if the file exists on the remote machine.
620 (void) snprintf(buf
, sizeof(buf
), "Q%s\n", rname
);
622 printf("buf = %s", buf
);
623 if (write(rem
, buf
, strlen(buf
)) < 0)
624 error("write to remote failed: %s\n", strerror(errno
));
628 if (read(rem
, cp
, 1) != 1)
630 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
636 case 'N': /* file doesn't exist so install it */
644 (void) write(2, s
, cp
- s
);
647 (void) fwrite(s
, 1, cp
- s
, lfp
);
654 dolog(lfp
, "update: note: %s\n", s
);
659 error("update: unexpected response '%s'\n", s
);
670 while (isdigit((unsigned char)*s
))
671 size
= size
* 10 + (*s
++ - '0');
673 error("update: size not delimited\n");
677 while (isdigit((unsigned char)*s
))
678 mtime
= mtime
* 10 + (*s
++ - '0');
680 error("update: mtime not delimited\n");
684 * File needs to be updated?
686 if (opts
& YOUNGER
) {
687 if (st
->st_mtime
== mtime
)
689 if (st
->st_mtime
< mtime
) {
690 dolog(lfp
, "Warning: %s: remote copy is newer\n",
694 } else if (st
->st_mtime
== mtime
&& st
->st_size
== size
)
700 * Query. Check to see if file exists. Return one of the following:
701 * N\n - doesn't exist
702 * Ysize mtime\n - exists and its a regular file (size & mtime of file)
703 * Y\n - exists and its a directory or symbolic link
712 (void) snprintf(tp
, sizeof(target
) - (tp
- target
),
715 if (lstat(target
, &stb
) < 0) {
716 if (errno
== ENOENT
) {
717 if (write(rem
, "N\n", 2) < 0)
718 error("write to remote failed: %s\n",
721 error("%s:%s: %s\n", host
, target
, strerror(errno
));
726 switch (stb
.st_mode
& S_IFMT
) {
728 (void)snprintf(buf
, sizeof(buf
), "Y%lld %ld\n",
729 (unsigned long long)stb
.st_size
, (u_long
)stb
.st_mtime
);
730 if (write(rem
, buf
, strlen(buf
)) < 0)
731 error("write to remote failed: %s\n", strerror(errno
));
736 if (write(rem
, "Y\n", 2) < 0)
737 error("write to remote failed: %s\n", strerror(errno
));
741 error("%s: not a file or directory\n", name
);
748 recvf(char *cmd
, int type
)
751 int f
= -1, opts
= 0, wrerr
, olderrno
;
758 extern char *tempname
;
760 while (*cp
>= '0' && *cp
<= '7')
761 opts
= (opts
<< 3) | (*cp
++ - '0');
763 error("recvf: options not delimited\n");
767 while (*cp
>= '0' && *cp
<= '7')
768 mode
= (mode
<< 3) | (*cp
++ - '0');
770 error("recvf: mode not delimited\n");
774 while (isdigit((unsigned char)*cp
))
775 size
= size
* 10 + (*cp
++ - '0');
777 error("recvf: size not delimited\n");
781 while (isdigit((unsigned char)*cp
))
782 mtime
= mtime
* 10 + (*cp
++ - '0');
784 error("recvf: mtime not delimited\n");
788 while (*cp
&& *cp
!= ' ')
791 error("recvf: owner name not delimited\n");
796 while (*cp
&& *cp
!= ' ')
799 error("recvf: group name not delimited\n");
804 if (type
== S_IFDIR
) {
805 if (catname
>= (int)sizeof(stp
)) {
806 error("%s:%s: too many directory levels\n",
813 while ((*tp
++ = *cp
++) != 0)
821 if (lstat(target
, &stb
) == 0) {
822 if (S_ISDIR(stb
.st_mode
)) {
823 if ((stb
.st_mode
& 07777) == mode
) {
828 (void) snprintf(buf
+ 1, sizeof(buf
) - 1,
829 "%s: Warning: remote mode %o != local mode %o\n",
830 target
, stb
.st_mode
& 07777, mode
);
831 if (write(rem
, buf
, strlen(buf
+ 1) + 1) < 0)
832 error("write to remote failed: %s\n",
837 } else if ((errno
== ENOENT
&& mkdir(target
, mode
) == 0) ||
838 (chkparent(target
) == 0 && mkdir(target
, mode
) == 0)) {
839 if (fchtogm(-1, target
, mtime
, owner
, group
, mode
) == 0)
843 error("%s:%s: %s\n", host
, target
, strerror(errno
));
850 (void) snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
851 cp
= strrchr(target
, '/');
853 strlcpy(new, tempname
, sizeof(new));
854 else if (cp
== target
)
855 (void) snprintf(new, sizeof(new), "/%s", tempname
);
858 (void) snprintf(new, sizeof(new), "%s/%s", target
, tempname
);
862 if (type
== S_IFLNK
) {
867 for (i
= 0; i
< size
; i
+= j
) {
868 if ((j
= read(rem
, cp
, size
- i
)) <= 0)
873 if (response() < 0) {
877 if (symlink(buf
, new) < 0) {
878 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
879 symlink(buf
, new) < 0)
883 if (opts
& COMPARE
) {
886 if ((i
= readlink(target
, tbuf
, BUFSIZ
)) >= 0 &&
887 i
== size
&& strncmp(buf
, tbuf
, size
) == 0) {
898 if ((f
= creat(new, mode
)) < 0) {
899 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
900 (f
= creat(new, mode
)) < 0)
906 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
913 int j
= read(rem
, cp
, amt
);
926 if (wrerr
== 0 && write(f
, buf
, amt
) != amt
) {
931 if (response() < 0) {
937 if (opts
& COMPARE
) {
941 if ((f1
= fopen(target
, "r")) == NULL
)
943 if ((f2
= fopen(new, "r")) == NULL
) {
944 badnew1
: error("%s:%s: %s\n", host
, new, strerror(errno
));
947 while ((c
= getc(f1
)) == getc(f2
))
957 differ
: buf
[0] = '\0';
958 (void)snprintf(buf
+ 1, sizeof(buf
) - 1,
959 "need to update: %s\n",target
);
960 (void) write(rem
, buf
, strlen(buf
+ 1) + 1);
965 if (fchtogm(f
, new, mtime
, owner
, group
, mode
) < 0) {
974 fixup
: if (rename(new, target
) < 0) {
975 badtarget
: error("%s:%s: %s\n", host
, target
, strerror(errno
));
980 if (opts
& COMPARE
) {
982 (void) snprintf(buf
+ 1, sizeof(buf
) - 1,
983 "updated %s\n", target
);
984 (void) write(rem
, buf
, strlen(buf
+ 1) + 1);
990 * Creat a hard link to existing file.
998 int opts
, exists
= 0;
1002 while (*cp
>= '0' && *cp
<= '7')
1003 opts
= (opts
<< 3) | (*cp
++ - '0');
1005 error("hardlink: options not delimited\n");
1009 while (*cp
&& *cp
!= ' ')
1012 error("hardlink: oldname name not delimited\n");
1018 (void) snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
1020 if (lstat(target
, &stb
) == 0) {
1021 if (!S_ISREG(stb
.st_mode
) && !S_ISLNK(stb
.st_mode
)) {
1022 error("%s: %s: not a regular file\n", host
, target
);
1027 if (chkparent(target
) < 0 ) {
1028 error("%s:%s: %s (no parent)\n",
1029 host
, target
, strerror(errno
));
1032 if (exists
&& (unlink(target
) < 0)) {
1033 error("%s:%s: %s (unlink)\n",
1034 host
, target
, strerror(errno
));
1037 if (link(oldname
, target
) < 0) {
1038 error("%s:can't link %s to %s\n",
1039 host
, target
, oldname
);
1046 * Check to see if parent directory exists and create one if not.
1049 chkparent(char *name
)
1054 cp
= strrchr(name
, '/');
1055 if (cp
== NULL
|| cp
== name
)
1058 if (lstat(name
, &stb
) < 0) {
1059 if (errno
== ENOENT
&& chkparent(name
) >= 0 &&
1060 mkdir(name
, 0777 & ~oumask
) >= 0) {
1064 } else if (S_ISDIR(stb
.st_mode
)) {
1073 * Change owner, group and mode of file.
1076 fchtogm(int fd
, char *file
, time_t mtime
, char *owner
, char *group
, __mode_t mode
)
1079 struct timeval tv
[2];
1086 if (*owner
== ':') {
1087 uid
= atoi(owner
+ 1);
1088 } else if (pw
== NULL
|| strcmp(owner
, pw
->pw_name
) != 0) {
1089 if ((pw
= getpwnam(owner
)) == NULL
) {
1091 note("%s:%s: unknown login name, clearing setuid",
1100 if (*group
== ':') {
1101 gid
= atoi(group
+ 1);
1104 } else if ((mode
& 04000) && strcmp(user
, owner
) != 0)
1107 if (gr
== NULL
|| strcmp(group
, gr
->gr_name
) != 0) {
1108 if ((*group
== ':' && (getgrgid(gid
= atoi(group
+ 1)) == NULL
))
1109 || ((gr
= getgrnam(group
)) == NULL
)) {
1111 note("%s:%s: unknown group", host
, group
);
1118 if (userid
&& gid
!= (gid_t
)-1) {
1119 if (gr
) for (i
= 0; gr
->gr_mem
[i
] != NULL
; i
++)
1120 if (!(strcmp(user
, gr
->gr_mem
[i
])))
1126 (void) gettimeofday(&tv
[0], (struct timezone
*)0);
1127 tv
[1].tv_sec
= mtime
;
1129 if (fd
!= -1 ? futimes(fd
, tv
) < 0 : utimes(file
, tv
) < 0)
1130 note("%s: %s utimes: %s", host
, file
, strerror(errno
));
1131 if (fd
!= -1 ? fchown(fd
, uid
, gid
) < 0 : chown(file
, uid
, gid
) < 0)
1132 note("%s: %s chown: %s", host
, file
, strerror(errno
));
1133 else if (mode
& 07000 &&
1134 (fd
!= -1 ? fchmod(fd
, mode
) < 0 : chmod(file
, mode
) < 0))
1135 note("%s: %s chmod: %s", host
, file
, strerror(errno
));
1140 * Check for files on the machine being updated that are not on the master
1141 * machine and remove them.
1150 printf("rmchk()\n");
1153 * Tell the remote to clean the files from the last directory sent.
1155 (void) snprintf(buf
, sizeof(buf
), "C%o\n", opts
& VERIFY
);
1157 printf("buf = %s", buf
);
1158 (void) write(rem
, buf
, strlen(buf
));
1164 if (read(rem
, cp
, 1) != 1)
1166 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1169 case 'Q': /* Query if file should be removed */
1171 * Return the following codes to remove query.
1172 * N\n -- file exists - DON'T remove.
1173 * Y\n -- file doesn't exist - REMOVE.
1176 (void) snprintf(tp
, sizeof(target
) - (tp
- target
),
1179 printf("check %s\n", target
);
1181 (void) write(rem
, "N\n", 2);
1182 else if (lstat(target
, &stb
) < 0)
1183 (void) write(rem
, "Y\n", 2);
1185 (void) write(rem
, "N\n", 2);
1191 dolog(lfp
, "%s\n", s
);
1205 (void) write(2, s
, cp
- s
);
1208 (void) fwrite(s
, 1, cp
- s
, lfp
);
1215 error("rmchk: unexpected response '%s'\n", buf
);
1222 * Check the current directory (initialized by the 'T' command to server())
1223 * for extraneous files and remove them.
1235 while (*cp
>= '0' && *cp
<= '7')
1236 opts
= (opts
<< 3) | (*cp
++ - '0');
1238 error("clean: options not delimited\n");
1241 if ((d
= opendir(target
)) == NULL
) {
1242 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1249 while ((dp
= readdir(d
)) != NULL
) {
1250 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1252 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1253 error("%s:%s/%s: Name too long\n",
1254 host
, target
, dp
->d_name
);
1260 while ((*tp
++ = *cp
++) != 0)
1263 if (lstat(target
, &stb
) < 0) {
1264 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1267 (void) snprintf(buf
, sizeof(buf
), "Q%s\n", dp
->d_name
);
1268 (void) write(rem
, buf
, strlen(buf
));
1271 if (read(rem
, cp
, 1) != 1)
1273 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1278 if (opts
& VERIFY
) {
1281 (void) snprintf(cp
, sizeof(buf
) - 1,
1282 "need to remove: %s\n", target
);
1283 (void) write(rem
, buf
, strlen(cp
) + 1);
1288 (void) write(rem
, "E\n", 2);
1295 * Remove a file or directory (recursively) and send back an acknowledge
1296 * or an error message.
1299 removeit(struct stat
*st
)
1308 switch (st
->st_mode
& S_IFMT
) {
1311 if (unlink(target
) < 0)
1319 error("%s:%s: not a plain file\n", host
, target
);
1323 if ((d
= opendir(target
)) == NULL
)
1328 while ((dp
= readdir(d
)) != NULL
) {
1329 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1331 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1332 error("%s:%s/%s: Name too long\n",
1333 host
, target
, dp
->d_name
);
1339 while ((*tp
++ = *cp
++) != 0)
1342 if (lstat(target
, &stb
) < 0) {
1343 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1351 if (rmdir(target
) < 0) {
1353 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1359 (void) snprintf(cp
, sizeof(buf
) - 1, "removed %s\n", target
);
1360 (void) write(rem
, buf
, strlen(cp
) + 1);
1364 * Execute a shell command to handle special cases.
1367 dospecial(char *cmd
)
1369 int fd
[2], status
, pid
, i
;
1374 error("%s\n", strerror(errno
));
1377 if ((pid
= fork()) == 0) {
1379 * Return everything the shell commands print.
1384 (void) open(_PATH_DEVNULL
, O_RDONLY
);
1387 (void) close(fd
[0]);
1388 (void) close(fd
[1]);
1391 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1394 (void) close(fd
[1]);
1397 while ((i
= read(fd
[0], buf
, sizeof(buf
))) > 0) {
1401 if (cp
[-1] != '\n') {
1402 if (s
< &sbuf
[sizeof(sbuf
)-1])
1407 * Throw away blank lines.
1409 if (s
== &sbuf
[2]) {
1413 (void) write(rem
, sbuf
, s
- sbuf
);
1419 (void) write(rem
, sbuf
, s
- sbuf
);
1421 while ((i
= wait(&status
)) != pid
&& i
!= -1)
1425 (void) close(fd
[0]);
1427 error("shell returned %d\n", status
);
1434 dolog(FILE *fp
, const char *fmt
, ...)
1438 /* Print changes locally if not quiet mode */
1441 (void)vprintf(fmt
, ap
);
1445 /* Save changes (for mailing) if really updating files */
1446 if (!(options
& VERIFY
) && fp
!= NULL
) {
1448 (void)vfprintf(fp
, fmt
, ap
);
1454 error(const char *fmt
, ...)
1460 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1464 (void)fprintf(fp
, "%crdist: ", 0x01);
1465 (void)vfprintf(fp
, fmt
, ap
);
1470 (void)fprintf(stderr
, "rdist: ");
1471 (void)vfprintf(stderr
, fmt
, ap
);
1476 (void)fprintf(lfp
, "rdist: ");
1478 (void)vfprintf(lfp
, fmt
, ap
);
1485 fatal(const char *fmt
, ...)
1491 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1495 (void)fprintf(fp
, "%crdist: ", 0x02);
1496 (void)vfprintf(fp
, fmt
, ap
);
1501 (void)fprintf(stderr
, "rdist: ");
1502 (void)vfprintf(stderr
, fmt
, ap
);
1507 (void)fprintf(lfp
, "rdist: ");
1509 (void)vfprintf(lfp
, fmt
, ap
);
1523 printf("response()\n");
1527 if (read(rem
, cp
, 1) != 1)
1529 } while (*cp
++ != '\n' && cp
< &resp
[BUFSIZ
]);
1535 dolog(lfp
, "%s\n", s
);
1541 dolog(lfp
, "Note: %s\n",s
);
1553 (void) write(2, s
, cp
- s
);
1556 (void) fwrite(s
, 1, cp
- s
, lfp
);
1558 if (resp
[0] == '\2')
1565 * Remove temporary files and do any cleanup operations before exiting.
1569 cleanup(int signo __unused
)
1571 (void) unlink(tempfile
);
1576 note(const char *fmt
, ...)
1578 static char nbuf
[BUFSIZ
];
1582 (void)vsnprintf(nbuf
, sizeof(nbuf
), fmt
, ap
);
1594 write(rem
, s
, strlen(s
));