Home | History | Annotate | Line # | Download | only in rdist
      1 /*	$NetBSD: server.c,v 1.33 2019/02/03 03:19:29 mrg Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1983, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     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.
     18  *
     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
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #ifndef lint
     34 #if 0
     35 static char sccsid[] = "@(#)server.c	8.1 (Berkeley) 6/9/93";
     36 #else
     37 __RCSID("$NetBSD: server.c,v 1.33 2019/02/03 03:19:29 mrg Exp $");
     38 #endif
     39 #endif /* not lint */
     40 
     41 #include <sys/types.h>
     42 #include <sys/wait.h>
     43 
     44 #include <errno.h>
     45 #include <fcntl.h>
     46 #include <grp.h>
     47 #include <pwd.h>
     48 #include <stdarg.h>
     49 
     50 #include "defs.h"
     51 
     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)
     54 
     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 */
     66 
     67 extern	FILE *lfp;		/* log file for mailing changes */
     68 
     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 *);
     86 
     87 /*
     88  * Server routine to read requests and process them.
     89  * Commands are:
     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.
     93  */
     94 void
     95 server(void)
     96 {
     97 	char cmdbuf[BUFSIZ];
     98 	char *cp;
     99 
    100 	signal(SIGHUP, cleanup);
    101 	signal(SIGINT, cleanup);
    102 	signal(SIGQUIT, cleanup);
    103 	signal(SIGTERM, cleanup);
    104 	signal(SIGPIPE, cleanup);
    105 
    106 	rem = 0;
    107 	oumask = umask(0);
    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",
    111 		    strerror(errno));
    112 
    113 	for (;;) {
    114 		cp = cmdbuf;
    115 		if (read(rem, cp, 1) <= 0)
    116 			return;
    117 		if (*cp++ == '\n') {
    118 			error("server: expected control record\n");
    119 			continue;
    120 		}
    121 		do {
    122 			if (read(rem, cp, 1) != 1)
    123 				cleanup(0);
    124 		} while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]);
    125 		*--cp = '\0';
    126 		cp = cmdbuf;
    127 		switch (*cp++) {
    128 		case 'T':  /* init target file/directory name */
    129 			catname = 1;	/* target should be directory */
    130 			goto dotarget;
    131 
    132 		case 't':  /* init target file/directory name */
    133 			catname = 0;
    134 		dotarget:
    135 			if (exptilde(target, cp) == NULL)
    136 				continue;
    137 			tp = target;
    138 			while (*tp)
    139 				tp++;
    140 			ack();
    141 			continue;
    142 
    143 		case 'R':  /* Transfer a regular file. */
    144 			recvf(cp, S_IFREG);
    145 			continue;
    146 
    147 		case 'D':  /* Transfer a directory. */
    148 			recvf(cp, S_IFDIR);
    149 			continue;
    150 
    151 		case 'K':  /* Transfer symbolic link. */
    152 			recvf(cp, S_IFLNK);
    153 			continue;
    154 
    155 		case 'k':  /* Transfer hard link. */
    156 			hardlink(cp);
    157 			continue;
    158 
    159 		case 'E':  /* End. (of directory) */
    160 			*tp = '\0';
    161 			if (catname <= 0) {
    162 				error("server: too many 'E's\n");
    163 				continue;
    164 			}
    165 			tp = stp[--catname];
    166 			*tp = '\0';
    167 			ack();
    168 			continue;
    169 
    170 		case 'C':  /* Clean. Cleanup a directory */
    171 			clean(cp);
    172 			continue;
    173 
    174 		case 'Q':  /* Query. Does the file/directory exist? */
    175 			query(cp);
    176 			continue;
    177 
    178 		case 'S':  /* Special. Execute commands */
    179 			dospecial(cp);
    180 			continue;
    181 
    182 #ifdef notdef
    183 		/*
    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.
    187 		 */
    188 		case 'X':  /* start a new list of files to exclude */
    189 			except = bp = NULL;
    190 		case 'x':  /* add name to list of files to exclude */
    191 			if (*cp == '\0') {
    192 				ack();
    193 				continue;
    194 			}
    195 			if (*cp == '~') {
    196 				if (exptilde(buf, cp) == NULL)
    197 					continue;
    198 				cp = buf;
    199 			}
    200 			if (bp == NULL)
    201 				except = bp = expand(makeblock(NAME, cp), E_VARS);
    202 			else
    203 				bp->b_next = expand(makeblock(NAME, cp), E_VARS);
    204 			while (bp->b_next != NULL)
    205 				bp = bp->b_next;
    206 			ack();
    207 			continue;
    208 
    209 		case 'I':  /* Install. Transfer file if out of date. */
    210 			opts = 0;
    211 			while (*cp >= '0' && *cp <= '7')
    212 				opts = (opts << 3) | (*cp++ - '0');
    213 			if (*cp++ != ' ') {
    214 				error("server: options not delimited\n");
    215 				return;
    216 			}
    217 			install(cp, opts);
    218 			continue;
    219 
    220 		case 'L':  /* Log. save message in log file */
    221 			log(lfp, cp);
    222 			continue;
    223 #endif
    224 
    225 		case '\1':
    226 			nerrs++;
    227 			continue;
    228 
    229 		case '\2':
    230 			return;
    231 
    232 		default:
    233 			error("server: unknown command '%s'\n", cp);
    234 			/* FALLTHROUGH */
    235 		case '\0':
    236 			continue;
    237 		}
    238 	}
    239 }
    240 
    241 /*
    242  * Update the file(s) if they are different.
    243  * destdir = 1 if destination should be a directory
    244  * (i.e., more than one source is being copied to the same destination).
    245  */
    246 void
    247 install(char *src, char *dest, int destdir, int opts)
    248 {
    249 	char *rname;
    250 	char destcopy[BUFSIZ];
    251 
    252 	if (dest == NULL) {
    253 		opts &= ~WHOLE; /* WHOLE mode only useful if renaming */
    254 		dest = src;
    255 	} else if (!(opts & WHOLE)) {
    256 		/* prepare for proper renaming of directory trees */
    257 		Destcopy = destcopy;
    258 		Destcopylen = strlen(dest);
    259 		while (Destcopylen > 0 && dest[Destcopylen] == '/')
    260 		    Destcopylen--;
    261 	}
    262 	strlcpy(destcopy, dest, sizeof(destcopy));
    263 
    264 	if (nflag || debug) {
    265 		printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
    266 			opts & WHOLE ? " -w" : "",
    267 			opts & YOUNGER ? " -y" : "",
    268 			opts & COMPARE ? " -b" : "",
    269 			opts & REMOVE ? " -R" : "", src, dest);
    270 		if (nflag)
    271 			return;
    272 	}
    273 
    274 	rname = exptilde(target, src);
    275 	if (rname == NULL)
    276 		return;
    277 	tp = target;
    278 	while (*tp)
    279 		tp++;
    280 	if (Destcopy) {
    281 		/* We can only do this after expansion of src */
    282 		Sourcelen = strlen(target);
    283 		while (Sourcelen > 0 && target[Sourcelen] == '/')
    284 		    Sourcelen--;
    285 	}
    286 	/*
    287 	 * If we are renaming a directory and we want to preserve
    288 	 * the directory hierarchy (-w), we must strip off the leading
    289 	 * directory name and preserve the rest.
    290 	 */
    291 	if (opts & WHOLE) {
    292 		while (*rname == '/')
    293 			rname++;
    294 		destdir = 1;
    295 	} else {
    296 		rname = strrchr(target, '/');
    297 		if (rname == NULL)
    298 			rname = target;
    299 		else
    300 			rname++;
    301 	}
    302 	if (debug)
    303 		printf("target = %s, rname = %s\n", target, rname);
    304 	/*
    305 	 * Pass the destination file/directory name to remote.
    306 	 */
    307 	(void) snprintf(buf, sizeof(buf), "%c%s\n", destdir ? 'T' : 't', dest);
    308 	if (debug)
    309 		printf("buf = %s", buf);
    310 	if (write(rem, buf, strlen(buf)) < 0)
    311 		error("could not pass filename to remote: %s\n",
    312 		    strerror(errno));
    313 	if (response() < 0)
    314 		return;
    315 
    316 	if (destdir)
    317 		Tdest = destcopy;
    318 	sendf(rname, opts);
    319 	Destcopy = 0;
    320 	Tdest = 0;
    321 }
    322 
    323 #define protoname() (pw ? pw->pw_name : user)
    324 #define protogroup() (gr ? gr->gr_name : group)
    325 /*
    326  * Transfer the file or directory in target[].
    327  * rname is the name of the file on the remote host.
    328  */
    329 static void
    330 sendf(char *rname, int opts)
    331 {
    332 	struct subcmd *sc;
    333 	struct stat stb;
    334 	int sizerr, f, u, len;
    335 	off_t i;
    336 	DIR *d;
    337 	struct dirent *dp;
    338 	char *otp, *cp;
    339 	extern struct subcmd *subcmds;
    340 	static char user[15], group[15];
    341 
    342 	if (debug)
    343 		printf("sendf(%s, %x)\n", rname, opts);
    344 
    345 	if (except(target))
    346 		return;
    347 	if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) {
    348 		error("%s: %s\n", target, strerror(errno));
    349 		return;
    350 	}
    351 	if ((u = update(rname, opts, &stb)) == 0) {
    352 		if (S_ISREG(stb.st_mode) && stb.st_nlink > 1)
    353 			(void) savelink(&stb);
    354 		return;
    355 	}
    356 
    357 	if (pw == NULL || pw->pw_uid != stb.st_uid)
    358 		if ((pw = getpwuid(stb.st_uid)) == NULL) {
    359 			dolog(lfp, "%s: no password entry for uid %d \n",
    360 				target, stb.st_uid);
    361 			pw = NULL;
    362 			(void)snprintf(user, sizeof(user), ":%lu",
    363 			    (u_long)stb.st_uid);
    364 		}
    365 	if (gr == NULL || gr->gr_gid != stb.st_gid)
    366 		if ((gr = getgrgid(stb.st_gid)) == NULL) {
    367 			dolog(lfp, "%s: no name for group %d\n",
    368 				target, stb.st_gid);
    369 			gr = NULL;
    370 			(void)snprintf(group, sizeof(group), ":%lu",
    371 			    (u_long)stb.st_gid);
    372 		}
    373 	if (u == 1) {
    374 		if (opts & VERIFY) {
    375 			dolog(lfp, "need to install: %s\n", target);
    376 			goto dospecial;
    377 		}
    378 		dolog(lfp, "installing: %s\n", target);
    379 		opts &= ~(COMPARE|REMOVE);
    380 	}
    381 
    382 	switch (stb.st_mode & S_IFMT) {
    383 	case S_IFDIR:
    384 		if ((d = opendir(target)) == NULL) {
    385 			error("%s: %s\n", target, strerror(errno));
    386 			return;
    387 		}
    388 		(void) snprintf(buf, sizeof(buf), "D%o %04o 0 0 %s %s %s\n",
    389 		    opts, stb.st_mode & 07777, protoname(), protogroup(),
    390 		    rname);
    391 		if (debug)
    392 			printf("buf = %s", buf);
    393 		if (write(rem, buf, strlen(buf)) < 0)
    394 			error("can not write dir spec to remote: %s\n",
    395 			    strerror(errno));
    396 
    397 		if (response() < 0) {
    398 			closedir(d);
    399 			return;
    400 		}
    401 
    402 		if (opts & REMOVE)
    403 			rmchk(opts);
    404 
    405 		otp = tp;
    406 		len = tp - target;
    407 		while ((dp = readdir(d)) != NULL) {
    408 			if (!strcmp(dp->d_name, ".") ||
    409 			    !strcmp(dp->d_name, ".."))
    410 				continue;
    411 			if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
    412 				error("%s/%s: Name too long\n", target,
    413 					dp->d_name);
    414 				continue;
    415 			}
    416 			tp = otp;
    417 			*tp++ = '/';
    418 			cp = dp->d_name;
    419 			while ((*tp++ = *cp++) != 0)
    420 				;
    421 			tp--;
    422 			sendf(dp->d_name, opts);
    423 		}
    424 		closedir(d);
    425 		if (write(rem, "E\n", 2) < 0)
    426 			error("can not write E to remote: %s\n",
    427 			    strerror(errno));
    428 		(void) response();
    429 		tp = otp;
    430 		*tp = '\0';
    431 		return;
    432 
    433 	case S_IFLNK:
    434 		if (u != 1)
    435 			opts |= COMPARE;
    436 		if (stb.st_nlink > 1) {
    437 			struct linkbuf *lp;
    438 
    439 			if ((lp = savelink(&stb)) != NULL) {
    440 				/* install link */
    441 				if (*lp->target == 0)
    442 				(void) snprintf(buf, sizeof(buf),
    443 				    "k%o %s %s\n", opts, lp->pathname, rname);
    444 				else
    445 				(void) snprintf(buf, sizeof(buf),
    446 				    "k%o %s/%s %s\n", opts, lp->target,
    447 				    lp->pathname, rname);
    448 				if (debug)
    449 					printf("buf = %s", buf);
    450 				if (write(rem, buf, strlen(buf)) < 0)
    451 					error("can not write link spec to remote: %s\n",
    452 					    strerror(errno));
    453 				(void) response();
    454 				return;
    455 			}
    456 		}
    457 		(void) snprintf(buf, sizeof(buf), "K%o %o %lld %ld %s %s %s\n",
    458 		    opts, stb.st_mode & 07777, (unsigned long long)stb.st_size,
    459 		    (u_long)stb.st_mtime, protoname(), protogroup(), rname);
    460 		if (debug)
    461 			printf("buf = %s", buf);
    462 		if (write(rem, buf, strlen(buf)) < 0)
    463 			error("can not write link spec to remote: %s\n",
    464 			    strerror(errno));
    465 		if (response() < 0)
    466 			return;
    467 		sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);
    468 		if (write(rem, buf, stb.st_size) < 0)
    469 			error("can not write link name to remote: %s\n",
    470 			    strerror(errno));
    471 		if (debug)
    472 			printf("readlink = %.*s\n", (int)stb.st_size, buf);
    473 		goto done;
    474 
    475 	case S_IFREG:
    476 		break;
    477 
    478 	default:
    479 		error("%s: not a file or directory\n", target);
    480 		return;
    481 	}
    482 
    483 	if (u == 2) {
    484 		if (opts & VERIFY) {
    485 			dolog(lfp, "need to update: %s\n", target);
    486 			goto dospecial;
    487 		}
    488 		dolog(lfp, "updating: %s\n", target);
    489 	}
    490 
    491 	if (stb.st_nlink > 1) {
    492 		struct linkbuf *lp;
    493 
    494 		if ((lp = savelink(&stb)) != NULL) {
    495 			/* install link */
    496 			if (*lp->target == 0)
    497 			(void) snprintf(buf, sizeof(buf), "k%o %s %s\n", opts,
    498 				lp->pathname, rname);
    499 			else
    500 			(void) snprintf(buf, sizeof(buf), "k%o %s/%s %s\n",
    501 			    opts, lp->target, lp->pathname, rname);
    502 			if (debug)
    503 				printf("buf = %s", buf);
    504 			if (write(rem, buf, strlen(buf)) <0)
    505 				error("write of file name failed: %s\n",
    506 				    strerror(errno));
    507 			(void) response();
    508 			return;
    509 		}
    510 	}
    511 
    512 	if ((f = open(target, O_RDONLY, 0)) < 0) {
    513 		error("%s: %s\n", target, strerror(errno));
    514 		return;
    515 	}
    516 	(void)snprintf(buf, sizeof(buf), "R%o %o %lld %lu %s %s %s\n", opts,
    517 		stb.st_mode & 07777, (unsigned long long)stb.st_size,
    518 		(u_long)stb.st_mtime, protoname(), protogroup(), rname);
    519 	if (debug)
    520 		printf("buf = %s", buf);
    521 	if (write(rem, buf, strlen(buf)) < 0)
    522 		error("write of file name failed: %s\n", strerror(errno));
    523 	if (response() < 0) {
    524 		(void) close(f);
    525 		return;
    526 	}
    527 	sizerr = 0;
    528 	for (i = 0; i < stb.st_size; i += BUFSIZ) {
    529 		int amt = BUFSIZ;
    530 		if (i + amt > stb.st_size)
    531 			amt = stb.st_size - i;
    532 		if (sizerr == 0 && read(f, buf, amt) != amt)
    533 			sizerr = 1;
    534 		if (write(rem, buf, amt) < 0)
    535 			error("write of file data failed: %s\n", strerror(errno));
    536 	}
    537 	(void) close(f);
    538 done:
    539 	if (sizerr) {
    540 		error("%s: file changed size\n", target);
    541 		err();
    542 	} else
    543 		ack();
    544 	f = response();
    545 	if (f < 0 || (f == 0 && (opts & COMPARE)))
    546 		return;
    547 dospecial:
    548 	for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
    549 		if (sc->sc_type != SPECIAL)
    550 			continue;
    551 		if (sc->sc_args != NULL && !inlist(sc->sc_args, target))
    552 			continue;
    553 		dolog(lfp, "special \"%s\"\n", sc->sc_name);
    554 		if (opts & VERIFY)
    555 			continue;
    556 		(void) snprintf(buf, sizeof(buf), "SFILE=%s;%s\n", target,
    557 		    sc->sc_name);
    558 		if (debug)
    559 			printf("buf = %s", buf);
    560 		if (write(rem, buf, strlen(buf)) < 0)
    561 			error("write of special failed: %s\n", strerror(errno));
    562 		while (response() > 0)
    563 			;
    564 	}
    565 }
    566 
    567 static struct linkbuf *
    568 savelink(struct stat *st)
    569 {
    570 	struct linkbuf *lp;
    571 
    572 	for (lp = ihead; lp != NULL; lp = lp->nextp)
    573 		if (lp->inum == st->st_ino && lp->devnum == st->st_dev) {
    574 			lp->count--;
    575 			return(lp);
    576 		}
    577 	lp = (struct linkbuf *) malloc(sizeof(*lp));
    578 	if (lp == NULL)
    579 		dolog(lfp, "out of memory, link information lost\n");
    580 	else {
    581 		lp->nextp = ihead;
    582 		ihead = lp;
    583 		lp->inum = st->st_ino;
    584 		lp->devnum = st->st_dev;
    585 		lp->count = st->st_nlink - 1;
    586  		if (Destcopy) {
    587  			/*
    588  			 * Change the starting directory of target
    589  			 * into the destination directory
    590  			 */
    591  			strncpy(lp->pathname, Destcopy, Destcopylen);
    592  			strlcpy(lp->pathname + Destcopylen, target + Sourcelen, sizeof(lp->pathname) - Destcopylen);
    593  		} else
    594 			strlcpy(lp->pathname, target, sizeof(lp->pathname));
    595 		if (Tdest)
    596 			strlcpy(lp->target, Tdest, sizeof(lp->target));
    597 		else
    598 			*lp->target = 0;
    599 	}
    600 	return(NULL);
    601 }
    602 
    603 /*
    604  * Check to see if file needs to be updated on the remote machine.
    605  * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
    606  * and 3 if comparing binaries to determine if out of date.
    607  */
    608 static int
    609 update(char *rname, int opts, struct stat *st)
    610 {
    611 	char *cp, *s;
    612 	off_t size;
    613 	time_t mtime;
    614 
    615 	if (debug)
    616 		printf("update(%s, %lx, %lx)\n", rname, (long)opts, (long)st);
    617 
    618 	/*
    619 	 * Check to see if the file exists on the remote machine.
    620 	 */
    621 	(void) snprintf(buf, sizeof(buf), "Q%s\n", rname);
    622 	if (debug)
    623 		printf("buf = %s", buf);
    624 	if (write(rem, buf, strlen(buf)) < 0)
    625 		error("write to remote failed: %s\n", strerror(errno));
    626 again:
    627 	cp = s = buf;
    628 	do {
    629 		if (read(rem, cp, 1) != 1)
    630 			lostconn(0);
    631 	} while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
    632 
    633 	switch (*s++) {
    634 	case 'Y':
    635 		break;
    636 
    637 	case 'N':  /* file doesn't exist so install it */
    638 		return(1);
    639 
    640 	case '\1':
    641 		nerrs++;
    642 		if (*s != '\n') {
    643 			if (!iamremote) {
    644 				fflush(stdout);
    645 				(void) write(2, s, cp - s);
    646 			}
    647 			if (lfp != NULL)
    648 				(void) fwrite(s, 1, cp - s, lfp);
    649 		}
    650 		return(0);
    651 
    652 	case '\3':
    653 		*--cp = '\0';
    654 		if (lfp != NULL)
    655 			dolog(lfp, "update: note: %s\n", s);
    656 		goto again;
    657 
    658 	default:
    659 		*--cp = '\0';
    660 		error("update: unexpected response '%s'\n", s);
    661 		return(0);
    662 	}
    663 
    664 	if (*s == '\n')
    665 		return(2);
    666 
    667 	if (opts & COMPARE)
    668 		return(3);
    669 
    670 	size = 0;
    671 	while (isdigit((unsigned char)*s))
    672 		size = size * 10 + (*s++ - '0');
    673 	if (*s++ != ' ') {
    674 		error("update: size not delimited\n");
    675 		return(0);
    676 	}
    677 	mtime = 0;
    678 	while (isdigit((unsigned char)*s))
    679 		mtime = mtime * 10 + (*s++ - '0');
    680 	if (*s != '\n') {
    681 		error("update: mtime not delimited\n");
    682 		return(0);
    683 	}
    684 	/*
    685 	 * File needs to be updated?
    686 	 */
    687 	if (opts & YOUNGER) {
    688 		if (st->st_mtime == mtime)
    689 			return(0);
    690 		if (st->st_mtime < mtime) {
    691 			dolog(lfp, "Warning: %s: remote copy is newer\n",
    692 			    target);
    693 			return(0);
    694 		}
    695 	} else if (st->st_mtime == mtime && st->st_size == size)
    696 		return(0);
    697 	return(2);
    698 }
    699 
    700 /*
    701  * Query. Check to see if file exists. Return one of the following:
    702  *	N\n		- doesn't exist
    703  *	Ysize mtime\n	- exists and its a regular file (size & mtime of file)
    704  *	Y\n		- exists and its a directory or symbolic link
    705  *	^Aerror message\n
    706  */
    707 static void
    708 query(char *name)
    709 {
    710 	struct stat stb;
    711 
    712 	if (catname)
    713 		(void) snprintf(tp, sizeof(target) - (tp - target),
    714 		    "/%s", name);
    715 
    716 	if (lstat(target, &stb) < 0) {
    717 		if (errno == ENOENT) {
    718 			if (write(rem, "N\n", 2) < 0)
    719 				error("write to remote failed: %s\n",
    720 				    strerror(errno));
    721 		} else
    722 			error("%s:%s: %s\n", host, target, strerror(errno));
    723 		*tp = '\0';
    724 		return;
    725 	}
    726 
    727 	switch (stb.st_mode & S_IFMT) {
    728 	case S_IFREG:
    729 		(void)snprintf(buf, sizeof(buf), "Y%lld %ld\n",
    730 		    (unsigned long long)stb.st_size, (u_long)stb.st_mtime);
    731 		if (write(rem, buf, strlen(buf)) < 0)
    732 			error("write to remote failed: %s\n", strerror(errno));
    733 		break;
    734 
    735 	case S_IFLNK:
    736 	case S_IFDIR:
    737 		if (write(rem, "Y\n", 2) < 0)
    738 			error("write to remote failed: %s\n", strerror(errno));
    739 		break;
    740 
    741 	default:
    742 		error("%s: not a file or directory\n", name);
    743 		break;
    744 	}
    745 	*tp = '\0';
    746 }
    747 
    748 static void
    749 recvf(char *cmd, int type)
    750 {
    751 	char *cp = cmd;
    752 	int f = -1, opts = 0, wrerr;
    753 	mode_t mode;
    754 	off_t i, size;
    755 	time_t mtime;
    756 	struct stat stb;
    757 	char *owner, *group;
    758 	char new[BUFSIZ];
    759 	extern char *tempname;
    760 
    761 	while (*cp >= '0' && *cp <= '7')
    762 		opts = (opts << 3) | (*cp++ - '0');
    763 	if (*cp++ != ' ') {
    764 		error("recvf: options not delimited\n");
    765 		return;
    766 	}
    767 	mode = 0;
    768 	while (*cp >= '0' && *cp <= '7')
    769 		mode = (mode << 3) | (*cp++ - '0');
    770 	if (*cp++ != ' ') {
    771 		error("recvf: mode not delimited\n");
    772 		return;
    773 	}
    774 	size = 0;
    775 	while (isdigit((unsigned char)*cp))
    776 		size = size * 10 + (*cp++ - '0');
    777 	if (*cp++ != ' ') {
    778 		error("recvf: size not delimited\n");
    779 		return;
    780 	}
    781 	mtime = 0;
    782 	while (isdigit((unsigned char)*cp))
    783 		mtime = mtime * 10 + (*cp++ - '0');
    784 	if (*cp++ != ' ') {
    785 		error("recvf: mtime not delimited\n");
    786 		return;
    787 	}
    788 	owner = cp;
    789 	while (*cp && *cp != ' ')
    790 		cp++;
    791 	if (*cp != ' ') {
    792 		error("recvf: owner name not delimited\n");
    793 		return;
    794 	}
    795 	*cp++ = '\0';
    796 	group = cp;
    797 	while (*cp && *cp != ' ')
    798 		cp++;
    799 	if (*cp != ' ') {
    800 		error("recvf: group name not delimited\n");
    801 		return;
    802 	}
    803 	*cp++ = '\0';
    804 
    805 	if (type == S_IFDIR) {
    806 		if (catname >= (int)sizeof(stp)) {
    807 			error("%s:%s: too many directory levels\n",
    808 				host, target);
    809 			return;
    810 		}
    811 		stp[catname] = tp;
    812 		if (catname++) {
    813 			*tp++ = '/';
    814 			while ((*tp++ = *cp++) != 0)
    815 				;
    816 			tp--;
    817 		}
    818 		if (opts & VERIFY) {
    819 			ack();
    820 			return;
    821 		}
    822 		if (lstat(target, &stb) == 0) {
    823 			if (S_ISDIR(stb.st_mode)) {
    824 				if ((stb.st_mode & 07777) == mode) {
    825 					ack();
    826 					return;
    827 				}
    828 				buf[0] = '\0';
    829 				(void) snprintf(buf + 1, sizeof(buf) - 1,
    830 			    "%s: Warning: remote mode %o != local mode %o\n",
    831 				    target, stb.st_mode & 07777, mode);
    832 				if (write(rem, buf, strlen(buf + 1) + 1) < 0)
    833 					error("write to remote failed: %s\n",
    834 					    strerror(errno));
    835 				return;
    836 			}
    837 			errno = ENOTDIR;
    838 		} else if ((errno == ENOENT && mkdir(target, mode) == 0) ||
    839 		    (chkparent(target) == 0 && mkdir(target, mode) == 0)) {
    840 			if (fchtogm(-1, target, mtime, owner, group, mode) == 0)
    841 				ack();
    842 			return;
    843 		}
    844 		error("%s:%s: %s\n", host, target, strerror(errno));
    845 		tp = stp[--catname];
    846 		*tp = '\0';
    847 		return;
    848 	}
    849 
    850 	if (catname)
    851 		(void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
    852 	cp = strrchr(target, '/');
    853 	if (cp == NULL)
    854 		strlcpy(new, tempname, sizeof(new));
    855 	else if (cp == target)
    856 		(void) snprintf(new, sizeof(new), "/%s", tempname);
    857 	else {
    858 		*cp = '\0';
    859 		(void) snprintf(new, sizeof(new), "%s/%s", target, tempname);
    860 		*cp = '/';
    861 	}
    862 
    863 	if (type == S_IFLNK) {
    864 		int j;
    865 
    866 		ack();
    867 		cp = buf;
    868 		for (i = 0; i < size; i += j) {
    869 			if ((j = read(rem, cp, size - i)) <= 0)
    870 				cleanup(0);
    871 			cp += j;
    872 		}
    873 		*cp = '\0';
    874 		if (response() < 0) {
    875 			err();
    876 			return;
    877 		}
    878 		if (symlink(buf, new) < 0) {
    879 			if (errno != ENOENT || chkparent(new) < 0 ||
    880 			    symlink(buf, new) < 0)
    881 				goto badnew1;
    882 		}
    883 		mode &= 0777;
    884 		if (opts & COMPARE) {
    885 			char tbuf[BUFSIZ];
    886 
    887 			if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 &&
    888 			    i == size && strncmp(buf, tbuf, size) == 0) {
    889 				(void) unlink(new);
    890 				ack();
    891 				return;
    892 			}
    893 			if (opts & VERIFY)
    894 				goto differ;
    895 		}
    896 		goto fixup;
    897 	}
    898 
    899 	if ((f = creat(new, mode)) < 0) {
    900 		if (errno != ENOENT || chkparent(new) < 0 ||
    901 		    (f = creat(new, mode)) < 0)
    902 			goto badnew1;
    903 	}
    904 
    905 	ack();
    906 	wrerr = 0;
    907 	for (i = 0; i < size; i += BUFSIZ) {
    908 		int amt = BUFSIZ;
    909 
    910 		cp = buf;
    911 		if (i + amt > size)
    912 			amt = size - i;
    913 		do {
    914 			int j = read(rem, cp, amt);
    915 
    916 			if (j <= 0) {
    917 				(void) close(f);
    918 				(void) unlink(new);
    919 				cleanup(0);
    920 			}
    921 			amt -= j;
    922 			cp += j;
    923 		} while (amt > 0);
    924 		amt = BUFSIZ;
    925 		if (i + amt > size)
    926 			amt = size - i;
    927 		if (wrerr == 0 && write(f, buf, amt) != amt) {
    928 			wrerr++;
    929 		}
    930 	}
    931 	if (response() < 0) {
    932 		err();
    933 		goto badnew2;
    934 	}
    935 	if (wrerr)
    936 		goto badnew1;
    937 	if (opts & COMPARE) {
    938 		FILE *f1, *f2;
    939 		int c;
    940 
    941 		if ((f1 = fopen(target, "r")) == NULL)
    942 			goto badtarget;
    943 		if ((f2 = fopen(new, "r")) == NULL) {
    944 badnew1:		error("%s:%s: %s\n", host, new, strerror(errno));
    945 			goto badnew2;
    946 		}
    947 		while ((c = getc(f1)) == getc(f2))
    948 			if (c == EOF) {
    949 				(void) fclose(f1);
    950 				(void) fclose(f2);
    951 				ack();
    952 				goto badnew2;
    953 			}
    954 		(void) fclose(f1);
    955 		(void) fclose(f2);
    956 		if (opts & VERIFY) {
    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);
    961 			goto badnew2;
    962 		}
    963 	}
    964 
    965 	if (fchtogm(f, new, mtime, owner, group, mode) < 0) {
    966 badnew2:
    967 		if (f != -1)
    968 			(void) close(f);
    969 		(void) unlink(new);
    970 		return;
    971 	}
    972 	(void) close(f);
    973 
    974 fixup:	if (rename(new, target) < 0) {
    975 badtarget:	error("%s:%s: %s\n", host, target, strerror(errno));
    976 		(void) unlink(new);
    977 		return;
    978 	}
    979 
    980 	if (opts & COMPARE) {
    981 		buf[0] = '\0';
    982 		(void) snprintf(buf + 1, sizeof(buf) - 1,
    983 		    "updated %s\n", target);
    984 		(void) write(rem, buf, strlen(buf + 1) + 1);
    985 	} else
    986 		ack();
    987 }
    988 
    989 /*
    990  * Creat a hard link to existing file.
    991  */
    992 static void
    993 hardlink(char *cmd)
    994 {
    995 	char *cp;
    996 	struct stat stb;
    997 	char *oldname;
    998 	int opts, exists = 0;
    999 
   1000 	cp = cmd;
   1001 	opts = 0;
   1002 	while (*cp >= '0' && *cp <= '7')
   1003 		opts = (opts << 3) | (*cp++ - '0');
   1004 	if (*cp++ != ' ') {
   1005 		error("hardlink: options not delimited\n");
   1006 		return;
   1007 	}
   1008 	oldname = cp;
   1009 	while (*cp && *cp != ' ')
   1010 		cp++;
   1011 	if (*cp != ' ') {
   1012 		error("hardlink: oldname name not delimited\n");
   1013 		return;
   1014 	}
   1015 	*cp++ = '\0';
   1016 
   1017 	if (catname) {
   1018 		(void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
   1019 	}
   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);
   1023 			return;
   1024 		}
   1025 		exists = 1;
   1026 	}
   1027 	if (chkparent(target) < 0 ) {
   1028 		error("%s:%s: %s (no parent)\n",
   1029 			host, target, strerror(errno));
   1030 		return;
   1031 	}
   1032 	if (exists && (unlink(target) < 0)) {
   1033 		error("%s:%s: %s (unlink)\n",
   1034 			host, target, strerror(errno));
   1035 		return;
   1036 	}
   1037 	if (link(oldname, target) < 0) {
   1038 		error("%s:can't link %s to %s\n",
   1039 			host, target, oldname);
   1040 		return;
   1041 	}
   1042 	ack();
   1043 }
   1044 
   1045 /*
   1046  * Check to see if parent directory exists and create one if not.
   1047  */
   1048 static int
   1049 chkparent(char *name)
   1050 {
   1051 	char *cp;
   1052 	struct stat stb;
   1053 
   1054 	cp = strrchr(name, '/');
   1055 	if (cp == NULL || cp == name)
   1056 		return(0);
   1057 	*cp = '\0';
   1058 	if (lstat(name, &stb) < 0) {
   1059 		if (errno == ENOENT && chkparent(name) >= 0 &&
   1060 		    mkdir(name, 0777 & ~oumask) >= 0) {
   1061 			*cp = '/';
   1062 			return(0);
   1063 		}
   1064 	} else if (S_ISDIR(stb.st_mode)) {
   1065 		*cp = '/';
   1066 		return(0);
   1067 	}
   1068 	*cp = '/';
   1069 	return(-1);
   1070 }
   1071 
   1072 /*
   1073  * Change owner, group and mode of file.
   1074  */
   1075 static int
   1076 fchtogm(int fd, char *file, time_t mtime, char *owner, char *group, __mode_t mode)
   1077 {
   1078 	int i;
   1079 	struct timeval tv[2];
   1080 	uid_t uid;
   1081 	gid_t gid;
   1082 	extern char user[];
   1083 
   1084 	uid = userid;
   1085 	if (userid == 0) {
   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) {
   1090 				if (mode & 04000) {
   1091 					note("%s:%s: unknown login name, clearing setuid",
   1092 						host, owner);
   1093 					mode &= ~04000;
   1094 					uid = 0;
   1095 				}
   1096 			} else
   1097 				uid = pw->pw_uid;
   1098 		} else
   1099 			uid = pw->pw_uid;
   1100 		if (*group == ':') {
   1101 			gid = atoi(group + 1);
   1102 			goto ok;
   1103 		}
   1104 	} else if ((mode & 04000) && strcmp(user, owner) != 0)
   1105 		mode &= ~04000;
   1106 	gid = -1;
   1107 	if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
   1108 		if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
   1109 		   || ((gr = getgrnam(group)) == NULL)) {
   1110 			if (mode & 02000) {
   1111 				note("%s:%s: unknown group", host, group);
   1112 				mode &= ~02000;
   1113 			}
   1114 		} else
   1115 			gid = gr->gr_gid;
   1116 	} else
   1117 		gid = gr->gr_gid;
   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])))
   1121 				goto ok;
   1122 		mode &= ~02000;
   1123 		gid = -1;
   1124 	}
   1125 ok:
   1126 	(void) gettimeofday(&tv[0], (struct timezone *)0);
   1127 	tv[1].tv_sec = mtime;
   1128 	tv[1].tv_usec = 0;
   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));
   1136 	return(0);
   1137 }
   1138 
   1139 /*
   1140  * Check for files on the machine being updated that are not on the master
   1141  * machine and remove them.
   1142  */
   1143 static void
   1144 rmchk(int opts)
   1145 {
   1146 	char *cp, *s;
   1147 	struct stat stb;
   1148 
   1149 	if (debug)
   1150 		printf("rmchk()\n");
   1151 
   1152 	/*
   1153 	 * Tell the remote to clean the files from the last directory sent.
   1154 	 */
   1155 	(void) snprintf(buf, sizeof(buf), "C%o\n", opts & VERIFY);
   1156 	if (debug)
   1157 		printf("buf = %s", buf);
   1158 	(void) write(rem, buf, strlen(buf));
   1159 	if (response() < 0)
   1160 		return;
   1161 	for (;;) {
   1162 		cp = s = buf;
   1163 		do {
   1164 			if (read(rem, cp, 1) != 1)
   1165 				lostconn(0);
   1166 		} while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
   1167 
   1168 		switch (*s++) {
   1169 		case 'Q': /* Query if file should be removed */
   1170 			/*
   1171 			 * Return the following codes to remove query.
   1172 			 * N\n -- file exists - DON'T remove.
   1173 			 * Y\n -- file doesn't exist - REMOVE.
   1174 			 */
   1175 			*--cp = '\0';
   1176 			(void) snprintf(tp, sizeof(target) - (tp - target),
   1177 			    "/%s", s);
   1178 			if (debug)
   1179 				printf("check %s\n", target);
   1180 			if (except(target))
   1181 				(void) write(rem, "N\n", 2);
   1182 			else if (lstat(target, &stb) < 0)
   1183 				(void) write(rem, "Y\n", 2);
   1184 			else
   1185 				(void) write(rem, "N\n", 2);
   1186 			break;
   1187 
   1188 		case '\0':
   1189 			*--cp = '\0';
   1190 			if (*s != '\0')
   1191 				dolog(lfp, "%s\n", s);
   1192 			break;
   1193 
   1194 		case 'E':
   1195 			*tp = '\0';
   1196 			ack();
   1197 			return;
   1198 
   1199 		case '\1':
   1200 		case '\2':
   1201 			nerrs++;
   1202 			if (*s != '\n') {
   1203 				if (!iamremote) {
   1204 					fflush(stdout);
   1205 					(void) write(2, s, cp - s);
   1206 				}
   1207 				if (lfp != NULL)
   1208 					(void) fwrite(s, 1, cp - s, lfp);
   1209 			}
   1210 			if (buf[0] == '\2')
   1211 				lostconn(0);
   1212 			break;
   1213 
   1214 		default:
   1215 			error("rmchk: unexpected response '%s'\n", buf);
   1216 			err();
   1217 		}
   1218 	}
   1219 }
   1220 
   1221 /*
   1222  * Check the current directory (initialized by the 'T' command to server())
   1223  * for extraneous files and remove them.
   1224  */
   1225 static void
   1226 clean(char *cp)
   1227 {
   1228 	DIR *d;
   1229 	struct dirent *dp;
   1230 	struct stat stb;
   1231 	char *otp;
   1232 	int len, opts;
   1233 
   1234 	opts = 0;
   1235 	while (*cp >= '0' && *cp <= '7')
   1236 		opts = (opts << 3) | (*cp++ - '0');
   1237 	if (*cp != '\0') {
   1238 		error("clean: options not delimited\n");
   1239 		return;
   1240 	}
   1241 	if ((d = opendir(target)) == NULL) {
   1242 		error("%s:%s: %s\n", host, target, strerror(errno));
   1243 		return;
   1244 	}
   1245 	ack();
   1246 
   1247 	otp = tp;
   1248 	len = tp - target;
   1249 	while ((dp = readdir(d)) != NULL) {
   1250 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
   1251 			continue;
   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);
   1255 			continue;
   1256 		}
   1257 		tp = otp;
   1258 		*tp++ = '/';
   1259 		cp = dp->d_name;
   1260 		while ((*tp++ = *cp++) != 0)
   1261 			;
   1262 		tp--;
   1263 		if (lstat(target, &stb) < 0) {
   1264 			error("%s:%s: %s\n", host, target, strerror(errno));
   1265 			continue;
   1266 		}
   1267 		(void) snprintf(buf, sizeof(buf), "Q%s\n", dp->d_name);
   1268 		(void) write(rem, buf, strlen(buf));
   1269 		cp = buf;
   1270 		do {
   1271 			if (read(rem, cp, 1) != 1)
   1272 				cleanup(0);
   1273 		} while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
   1274 		*--cp = '\0';
   1275 		cp = buf;
   1276 		if (*cp != 'Y')
   1277 			continue;
   1278 		if (opts & VERIFY) {
   1279 			cp = buf;
   1280 			*cp++ = '\0';
   1281 			(void) snprintf(cp, sizeof(buf) - 1,
   1282 			    "need to remove: %s\n", target);
   1283 			(void) write(rem, buf, strlen(cp) + 1);
   1284 		} else
   1285 			removeit(&stb);
   1286 	}
   1287 	closedir(d);
   1288 	(void) write(rem, "E\n", 2);
   1289 	(void) response();
   1290 	tp = otp;
   1291 	*tp = '\0';
   1292 }
   1293 
   1294 /*
   1295  * Remove a file or directory (recursively) and send back an acknowledge
   1296  * or an error message.
   1297  */
   1298 static void
   1299 removeit(struct stat *st)
   1300 {
   1301 	DIR *d;
   1302 	struct dirent *dp;
   1303 	char *cp;
   1304 	struct stat stb;
   1305 	char *otp;
   1306 	int len;
   1307 
   1308 	switch (st->st_mode & S_IFMT) {
   1309 	case S_IFREG:
   1310 	case S_IFLNK:
   1311 		if (unlink(target) < 0)
   1312 			goto bad;
   1313 		goto removed;
   1314 
   1315 	case S_IFDIR:
   1316 		break;
   1317 
   1318 	default:
   1319 		error("%s:%s: not a plain file\n", host, target);
   1320 		return;
   1321 	}
   1322 
   1323 	if ((d = opendir(target)) == NULL)
   1324 		goto bad;
   1325 
   1326 	otp = tp;
   1327 	len = tp - target;
   1328 	while ((dp = readdir(d)) != NULL) {
   1329 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
   1330 			continue;
   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);
   1334 			continue;
   1335 		}
   1336 		tp = otp;
   1337 		*tp++ = '/';
   1338 		cp = dp->d_name;
   1339 		while ((*tp++ = *cp++) != 0)
   1340 			;
   1341 		tp--;
   1342 		if (lstat(target, &stb) < 0) {
   1343 			error("%s:%s: %s\n", host, target, strerror(errno));
   1344 			continue;
   1345 		}
   1346 		removeit(&stb);
   1347 	}
   1348 	closedir(d);
   1349 	tp = otp;
   1350 	*tp = '\0';
   1351 	if (rmdir(target) < 0) {
   1352 bad:
   1353 		error("%s:%s: %s\n", host, target, strerror(errno));
   1354 		return;
   1355 	}
   1356 removed:
   1357 	cp = buf;
   1358 	*cp++ = '\0';
   1359 	(void) snprintf(cp, sizeof(buf) - 1, "removed %s\n", target);
   1360 	(void) write(rem, buf, strlen(cp) + 1);
   1361 }
   1362 
   1363 /*
   1364  * Execute a shell command to handle special cases.
   1365  */
   1366 static void
   1367 dospecial(char *cmd)
   1368 {
   1369 	int fd[2], status, pid, i;
   1370 	char *cp, *s;
   1371 	char sbuf[BUFSIZ];
   1372 
   1373 	if (pipe(fd) < 0) {
   1374 		error("%s\n", strerror(errno));
   1375 		return;
   1376 	}
   1377 	if ((pid = fork()) == 0) {
   1378 		/*
   1379 		 * Return everything the shell commands print.
   1380 		 */
   1381 		(void) close(0);
   1382 		(void) close(1);
   1383 		(void) close(2);
   1384 		(void) open(_PATH_DEVNULL, O_RDONLY);
   1385 		(void) dup(fd[1]);
   1386 		(void) dup(fd[1]);
   1387 		(void) close(fd[0]);
   1388 		(void) close(fd[1]);
   1389 		setgid(groupid);
   1390 		setuid(userid);
   1391 		execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
   1392 		_exit(127);
   1393 	}
   1394 	(void) close(fd[1]);
   1395 	s = sbuf;
   1396 	*s++ = '\0';
   1397 	while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
   1398 		cp = buf;
   1399 		do {
   1400 			*s++ = *cp++;
   1401 			if (cp[-1] != '\n') {
   1402 				if (s < &sbuf[sizeof(sbuf)-1])
   1403 					continue;
   1404 				*s++ = '\n';
   1405 			}
   1406 			/*
   1407 			 * Throw away blank lines.
   1408 			 */
   1409 			if (s == &sbuf[2]) {
   1410 				s--;
   1411 				continue;
   1412 			}
   1413 			(void) write(rem, sbuf, s - sbuf);
   1414 			s = &sbuf[1];
   1415 		} while (--i);
   1416 	}
   1417 	if (s > &sbuf[1]) {
   1418 		*s++ = '\n';
   1419 		(void) write(rem, sbuf, s - sbuf);
   1420 	}
   1421 	while ((i = wait(&status)) != pid && i != -1)
   1422 		;
   1423 	if (i == -1)
   1424 		status = -1;
   1425 	(void) close(fd[0]);
   1426 	if (status)
   1427 		error("shell returned %d\n", status);
   1428 	else
   1429 		ack();
   1430 }
   1431 
   1432 
   1433 void
   1434 dolog(FILE *fp, const char *fmt, ...)
   1435 {
   1436 	va_list ap;
   1437 
   1438 	/* Print changes locally if not quiet mode */
   1439 	if (!qflag) {
   1440 		va_start(ap, fmt);
   1441 		(void)vprintf(fmt, ap);
   1442 		va_end(ap);
   1443 	}
   1444 
   1445 	/* Save changes (for mailing) if really updating files */
   1446 	if (!(options & VERIFY) && fp != NULL) {
   1447 		va_start(ap, fmt);
   1448 		(void)vfprintf(fp, fmt, ap);
   1449 		va_end(ap);
   1450 	}
   1451 }
   1452 
   1453 void
   1454 error(const char *fmt, ...)
   1455 {
   1456 	static FILE *fp;
   1457 	va_list ap;
   1458 
   1459 	++nerrs;
   1460 	if (!fp && !(fp = fdopen(rem, "w")))
   1461 		return;
   1462 	va_start(ap, fmt);
   1463 	if (iamremote) {
   1464 		(void)fprintf(fp, "%crdist: ", 0x01);
   1465 		(void)vfprintf(fp, fmt, ap);
   1466 		fflush(fp);
   1467 	}
   1468 	else {
   1469 		fflush(stdout);
   1470 		(void)fprintf(stderr, "rdist: ");
   1471 		(void)vfprintf(stderr, fmt, ap);
   1472 		fflush(stderr);
   1473 	}
   1474 	va_end(ap);
   1475 	if (lfp != NULL) {
   1476 		(void)fprintf(lfp, "rdist: ");
   1477 		va_start(ap, fmt);
   1478 		(void)vfprintf(lfp, fmt, ap);
   1479 		va_end(ap);
   1480 		fflush(lfp);
   1481 	}
   1482 }
   1483 
   1484 void
   1485 fatal(const char *fmt, ...)
   1486 {
   1487 	static FILE *fp;
   1488 	va_list ap;
   1489 
   1490 	++nerrs;
   1491 	if (!fp && !(fp = fdopen(rem, "w")))
   1492 		return;
   1493 	va_start(ap, fmt);
   1494 	if (iamremote) {
   1495 		(void)fprintf(fp, "%crdist: ", 0x02);
   1496 		(void)vfprintf(fp, fmt, ap);
   1497 		fflush(fp);
   1498 	}
   1499 	else {
   1500 		fflush(stdout);
   1501 		(void)fprintf(stderr, "rdist: ");
   1502 		(void)vfprintf(stderr, fmt, ap);
   1503 		fflush(stderr);
   1504 	}
   1505 	va_end(ap);
   1506 	if (lfp != NULL) {
   1507 		(void)fprintf(lfp, "rdist: ");
   1508 		va_start(ap, fmt);
   1509 		(void)vfprintf(lfp, fmt, ap);
   1510 		va_end(ap);
   1511 		fflush(lfp);
   1512 	}
   1513 	cleanup(0);
   1514 }
   1515 
   1516 static int
   1517 response(void)
   1518 {
   1519 	char *cp, *s;
   1520 	char resp[BUFSIZ];
   1521 
   1522 	if (debug)
   1523 		printf("response()\n");
   1524 
   1525 	cp = s = resp;
   1526 	do {
   1527 		if (read(rem, cp, 1) != 1)
   1528 			lostconn(0);
   1529 	} while (*cp++ != '\n' && cp < &resp[BUFSIZ]);
   1530 
   1531 	switch (*s++) {
   1532 	case '\0':
   1533 		*--cp = '\0';
   1534 		if (*s != '\0') {
   1535 			dolog(lfp, "%s\n", s);
   1536 			return(1);
   1537 		}
   1538 		return(0);
   1539 	case '\3':
   1540 		*--cp = '\0';
   1541 		dolog(lfp, "Note: %s\n",s);
   1542 		return(response());
   1543 
   1544 	default:
   1545 		s--;
   1546 		/* FALLTHROUGH */
   1547 	case '\1':
   1548 	case '\2':
   1549 		nerrs++;
   1550 		if (*s != '\n') {
   1551 			if (!iamremote) {
   1552 				fflush(stdout);
   1553 				(void) write(2, s, cp - s);
   1554 			}
   1555 			if (lfp != NULL)
   1556 				(void) fwrite(s, 1, cp - s, lfp);
   1557 		}
   1558 		if (resp[0] == '\2')
   1559 			lostconn(0);
   1560 		return(-1);
   1561 	}
   1562 }
   1563 
   1564 /*
   1565  * Remove temporary files and do any cleanup operations before exiting.
   1566  */
   1567 void
   1568 /*ARGSUSED*/
   1569 cleanup(int signo __unused)
   1570 {
   1571 	(void) unlink(tempfile);
   1572 	exit(1);
   1573 }
   1574 
   1575 static void
   1576 note(const char *fmt, ...)
   1577 {
   1578 	static char nbuf[BUFSIZ];
   1579 	va_list ap;
   1580 
   1581 	va_start(ap, fmt);
   1582 	(void)vsnprintf(nbuf, sizeof(nbuf), fmt, ap);
   1583 	va_end(ap);
   1584 	comment(nbuf);
   1585 }
   1586 
   1587 static void
   1588 comment(char *s)
   1589 {
   1590 	char c;
   1591 
   1592 	c = '\3';
   1593 	write(rem, &c, 1);
   1594 	write(rem, s, strlen(s));
   1595 	c = '\n';
   1596 	write(rem, &c, 1);
   1597 }
   1598