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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)server.c 8.1 (Berkeley) 6/9/93
34 * $FreeBSD: src/usr.bin/rdist/server.c,v 1.10 1999/08/28 01:05:09 peter Exp $
35 * $DragonFly: src/usr.bin/rdist/server.c,v 1.7 2008/10/16 01:52:33 swildner Exp $
44 #define ack() write(rem, "\0\n", 2)
45 #define err() write(rem, "\1\n", 2)
46 #define protoname() (pw ? pw->pw_name : user)
47 #define protogroup() (gr ? gr->gr_name : group)
49 struct linkbuf
*ihead
= NULL
; /* list of files with more than one link */
50 char buf
[BUFSIZ
]; /* general purpose buffer */
51 char target
[BUFSIZ
]; /* target/source directory name */
52 char source
[BUFSIZ
]; /* source directory name */
53 char *tp
; /* pointer to end of target name */
54 char *Tdest
; /* pointer to last T dest*/
55 int catname
; /* cat name to target name */
56 char *stp
[32]; /* stack of saved tp's for directories */
57 int oumask
; /* old umask for creating files */
59 extern FILE *lfp
; /* log file for mailing changes */
61 static int chkparent(char *);
62 static void clean(char *);
63 static void comment(char *);
64 static void dospecial(char *);
65 static int fchog(int, char *, char *, char *, int);
66 static void hardlink(char *);
67 static void note(const char *, ...);
68 static void query(char *);
69 static void recvf(char *, int);
70 static void removeit(struct stat
*);
71 static int response(void);
72 static void rmchk(int);
73 static struct linkbuf
*savelink(struct stat
*);
74 static void sendf(char *, int);
75 static int update(char *, int, struct stat
*);
78 * Server routine to read requests and process them.
80 * Tname - Transmit file if out of date
81 * Vname - Verify if file out of date or not
82 * Qname - Query if file exists. Return mtime & size if it does.
90 signal(SIGHUP
, cleanup
);
91 signal(SIGINT
, cleanup
);
92 signal(SIGQUIT
, cleanup
);
93 signal(SIGTERM
, cleanup
);
94 signal(SIGPIPE
, cleanup
);
98 snprintf(buf
, sizeof(buf
), "V%d\n", VERSION
);
99 write(rem
, buf
, strlen(buf
));
103 if (read(rem
, cp
, 1) <= 0)
106 error("server: expected control record\n");
110 if (read(rem
, cp
, 1) != 1)
112 } while (*cp
++ != '\n' && cp
< &cmdbuf
[BUFSIZ
]);
116 case 'T': /* init target file/directory name */
117 catname
= 1; /* target should be directory */
120 case 't': /* init target file/directory name */
123 if (exptilde(target
, cp
, sizeof(target
)) == NULL
)
131 case 'R': /* Transfer a regular file. */
135 case 'D': /* Transfer a directory. */
139 case 'K': /* Transfer symbolic link. */
143 case 'k': /* Transfer hard link. */
147 case 'E': /* End. (of directory) */
150 error("server: too many 'E's\n");
158 case 'C': /* Clean. Cleanup a directory */
162 case 'Q': /* Query. Does the file/directory exist? */
166 case 'S': /* Special. Execute commands */
172 * These entries are reserved but not currently used.
173 * The intent is to allow remote hosts to have master copies.
174 * Currently, only the host rdist runs on can have masters.
176 case 'X': /* start a new list of files to exclude */
178 case 'x': /* add name to list of files to exclude */
184 if (exptilde(buf
, cp
, sizeof(buf
)) == NULL
)
189 except
= bp
= expand(makeblock(NAME
, cp
), E_VARS
);
191 bp
->b_next
= expand(makeblock(NAME
, cp
), E_VARS
);
192 while (bp
->b_next
!= NULL
)
197 case 'I': /* Install. Transfer file if out of date. */
199 while (*cp
>= '0' && *cp
<= '7')
200 opts
= (opts
<< 3) | (*cp
++ - '0');
202 error("server: options not delimited\n");
208 case 'L': /* Log. save message in log file */
221 error("server: unknown command '%s'\n", cp
);
229 * Update the file(s) if they are different.
230 * destdir = 1 if destination should be a directory
231 * (i.e., more than one source is being copied to the same destination).
234 install(char *src
, char *dest
, int destdir
, int opts
)
237 char destcopy
[BUFSIZ
];
245 opts
&= ~WHOLE
; /* WHOLE mode only useful if renaming */
249 if (nflag
|| debug
) {
250 printf("%s%s%s%s%s %s %s\n", opts
& VERIFY
? "verify":"install",
251 opts
& WHOLE
? " -w" : "",
252 opts
& YOUNGER
? " -y" : "",
253 opts
& COMPARE
? " -b" : "",
254 opts
& REMOVE
? " -R" : "", src
, dest
);
259 rname
= exptilde(target
, src
, sizeof(target
));
266 * If we are renaming a directory and we want to preserve
267 * the directory heirarchy (-w), we must strip off the leading
268 * directory name and preserve the rest.
271 while (*rname
== '/')
275 rname
= rindex(target
, '/');
282 printf("target = %s, rname = %s\n", target
, rname
);
284 * Pass the destination file/directory name to remote.
286 snprintf(buf
, sizeof(buf
), "%c%s\n", destdir
? 'T' : 't', dest
);
288 printf("buf = %s", buf
);
289 write(rem
, buf
, strlen(buf
));
294 * Save the name of the remote target destination if we are
295 * in WHOLE mode (destdir > 0) or if the source and destination
296 * are not the same. This info will be used later for maintaining
299 if (destdir
|| (src
&& dest
&& strcmp(src
, dest
))) {
300 strcpy(destcopy
, dest
);
308 remotename(char *pathname
, char *src
)
315 if (0 == strncmp(pathname
, src
, len
))
323 installlink(struct linkbuf
*lp
, char *rname
, int opts
)
325 if (*lp
->target
== 0)
326 snprintf(buf
, sizeof(buf
), "k%o %s %s\n", opts
, lp
->pathname
, rname
);
328 snprintf(buf
, sizeof(buf
), "k%o %s/%s %s\n", opts
, lp
->target
,
329 remotename(lp
->pathname
, lp
->src
), rname
);
332 printf("lp->src = %s\n", lp
->src
);
333 printf("lp->target = %s\n", lp
->target
);
334 printf("lp->pathname = %s\n", lp
->pathname
);
335 printf("rname = %s\n", rname
);
336 printf("buf = %s", buf
);
338 write(rem
, buf
, strlen(buf
));
343 * Transfer the file or directory in target[].
344 * rname is the name of the file on the remote host.
347 sendf(char *rname
, int opts
)
351 int sizerr
, f
, u
, len
;
356 extern struct subcmd
*subcmds
;
357 static char user
[15], group
[15];
360 printf("sendf(%s, %x)\n", rname
, opts
);
364 if ((opts
& FOLLOW
? stat(target
, &stb
) : lstat(target
, &stb
)) < 0) {
365 error("%s: %s\n", target
, strerror(errno
));
368 if ((u
= update(rname
, opts
, &stb
)) == 0) {
369 if ((stb
.st_mode
& S_IFMT
) == S_IFREG
&& stb
.st_nlink
> 1)
374 if (pw
== NULL
|| pw
->pw_uid
!= stb
.st_uid
)
375 if ((pw
= getpwuid(stb
.st_uid
)) == NULL
) {
376 dolog(lfp
, "%s: no password entry for uid %d \n",
379 snprintf(user
, sizeof(user
), ":%lu", stb
.st_uid
);
381 if (gr
== NULL
|| gr
->gr_gid
!= stb
.st_gid
)
382 if ((gr
= getgrgid(stb
.st_gid
)) == NULL
) {
383 dolog(lfp
, "%s: no name for group %d\n",
386 snprintf(group
, sizeof(group
), ":%lu", stb
.st_gid
);
390 dolog(lfp
, "need to install: %s\n", target
);
393 dolog(lfp
, "installing: %s\n", target
);
394 opts
&= ~(COMPARE
|REMOVE
);
397 switch (stb
.st_mode
& S_IFMT
) {
399 if ((d
= opendir(target
)) == NULL
) {
400 error("%s: %s\n", target
, strerror(errno
));
403 snprintf(buf
, sizeof(buf
), "D%o %04o 0 0 %s %s %s\n",
404 opts
, stb
.st_mode
& 07777, protoname(), protogroup(),
407 printf("buf = %s", buf
);
408 write(rem
, buf
, strlen(buf
));
409 if (response() < 0) {
419 while ((dp
= readdir(d
))) {
420 if (!strcmp(dp
->d_name
, ".") ||
421 !strcmp(dp
->d_name
, ".."))
423 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
424 error("%s/%s: Name too long\n", target
,
431 while ((*tp
++ = *cp
++))
434 sendf(dp
->d_name
, opts
);
437 write(rem
, "E\n", 2);
446 if (stb
.st_nlink
> 1) {
449 if ((lp
= savelink(&stb
)) != NULL
) {
450 installlink(lp
, rname
, opts
);
454 snprintf(buf
, sizeof(buf
),
455 "K%o %o %qd %ld %s %s %s\n", opts
,
456 stb
.st_mode
& 07777, stb
.st_size
, stb
.st_mtime
,
457 protoname(), protogroup(), rname
);
459 printf("buf = %s", buf
);
460 write(rem
, buf
, strlen(buf
));
463 sizerr
= (readlink(target
, buf
, BUFSIZ
- 1) != stb
.st_size
);
464 write(rem
, buf
, stb
.st_size
);
466 printf("readlink = %.*s\n", (int)stb
.st_size
, buf
);
473 error("%s: not a file or directory\n", target
);
479 dolog(lfp
, "need to update: %s\n", target
);
482 dolog(lfp
, "updating: %s\n", target
);
485 if (stb
.st_nlink
> 1) {
488 if ((lp
= savelink(&stb
)) != NULL
) {
489 installlink(lp
, rname
, opts
);
494 if ((f
= open(target
, O_RDONLY
, 0)) < 0) {
495 error("%s: %s\n", target
, strerror(errno
));
498 snprintf(buf
, sizeof(buf
), "R%o %o %qd %ld %s %s %s\n", opts
,
499 stb
.st_mode
& 07777, stb
.st_size
, stb
.st_mtime
,
500 protoname(), protogroup(), rname
);
502 printf("buf = %s", buf
);
503 write(rem
, buf
, strlen(buf
));
504 if (response() < 0) {
509 for (i
= 0; i
< stb
.st_size
; i
+= BUFSIZ
) {
511 if (i
+ amt
> stb
.st_size
)
512 amt
= stb
.st_size
- i
;
513 if (sizerr
== 0 && read(f
, buf
, amt
) != amt
)
515 write(rem
, buf
, amt
);
520 error("%s: file changed size\n", target
);
525 if (f
< 0 || (f
== 0 && (opts
& COMPARE
)))
528 for (sc
= subcmds
; sc
!= NULL
; sc
= sc
->sc_next
) {
529 if (sc
->sc_type
!= SPECIAL
)
531 if (sc
->sc_args
!= NULL
&& !inlist(sc
->sc_args
, target
))
533 dolog(lfp
, "special \"%s\"\n", sc
->sc_name
);
536 snprintf(buf
, sizeof(buf
), "SFILE=%s;%s\n", target
,
539 printf("buf = %s", buf
);
540 write(rem
, buf
, strlen(buf
));
541 while (response() > 0)
546 static struct linkbuf
*
547 savelink(struct stat
*stp
)
551 for (lp
= ihead
; lp
!= NULL
; lp
= lp
->nextp
)
552 if (lp
->inum
== stp
->st_ino
&& lp
->devnum
== stp
->st_dev
) {
556 lp
= (struct linkbuf
*) malloc(sizeof(*lp
));
558 dolog(lfp
, "out of memory, link information lost\n");
562 lp
->inum
= stp
->st_ino
;
563 lp
->devnum
= stp
->st_dev
;
564 lp
->count
= stp
->st_nlink
- 1;
565 strcpy(lp
->pathname
, target
);
566 strcpy(lp
->src
, source
);
568 strcpy(lp
->target
, Tdest
);
576 * Check to see if file needs to be updated on the remote machine.
577 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
578 * and 3 if comparing binaries to determine if out of date.
581 update(char *rname
, int opts
, struct stat
*stp
)
588 printf("update(%s, %x, %p)\n", rname
, opts
, stp
);
591 * Check to see if the file exists on the remote machine.
593 snprintf(buf
, sizeof(buf
), "Q%s\n", rname
);
595 printf("buf = %s", buf
);
596 write(rem
, buf
, strlen(buf
));
600 if (read(rem
, cp
, 1) != 1)
602 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
608 case 'N': /* file doesn't exist so install it */
619 fwrite(s
, 1, cp
- s
, lfp
);
626 dolog(lfp
, "update: note: %s\n", s
);
631 error("update: unexpected response '%s'\n", s
);
643 size
= size
* 10 + (*s
++ - '0');
645 error("update: size not delimited\n");
650 mtime
= mtime
* 10 + (*s
++ - '0');
652 error("update: mtime not delimited\n");
656 * File needs to be updated?
658 if (opts
& YOUNGER
) {
659 if (stp
->st_mtime
== mtime
)
661 if (stp
->st_mtime
< mtime
) {
662 dolog(lfp
, "Warning: %s: remote copy is newer\n", target
);
665 } else if (stp
->st_mtime
== mtime
&& stp
->st_size
== size
)
671 * Query. Check to see if file exists. Return one of the following:
672 * N\n - doesn't exist
673 * Ysize mtime\n - exists and its a regular file (size & mtime of file)
674 * Y\n - exists and its a directory or symbolic link
683 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s",
686 if (lstat(target
, &stb
) < 0) {
688 write(rem
, "N\n", 2);
690 error("%s:%s: %s\n", host
, target
, strerror(errno
));
695 switch (stb
.st_mode
& S_IFMT
) {
697 snprintf(buf
, sizeof(buf
), "Y%qd %ld\n", stb
.st_size
,
699 write(rem
, buf
, strlen(buf
));
704 write(rem
, "Y\n", 2);
708 error("%s: not a file or directory\n", name
);
715 recvf(char *cmd
, int type
)
718 int f
, mode
, opts
, wrerr
, olderrno
;
722 struct timeval tvp
[2];
725 extern char *tempname
;
730 while (*cp
>= '0' && *cp
<= '7')
731 opts
= (opts
<< 3) | (*cp
++ - '0');
733 error("recvf: options not delimited\n");
737 while (*cp
>= '0' && *cp
<= '7')
738 mode
= (mode
<< 3) | (*cp
++ - '0');
740 error("recvf: mode not delimited\n");
745 size
= size
* 10 + (*cp
++ - '0');
747 error("recvf: size not delimited\n");
752 mtime
= mtime
* 10 + (*cp
++ - '0');
754 error("recvf: mtime not delimited\n");
758 while (*cp
&& *cp
!= ' ')
761 error("recvf: owner name not delimited\n");
766 while (*cp
&& *cp
!= ' ')
769 error("recvf: group name not delimited\n");
774 if (type
== S_IFDIR
) {
775 if (catname
>= sizeof(stp
)) {
776 error("%s:%s: too many directory levels\n",
783 while ((*tp
++ = *cp
++))
791 if (lstat(target
, &stb
) == 0) {
792 if (ISDIR(stb
.st_mode
)) {
793 if ((stb
.st_mode
& 07777) == mode
) {
798 snprintf(buf
+ 1, sizeof(buf
) - 1,
799 "%s: Warning: remote mode %o != local mode %o\n",
800 target
, stb
.st_mode
& 07777, mode
);
801 write(rem
, buf
, strlen(buf
+ 1) + 1);
805 } else if ((errno
== ENOENT
&& mkdir(target
, mode
) == 0) ||
806 (chkparent(target
) == 0 && mkdir(target
, mode
) == 0)) {
807 if (fchog(-1, target
, owner
, group
, mode
) == 0)
811 error("%s:%s: %s\n", host
, target
, strerror(errno
));
818 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
819 cp
= rindex(target
, '/');
821 strcpy(new, tempname
);
822 else if (cp
== target
)
823 snprintf(new, sizeof(new), "/%s", tempname
);
826 snprintf(new, sizeof(new), "%s/%s", target
, tempname
);
830 if (type
== S_IFLNK
) {
835 for (i
= 0; i
< size
; i
+= j
) {
836 if ((j
= read(rem
, cp
, size
- i
)) <= 0)
841 if (response() < 0) {
845 if (symlink(buf
, new) < 0) {
846 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
847 symlink(buf
, new) < 0)
851 if (opts
& COMPARE
) {
854 if ((i
= readlink(target
, tbuf
, BUFSIZ
- 1)) >= 0 &&
855 i
== size
&& strncmp(buf
, tbuf
, size
) == 0) {
866 if ((f
= creat(new, mode
)) < 0) {
867 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
868 (f
= creat(new, mode
)) < 0)
874 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
882 int j
= read(rem
, cp
, amt
);
895 if (wrerr
== 0 && write(f
, buf
, amt
) != amt
) {
900 if (response() < 0) {
906 if (opts
& COMPARE
) {
910 if ((f1
= fopen(target
, "r")) == NULL
)
912 if ((f2
= fopen(new, "r")) == NULL
) {
913 badnew1
: error("%s:%s: %s\n", host
, new, strerror(errno
));
916 while ((c
= getc(f1
)) == getc(f2
))
926 differ
: buf
[0] = '\0';
927 snprintf(buf
+ 1, sizeof(buf
) - 1,
928 "need to update: %s\n",target
);
929 write(rem
, buf
, strlen(buf
+ 1) + 1);
935 * Set last modified time
937 tvp
[0].tv_sec
= time(0);
939 tvp
[1].tv_sec
= mtime
;
941 if (utimes(new, tvp
) < 0)
942 note("%s: utimes failed %s: %s\n", host
, new, strerror(errno
));
944 if (fchog(f
, new, owner
, group
, mode
) < 0) {
945 badnew2
: if (f
!= -1)
952 fixup
: if (rename(new, target
) < 0) {
953 badtarget
: error("%s:%s: %s\n", host
, target
, strerror(errno
));
958 if (opts
& COMPARE
) {
960 snprintf(buf
+ 1, sizeof(buf
) - 1,
961 "updated %s\n", target
);
962 write(rem
, buf
, strlen(buf
+ 1) + 1);
968 * Creat a hard link to existing file.
981 while (*cp
>= '0' && *cp
<= '7')
982 opts
= (opts
<< 3) | (*cp
++ - '0');
984 error("hardlink: options not delimited\n");
988 while (*cp
&& *cp
!= ' ')
991 error("hardlink: oldname name not delimited\n");
997 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", cp
);
999 if (lstat(target
, &stb
) == 0) {
1000 int mode
= stb
.st_mode
& S_IFMT
;
1001 if (mode
!= S_IFREG
&& mode
!= S_IFLNK
) {
1002 error("%s:%s: not a regular file\n", host
, target
);
1007 if (chkparent(target
) < 0 ) {
1008 error("%s:%s: %s (no parent)\n",
1009 host
, target
, strerror(errno
));
1012 if (exists
&& (unlink(target
) < 0)) {
1013 error("%s:%s: %s (unlink)\n",
1014 host
, target
, strerror(errno
));
1017 if (link(oldname
, target
) < 0) {
1018 error("%s:can't link %s to %s\n",
1019 host
, target
, oldname
);
1026 * Check to see if parent directory exists and create one if not.
1029 chkparent(char *name
)
1034 cp
= rindex(name
, '/');
1035 if (cp
== NULL
|| cp
== name
)
1038 if (lstat(name
, &stb
) < 0) {
1039 if (errno
== ENOENT
&& chkparent(name
) >= 0 &&
1040 mkdir(name
, 0777 & ~oumask
) >= 0) {
1044 } else if (ISDIR(stb
.st_mode
)) {
1053 * Change owner, group and mode of file.
1056 fchog(int fd
, char *file
, char *owner
, char *group
, int mode
)
1065 if (*owner
== ':') {
1066 uid
= atoi(owner
+ 1);
1067 } else if (pw
== NULL
|| strcmp(owner
, pw
->pw_name
) != 0) {
1068 if ((pw
= getpwnam(owner
)) == NULL
) {
1070 note("%s:%s: unknown login name, clearing setuid",
1079 if (*group
== ':') {
1080 gid
= atoi(group
+ 1);
1083 } else if ((mode
& 04000) && strcmp(user
, owner
) != 0)
1086 if (gr
== NULL
|| strcmp(group
, gr
->gr_name
) != 0) {
1087 if ((*group
== ':' && (getgrgid(gid
= atoi(group
+ 1)) == NULL
))
1088 || ((gr
= getgrnam(group
)) == NULL
)) {
1090 note("%s:%s: unknown group", host
, group
);
1097 if (userid
&& gid
>= 0) {
1098 if (gr
) for (i
= 0; gr
->gr_mem
[i
] != NULL
; i
++)
1099 if (!(strcmp(user
, gr
->gr_mem
[i
])))
1104 ok
: if ((fd
!= -1 && fchown(fd
, uid
, gid
) < 0) || chown(file
, uid
, gid
) < 0)
1105 note("%s: %s chown: %s", host
, file
, strerror(errno
));
1106 else if (mode
& 07000 &&
1107 ((fd
!= -1 && fchmod(fd
, mode
) < 0) || chmod(file
, mode
) < 0))
1108 note("%s: %s chmod: %s", host
, file
, strerror(errno
));
1113 * Check for files on the machine being updated that are not on the master
1114 * machine and remove them.
1123 printf("rmchk()\n");
1126 * Tell the remote to clean the files from the last directory sent.
1128 snprintf(buf
, sizeof(buf
), "C%o\n", opts
& VERIFY
);
1130 printf("buf = %s", buf
);
1131 write(rem
, buf
, strlen(buf
));
1137 if (read(rem
, cp
, 1) != 1)
1139 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1142 case 'Q': /* Query if file should be removed */
1144 * Return the following codes to remove query.
1145 * N\n -- file exists - DON'T remove.
1146 * Y\n -- file doesn't exist - REMOVE.
1149 snprintf(tp
, sizeof(target
) - (tp
- target
), "/%s", s
);
1151 printf("check %s\n", target
);
1153 write(rem
, "N\n", 2);
1154 else if (lstat(target
, &stb
) < 0)
1155 write(rem
, "Y\n", 2);
1157 write(rem
, "N\n", 2);
1163 dolog(lfp
, "%s\n", s
);
1177 write(2, s
, cp
- s
);
1180 fwrite(s
, 1, cp
- s
, lfp
);
1187 error("rmchk: unexpected response '%s'\n", buf
);
1194 * Check the current directory (initialized by the 'T' command to server())
1195 * for extraneous files and remove them.
1207 while (*cp
>= '0' && *cp
<= '7')
1208 opts
= (opts
<< 3) | (*cp
++ - '0');
1210 error("clean: options not delimited\n");
1213 if ((d
= opendir(target
)) == NULL
) {
1214 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1221 while ((dp
= readdir(d
))) {
1222 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1224 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1225 error("%s:%s/%s: Name too long\n",
1226 host
, target
, dp
->d_name
);
1232 while ((*tp
++ = *cp
++))
1235 if (lstat(target
, &stb
) < 0) {
1236 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1239 snprintf(buf
, sizeof(buf
), "Q%s\n", dp
->d_name
);
1240 write(rem
, buf
, strlen(buf
));
1243 if (read(rem
, cp
, 1) != 1)
1245 } while (*cp
++ != '\n' && cp
< &buf
[BUFSIZ
]);
1250 if (opts
& VERIFY
) {
1253 snprintf(cp
, sizeof(buf
) - 1, "need to remove: %s\n", target
);
1254 write(rem
, buf
, strlen(cp
) + 1);
1259 write(rem
, "E\n", 2);
1266 * Remove a file or directory (recursively) and send back an acknowledge
1267 * or an error message.
1270 removeit(struct stat
*stp
)
1279 switch (stp
->st_mode
& S_IFMT
) {
1282 if (unlink(target
) < 0)
1290 error("%s:%s: not a plain file\n", host
, target
);
1294 if ((d
= opendir(target
)) == NULL
)
1299 while ((dp
= readdir(d
))) {
1300 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
1302 if (len
+ 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
1303 error("%s:%s/%s: Name too long\n",
1304 host
, target
, dp
->d_name
);
1310 while ((*tp
++ = *cp
++))
1313 if (lstat(target
, &stb
) < 0) {
1314 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1322 if (rmdir(target
) < 0) {
1324 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1330 snprintf(cp
, sizeof(buf
) - 1, "removed %s\n", target
);
1331 write(rem
, buf
, strlen(cp
) + 1);
1335 * Execute a shell command to handle special cases.
1338 dospecial(char *cmd
)
1340 int fd
[2], status
, pid
, i
;
1343 extern int userid
, groupid
;
1346 error("%s\n", strerror(errno
));
1349 if ((pid
= fork()) == 0) {
1351 * Return everything the shell commands print.
1356 open(_PATH_DEVNULL
, O_RDONLY
);
1363 execl(_PATH_BSHELL
, "sh", "-c", cmd
, NULL
);
1369 while ((i
= read(fd
[0], buf
, sizeof(buf
))) > 0) {
1373 if (cp
[-1] != '\n') {
1374 if (s
< &sbuf
[sizeof(sbuf
)-1])
1379 * Throw away blank lines.
1381 if (s
== &sbuf
[2]) {
1385 write(rem
, sbuf
, s
- sbuf
);
1391 write(rem
, sbuf
, s
- sbuf
);
1393 while ((i
= wait(&status
)) != pid
&& i
!= -1)
1399 error("shell returned %d\n", status
);
1405 dolog(FILE *fp
, const char *fmt
, ...)
1410 /* Print changes locally if not quiet mode */
1414 /* Save changes (for mailing) if really updating files */
1415 if (!(options
& VERIFY
) && fp
!= NULL
)
1416 vfprintf(fp
, fmt
, ap
);
1421 error(const char *fmt
, ...)
1429 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1432 fprintf(fp
, "%crdist: ", 0x01);
1433 vfprintf(fp
, fmt
, ap
);
1438 fprintf(stderr
, "rdist: ");
1439 vfprintf(stderr
, fmt
, ap
);
1443 fprintf(lfp
, "rdist: ");
1444 vfprintf(lfp
, fmt
, ap
);
1451 fatal(const char *fmt
, ...)
1459 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1462 fprintf(fp
, "%crdist: ", 0x02);
1463 vfprintf(fp
, fmt
, ap
);
1468 fprintf(stderr
, "rdist: ");
1469 vfprintf(stderr
, fmt
, ap
);
1473 fprintf(lfp
, "rdist: ");
1474 vfprintf(lfp
, fmt
, ap
);
1488 printf("response()\n");
1492 if (read(rem
, cp
, 1) != 1)
1494 } while (*cp
++ != '\n' && cp
< &resp
[BUFSIZ
]);
1500 dolog(lfp
, "%s\n", s
);
1506 dolog(lfp
, "Note: %s\n",s
);
1518 write(2, s
, cp
- s
);
1521 fwrite(s
, 1, cp
- s
, lfp
);
1523 if (resp
[0] == '\2')
1530 * Remove temporary files and do any cleanup operations before exiting.
1540 note(const char *fmt
, ...)
1542 static char buf
[BUFSIZ
];
1546 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
1558 write(rem
, s
, strlen(s
));