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