2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * @(#)server.c 8.1 (Berkeley) 6/9/93
30 * $FreeBSD: src/usr.bin/rdist/server.c,v 1.10 1999/08/28 01:05:09 peter Exp $
39 #define ack() write(rem, "\0\n", 2)
40 #define err() write(rem, "\1\n", 2)
41 #define protoname() (pw ? pw->pw_name : user)
42 #define protogroup() (gr ? gr->gr_name : group)
44 struct linkbuf
*ihead
= NULL
; /* list of files with more than one link */
45 char buf
[BUFSIZ
]; /* general purpose buffer */
46 char target
[BUFSIZ
]; /* target/source directory name */
47 char source
[BUFSIZ
]; /* source directory name */
48 char *tp
; /* pointer to end of target name */
49 char *Tdest
; /* pointer to last T dest*/
50 int catname
; /* cat name to target name */
51 char *stp
[32]; /* stack of saved tp's for directories */
52 int oumask
; /* old umask for creating files */
54 extern FILE *lfp
; /* log file for mailing changes */
56 static int chkparent(char *);
57 static void clean(char *);
58 static void comment(char *);
59 static void dospecial(char *);
60 static int fchog(int, char *, char *, char *, int);
61 static void hardlink(char *);
62 static void note(const char *, ...) __printflike(1, 2);
63 static void query(char *);
64 static void recvf(char *, int);
65 static void removeit(struct stat
*);
66 static int response(void);
67 static void rmchk(int);
68 static struct linkbuf
*savelink(struct stat
*);
69 static void sendf(char *, int);
70 static int update(char *, int, struct stat
*);
73 * Server routine to read requests and process them.
75 * Tname - Transmit file if out of date
76 * Vname - Verify if file out of date or not
77 * Qname - Query if file exists. Return mtime & size if it does.
85 signal(SIGHUP
, cleanup
);
86 signal(SIGINT
, cleanup
);
87 signal(SIGQUIT
, cleanup
);
88 signal(SIGTERM
, cleanup
);
89 signal(SIGPIPE
, cleanup
);
93 snprintf(buf
, sizeof(buf
), "V%d\n", VERSION
);
94 write(rem
, buf
, strlen(buf
));
98 if (read(rem
, cp
, 1) <= 0)
101 error("server: expected control record\n");
105 if (read(rem
, cp
, 1) != 1)
107 } while (*cp
++ != '\n' && cp
< &cmdbuf
[BUFSIZ
]);
111 case 'T': /* init target file/directory name */
112 catname
= 1; /* target should be directory */
115 case 't': /* init target file/directory name */
118 if (exptilde(target
, cp
, sizeof(target
)) == NULL
)
126 case 'R': /* Transfer a regular file. */
130 case 'D': /* Transfer a directory. */
134 case 'K': /* Transfer symbolic link. */
138 case 'k': /* Transfer hard link. */
142 case 'E': /* End. (of directory) */
145 error("server: too many 'E's\n");
153 case 'C': /* Clean. Cleanup a directory */
157 case 'Q': /* Query. Does the file/directory exist? */
161 case 'S': /* Special. Execute commands */
167 * These entries are reserved but not currently used.
168 * The intent is to allow remote hosts to have master copies.
169 * Currently, only the host rdist runs on can have masters.
171 case 'X': /* start a new list of files to exclude */
173 case 'x': /* add name to list of files to exclude */
179 if (exptilde(buf
, cp
, sizeof(buf
)) == NULL
)
184 except
= bp
= expand(makeblock(NAME
, cp
), E_VARS
);
186 bp
->b_next
= expand(makeblock(NAME
, cp
), E_VARS
);
187 while (bp
->b_next
!= NULL
)
192 case 'I': /* Install. Transfer file if out of date. */
194 while (*cp
>= '0' && *cp
<= '7')
195 opts
= (opts
<< 3) | (*cp
++ - '0');
197 error("server: options not delimited\n");
203 case 'L': /* Log. save message in log file */
216 error("server: unknown command '%s'\n", cp
);
224 * Update the file(s) if they are different.
225 * destdir = 1 if destination should be a directory
226 * (i.e., more than one source is being copied to the same destination).
229 install(char *src
, char *dest
, int destdir
, int opts
)
232 char destcopy
[BUFSIZ
];
240 opts
&= ~WHOLE
; /* WHOLE mode only useful if renaming */
244 if (nflag
|| debug
) {
245 printf("%s%s%s%s%s %s %s\n", opts
& VERIFY
? "verify":"install",
246 opts
& WHOLE
? " -w" : "",
247 opts
& YOUNGER
? " -y" : "",
248 opts
& COMPARE
? " -b" : "",
249 opts
& REMOVE
? " -R" : "", src
, dest
);
254 rname
= exptilde(target
, src
, sizeof(target
));
261 * If we are renaming a directory and we want to preserve
262 * the directory heirarchy (-w), we must strip off the leading
263 * directory name and preserve the rest.
266 while (*rname
== '/')
270 rname
= rindex(target
, '/');
277 printf("target = %s, rname = %s\n", target
, rname
);
279 * Pass the destination file/directory name to remote.
281 snprintf(buf
, sizeof(buf
), "%c%s\n", destdir
? 'T' : 't', dest
);
283 printf("buf = %s", buf
);
284 write(rem
, buf
, strlen(buf
));
289 * Save the name of the remote target destination if we are
290 * in WHOLE mode (destdir > 0) or if the source and destination
291 * are not the same. This info will be used later for maintaining
294 if (destdir
|| (src
&& dest
&& strcmp(src
, dest
))) {
295 strcpy(destcopy
, dest
);
303 remotename(char *pathname
, char *src
)
310 if (0 == strncmp(pathname
, src
, len
))
318 installlink(struct linkbuf
*lp
, char *rname
, int opts
)
320 if (*lp
->target
== 0)
321 snprintf(buf
, sizeof(buf
), "k%o %s %s\n", opts
, lp
->pathname
, rname
);
323 snprintf(buf
, sizeof(buf
), "k%o %s/%s %s\n", opts
, lp
->target
,
324 remotename(lp
->pathname
, lp
->src
), rname
);
327 printf("lp->src = %s\n", lp
->src
);
328 printf("lp->target = %s\n", lp
->target
);
329 printf("lp->pathname = %s\n", lp
->pathname
);
330 printf("rname = %s\n", rname
);
331 printf("buf = %s", buf
);
333 write(rem
, buf
, strlen(buf
));
338 * Transfer the file or directory in target[].
339 * rname is the name of the file on the remote host.
342 sendf(char *rname
, int opts
)
346 int sizerr
, f
, u
, len
;
351 extern struct subcmd
*subcmds
;
352 static char user
[15], group
[15];
355 printf("sendf(%s, %x)\n", rname
, opts
);
359 if ((opts
& FOLLOW
? stat(target
, &stb
) : lstat(target
, &stb
)) < 0) {
360 error("%s: %s\n", target
, strerror(errno
));
363 if ((u
= update(rname
, opts
, &stb
)) == 0) {
364 if ((stb
.st_mode
& S_IFMT
) == S_IFREG
&& stb
.st_nlink
> 1)
369 if (pw
== NULL
|| pw
->pw_uid
!= stb
.st_uid
)
370 if ((pw
= getpwuid(stb
.st_uid
)) == NULL
) {
371 dolog(lfp
, "%s: no password entry for uid %d \n",
374 snprintf(user
, sizeof(user
), ":%u", stb
.st_uid
);
376 if (gr
== NULL
|| gr
->gr_gid
!= stb
.st_gid
)
377 if ((gr
= getgrgid(stb
.st_gid
)) == NULL
) {
378 dolog(lfp
, "%s: no name for group %d\n",
381 snprintf(group
, sizeof(group
), ":%u", stb
.st_gid
);
385 dolog(lfp
, "need to install: %s\n", target
);
388 dolog(lfp
, "installing: %s\n", target
);
389 opts
&= ~(COMPARE
|REMOVE
);
392 switch (stb
.st_mode
& S_IFMT
) {
394 if ((d
= opendir(target
)) == NULL
) {
395 error("%s: %s\n", target
, strerror(errno
));
398 snprintf(buf
, sizeof(buf
), "D%o %04o 0 0 %s %s %s\n",
399 opts
, stb
.st_mode
& 07777, protoname(), protogroup(),
402 printf("buf = %s", buf
);
403 write(rem
, buf
, strlen(buf
));
404 if (response() < 0) {
414 while ((dp
= readdir(d
))) {
415 if (!strcmp(dp
->d_name
, ".") ||
416 !strcmp(dp
->d_name
, ".."))
418 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
419 error("%s/%s: Name too long\n", target
,
426 while ((*tp
++ = *cp
++))
429 sendf(dp
->d_name
, opts
);
432 write(rem
, "E\n", 2);
441 if (stb
.st_nlink
> 1) {
444 if ((lp
= savelink(&stb
)) != NULL
) {
445 installlink(lp
, rname
, opts
);
449 snprintf(buf
, sizeof(buf
),
450 "K%o %o %jd %ld %s %s %s\n", opts
,
451 stb
.st_mode
& 07777, (intmax_t)stb
.st_size
, stb
.st_mtime
,
452 protoname(), protogroup(), rname
);
454 printf("buf = %s", buf
);
455 write(rem
, buf
, strlen(buf
));
458 sizerr
= (readlink(target
, buf
, BUFSIZ
- 1) != stb
.st_size
);
459 write(rem
, buf
, stb
.st_size
);
461 printf("readlink = %.*s\n", (int)stb
.st_size
, buf
);
468 error("%s: not a file or directory\n", target
);
474 dolog(lfp
, "need to update: %s\n", target
);
477 dolog(lfp
, "updating: %s\n", target
);
480 if (stb
.st_nlink
> 1) {
483 if ((lp
= savelink(&stb
)) != NULL
) {
484 installlink(lp
, rname
, opts
);
489 if ((f
= open(target
, O_RDONLY
, 0)) < 0) {
490 error("%s: %s\n", target
, strerror(errno
));
493 snprintf(buf
, sizeof(buf
), "R%o %o %jd %ld %s %s %s\n", opts
,
494 stb
.st_mode
& 07777, (intmax_t)stb
.st_size
, stb
.st_mtime
,
495 protoname(), protogroup(), rname
);
497 printf("buf = %s", buf
);
498 write(rem
, buf
, strlen(buf
));
499 if (response() < 0) {
504 for (i
= 0; i
< stb
.st_size
; i
+= BUFSIZ
) {
506 if (i
+ amt
> stb
.st_size
)
507 amt
= stb
.st_size
- i
;
508 if (sizerr
== 0 && read(f
, buf
, amt
) != amt
)
510 write(rem
, buf
, amt
);
515 error("%s: file changed size\n", target
);
520 if (f
< 0 || (f
== 0 && (opts
& COMPARE
)))
523 for (sc
= subcmds
; sc
!= NULL
; sc
= sc
->sc_next
) {
524 if (sc
->sc_type
!= SPECIAL
)
526 if (sc
->sc_args
!= NULL
&& !inlist(sc
->sc_args
, target
))
528 dolog(lfp
, "special \"%s\"\n", sc
->sc_name
);
531 snprintf(buf
, sizeof(buf
), "SFILE=%s;%s\n", target
,
534 printf("buf = %s", buf
);
535 write(rem
, buf
, strlen(buf
));
536 while (response() > 0)
541 static struct linkbuf
*
542 savelink(struct stat
*stp
)
546 for (lp
= ihead
; lp
!= NULL
; lp
= lp
->nextp
)
547 if (lp
->inum
== stp
->st_ino
&& lp
->devnum
== stp
->st_dev
) {
551 lp
= (struct linkbuf
*) malloc(sizeof(*lp
));
553 dolog(lfp
, "out of memory, link information lost\n");
557 lp
->inum
= stp
->st_ino
;
558 lp
->devnum
= stp
->st_dev
;
559 lp
->count
= stp
->st_nlink
- 1;
560 strcpy(lp
->pathname
, target
);
561 strcpy(lp
->src
, source
);
563 strcpy(lp
->target
, Tdest
);
571 * Check to see if file needs to be updated on the remote machine.
572 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
573 * and 3 if comparing binaries to determine if out of date.
576 update(char *rname
, int opts
, struct stat
*stp
)
583 printf("update(%s, %x, %p)\n", rname
, opts
, stp
);
586 * Check to see if the file exists on the remote machine.
588 snprintf(buf
, sizeof(buf
), "Q%s\n", rname
);
590 printf("buf = %s", buf
);
591 write(rem
, buf
, strlen(buf
));
595 if (read(rem
, cp
, 1) != 1)
597 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
603 case 'N': /* file doesn't exist so install it */
614 fwrite(s
, 1, cp
- s
, lfp
);
621 dolog(lfp
, "update: note: %s\n", s
);
626 error("update: unexpected response '%s'\n", s
);
638 size
= size
* 10 + (*s
++ - '0');
640 error("update: size not delimited\n");
645 mtime
= mtime
* 10 + (*s
++ - '0');
647 error("update: mtime not delimited\n");
651 * File needs to be updated?
653 if (opts
& YOUNGER
) {
654 if (stp
->st_mtime
== mtime
)
656 if (stp
->st_mtime
< mtime
) {
657 dolog(lfp
, "Warning: %s: remote copy is newer\n", target
);
660 } else if (stp
->st_mtime
== mtime
&& stp
->st_size
== size
)
666 * Query. Check to see if file exists. Return one of the following:
667 * N\n - doesn't exist
668 * Ysize mtime\n - exists and its a regular file (size & mtime of file)
669 * Y\n - exists and its a directory or symbolic link
678 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s",
681 if (lstat(target
, &stb
) < 0) {
683 write(rem
, "N\n", 2);
685 error("%s:%s: %s\n", host
, target
, strerror(errno
));
690 switch (stb
.st_mode
& S_IFMT
) {
692 snprintf(buf
, sizeof(buf
), "Y%jd %ld\n", (intmax_t)stb
.st_size
,
694 write(rem
, buf
, strlen(buf
));
699 write(rem
, "Y\n", 2);
703 error("%s: not a file or directory\n", name
);
710 recvf(char *cmd
, int type
)
713 int f
, mode
, opts
, wrerr
, olderrno
;
717 struct timeval tvp
[2];
720 extern char *tempname
;
725 while (*cp
>= '0' && *cp
<= '7')
726 opts
= (opts
<< 3) | (*cp
++ - '0');
728 error("recvf: options not delimited\n");
732 while (*cp
>= '0' && *cp
<= '7')
733 mode
= (mode
<< 3) | (*cp
++ - '0');
735 error("recvf: mode not delimited\n");
740 size
= size
* 10 + (*cp
++ - '0');
742 error("recvf: size not delimited\n");
747 mtime
= mtime
* 10 + (*cp
++ - '0');
749 error("recvf: mtime not delimited\n");
753 while (*cp
&& *cp
!= ' ')
756 error("recvf: owner name not delimited\n");
761 while (*cp
&& *cp
!= ' ')
764 error("recvf: group name not delimited\n");
769 if (type
== S_IFDIR
) {
770 if (catname
>= sizeof(stp
)) {
771 error("%s:%s: too many directory levels\n",
778 while ((*tp
++ = *cp
++))
786 if (lstat(target
, &stb
) == 0) {
787 if (ISDIR(stb
.st_mode
)) {
788 if ((stb
.st_mode
& 07777) == mode
) {
793 snprintf(buf
+ 1, sizeof(buf
) - 1,
794 "%s: Warning: remote mode %o != local mode %o\n",
795 target
, stb
.st_mode
& 07777, mode
);
796 write(rem
, buf
, strlen(buf
+ 1) + 1);
800 } else if ((errno
== ENOENT
&& mkdir(target
, mode
) == 0) ||
801 (chkparent(target
) == 0 && mkdir(target
, mode
) == 0)) {
802 if (fchog(-1, target
, owner
, group
, mode
) == 0)
806 error("%s:%s: %s\n", host
, target
, strerror(errno
));
813 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
814 cp
= rindex(target
, '/');
816 strcpy(new, tempname
);
817 else if (cp
== target
)
818 snprintf(new, sizeof(new), "/%s", tempname
);
821 snprintf(new, sizeof(new), "%s/%s", target
, tempname
);
825 if (type
== S_IFLNK
) {
830 for (i
= 0; i
< size
; i
+= j
) {
831 if ((j
= read(rem
, cp
, size
- i
)) <= 0)
836 if (response() < 0) {
840 if (symlink(buf
, new) < 0) {
841 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
842 symlink(buf
, new) < 0)
846 if (opts
& COMPARE
) {
849 if ((i
= readlink(target
, tbuf
, BUFSIZ
- 1)) >= 0 &&
850 i
== size
&& strncmp(buf
, tbuf
, size
) == 0) {
861 if ((f
= creat(new, mode
)) < 0) {
862 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
863 (f
= creat(new, mode
)) < 0)
869 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
877 int j
= read(rem
, cp
, amt
);
890 if (wrerr
== 0 && write(f
, buf
, amt
) != amt
) {
895 if (response() < 0) {
901 if (opts
& COMPARE
) {
905 if ((f1
= fopen(target
, "r")) == NULL
)
907 if ((f2
= fopen(new, "r")) == NULL
) {
908 badnew1
: error("%s:%s: %s\n", host
, new, strerror(errno
));
911 while ((c
= getc(f1
)) == getc(f2
))
921 differ
: buf
[0] = '\0';
922 snprintf(buf
+ 1, sizeof(buf
) - 1,
923 "need to update: %s\n",target
);
924 write(rem
, buf
, strlen(buf
+ 1) + 1);
930 * Set last modified time
932 tvp
[0].tv_sec
= time(0);
934 tvp
[1].tv_sec
= mtime
;
936 if (utimes(new, tvp
) < 0)
937 note("%s: utimes failed %s: %s\n", host
, new, strerror(errno
));
939 if (fchog(f
, new, owner
, group
, mode
) < 0) {
940 badnew2
: if (f
!= -1)
947 fixup
: if (rename(new, target
) < 0) {
948 badtarget
: error("%s:%s: %s\n", host
, target
, strerror(errno
));
953 if (opts
& COMPARE
) {
955 snprintf(buf
+ 1, sizeof(buf
) - 1,
956 "updated %s\n", target
);
957 write(rem
, buf
, strlen(buf
+ 1) + 1);
963 * Creat a hard link to existing file.
976 while (*cp
>= '0' && *cp
<= '7')
977 opts
= (opts
<< 3) | (*cp
++ - '0');
979 error("hardlink: options not delimited\n");
983 while (*cp
&& *cp
!= ' ')
986 error("hardlink: oldname name not delimited\n");
992 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
994 if (lstat(target
, &stb
) == 0) {
995 int mode
= stb
.st_mode
& S_IFMT
;
996 if (mode
!= S_IFREG
&& mode
!= S_IFLNK
) {
997 error("%s:%s: not a regular file\n", host
, target
);
1002 if (chkparent(target
) < 0 ) {
1003 error("%s:%s: %s (no parent)\n",
1004 host
, target
, strerror(errno
));
1007 if (exists
&& (unlink(target
) < 0)) {
1008 error("%s:%s: %s (unlink)\n",
1009 host
, target
, strerror(errno
));
1012 if (link(oldname
, target
) < 0) {
1013 error("%s:can't link %s to %s\n",
1014 host
, target
, oldname
);
1021 * Check to see if parent directory exists and create one if not.
1024 chkparent(char *name
)
1029 cp
= rindex(name
, '/');
1030 if (cp
== NULL
|| cp
== name
)
1033 if (lstat(name
, &stb
) < 0) {
1034 if (errno
== ENOENT
&& chkparent(name
) >= 0 &&
1035 mkdir(name
, 0777 & ~oumask
) >= 0) {
1039 } else if (ISDIR(stb
.st_mode
)) {
1048 * Change owner, group and mode of file.
1051 fchog(int fd
, char *file
, char *owner
, char *group
, int mode
)
1060 if (*owner
== ':') {
1061 uid
= atoi(owner
+ 1);
1062 } else if (pw
== NULL
|| strcmp(owner
, pw
->pw_name
) != 0) {
1063 if ((pw
= getpwnam(owner
)) == NULL
) {
1065 note("%s:%s: unknown login name, clearing setuid",
1074 if (*group
== ':') {
1075 gid
= atoi(group
+ 1);
1078 } else if ((mode
& 04000) && strcmp(user
, owner
) != 0)
1081 if (gr
== NULL
|| strcmp(group
, gr
->gr_name
) != 0) {
1082 if ((*group
== ':' && (getgrgid(gid
= atoi(group
+ 1)) == NULL
))
1083 || ((gr
= getgrnam(group
)) == NULL
)) {
1085 note("%s:%s: unknown group", host
, group
);
1092 if (userid
&& gid
>= 0) {
1093 if (gr
) for (i
= 0; gr
->gr_mem
[i
] != NULL
; i
++)
1094 if (!(strcmp(user
, gr
->gr_mem
[i
])))
1099 ok
: if ((fd
!= -1 && fchown(fd
, uid
, gid
) < 0) || chown(file
, uid
, gid
) < 0)
1100 note("%s: %s chown: %s", host
, file
, strerror(errno
));
1101 else if (mode
& 07000 &&
1102 ((fd
!= -1 && fchmod(fd
, mode
) < 0) || chmod(file
, mode
) < 0))
1103 note("%s: %s chmod: %s", host
, file
, strerror(errno
));
1108 * Check for files on the machine being updated that are not on the master
1109 * machine and remove them.
1118 printf("rmchk()\n");
1121 * Tell the remote to clean the files from the last directory sent.
1123 snprintf(buf
, sizeof(buf
), "C%o\n", opts
& VERIFY
);
1125 printf("buf = %s", buf
);
1126 write(rem
, buf
, strlen(buf
));
1132 if (read(rem
, cp
, 1) != 1)
1134 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1137 case 'Q': /* Query if file should be removed */
1139 * Return the following codes to remove query.
1140 * N\n -- file exists - DON'T remove.
1141 * Y\n -- file doesn't exist - REMOVE.
1144 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", s
);
1146 printf("check %s\n", target
);
1148 write(rem
, "N\n", 2);
1149 else if (lstat(target
, &stb
) < 0)
1150 write(rem
, "Y\n", 2);
1152 write(rem
, "N\n", 2);
1158 dolog(lfp
, "%s\n", s
);
1172 write(2, s
, cp
- s
);
1175 fwrite(s
, 1, cp
- s
, lfp
);
1182 error("rmchk: unexpected response '%s'\n", buf
);
1189 * Check the current directory (initialized by the 'T' command to server())
1190 * for extraneous files and remove them.
1202 while (*cp
>= '0' && *cp
<= '7')
1203 opts
= (opts
<< 3) | (*cp
++ - '0');
1205 error("clean: options not delimited\n");
1208 if ((d
= opendir(target
)) == NULL
) {
1209 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1216 while ((dp
= readdir(d
))) {
1217 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1219 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1220 error("%s:%s/%s: Name too long\n",
1221 host
, target
, dp
->d_name
);
1227 while ((*tp
++ = *cp
++))
1230 if (lstat(target
, &stb
) < 0) {
1231 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1234 snprintf(buf
, sizeof(buf
), "Q%s\n", dp
->d_name
);
1235 write(rem
, buf
, strlen(buf
));
1238 if (read(rem
, cp
, 1) != 1)
1240 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1245 if (opts
& VERIFY
) {
1248 snprintf(cp
, sizeof(buf
) - 1, "need to remove: %s\n", target
);
1249 write(rem
, buf
, strlen(cp
) + 1);
1254 write(rem
, "E\n", 2);
1261 * Remove a file or directory (recursively) and send back an acknowledge
1262 * or an error message.
1265 removeit(struct stat
*stp
)
1274 switch (stp
->st_mode
& S_IFMT
) {
1277 if (unlink(target
) < 0)
1285 error("%s:%s: not a plain file\n", host
, target
);
1289 if ((d
= opendir(target
)) == NULL
)
1294 while ((dp
= readdir(d
))) {
1295 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1297 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1298 error("%s:%s/%s: Name too long\n",
1299 host
, target
, dp
->d_name
);
1305 while ((*tp
++ = *cp
++))
1308 if (lstat(target
, &stb
) < 0) {
1309 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1317 if (rmdir(target
) < 0) {
1319 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1325 snprintf(cp
, sizeof(buf
) - 1, "removed %s\n", target
);
1326 write(rem
, buf
, strlen(cp
) + 1);
1330 * Execute a shell command to handle special cases.
1333 dospecial(char *cmd
)
1335 int fd
[2], status
, pid
, i
;
1338 extern int userid
, groupid
;
1341 error("%s\n", strerror(errno
));
1344 if ((pid
= fork()) == 0) {
1346 * Return everything the shell commands print.
1351 open(_PATH_DEVNULL
, O_RDONLY
);
1358 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1364 while ((i
= read(fd
[0], buf
, sizeof(buf
))) > 0) {
1368 if (cp
[-1] != '\n') {
1369 if (s
< &sbuf
[sizeof(sbuf
)-1])
1374 * Throw away blank lines.
1376 if (s
== &sbuf
[2]) {
1380 write(rem
, sbuf
, s
- sbuf
);
1386 write(rem
, sbuf
, s
- sbuf
);
1388 while ((i
= wait(&status
)) != pid
&& i
!= -1)
1394 error("shell returned %d\n", status
);
1400 dolog(FILE *fp
, const char *fmt
, ...)
1405 /* Print changes locally if not quiet mode */
1409 /* Save changes (for mailing) if really updating files */
1410 if (!(options
& VERIFY
) && fp
!= NULL
)
1411 vfprintf(fp
, fmt
, ap
);
1416 error(const char *fmt
, ...)
1424 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1427 fprintf(fp
, "%crdist: ", 0x01);
1428 vfprintf(fp
, fmt
, ap
);
1433 fprintf(stderr
, "rdist: ");
1434 vfprintf(stderr
, fmt
, ap
);
1438 fprintf(lfp
, "rdist: ");
1439 vfprintf(lfp
, fmt
, ap
);
1446 fatal(const char *fmt
, ...)
1454 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1457 fprintf(fp
, "%crdist: ", 0x02);
1458 vfprintf(fp
, fmt
, ap
);
1463 fprintf(stderr
, "rdist: ");
1464 vfprintf(stderr
, fmt
, ap
);
1468 fprintf(lfp
, "rdist: ");
1469 vfprintf(lfp
, fmt
, ap
);
1483 printf("response()\n");
1487 if (read(rem
, cp
, 1) != 1)
1489 } while (*cp
++ != '\n' && cp
< &resp
[BUFSIZ
]);
1495 dolog(lfp
, "%s\n", s
);
1501 dolog(lfp
, "Note: %s\n",s
);
1513 write(2, s
, cp
- s
);
1516 fwrite(s
, 1, cp
- s
, lfp
);
1518 if (resp
[0] == '\2')
1525 * Remove temporary files and do any cleanup operations before exiting.
1535 note(const char *fmt
, ...)
1537 static char buf
[BUFSIZ
];
1541 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1553 write(rem
, s
, strlen(s
));