xref: /netbsd-src/usr.bin/rdist/server.c (revision 08c81a9c2dc8c7300e893321eb65c0925d60871c)
1 /*	$NetBSD: server.c,v 1.23 2002/06/14 01:18:55 wiz 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.23 2002/06/14 01:18:55 wiz 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 			log(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 			log(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 			log(lfp, "need to install: %s\n", target);
364 			goto dospecial;
365 		}
366 		log(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 			log(lfp, "need to update: %s\n", target);
474 			goto dospecial;
475 		}
476 		log(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 		log(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 		log(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 			log(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 			log(lfp, "Warning: %s: remote copy is newer\n", target);
672 			return(0);
673 		}
674 	} else if (stp->st_mtime == mtime && stp->st_size == size)
675 		return(0);
676 	return(2);
677 }
678 
679 /*
680  * Query. Check to see if file exists. Return one of the following:
681  *	N\n		- doesn't exist
682  *	Ysize mtime\n	- exists and its a regular file (size & mtime of file)
683  *	Y\n		- exists and its a directory or symbolic link
684  *	^Aerror message\n
685  */
686 static void
687 query(char *name)
688 {
689 	struct stat stb;
690 
691 	if (catname)
692 		(void) snprintf(tp, sizeof(target) - (tp - target),
693 		    "/%s", name);
694 
695 	if (lstat(target, &stb) < 0) {
696 		if (errno == ENOENT) {
697 			if (write(rem, "N\n", 2) < 0)
698 				error("write to remote failed: %s\n",
699 				    strerror(errno));
700 		} else
701 			error("%s:%s: %s\n", host, target, strerror(errno));
702 		*tp = '\0';
703 		return;
704 	}
705 
706 	switch (stb.st_mode & S_IFMT) {
707 	case S_IFREG:
708 		(void)snprintf(buf, sizeof(buf), "Y%lld %ld\n",
709 		    (unsigned long long)stb.st_size, (u_long)stb.st_mtime);
710 		if (write(rem, buf, strlen(buf)) < 0)
711 			error("write to remote failed: %s\n", strerror(errno));
712 		break;
713 
714 	case S_IFLNK:
715 	case S_IFDIR:
716 		if (write(rem, "Y\n", 2) < 0)
717 			error("write to remote failed: %s\n", strerror(errno));
718 		break;
719 
720 	default:
721 		error("%s: not a file or directory\n", name);
722 		break;
723 	}
724 	*tp = '\0';
725 }
726 
727 static void
728 recvf(char *cmd, int type)
729 {
730 	char *cp = cmd;
731 	int f = -1, opts = 0, wrerr, olderrno;
732 	mode_t mode;
733 	off_t i, size;
734 	time_t mtime;
735 	struct stat stb;
736 	char *owner, *group;
737 	char new[BUFSIZ];
738 	extern char *tempname;
739 
740 	while (*cp >= '0' && *cp <= '7')
741 		opts = (opts << 3) | (*cp++ - '0');
742 	if (*cp++ != ' ') {
743 		error("recvf: options not delimited\n");
744 		return;
745 	}
746 	mode = 0;
747 	while (*cp >= '0' && *cp <= '7')
748 		mode = (mode << 3) | (*cp++ - '0');
749 	if (*cp++ != ' ') {
750 		error("recvf: mode not delimited\n");
751 		return;
752 	}
753 	size = 0;
754 	while (isdigit((unsigned char)*cp))
755 		size = size * 10 + (*cp++ - '0');
756 	if (*cp++ != ' ') {
757 		error("recvf: size not delimited\n");
758 		return;
759 	}
760 	mtime = 0;
761 	while (isdigit((unsigned char)*cp))
762 		mtime = mtime * 10 + (*cp++ - '0');
763 	if (*cp++ != ' ') {
764 		error("recvf: mtime not delimited\n");
765 		return;
766 	}
767 	owner = cp;
768 	while (*cp && *cp != ' ')
769 		cp++;
770 	if (*cp != ' ') {
771 		error("recvf: owner name not delimited\n");
772 		return;
773 	}
774 	*cp++ = '\0';
775 	group = cp;
776 	while (*cp && *cp != ' ')
777 		cp++;
778 	if (*cp != ' ') {
779 		error("recvf: group name not delimited\n");
780 		return;
781 	}
782 	*cp++ = '\0';
783 
784 	if (type == S_IFDIR) {
785 		if (catname >= sizeof(stp)) {
786 			error("%s:%s: too many directory levels\n",
787 				host, target);
788 			return;
789 		}
790 		stp[catname] = tp;
791 		if (catname++) {
792 			*tp++ = '/';
793 			while ((*tp++ = *cp++) != 0)
794 				;
795 			tp--;
796 		}
797 		if (opts & VERIFY) {
798 			ack();
799 			return;
800 		}
801 		if (lstat(target, &stb) == 0) {
802 			if (S_ISDIR(stb.st_mode)) {
803 				if ((stb.st_mode & 07777) == mode) {
804 					ack();
805 					return;
806 				}
807 				buf[0] = '\0';
808 				(void) snprintf(buf + 1, sizeof(buf) - 1,
809 			    "%s: Warning: remote mode %o != local mode %o\n",
810 				    target, stb.st_mode & 07777, mode);
811 				if (write(rem, buf, strlen(buf + 1) + 1) < 0)
812 					error("write to remote failed: %s\n",
813 					    strerror(errno));
814 				return;
815 			}
816 			errno = ENOTDIR;
817 		} else if ((errno == ENOENT && mkdir(target, mode) == 0) ||
818 		    (chkparent(target) == 0 && mkdir(target, mode) == 0)) {
819 			if (fchtogm(-1, target, mtime, owner, group, mode) == 0)
820 				ack();
821 			return;
822 		}
823 		error("%s:%s: %s\n", host, target, strerror(errno));
824 		tp = stp[--catname];
825 		*tp = '\0';
826 		return;
827 	}
828 
829 	if (catname)
830 		(void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
831 	cp = strrchr(target, '/');
832 	if (cp == NULL)
833 		strcpy(new, tempname);
834 	else if (cp == target)
835 		(void) snprintf(new, sizeof(new), "/%s", tempname);
836 	else {
837 		*cp = '\0';
838 		(void) snprintf(new, sizeof(new), "%s/%s", target, tempname);
839 		*cp = '/';
840 	}
841 
842 	if (type == S_IFLNK) {
843 		int j;
844 
845 		ack();
846 		cp = buf;
847 		for (i = 0; i < size; i += j) {
848 			if ((j = read(rem, cp, size - i)) <= 0)
849 				cleanup(0);
850 			cp += j;
851 		}
852 		*cp = '\0';
853 		if (response() < 0) {
854 			err();
855 			return;
856 		}
857 		if (symlink(buf, new) < 0) {
858 			if (errno != ENOENT || chkparent(new) < 0 ||
859 			    symlink(buf, new) < 0)
860 				goto badnew1;
861 		}
862 		mode &= 0777;
863 		if (opts & COMPARE) {
864 			char tbuf[BUFSIZ];
865 
866 			if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 &&
867 			    i == size && strncmp(buf, tbuf, size) == 0) {
868 				(void) unlink(new);
869 				ack();
870 				return;
871 			}
872 			if (opts & VERIFY)
873 				goto differ;
874 		}
875 		goto fixup;
876 	}
877 
878 	if ((f = creat(new, mode)) < 0) {
879 		if (errno != ENOENT || chkparent(new) < 0 ||
880 		    (f = creat(new, mode)) < 0)
881 			goto badnew1;
882 	}
883 
884 	ack();
885 	wrerr = 0;
886 	for (i = 0; i < size; i += BUFSIZ) {
887 		int amt = BUFSIZ;
888 
889 		cp = buf;
890 		if (i + amt > size)
891 			amt = size - i;
892 		do {
893 			int j = read(rem, cp, amt);
894 
895 			if (j <= 0) {
896 				(void) close(f);
897 				(void) unlink(new);
898 				cleanup(0);
899 			}
900 			amt -= j;
901 			cp += j;
902 		} while (amt > 0);
903 		amt = BUFSIZ;
904 		if (i + amt > size)
905 			amt = size - i;
906 		if (wrerr == 0 && write(f, buf, amt) != amt) {
907 			olderrno = errno;
908 			wrerr++;
909 		}
910 	}
911 	if (response() < 0) {
912 		err();
913 		goto badnew2;
914 	}
915 	if (wrerr)
916 		goto badnew1;
917 	if (opts & COMPARE) {
918 		FILE *f1, *f2;
919 		int c;
920 
921 		if ((f1 = fopen(target, "r")) == NULL)
922 			goto badtarget;
923 		if ((f2 = fopen(new, "r")) == NULL) {
924 badnew1:		error("%s:%s: %s\n", host, new, strerror(errno));
925 			goto badnew2;
926 		}
927 		while ((c = getc(f1)) == getc(f2))
928 			if (c == EOF) {
929 				(void) fclose(f1);
930 				(void) fclose(f2);
931 				ack();
932 				goto badnew2;
933 			}
934 		(void) fclose(f1);
935 		(void) fclose(f2);
936 		if (opts & VERIFY) {
937 differ:			buf[0] = '\0';
938 			(void)snprintf(buf + 1, sizeof(buf) - 1,
939 			    "need to update: %s\n",target);
940 			(void) write(rem, buf, strlen(buf + 1) + 1);
941 			goto badnew2;
942 		}
943 	}
944 
945 	if (fchtogm(f, new, mtime, owner, group, mode) < 0) {
946 badnew2:
947 		if (f != -1)
948 			(void) close(f);
949 		(void) unlink(new);
950 		return;
951 	}
952 	(void) close(f);
953 
954 fixup:	if (rename(new, target) < 0) {
955 badtarget:	error("%s:%s: %s\n", host, target, strerror(errno));
956 		(void) unlink(new);
957 		return;
958 	}
959 
960 	if (opts & COMPARE) {
961 		buf[0] = '\0';
962 		(void) snprintf(buf + 1, sizeof(buf) - 1,
963 		    "updated %s\n", target);
964 		(void) write(rem, buf, strlen(buf + 1) + 1);
965 	} else
966 		ack();
967 }
968 
969 /*
970  * Creat a hard link to existing file.
971  */
972 static void
973 hardlink(char *cmd)
974 {
975 	char *cp;
976 	struct stat stb;
977 	char *oldname;
978 	int opts, exists = 0;
979 
980 	cp = cmd;
981 	opts = 0;
982 	while (*cp >= '0' && *cp <= '7')
983 		opts = (opts << 3) | (*cp++ - '0');
984 	if (*cp++ != ' ') {
985 		error("hardlink: options not delimited\n");
986 		return;
987 	}
988 	oldname = cp;
989 	while (*cp && *cp != ' ')
990 		cp++;
991 	if (*cp != ' ') {
992 		error("hardlink: oldname name not delimited\n");
993 		return;
994 	}
995 	*cp++ = '\0';
996 
997 	if (catname) {
998 		(void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp);
999 	}
1000 	if (lstat(target, &stb) == 0) {
1001 		if (!S_ISREG(stb.st_mode) && !S_ISLNK(stb.st_mode)) {
1002 			error("%s: %s: not a regular file\n", host, target);
1003 			return;
1004 		}
1005 		exists = 1;
1006 	}
1007 	if (chkparent(target) < 0 ) {
1008 		error("%s:%s: %s (no parent)\n",
1009 			host, target, strerror(errno));
1010 		return;
1011 	}
1012 	if (exists && (unlink(target) < 0)) {
1013 		error("%s:%s: %s (unlink)\n",
1014 			host, target, strerror(errno));
1015 		return;
1016 	}
1017 	if (link(oldname, target) < 0) {
1018 		error("%s:can't link %s to %s\n",
1019 			host, target, oldname);
1020 		return;
1021 	}
1022 	ack();
1023 }
1024 
1025 /*
1026  * Check to see if parent directory exists and create one if not.
1027  */
1028 static int
1029 chkparent(char *name)
1030 {
1031 	char *cp;
1032 	struct stat stb;
1033 
1034 	cp = strrchr(name, '/');
1035 	if (cp == NULL || cp == name)
1036 		return(0);
1037 	*cp = '\0';
1038 	if (lstat(name, &stb) < 0) {
1039 		if (errno == ENOENT && chkparent(name) >= 0 &&
1040 		    mkdir(name, 0777 & ~oumask) >= 0) {
1041 			*cp = '/';
1042 			return(0);
1043 		}
1044 	} else if (S_ISDIR(stb.st_mode)) {
1045 		*cp = '/';
1046 		return(0);
1047 	}
1048 	*cp = '/';
1049 	return(-1);
1050 }
1051 
1052 /*
1053  * Change owner, group and mode of file.
1054  */
1055 static int
1056 fchtogm(int fd, char *file, time_t mtime, char *owner, char *group, __mode_t mode)
1057 {
1058 	int i;
1059 	struct timeval tv[2];
1060 	uid_t uid;
1061 	gid_t gid;
1062 	extern char user[];
1063 
1064 	uid = userid;
1065 	if (userid == 0) {
1066 		if (*owner == ':') {
1067 			uid = atoi(owner + 1);
1068 		} else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
1069 			if ((pw = getpwnam(owner)) == NULL) {
1070 				if (mode & 04000) {
1071 					note("%s:%s: unknown login name, clearing setuid",
1072 						host, owner);
1073 					mode &= ~04000;
1074 					uid = 0;
1075 				}
1076 			} else
1077 				uid = pw->pw_uid;
1078 		} else
1079 			uid = pw->pw_uid;
1080 		if (*group == ':') {
1081 			gid = atoi(group + 1);
1082 			goto ok;
1083 		}
1084 	} else if ((mode & 04000) && strcmp(user, owner) != 0)
1085 		mode &= ~04000;
1086 	gid = -1;
1087 	if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
1088 		if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
1089 		   || ((gr = getgrnam(group)) == NULL)) {
1090 			if (mode & 02000) {
1091 				note("%s:%s: unknown group", host, group);
1092 				mode &= ~02000;
1093 			}
1094 		} else
1095 			gid = gr->gr_gid;
1096 	} else
1097 		gid = gr->gr_gid;
1098 	if (userid && gid >= 0) {
1099 		if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++)
1100 			if (!(strcmp(user, gr->gr_mem[i])))
1101 				goto ok;
1102 		mode &= ~02000;
1103 		gid = -1;
1104 	}
1105 ok:
1106 	(void) gettimeofday(&tv[0], (struct timezone *)0);
1107 	tv[1].tv_sec = mtime;
1108 	tv[1].tv_usec = 0;
1109 	if (fd != -1 ? futimes(fd, tv) < 0 : utimes(file, tv) < 0)
1110 		note("%s: %s utimes: %s", host, file, strerror(errno));
1111 	if (fd != -1 ? fchown(fd, uid, gid) < 0 : chown(file, uid, gid) < 0)
1112 		note("%s: %s chown: %s", host, file, strerror(errno));
1113 	else if (mode & 07000 &&
1114 	   (fd != -1 ? fchmod(fd, mode) < 0 : chmod(file, mode) < 0))
1115 		note("%s: %s chmod: %s", host, file, strerror(errno));
1116 	return(0);
1117 }
1118 
1119 /*
1120  * Check for files on the machine being updated that are not on the master
1121  * machine and remove them.
1122  */
1123 static void
1124 rmchk(int opts)
1125 {
1126 	char *cp, *s;
1127 	struct stat stb;
1128 
1129 	if (debug)
1130 		printf("rmchk()\n");
1131 
1132 	/*
1133 	 * Tell the remote to clean the files from the last directory sent.
1134 	 */
1135 	(void) snprintf(buf, sizeof(buf), "C%o\n", opts & VERIFY);
1136 	if (debug)
1137 		printf("buf = %s", buf);
1138 	(void) write(rem, buf, strlen(buf));
1139 	if (response() < 0)
1140 		return;
1141 	for (;;) {
1142 		cp = s = buf;
1143 		do {
1144 			if (read(rem, cp, 1) != 1)
1145 				lostconn(0);
1146 		} while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
1147 
1148 		switch (*s++) {
1149 		case 'Q': /* Query if file should be removed */
1150 			/*
1151 			 * Return the following codes to remove query.
1152 			 * N\n -- file exists - DON'T remove.
1153 			 * Y\n -- file doesn't exist - REMOVE.
1154 			 */
1155 			*--cp = '\0';
1156 			(void) snprintf(tp, sizeof(target) - (tp - target),
1157 			    "/%s", s);
1158 			if (debug)
1159 				printf("check %s\n", target);
1160 			if (except(target))
1161 				(void) write(rem, "N\n", 2);
1162 			else if (lstat(target, &stb) < 0)
1163 				(void) write(rem, "Y\n", 2);
1164 			else
1165 				(void) write(rem, "N\n", 2);
1166 			break;
1167 
1168 		case '\0':
1169 			*--cp = '\0';
1170 			if (*s != '\0')
1171 				log(lfp, "%s\n", s);
1172 			break;
1173 
1174 		case 'E':
1175 			*tp = '\0';
1176 			ack();
1177 			return;
1178 
1179 		case '\1':
1180 		case '\2':
1181 			nerrs++;
1182 			if (*s != '\n') {
1183 				if (!iamremote) {
1184 					fflush(stdout);
1185 					(void) write(2, s, cp - s);
1186 				}
1187 				if (lfp != NULL)
1188 					(void) fwrite(s, 1, cp - s, lfp);
1189 			}
1190 			if (buf[0] == '\2')
1191 				lostconn(0);
1192 			break;
1193 
1194 		default:
1195 			error("rmchk: unexpected response '%s'\n", buf);
1196 			err();
1197 		}
1198 	}
1199 }
1200 
1201 /*
1202  * Check the current directory (initialized by the 'T' command to server())
1203  * for extraneous files and remove them.
1204  */
1205 static void
1206 clean(char *cp)
1207 {
1208 	DIR *d;
1209 	struct dirent *dp;
1210 	struct stat stb;
1211 	char *otp;
1212 	int len, opts;
1213 
1214 	opts = 0;
1215 	while (*cp >= '0' && *cp <= '7')
1216 		opts = (opts << 3) | (*cp++ - '0');
1217 	if (*cp != '\0') {
1218 		error("clean: options not delimited\n");
1219 		return;
1220 	}
1221 	if ((d = opendir(target)) == NULL) {
1222 		error("%s:%s: %s\n", host, target, strerror(errno));
1223 		return;
1224 	}
1225 	ack();
1226 
1227 	otp = tp;
1228 	len = tp - target;
1229 	while ((dp = readdir(d)) != NULL) {
1230 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1231 			continue;
1232 		if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
1233 			error("%s:%s/%s: Name too long\n",
1234 				host, target, dp->d_name);
1235 			continue;
1236 		}
1237 		tp = otp;
1238 		*tp++ = '/';
1239 		cp = dp->d_name;;
1240 		while ((*tp++ = *cp++) != 0)
1241 			;
1242 		tp--;
1243 		if (lstat(target, &stb) < 0) {
1244 			error("%s:%s: %s\n", host, target, strerror(errno));
1245 			continue;
1246 		}
1247 		(void) snprintf(buf, sizeof(buf), "Q%s\n", dp->d_name);
1248 		(void) write(rem, buf, strlen(buf));
1249 		cp = buf;
1250 		do {
1251 			if (read(rem, cp, 1) != 1)
1252 				cleanup(0);
1253 		} while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
1254 		*--cp = '\0';
1255 		cp = buf;
1256 		if (*cp != 'Y')
1257 			continue;
1258 		if (opts & VERIFY) {
1259 			cp = buf;
1260 			*cp++ = '\0';
1261 			(void) snprintf(cp, sizeof(buf) - 1,
1262 			    "need to remove: %s\n", target);
1263 			(void) write(rem, buf, strlen(cp) + 1);
1264 		} else
1265 			removeit(&stb);
1266 	}
1267 	closedir(d);
1268 	(void) write(rem, "E\n", 2);
1269 	(void) response();
1270 	tp = otp;
1271 	*tp = '\0';
1272 }
1273 
1274 /*
1275  * Remove a file or directory (recursively) and send back an acknowledge
1276  * or an error message.
1277  */
1278 static void
1279 removeit(struct stat *stp)
1280 {
1281 	DIR *d;
1282 	struct dirent *dp;
1283 	char *cp;
1284 	struct stat stb;
1285 	char *otp;
1286 	int len;
1287 
1288 	switch (stp->st_mode & S_IFMT) {
1289 	case S_IFREG:
1290 	case S_IFLNK:
1291 		if (unlink(target) < 0)
1292 			goto bad;
1293 		goto removed;
1294 
1295 	case S_IFDIR:
1296 		break;
1297 
1298 	default:
1299 		error("%s:%s: not a plain file\n", host, target);
1300 		return;
1301 	}
1302 
1303 	if ((d = opendir(target)) == NULL)
1304 		goto bad;
1305 
1306 	otp = tp;
1307 	len = tp - target;
1308 	while ((dp = readdir(d)) != NULL) {
1309 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1310 			continue;
1311 		if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
1312 			error("%s:%s/%s: Name too long\n",
1313 				host, target, dp->d_name);
1314 			continue;
1315 		}
1316 		tp = otp;
1317 		*tp++ = '/';
1318 		cp = dp->d_name;;
1319 		while ((*tp++ = *cp++) != 0)
1320 			;
1321 		tp--;
1322 		if (lstat(target, &stb) < 0) {
1323 			error("%s:%s: %s\n", host, target, strerror(errno));
1324 			continue;
1325 		}
1326 		removeit(&stb);
1327 	}
1328 	closedir(d);
1329 	tp = otp;
1330 	*tp = '\0';
1331 	if (rmdir(target) < 0) {
1332 bad:
1333 		error("%s:%s: %s\n", host, target, strerror(errno));
1334 		return;
1335 	}
1336 removed:
1337 	cp = buf;
1338 	*cp++ = '\0';
1339 	(void) snprintf(cp, sizeof(buf) - 1, "removed %s\n", target);
1340 	(void) write(rem, buf, strlen(cp) + 1);
1341 }
1342 
1343 /*
1344  * Execute a shell command to handle special cases.
1345  */
1346 static void
1347 dospecial(char *cmd)
1348 {
1349 	int fd[2], status, pid, i;
1350 	char *cp, *s;
1351 	char sbuf[BUFSIZ];
1352 
1353 	if (pipe(fd) < 0) {
1354 		error("%s\n", strerror(errno));
1355 		return;
1356 	}
1357 	if ((pid = fork()) == 0) {
1358 		/*
1359 		 * Return everything the shell commands print.
1360 		 */
1361 		(void) close(0);
1362 		(void) close(1);
1363 		(void) close(2);
1364 		(void) open(_PATH_DEVNULL, O_RDONLY);
1365 		(void) dup(fd[1]);
1366 		(void) dup(fd[1]);
1367 		(void) close(fd[0]);
1368 		(void) close(fd[1]);
1369 		setgid(groupid);
1370 		setuid(userid);
1371 		execl(_PATH_BSHELL, "sh", "-c", cmd, 0);
1372 		_exit(127);
1373 	}
1374 	(void) close(fd[1]);
1375 	s = sbuf;
1376 	*s++ = '\0';
1377 	while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
1378 		cp = buf;
1379 		do {
1380 			*s++ = *cp++;
1381 			if (cp[-1] != '\n') {
1382 				if (s < &sbuf[sizeof(sbuf)-1])
1383 					continue;
1384 				*s++ = '\n';
1385 			}
1386 			/*
1387 			 * Throw away blank lines.
1388 			 */
1389 			if (s == &sbuf[2]) {
1390 				s--;
1391 				continue;
1392 			}
1393 			(void) write(rem, sbuf, s - sbuf);
1394 			s = &sbuf[1];
1395 		} while (--i);
1396 	}
1397 	if (s > &sbuf[1]) {
1398 		*s++ = '\n';
1399 		(void) write(rem, sbuf, s - sbuf);
1400 	}
1401 	while ((i = wait(&status)) != pid && i != -1)
1402 		;
1403 	if (i == -1)
1404 		status = -1;
1405 	(void) close(fd[0]);
1406 	if (status)
1407 		error("shell returned %d\n", status);
1408 	else
1409 		ack();
1410 }
1411 
1412 
1413 void
1414 log(FILE *fp, const char *fmt, ...)
1415 {
1416 	va_list ap;
1417 
1418 	/* Print changes locally if not quiet mode */
1419 	if (!qflag) {
1420 		va_start(ap, fmt);
1421 		(void)vprintf(fmt, ap);
1422 		va_end(ap);
1423 	}
1424 
1425 	/* Save changes (for mailing) if really updating files */
1426 	if (!(options & VERIFY) && fp != NULL) {
1427 		va_start(ap, fmt);
1428 		(void)vfprintf(fp, fmt, ap);
1429 		va_end(ap);
1430 	}
1431 }
1432 
1433 void
1434 error(const char *fmt, ...)
1435 {
1436 	static FILE *fp;
1437 	va_list ap;
1438 
1439 	++nerrs;
1440 	if (!fp && !(fp = fdopen(rem, "w")))
1441 		return;
1442 	va_start(ap, fmt);
1443 	if (iamremote) {
1444 		(void)fprintf(fp, "%crdist: ", 0x01);
1445 		(void)vfprintf(fp, fmt, ap);
1446 		fflush(fp);
1447 	}
1448 	else {
1449 		fflush(stdout);
1450 		(void)fprintf(stderr, "rdist: ");
1451 		(void)vfprintf(stderr, fmt, ap);
1452 		fflush(stderr);
1453 	}
1454 	va_end(ap);
1455 	if (lfp != NULL) {
1456 		(void)fprintf(lfp, "rdist: ");
1457 		va_start(ap, fmt);
1458 		(void)vfprintf(lfp, fmt, ap);
1459 		va_end(ap);
1460 		fflush(lfp);
1461 	}
1462 }
1463 
1464 void
1465 fatal(const char *fmt, ...)
1466 {
1467 	static FILE *fp;
1468 	va_list ap;
1469 
1470 	++nerrs;
1471 	if (!fp && !(fp = fdopen(rem, "w")))
1472 		return;
1473 	va_start(ap, fmt);
1474 	if (iamremote) {
1475 		(void)fprintf(fp, "%crdist: ", 0x02);
1476 		(void)vfprintf(fp, fmt, ap);
1477 		fflush(fp);
1478 	}
1479 	else {
1480 		fflush(stdout);
1481 		(void)fprintf(stderr, "rdist: ");
1482 		(void)vfprintf(stderr, fmt, ap);
1483 		fflush(stderr);
1484 	}
1485 	va_end(ap);
1486 	if (lfp != NULL) {
1487 		(void)fprintf(lfp, "rdist: ");
1488 		va_start(ap, fmt);
1489 		(void)vfprintf(lfp, fmt, ap);
1490 		va_end(ap);
1491 		fflush(lfp);
1492 	}
1493 	cleanup(0);
1494 }
1495 
1496 static int
1497 response(void)
1498 {
1499 	char *cp, *s;
1500 	char resp[BUFSIZ];
1501 
1502 	if (debug)
1503 		printf("response()\n");
1504 
1505 	cp = s = resp;
1506 	do {
1507 		if (read(rem, cp, 1) != 1)
1508 			lostconn(0);
1509 	} while (*cp++ != '\n' && cp < &resp[BUFSIZ]);
1510 
1511 	switch (*s++) {
1512 	case '\0':
1513 		*--cp = '\0';
1514 		if (*s != '\0') {
1515 			log(lfp, "%s\n", s);
1516 			return(1);
1517 		}
1518 		return(0);
1519 	case '\3':
1520 		*--cp = '\0';
1521 		log(lfp, "Note: %s\n",s);
1522 		return(response());
1523 
1524 	default:
1525 		s--;
1526 		/* fall into... */
1527 	case '\1':
1528 	case '\2':
1529 		nerrs++;
1530 		if (*s != '\n') {
1531 			if (!iamremote) {
1532 				fflush(stdout);
1533 				(void) write(2, s, cp - s);
1534 			}
1535 			if (lfp != NULL)
1536 				(void) fwrite(s, 1, cp - s, lfp);
1537 		}
1538 		if (resp[0] == '\2')
1539 			lostconn(0);
1540 		return(-1);
1541 	}
1542 }
1543 
1544 /*
1545  * Remove temporary files and do any cleanup operations before exiting.
1546  */
1547 void
1548 cleanup(int signo)
1549 {
1550 	(void) unlink(tempfile);
1551 	exit(1);
1552 }
1553 
1554 static void
1555 note(const char *fmt, ...)
1556 {
1557 	static char buf[BUFSIZ];
1558 	va_list ap;
1559 
1560 	va_start(ap, fmt);
1561 	(void)vsnprintf(buf, sizeof(buf), fmt, ap);
1562 	va_end(ap);
1563 	comment(buf);
1564 }
1565 
1566 static void
1567 comment(char *s)
1568 {
1569 	char c;
1570 
1571 	c = '\3';
1572 	write(rem, &c, 1);
1573 	write(rem, s, strlen(s));
1574 	c = '\n';
1575 	write(rem, &c, 1);
1576 }
1577