xref: /openbsd/usr.bin/rdistd/server.c (revision 5af055cd)
1 /*	$OpenBSD: server.c,v 1.40 2015/12/22 08:48:39 mmcc Exp $	*/
2 
3 /*
4  * Copyright (c) 1983 Regents of the University of California.
5  * 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 <ctype.h>
33 #include <dirent.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <grp.h>
37 #include <limits.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42 #include <unistd.h>
43 
44 #include "server.h"
45 
46 /*
47  * Server routines
48  */
49 
50 char	tempname[sizeof _RDIST_TMP + 1]; /* Tmp file name */
51 char	buf[BUFSIZ];		/* general purpose buffer */
52 char	target[PATH_MAX];	/* target/source directory name */
53 char	*ptarget;		/* pointer to end of target name */
54 int	catname = 0;		/* cat name to target name */
55 char	*sptarget[32];		/* stack of saved ptarget's for directories */
56 char   *fromhost = NULL;	/* Client hostname */
57 static int64_t min_freespace = 0; /* Minimium free space on a filesystem */
58 static int64_t min_freefiles = 0; /* Minimium free # files on a filesystem */
59 int	oumask;			/* Old umask */
60 
61 static int cattarget(char *);
62 static int setownership(char *, int, uid_t, gid_t, int);
63 static int setfilemode(char *, int, int, int);
64 static int fchog(int, char *, char *, char *, int);
65 static int removefile(struct stat *, int);
66 static void doclean(char *);
67 static void clean(char *);
68 static void dospecial(char *);
69 static void docmdspecial(void);
70 static void query(char *);
71 static int chkparent(char *, opt_t);
72 static char *savetarget(char *, opt_t);
73 static void recvfile(char *, opt_t, int, char *, char *, time_t, time_t, off_t);
74 static void recvdir(opt_t, int, char *, char *);
75 static void recvlink(char *, opt_t, int, off_t);
76 static void hardlink(char *);
77 static void setconfig(char *);
78 static void recvit(char *, int);
79 static void dochmog(char *);
80 static void settarget(char *, int);
81 
82 /*
83  * Cat "string" onto the target buffer with error checking.
84  */
85 static int
86 cattarget(char *string)
87 {
88 	if (strlen(string) + strlen(target) + 2 > sizeof(target)) {
89 		message(MT_INFO, "target buffer is not large enough.");
90 		return(-1);
91 	}
92 	if (!ptarget) {
93 		message(MT_INFO, "NULL target pointer set.");
94 		return(-10);
95 	}
96 
97 	(void) snprintf(ptarget, sizeof(target) - (ptarget - target),
98 			"/%s", string);
99 
100 	return(0);
101 }
102 
103 /*
104  * Set uid and gid ownership of a file.
105  */
106 static int
107 setownership(char *file, int fd, uid_t uid, gid_t gid, int islink)
108 {
109 	static int is_root = -1;
110 	int status = -1;
111 
112 	/*
113 	 * We assume only the Superuser can change uid ownership.
114 	 */
115 	switch (is_root) {
116 	case -1:
117 		is_root = getuid() == 0;
118 		if (is_root)
119 			break;
120 		/* FALLTHROUGH */
121 	case 0:
122 		uid = -1;
123 		break;
124 	case 1:
125 		break;
126 	}
127 
128 	if (fd != -1 && !islink)
129 		status = fchown(fd, uid, gid);
130 	else
131 		status = fchownat(AT_FDCWD, file, uid, gid,
132 		    AT_SYMLINK_NOFOLLOW);
133 
134 	if (status < 0) {
135 		if (uid == (uid_t)-1)
136 			message(MT_NOTICE, "%s: chgrp %d failed: %s",
137 				target, gid, SYSERR);
138 		else
139 			message(MT_NOTICE, "%s: chown %d:%d failed: %s",
140 				target, uid, gid, SYSERR);
141 		return(-1);
142 	}
143 
144 	return(0);
145 }
146 
147 /*
148  * Set mode of a file
149  */
150 static int
151 setfilemode(char *file, int fd, int mode, int islink)
152 {
153 	int status = -1;
154 
155 	if (mode == -1)
156 		return(0);
157 
158 	if (islink)
159 		status = fchmodat(AT_FDCWD, file, mode, AT_SYMLINK_NOFOLLOW);
160 
161 	if (fd != -1 && !islink)
162 		status = fchmod(fd, mode);
163 
164 	if (status < 0 && !islink)
165 		status = chmod(file, mode);
166 
167 	if (status < 0) {
168 		message(MT_NOTICE, "%s: chmod failed: %s", target, SYSERR);
169 		return(-1);
170 	}
171 
172 	return(0);
173 }
174 /*
175  * Change owner, group and mode of file.
176  */
177 static int
178 fchog(int fd, char *file, char *owner, char *group, int mode)
179 {
180 	static struct group *gr = NULL;
181 	int i;
182 	struct stat st;
183 	uid_t uid;
184 	gid_t gid;
185 	gid_t primegid = (gid_t)-2;
186 
187 	uid = userid;
188 	if (userid == 0) {	/* running as root; take anything */
189 		if (*owner == ':') {
190 			uid = (uid_t) atoi(owner + 1);
191 		} else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
192 			if ((pw = getpwnam(owner)) == NULL) {
193 				if (mode != -1 && IS_ON(mode, S_ISUID)) {
194 					message(MT_NOTICE,
195 			      "%s: unknown login name \"%s\", clearing setuid",
196 						target, owner);
197 					mode &= ~S_ISUID;
198 					uid = 0;
199 				} else
200 					message(MT_NOTICE,
201 					"%s: unknown login name \"%s\"",
202 						target, owner);
203 			} else
204 				uid = pw->pw_uid;
205 		} else {
206 			uid = pw->pw_uid;
207 			primegid = pw->pw_gid;
208 		}
209 		if (*group == ':') {
210 			gid = (gid_t)atoi(group + 1);
211 			goto ok;
212 		}
213 	} else {	/* not root, setuid only if user==owner */
214 		struct passwd *lupw;
215 
216 		if (mode != -1) {
217 			if (IS_ON(mode, S_ISUID) &&
218 			    strcmp(locuser, owner) != 0)
219 				mode &= ~S_ISUID;
220 			if (mode)
221 				mode &= ~S_ISVTX; /* and strip sticky too */
222 		}
223 
224 		if ((lupw = getpwnam(locuser)) != NULL)
225 			primegid = lupw->pw_gid;
226 	}
227 
228 	gid = (gid_t)-1;
229 	if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
230 		if ((*group == ':' &&
231 		     (getgrgid(gid = atoi(group + 1)) == NULL))
232 		    || ((gr = (struct group *)getgrnam(group)) == NULL)) {
233 			if (mode != -1 && IS_ON(mode, S_ISGID)) {
234 				message(MT_NOTICE,
235 				"%s: unknown group \"%s\", clearing setgid",
236 					target, group);
237 				mode &= ~S_ISGID;
238 			} else
239 				message(MT_NOTICE,
240 					"%s: unknown group \"%s\"",
241 					target, group);
242 		} else
243 			gid = gr->gr_gid;
244 	} else
245 		gid = gr->gr_gid;
246 
247 	if (userid && gid >= 0 && gid != primegid) {
248 		if (gr)
249 			for (i = 0; gr->gr_mem[i] != NULL; i++)
250 				if (strcmp(locuser, gr->gr_mem[i]) == 0)
251 					goto ok;
252 		if (mode != -1 && IS_ON(mode, S_ISGID)) {
253 			message(MT_NOTICE,
254 				"%s: user %s not in group %s, clearing setgid",
255 				target, locuser, group);
256 			mode &= ~S_ISGID;
257 		}
258 		gid = (gid_t)-1;
259 	}
260 ok:
261 	if (stat(file, &st) == -1) {
262 		error("%s: Stat failed %s", file, SYSERR);
263 		return -1;
264 	}
265 	/*
266 	 * Set uid and gid ownership.  If that fails, strip setuid and
267 	 * setgid bits from mode.  Once ownership is set, successful
268 	 * or otherwise, set the new file mode.
269 	 */
270 	if (setownership(file, fd, uid, gid, S_ISLNK(st.st_mode)) < 0) {
271 		if (mode != -1 && IS_ON(mode, S_ISUID)) {
272 			message(MT_NOTICE,
273 				"%s: chown failed, clearing setuid", target);
274 			mode &= ~S_ISUID;
275 		}
276 		if (mode != -1 && IS_ON(mode, S_ISGID)) {
277 			message(MT_NOTICE,
278 				"%s: chown failed, clearing setgid", target);
279 			mode &= ~S_ISGID;
280 		}
281 	}
282 	(void) setfilemode(file, fd, mode, S_ISLNK(st.st_mode));
283 
284 
285 	return(0);
286 }
287 
288 /*
289  * Remove a file or directory (recursively) and send back an acknowledge
290  * or an error message.
291  */
292 static int
293 removefile(struct stat *statb, int silent)
294 {
295 	DIR *d;
296 	static struct dirent *dp;
297 	char *cp;
298 	struct stat stb;
299 	char *optarget;
300 	int len, failures = 0;
301 
302 	switch (statb->st_mode & S_IFMT) {
303 	case S_IFREG:
304 	case S_IFLNK:
305 	case S_IFCHR:
306 	case S_IFBLK:
307 	case S_IFSOCK:
308 	case S_IFIFO:
309 		if (unlink(target) < 0) {
310 			if (errno == ETXTBSY) {
311 				if (!silent)
312 					message(MT_REMOTE|MT_NOTICE,
313 						"%s: unlink failed: %s",
314 						target, SYSERR);
315 				return(0);
316 			} else {
317 				error("%s: unlink failed: %s", target, SYSERR);
318 				return(-1);
319 			}
320 		}
321 		goto removed;
322 
323 	case S_IFDIR:
324 		break;
325 
326 	default:
327 		error("%s: not a plain file", target);
328 		return(-1);
329 	}
330 
331 	errno = 0;
332 	if ((d = opendir(target)) == NULL) {
333 		error("%s: opendir failed: %s", target, SYSERR);
334 		return(-1);
335 	}
336 
337 	optarget = ptarget;
338 	len = ptarget - target;
339 	while ((dp = readdir(d)) != NULL) {
340 		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
341 		    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
342 			continue;
343 
344 		if (len + 1 + (int)strlen(dp->d_name) >= PATH_MAX - 1) {
345 			if (!silent)
346 				message(MT_REMOTE|MT_WARNING,
347 					"%s/%s: Name too long",
348 					target, dp->d_name);
349 			continue;
350 		}
351 		ptarget = optarget;
352 		*ptarget++ = '/';
353 		cp = dp->d_name;
354 		while ((*ptarget++ = *cp++) != '\0')
355 			continue;
356 		ptarget--;
357 		if (lstat(target, &stb) < 0) {
358 			if (!silent)
359 				message(MT_REMOTE|MT_WARNING,
360 					"%s: lstat failed: %s",
361 					target, SYSERR);
362 			continue;
363 		}
364 		if (removefile(&stb, 0) < 0)
365 			++failures;
366 	}
367 	(void) closedir(d);
368 	ptarget = optarget;
369 	*ptarget = CNULL;
370 
371 	if (failures)
372 		return(-1);
373 
374 	if (rmdir(target) < 0) {
375 		error("%s: rmdir failed: %s", target, SYSERR);
376 		return(-1);
377 	}
378 removed:
379 #if NEWWAY
380 	if (!silent)
381 		message(MT_CHANGE|MT_REMOTE, "%s: removed", target);
382 #else
383 	/*
384 	 * We use MT_NOTICE instead of MT_CHANGE because this function is
385 	 * sometimes called by other functions that are suppose to return a
386 	 * single ack() back to the client (rdist).  This is a kludge until
387 	 * the Rdist protocol is re-done.  Sigh.
388 	 */
389 	message(MT_NOTICE|MT_REMOTE, "%s: removed", target);
390 #endif
391 	return(0);
392 }
393 
394 /*
395  * Check the current directory (initialized by the 'T' command to server())
396  * for extraneous files and remove them.
397  */
398 static void
399 doclean(char *cp)
400 {
401 	DIR *d;
402 	struct dirent *dp;
403 	struct stat stb;
404 	char *optarget, *ep;
405 	int len;
406 	opt_t opts;
407 	char targ[PATH_MAX*4];
408 
409 	opts = strtol(cp, &ep, 8);
410 	if (*ep != CNULL) {
411 		error("clean: options not delimited");
412 		return;
413 	}
414 	if ((d = opendir(target)) == NULL) {
415 		error("%s: opendir failed: %s", target, SYSERR);
416 		return;
417 	}
418 	ack();
419 
420 	optarget = ptarget;
421 	len = ptarget - target;
422 	while ((dp = readdir(d)) != NULL) {
423 		if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
424 		    (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
425 			continue;
426 
427 		if (len + 1 + (int)strlen(dp->d_name) >= PATH_MAX - 1) {
428 			message(MT_REMOTE|MT_WARNING, "%s/%s: Name too long",
429 				target, dp->d_name);
430 			continue;
431 		}
432 		ptarget = optarget;
433 		*ptarget++ = '/';
434 		cp = dp->d_name;
435 		while ((*ptarget++ = *cp++) != '\0')
436 			continue;
437 		ptarget--;
438 		if (lstat(target, &stb) < 0) {
439 			message(MT_REMOTE|MT_WARNING, "%s: lstat failed: %s",
440 				target, SYSERR);
441 			continue;
442 		}
443 
444 		ENCODE(targ, dp->d_name);
445 		(void) sendcmd(CC_QUERY, "%s", targ);
446 		(void) remline(cp = buf, sizeof(buf), TRUE);
447 
448 		if (*cp != CC_YES)
449 			continue;
450 
451 		if (IS_ON(opts, DO_VERIFY))
452 			message(MT_REMOTE|MT_INFO, "%s: need to remove",
453 				target);
454 		else
455 			(void) removefile(&stb, 0);
456 	}
457 	(void) closedir(d);
458 
459 	ptarget = optarget;
460 	*ptarget = CNULL;
461 }
462 
463 /*
464  * Frontend to doclean().
465  */
466 static void
467 clean(char *cp)
468 {
469 	doclean(cp);
470 	(void) sendcmd(CC_END, NULL);
471 	(void) response();
472 }
473 
474 /*
475  * Execute a shell command to handle special cases.
476  * We can't really set an alarm timeout here since we
477  * have no idea how long the command should take.
478  */
479 static void
480 dospecial(char *xcmd)
481 {
482 	char cmd[BUFSIZ];
483 	if (DECODE(cmd, xcmd) == -1) {
484 		error("dospecial: Cannot decode command.");
485 		return;
486 	}
487 	runcommand(cmd);
488 }
489 
490 /*
491  * Do a special cmd command.  This differs from normal special
492  * commands in that it's done after an entire command has been updated.
493  * The list of updated target files is sent one at a time with RC_FILE
494  * commands.  Each one is added to an environment variable defined by
495  * E_FILES.  When an RC_COMMAND is finally received, the E_FILES variable
496  * is stuffed into our environment and a normal dospecial() command is run.
497  */
498 static void
499 docmdspecial(void)
500 {
501 	char *cp;
502 	char *cmd, *env = NULL;
503 	int n;
504 	size_t len;
505 
506 	/* We're ready */
507 	ack();
508 
509 	for ( ; ; ) {
510 		n = remline(cp = buf, sizeof(buf), FALSE);
511 		if (n <= 0) {
512 			error("cmdspecial: premature end of input.");
513 			return;
514 		}
515 
516 		switch (*cp++) {
517 		case RC_FILE:
518 			if (env == NULL) {
519 				len = (2 * sizeof(E_FILES)) + strlen(cp) + 10;
520 				env = xmalloc(len);
521 				(void) snprintf(env, len, "export %s;%s=%s",
522 					       E_FILES, E_FILES, cp);
523 			} else {
524 				len = strlen(env) + 1 + strlen(cp) + 1;
525 				env = xrealloc(env, len);
526 				(void) strlcat(env, ":", len);
527 				(void) strlcat(env, cp, len);
528 			}
529 			ack();
530 			break;
531 
532 		case RC_COMMAND:
533 			if (env) {
534 				len = strlen(env) + 1 + strlen(cp) + 1;
535 				env = xrealloc(env, len);
536 				(void) strlcat(env, ";", len);
537 				(void) strlcat(env, cp, len);
538 				cmd = env;
539 			} else
540 				cmd = cp;
541 
542 			dospecial(cmd);
543 			if (env)
544 				(void) free(env);
545 			return;
546 
547 		default:
548 			error("Unknown cmdspecial command '%s'.", cp);
549 			return;
550 		}
551 	}
552 }
553 
554 /*
555  * Query. Check to see if file exists. Return one of the following:
556  *
557  *  QC_ONNFS		- resides on a NFS
558  *  QC_ONRO		- resides on a Read-Only filesystem
559  *  QC_NO		- doesn't exist
560  *  QC_YESsize mtime 	- exists and its a regular file (size & mtime of file)
561  *  QC_YES		- exists and its a directory or symbolic link
562  *  QC_ERRMSGmessage 	- error message
563  */
564 static void
565 query(char *xname)
566 {
567 	static struct stat stb;
568 	int s = -1, stbvalid = 0;
569 	char name[PATH_MAX];
570 
571 	if (DECODE(name, xname) == -1) {
572 		error("query: Cannot decode filename");
573 		return;
574 	}
575 
576 	if (catname && cattarget(name) < 0)
577 		return;
578 
579 	if (IS_ON(options, DO_CHKNFS)) {
580 		s = is_nfs_mounted(target, &stb, &stbvalid);
581 		if (s > 0)
582 			(void) sendcmd(QC_ONNFS, NULL);
583 
584 		/* Either the above check was true or an error occurred */
585 		/* and is_nfs_mounted sent the error message */
586 		if (s != 0) {
587 			*ptarget = CNULL;
588 			return;
589 		}
590 	}
591 
592 	if (IS_ON(options, DO_CHKREADONLY)) {
593 		s = is_ro_mounted(target, &stb, &stbvalid);
594 		if (s > 0)
595 			(void) sendcmd(QC_ONRO, NULL);
596 
597 		/* Either the above check was true or an error occurred */
598 		/* and is_ro_mounted sent the error message */
599 		if (s != 0) {
600 			*ptarget = CNULL;
601 			return;
602 		}
603 	}
604 
605 	if (IS_ON(options, DO_CHKSYM)) {
606 		if (is_symlinked(target, &stb, &stbvalid) > 0) {
607 			(void) sendcmd(QC_SYM, NULL);
608 			return;
609 		}
610 	}
611 
612 	/*
613 	 * If stbvalid is false, "stb" is not valid because the stat()
614 	 * by is_*_mounted() either failed or does not match "target".
615 	 */
616 	if (!stbvalid && lstat(target, &stb) < 0) {
617 		if (errno == ENOENT)
618 			(void) sendcmd(QC_NO, NULL);
619 		else
620 			error("%s: lstat failed: %s", target, SYSERR);
621 		*ptarget = CNULL;
622 		return;
623 	}
624 
625 	switch (stb.st_mode & S_IFMT) {
626 	case S_IFLNK:
627 	case S_IFDIR:
628 	case S_IFREG:
629 		(void) sendcmd(QC_YES, "%lld %lld %o %s %s",
630 			       (long long) stb.st_size,
631 			       (long long) stb.st_mtime,
632 			       stb.st_mode & 07777,
633 			       getusername(stb.st_uid, target, options),
634 			       getgroupname(stb.st_gid, target, options));
635 		break;
636 
637 	default:
638 		error("%s: not a file or directory", target);
639 		break;
640 	}
641 	*ptarget = CNULL;
642 }
643 
644 /*
645  * Check to see if parent directory exists and create one if not.
646  */
647 static int
648 chkparent(char *name, opt_t opts)
649 {
650 	char *cp;
651 	struct stat stb;
652 	int r = -1;
653 
654 	debugmsg(DM_CALL, "chkparent(%s, %#x) start\n", name, opts);
655 
656 	cp = strrchr(name, '/');
657 	if (cp == NULL || cp == name)
658 		return(0);
659 
660 	*cp = CNULL;
661 
662 	if (lstat(name, &stb) < 0) {
663 		if (errno == ENOENT && chkparent(name, opts) >= 0) {
664 			if (mkdir(name, 0777 & ~oumask) == 0) {
665 				message(MT_NOTICE, "%s: mkdir", name);
666 				r = 0;
667 			} else
668 				debugmsg(DM_MISC,
669 					 "chkparent(%s, %#04o) mkdir fail: %s\n",
670 					 name, opts, SYSERR);
671 		}
672 	} else	/* It exists */
673 		r = 0;
674 
675 	/* Put back what we took away */
676 	*cp = '/';
677 
678 	return(r);
679 }
680 
681 /*
682  * Save a copy of 'file' by renaming it.
683  */
684 static char *
685 savetarget(char *file, opt_t opts)
686 {
687 	static char savefile[PATH_MAX];
688 
689 	if (strlen(file) + sizeof(SAVE_SUFFIX) + 1 > PATH_MAX) {
690 		error("%s: Cannot save: Save name too long", file);
691 		return(NULL);
692 	}
693 
694 	if (IS_ON(opts, DO_HISTORY)) {
695 		int i;
696 		struct stat st;
697 		/*
698 		 * There is a race here, but the worst that can happen
699 		 * is to lose a version of the file
700 		 */
701 		for (i = 1; i < 1000; i++) {
702 			(void) snprintf(savefile, sizeof(savefile),
703 					"%s;%.3d", file, i);
704 			if (lstat(savefile, &st) == -1 && errno == ENOENT)
705 				break;
706 
707 		}
708 		if (i == 1000) {
709 			message(MT_NOTICE,
710 			    "%s: More than 1000 versions for %s; reusing 1\n",
711 				savefile, SYSERR);
712 			i = 1;
713 			(void) snprintf(savefile, sizeof(savefile),
714 					"%s;%.3d", file, i);
715 		}
716 	}
717 	else {
718 		(void) snprintf(savefile, sizeof(savefile), "%s%s",
719 				file, SAVE_SUFFIX);
720 
721 		if (unlink(savefile) != 0 && errno != ENOENT) {
722 			message(MT_NOTICE, "%s: remove failed: %s",
723 				savefile, SYSERR);
724 			return(NULL);
725 		}
726 	}
727 
728 	if (rename(file, savefile) != 0 && errno != ENOENT) {
729 		error("%s -> %s: rename failed: %s",
730 		      file, savefile, SYSERR);
731 		return(NULL);
732 	}
733 
734 	return(savefile);
735 }
736 
737 /*
738  * Receive a file
739  */
740 static void
741 recvfile(char *new, opt_t opts, int mode, char *owner, char *group,
742 	 time_t mtime, time_t atime, off_t size)
743 {
744 	int f, wrerr, olderrno;
745 	off_t i;
746 	char *cp;
747 	char *savefile = NULL;
748 	static struct stat statbuff;
749 
750 	/*
751 	 * Create temporary file
752 	 */
753 	if ((f = mkstemp(new)) < 0) {
754 		if (errno != ENOENT || chkparent(new, opts) < 0 ||
755 		    (f = mkstemp(new)) < 0) {
756 			error("%s: create failed: %s", new, SYSERR);
757 			return;
758 		}
759 	}
760 
761 	/*
762 	 * Receive the file itself
763 	 */
764 	ack();
765 	wrerr = 0;
766 	olderrno = 0;
767 	for (i = 0; i < size; i += BUFSIZ) {
768 		off_t amt = BUFSIZ;
769 
770 		cp = buf;
771 		if (i + amt > size)
772 			amt = size - i;
773 		do {
774 			ssize_t j;
775 
776 			j = readrem(cp, amt);
777 			if (j <= 0) {
778 				(void) close(f);
779 				(void) unlink(new);
780 				fatalerr(
781 				   "Read error occurred while receiving file.");
782 				finish();
783 			}
784 			amt -= j;
785 			cp += j;
786 		} while (amt > 0);
787 		amt = BUFSIZ;
788 		if (i + amt > size)
789 			amt = size - i;
790 		if (wrerr == 0 && xwrite(f, buf, amt) != amt) {
791 			olderrno = errno;
792 			wrerr++;
793 		}
794 	}
795 
796 	if (response() < 0) {
797 		(void) close(f);
798 		(void) unlink(new);
799 		return;
800 	}
801 
802 	if (wrerr) {
803 		error("%s: Write error: %s", new, strerror(olderrno));
804 		(void) close(f);
805 		(void) unlink(new);
806 		return;
807 	}
808 
809 	/*
810 	 * Do file comparison if enabled
811 	 */
812 	if (IS_ON(opts, DO_COMPARE)) {
813 		FILE *f1, *f2;
814 		int c;
815 
816 		errno = 0;	/* fopen is not a syscall */
817 		if ((f1 = fopen(target, "r")) == NULL) {
818 			error("%s: open for read failed: %s", target, SYSERR);
819 			(void) close(f);
820 			(void) unlink(new);
821 			return;
822 		}
823 		errno = 0;
824 		if ((f2 = fopen(new, "r")) == NULL) {
825 			error("%s: open for read failed: %s", new, SYSERR);
826 			(void) fclose(f1);
827 			(void) close(f);
828 			(void) unlink(new);
829 			return;
830 		}
831 		while ((c = getc(f1)) == getc(f2))
832 			if (c == EOF) {
833 				debugmsg(DM_MISC,
834 					 "Files are the same '%s' '%s'.",
835 					 target, new);
836 				(void) fclose(f1);
837 				(void) fclose(f2);
838 				(void) close(f);
839 				(void) unlink(new);
840 				/*
841 				 * This isn't an error per-se, but we
842 				 * need to indicate to the master that
843 				 * the file was not updated.
844 				 */
845 				error("");
846 				return;
847 			}
848 		debugmsg(DM_MISC, "Files are different '%s' '%s'.",
849 			 target, new);
850 		(void) fclose(f1);
851 		(void) fclose(f2);
852 		if (IS_ON(opts, DO_VERIFY)) {
853 			message(MT_REMOTE|MT_INFO, "%s: need to update",
854 				target);
855 			(void) close(f);
856 			(void) unlink(new);
857 			return;
858 		}
859 	}
860 
861 	/*
862 	 * Set owner, group, and file mode
863 	 */
864 	if (fchog(f, new, owner, group, mode) < 0) {
865 		(void) close(f);
866 		(void) unlink(new);
867 		return;
868 	}
869 	(void) close(f);
870 
871 	/*
872 	 * Perform utimes() after file is closed to make
873 	 * certain OS's, such as NeXT 2.1, happy.
874 	 */
875 	if (setfiletime(new, time(NULL), mtime) < 0)
876 		message(MT_NOTICE, "%s: utimes failed: %s", new, SYSERR);
877 
878 	/*
879 	 * Try to save target file from being over-written
880 	 */
881 	if (IS_ON(opts, DO_SAVETARGETS))
882 		if ((savefile = savetarget(target, opts)) == NULL) {
883 			(void) unlink(new);
884 			return;
885 		}
886 
887 	/*
888 	 * If the target is a directory, we need to remove it first
889 	 * before we can rename the new file.
890 	 */
891 	if ((stat(target, &statbuff) == 0) && S_ISDIR(statbuff.st_mode)) {
892 		char *saveptr = ptarget;
893 
894 		ptarget = &target[strlen(target)];
895 		removefile(&statbuff, 0);
896 		ptarget = saveptr;
897 	}
898 
899 	/*
900 	 * Install new (temporary) file as the actual target
901 	 */
902 	if (rename(new, target) < 0) {
903 		static const char fmt[] = "%s -> %s: rename failed: %s";
904 		struct stat stb;
905 		/*
906 		 * If the rename failed due to "Text file busy", then
907 		 * try to rename the target file and retry the rename.
908 		 */
909 		switch (errno) {
910 		case ETXTBSY:
911 			/* Save the target */
912 			if ((savefile = savetarget(target, opts)) != NULL) {
913 				/* Retry installing new file as target */
914 				if (rename(new, target) < 0) {
915 					error(fmt, new, target, SYSERR);
916 					/* Try to put back save file */
917 					if (rename(savefile, target) < 0)
918 						error(fmt,
919 						      savefile, target, SYSERR);
920 					(void) unlink(new);
921 				} else
922 					message(MT_NOTICE, "%s: renamed to %s",
923 						target, savefile);
924 				/*
925 				 * XXX: We should remove the savefile here.
926 				 *	But we are nice to nfs clients and
927 				 *	we keep it.
928 				 */
929 			}
930 			break;
931 		case EISDIR:
932 			/*
933 			 * See if target is a directory and remove it if it is
934 			 */
935 			if (lstat(target, &stb) == 0) {
936 				if (S_ISDIR(stb.st_mode)) {
937 					char *optarget = ptarget;
938 					for (ptarget = target; *ptarget;
939 						ptarget++);
940 					/* If we failed to remove, we'll catch
941 					   it later */
942 					(void) removefile(&stb, 1);
943 					ptarget = optarget;
944 				}
945 			}
946 			if (rename(new, target) >= 0)
947 				break;
948 			/*FALLTHROUGH*/
949 
950 		default:
951 			error(fmt, new, target, SYSERR);
952 			(void) unlink(new);
953 			break;
954 		}
955 	}
956 
957 	if (IS_ON(opts, DO_COMPARE))
958 		message(MT_REMOTE|MT_CHANGE, "%s: updated", target);
959 	else
960 		ack();
961 }
962 
963 /*
964  * Receive a directory
965  */
966 static void
967 recvdir(opt_t opts, int mode, char *owner, char *group)
968 {
969 	static char lowner[100], lgroup[100];
970 	char *cp;
971 	struct stat stb;
972 	int s;
973 
974 	s = lstat(target, &stb);
975 	if (s == 0) {
976 		/*
977 		 * If target is not a directory, remove it
978 		 */
979 		if (!S_ISDIR(stb.st_mode)) {
980 			if (IS_ON(opts, DO_VERIFY))
981 				message(MT_NOTICE, "%s: need to remove",
982 					target);
983 			else {
984 				if (unlink(target) < 0) {
985 					error("%s: remove failed: %s",
986 					      target, SYSERR);
987 					return;
988 				}
989 			}
990 			s = -1;
991 			errno = ENOENT;
992 		} else {
993 			if (!IS_ON(opts, DO_NOCHKMODE) &&
994 			    (stb.st_mode & 07777) != mode) {
995 				if (IS_ON(opts, DO_VERIFY))
996 					message(MT_NOTICE,
997 						"%s: need to chmod to %#04o",
998 						target, mode);
999 				else if (chmod(target, mode) != 0)
1000 					message(MT_NOTICE,
1001 				  "%s: chmod from %#04o to %#04o failed: %s",
1002 						target,
1003 						stb.st_mode & 07777,
1004 						mode,
1005 						SYSERR);
1006 				else
1007 					message(MT_NOTICE,
1008 						"%s: chmod from %#04o to %#04o",
1009 						target,
1010 						stb.st_mode & 07777,
1011 						mode);
1012 			}
1013 
1014 			/*
1015 			 * Check ownership and set if necessary
1016 			 */
1017 			lowner[0] = CNULL;
1018 			lgroup[0] = CNULL;
1019 
1020 			if (!IS_ON(opts, DO_NOCHKOWNER) && owner) {
1021 				int o;
1022 
1023 				o = (owner[0] == ':') ? opts & DO_NUMCHKOWNER :
1024 					opts;
1025 				if ((cp = getusername(stb.st_uid, target, o))
1026 				    != NULL)
1027 					if (strcmp(owner, cp))
1028 						(void) strlcpy(lowner, cp,
1029 						    sizeof(lowner));
1030 			}
1031 			if (!IS_ON(opts, DO_NOCHKGROUP) && group) {
1032 				int o;
1033 
1034 				o = (group[0] == ':') ? opts & DO_NUMCHKGROUP :
1035 					opts;
1036 				if ((cp = getgroupname(stb.st_gid, target, o))
1037 				    != NULL)
1038 					if (strcmp(group, cp))
1039 						(void) strlcpy(lgroup, cp,
1040 						    sizeof(lgroup));
1041 			}
1042 
1043 			/*
1044 			 * Need to set owner and/or group
1045 			 */
1046 #define PRN(n) ((n[0] == ':') ? n+1 : n)
1047 			if (lowner[0] != CNULL || lgroup[0] != CNULL) {
1048 				if (lowner[0] == CNULL &&
1049 				    (cp = getusername(stb.st_uid,
1050 						      target, opts)))
1051 					(void) strlcpy(lowner, cp,
1052 					    sizeof(lowner));
1053 				if (lgroup[0] == CNULL &&
1054 				    (cp = getgroupname(stb.st_gid,
1055 						       target, opts)))
1056 					(void) strlcpy(lgroup, cp,
1057 					    sizeof(lgroup));
1058 
1059 				if (IS_ON(opts, DO_VERIFY))
1060 					message(MT_NOTICE,
1061 				"%s: need to chown from %s:%s to %s:%s",
1062 						target,
1063 						PRN(lowner), PRN(lgroup),
1064 						PRN(owner), PRN(group));
1065 				else {
1066 					if (fchog(-1, target, owner,
1067 						  group, -1) == 0)
1068 						message(MT_NOTICE,
1069 					       "%s: chown from %s:%s to %s:%s",
1070 							target,
1071 							PRN(lowner),
1072 							PRN(lgroup),
1073 							PRN(owner),
1074 							PRN(group));
1075 				}
1076 			}
1077 #undef PRN
1078 			ack();
1079 			return;
1080 		}
1081 	}
1082 
1083 	if (IS_ON(opts, DO_VERIFY)) {
1084 		ack();
1085 		return;
1086 	}
1087 
1088 	/*
1089 	 * Create the directory
1090 	 */
1091 	if (s < 0) {
1092 		if (errno == ENOENT) {
1093 			if (mkdir(target, mode) == 0 ||
1094 			    (chkparent(target, opts) == 0 &&
1095 			    mkdir(target, mode) == 0)) {
1096 				message(MT_NOTICE, "%s: mkdir", target);
1097 				(void) fchog(-1, target, owner, group, mode);
1098 				ack();
1099 			} else {
1100 				error("%s: mkdir failed: %s", target, SYSERR);
1101 				ptarget = sptarget[--catname];
1102 				*ptarget = CNULL;
1103 			}
1104 			return;
1105 		}
1106 	}
1107 	error("%s: lstat failed: %s", target, SYSERR);
1108 	ptarget = sptarget[--catname];
1109 	*ptarget = CNULL;
1110 }
1111 
1112 /*
1113  * Receive a link
1114  */
1115 static void
1116 recvlink(char *new, opt_t opts, int mode, off_t size)
1117 {
1118 	char tbuf[PATH_MAX], dbuf[BUFSIZ];
1119 	struct stat stb;
1120 	char *optarget;
1121 	int uptodate;
1122 	off_t i;
1123 
1124 	/*
1125 	 * Read basic link info
1126 	 */
1127 	ack();
1128 	(void) remline(buf, sizeof(buf), TRUE);
1129 
1130 	if (response() < 0) {
1131 		err();
1132 		return;
1133 	}
1134 
1135 	if (DECODE(dbuf, buf) == -1) {
1136 		error("recvlink: cannot decode symlink target");
1137 		return;
1138 	}
1139 
1140 	uptodate = 0;
1141 	if ((i = readlink(target, tbuf, sizeof(tbuf)-1)) != -1) {
1142 		tbuf[i] = '\0';
1143 		if (i == size && strncmp(dbuf, tbuf, (int) size) == 0)
1144 			uptodate = 1;
1145 	}
1146 	mode &= 0777;
1147 
1148 	if (IS_ON(opts, DO_VERIFY) || uptodate) {
1149 		if (uptodate)
1150 			message(MT_REMOTE|MT_INFO, "");
1151 		else
1152 			message(MT_REMOTE|MT_INFO, "%s: need to update",
1153 				target);
1154 		if (IS_ON(opts, DO_COMPARE))
1155 			return;
1156 		(void) sendcmd(C_END, NULL);
1157 		(void) response();
1158 		return;
1159 	}
1160 
1161 	/*
1162 	 * Make new symlink using a temporary name
1163 	 */
1164 	if (mktemp(new) == NULL || symlink(dbuf, new) < 0) {
1165 		if (errno != ENOENT || chkparent(new, opts) < 0 ||
1166 		    mktemp(new) == NULL || symlink(dbuf, new) < 0) {
1167 			error("%s -> %s: symlink failed: %s", new, dbuf,
1168 			    SYSERR);
1169 			return;
1170 		}
1171 	}
1172 
1173 	/*
1174 	 * See if target is a directory and remove it if it is
1175 	 */
1176 	if (lstat(target, &stb) == 0) {
1177 		if (S_ISDIR(stb.st_mode)) {
1178 			optarget = ptarget;
1179 			for (ptarget = target; *ptarget; ptarget++);
1180 			if (removefile(&stb, 0) < 0) {
1181 				ptarget = optarget;
1182 				(void) unlink(new);
1183 				(void) sendcmd(C_END, NULL);
1184 				(void) response();
1185 				return;
1186 			}
1187 			ptarget = optarget;
1188 		}
1189 	}
1190 
1191 	/*
1192 	 * Install link as the target
1193 	 */
1194 	if (rename(new, target) < 0) {
1195 		error("%s -> %s: symlink rename failed: %s",
1196 		      new, target, SYSERR);
1197 		(void) unlink(new);
1198 		(void) sendcmd(C_END, NULL);
1199 		(void) response();
1200 		return;
1201 	}
1202 
1203 	message(MT_REMOTE|MT_CHANGE, "%s: updated", target);
1204 
1205 	/*
1206 	 * Indicate end of receive operation
1207 	 */
1208 	(void) sendcmd(C_END, NULL);
1209 	(void) response();
1210 }
1211 
1212 /*
1213  * Creat a hard link to existing file.
1214  */
1215 static void
1216 hardlink(char *cmd)
1217 {
1218 	struct stat stb;
1219 	int exists = 0;
1220 	char *xoldname, *xnewname;
1221 	char *cp = cmd;
1222 	static char expbuf[BUFSIZ];
1223 	char oldname[BUFSIZ], newname[BUFSIZ];
1224 
1225 	/* Skip over opts */
1226 	(void) strtol(cp, &cp, 8);
1227 	if (*cp++ != ' ') {
1228 		error("hardlink: options not delimited");
1229 		return;
1230 	}
1231 
1232 	xoldname = strtok(cp, " ");
1233 	if (xoldname == NULL) {
1234 		error("hardlink: oldname name not delimited");
1235 		return;
1236 	}
1237 
1238 	if (DECODE(oldname, xoldname) == -1) {
1239 		error("hardlink: Cannot decode oldname");
1240 		return;
1241 	}
1242 
1243 	xnewname = strtok(NULL, " ");
1244 	if (xnewname == NULL) {
1245 		error("hardlink: new name not specified");
1246 		return;
1247 	}
1248 
1249 	if (DECODE(newname, xnewname) == -1) {
1250 		error("hardlink: Cannot decode newname");
1251 		return;
1252 	}
1253 
1254 	if (exptilde(expbuf, oldname, sizeof(expbuf)) == NULL) {
1255 		error("hardlink: tilde expansion failed");
1256 		return;
1257 	}
1258 
1259 	if (catname && cattarget(newname) < 0) {
1260 		error("Cannot set newname target.");
1261 		return;
1262 	}
1263 
1264 	if (lstat(target, &stb) == 0) {
1265 		int mode = stb.st_mode & S_IFMT;
1266 
1267 		if (mode != S_IFREG && mode != S_IFLNK) {
1268 			error("%s: not a regular file", target);
1269 			return;
1270 		}
1271 		exists = 1;
1272 	}
1273 
1274 	if (chkparent(target, options) < 0 ) {
1275 		error("%s: no parent: %s ", target, SYSERR);
1276 		return;
1277 	}
1278 	if (exists && (unlink(target) < 0)) {
1279 		error("%s: unlink failed: %s", target, SYSERR);
1280 		return;
1281 	}
1282 	if (linkat(AT_FDCWD, expbuf, AT_FDCWD, target, 0) < 0) {
1283 		error("%s: cannot link to %s: %s", target, oldname, SYSERR);
1284 		return;
1285 	}
1286 	ack();
1287 }
1288 
1289 /*
1290  * Set configuration information.
1291  *
1292  * A key letter is followed immediately by the value
1293  * to set.  The keys are:
1294  *	SC_FREESPACE	- Set minimium free space of filesystem
1295  *	SC_FREEFILES	- Set minimium free number of files of filesystem
1296  */
1297 static void
1298 setconfig(char *cmd)
1299 {
1300 	char *cp = cmd;
1301 	char *estr;
1302 	const char *errstr;
1303 
1304 	switch (*cp++) {
1305 	case SC_HOSTNAME:	/* Set hostname */
1306 		/*
1307 		 * Only use info if we don't know who this is.
1308 		 */
1309 		if (!fromhost) {
1310 			fromhost = xstrdup(cp);
1311 			message(MT_SYSLOG, "startup for %s", fromhost);
1312 			setproctitle("serving %s", cp);
1313 		}
1314 		break;
1315 
1316 	case SC_FREESPACE: 	/* Minimium free space */
1317 		min_freespace = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr);
1318 		if (errstr)
1319 			fatalerr("Minimum free space is %s: '%s'", errstr,
1320 				optarg);
1321 		break;
1322 
1323 	case SC_FREEFILES: 	/* Minimium free files */
1324 		min_freefiles = (int64_t)strtonum(cp, 0, LLONG_MAX, &errstr);
1325 		if (errstr)
1326 			fatalerr("Minimum free files is %s: '%s'", errstr,
1327 				optarg);
1328 		break;
1329 
1330 	case SC_LOGGING:	/* Logging options */
1331 		if ((estr = msgparseopts(cp, TRUE)) != NULL) {
1332 			fatalerr("Bad message option string (%s): %s",
1333 				 cp, estr);
1334 			return;
1335 		}
1336 		break;
1337 
1338 	case SC_DEFOWNER:
1339 		(void) strlcpy(defowner, cp, sizeof(defowner));
1340 		break;
1341 
1342 	case SC_DEFGROUP:
1343 		(void) strlcpy(defgroup, cp, sizeof(defgroup));
1344 		break;
1345 
1346 	default:
1347 		message(MT_NOTICE, "Unknown config command \"%s\".", cp-1);
1348 		return;
1349 	}
1350 }
1351 
1352 /*
1353  * Receive something
1354  */
1355 static void
1356 recvit(char *cmd, int type)
1357 {
1358 	int mode;
1359 	opt_t opts;
1360 	off_t size;
1361 	time_t mtime, atime;
1362 	char *owner, *group, *file;
1363 	char new[PATH_MAX];
1364 	char fileb[PATH_MAX];
1365 	int64_t freespace = -1, freefiles = -1;
1366 	char *cp = cmd;
1367 
1368 	/*
1369 	 * Get rdist option flags
1370 	 */
1371 	opts = strtol(cp, &cp, 8);
1372 	if (*cp++ != ' ') {
1373 		error("recvit: options not delimited");
1374 		return;
1375 	}
1376 
1377 	/*
1378 	 * Get file mode
1379 	 */
1380 	mode = strtol(cp, &cp, 8);
1381 	if (*cp++ != ' ') {
1382 		error("recvit: mode not delimited");
1383 		return;
1384 	}
1385 
1386 	/*
1387 	 * Get file size
1388 	 */
1389 	size = (off_t) strtoll(cp, &cp, 10);
1390 	if (*cp++ != ' ') {
1391 		error("recvit: size not delimited");
1392 		return;
1393 	}
1394 
1395 	/*
1396 	 * Get modification time
1397 	 */
1398 	mtime = (time_t) strtoll(cp, &cp, 10);
1399 	if (*cp++ != ' ') {
1400 		error("recvit: mtime not delimited");
1401 		return;
1402 	}
1403 
1404 	/*
1405 	 * Get access time
1406 	 */
1407 	atime = (time_t) strtoll(cp, &cp, 10);
1408 	if (*cp++ != ' ') {
1409 		error("recvit: atime not delimited");
1410 		return;
1411 	}
1412 
1413 	/*
1414 	 * Get file owner name
1415 	 */
1416 	owner = strtok(cp, " ");
1417 	if (owner == NULL) {
1418 		error("recvit: owner name not delimited");
1419 		return;
1420 	}
1421 
1422 	/*
1423 	 * Get file group name
1424 	 */
1425 	group = strtok(NULL, " ");
1426 	if (group == NULL) {
1427 		error("recvit: group name not delimited");
1428 		return;
1429 	}
1430 
1431 	/*
1432 	 * Get file name. Can't use strtok() since there could
1433 	 * be white space in the file name.
1434 	 */
1435 	if (DECODE(fileb, group + strlen(group) + 1) == -1) {
1436 		error("recvit: Cannot decode file name");
1437 		return;
1438 	}
1439 
1440 	if (fileb[0] == '\0') {
1441 		error("recvit: no file name");
1442 		return;
1443 	}
1444 	file = fileb;
1445 
1446 	debugmsg(DM_MISC,
1447 		 "recvit: opts = %#x mode = %#04o size = %lld mtime = %lld",
1448 		 opts, mode, (long long) size, (long long)mtime);
1449 	debugmsg(DM_MISC,
1450        "recvit: owner = '%s' group = '%s' file = '%s' catname = %d isdir = %d",
1451 		 owner, group, file, catname, (type == S_IFDIR) ? 1 : 0);
1452 
1453 	if (type == S_IFDIR) {
1454 		if ((size_t) catname >= sizeof(sptarget)) {
1455 			error("%s: too many directory levels", target);
1456 			return;
1457 		}
1458 		sptarget[catname] = ptarget;
1459 		if (catname++) {
1460 			*ptarget++ = '/';
1461 			while ((*ptarget++ = *file++) != '\0')
1462 			    continue;
1463 			ptarget--;
1464 		}
1465 	} else {
1466 		/*
1467 		 * Create name of temporary file
1468 		 */
1469 		if (catname && cattarget(file) < 0) {
1470 			error("Cannot set file name.");
1471 			return;
1472 		}
1473 		file = strrchr(target, '/');
1474 		if (file == NULL)
1475 			(void) strlcpy(new, tempname, sizeof(new));
1476 		else if (file == target)
1477 			(void) snprintf(new, sizeof(new), "/%s", tempname);
1478 		else {
1479 			*file = CNULL;
1480 			(void) snprintf(new, sizeof(new), "%s/%s", target,
1481 					tempname);
1482 			*file = '/';
1483 		}
1484 	}
1485 
1486 	/*
1487 	 * Check to see if there is enough free space and inodes
1488 	 * to install this file.
1489 	 */
1490 	if (min_freespace || min_freefiles) {
1491 		/* Convert file size to kilobytes */
1492 		int64_t fsize = (int64_t)size / 1024;
1493 
1494 		if (getfilesysinfo(target, &freespace, &freefiles) != 0)
1495 			return;
1496 
1497 		/*
1498 		 * filesystem values < 0 indicate unsupported or unavailable
1499 		 * information.
1500 		 */
1501 		if (min_freespace && (freespace >= 0) &&
1502 		    (freespace - fsize < min_freespace)) {
1503 			error(
1504 		     "%s: Not enough free space on filesystem: min %lld "
1505 		     "free %lld", target, min_freespace, freespace);
1506 			return;
1507 		}
1508 		if (min_freefiles && (freefiles >= 0) &&
1509 		    (freefiles - 1 < min_freefiles)) {
1510 			error(
1511 		     "%s: Not enough free files on filesystem: min %lld free "
1512 		     "%lld", target, min_freefiles, freefiles);
1513 			return;
1514 		}
1515 	}
1516 
1517 	/*
1518 	 * Call appropriate receive function to receive file
1519 	 */
1520 	switch (type) {
1521 	case S_IFDIR:
1522 		recvdir(opts, mode, owner, group);
1523 		break;
1524 
1525 	case S_IFLNK:
1526 		recvlink(new, opts, mode, size);
1527 		break;
1528 
1529 	case S_IFREG:
1530 		recvfile(new, opts, mode, owner, group, mtime, atime, size);
1531 		break;
1532 
1533 	default:
1534 		error("%d: unknown file type", type);
1535 		break;
1536 	}
1537 }
1538 
1539 /*
1540  * Chmog something
1541  */
1542 static void
1543 dochmog(char *cmd)
1544 {
1545 	int mode;
1546 	opt_t opts;
1547 	char *owner, *group, *file;
1548 	char *cp = cmd;
1549 	char fileb[PATH_MAX];
1550 
1551 	/*
1552 	 * Get rdist option flags
1553 	 */
1554 	opts = strtol(cp, &cp, 8);
1555 	if (*cp++ != ' ') {
1556 		error("dochmog: options not delimited");
1557 		return;
1558 	}
1559 
1560 	/*
1561 	 * Get file mode
1562 	 */
1563 	mode = strtol(cp, &cp, 8);
1564 	if (*cp++ != ' ') {
1565 		error("dochmog: mode not delimited");
1566 		return;
1567 	}
1568 
1569 	/*
1570 	 * Get file owner name
1571 	 */
1572 	owner = strtok(cp, " ");
1573 	if (owner == NULL) {
1574 		error("dochmog: owner name not delimited");
1575 		return;
1576 	}
1577 
1578 	/*
1579 	 * Get file group name
1580 	 */
1581 	group = strtok(NULL, " ");
1582 	if (group == NULL) {
1583 		error("dochmog: group name not delimited");
1584 		return;
1585 	}
1586 
1587 	/*
1588 	 * Get file name. Can't use strtok() since there could
1589 	 * be white space in the file name.
1590 	 */
1591 	if (DECODE(fileb, group + strlen(group) + 1) == -1) {
1592 		error("dochmog: Cannot decode file name");
1593 		return;
1594 	}
1595 
1596 	if (fileb[0] == '\0') {
1597 		error("dochmog: no file name");
1598 		return;
1599 	}
1600 	file = fileb;
1601 
1602 	debugmsg(DM_MISC,
1603 		 "dochmog: opts = %#x mode = %#04o", opts, mode);
1604 	debugmsg(DM_MISC,
1605 	         "dochmog: owner = '%s' group = '%s' file = '%s' catname = %d",
1606 		 owner, group, file, catname);
1607 
1608 	if (catname && cattarget(file) < 0) {
1609 		error("Cannot set newname target.");
1610 		return;
1611 	}
1612 
1613 	(void) fchog(-1, target, owner, group, mode);
1614 
1615 	ack();
1616 }
1617 
1618 /*
1619  * Set target information
1620  */
1621 static void
1622 settarget(char *cmd, int isdir)
1623 {
1624 	char *cp = cmd;
1625 	opt_t opts;
1626 	char file[BUFSIZ];
1627 
1628 	catname = isdir;
1629 
1630 	/*
1631 	 * Parse options for this target
1632 	 */
1633 	opts = strtol(cp, &cp, 8);
1634 	if (*cp++ != ' ') {
1635 		error("settarget: options not delimited");
1636 		return;
1637 	}
1638 	options = opts;
1639 
1640 	if (DECODE(file, cp) == -1) {
1641 		error("settarget: Cannot decode target name");
1642 		return;
1643 	}
1644 
1645 	/*
1646 	 * Handle target
1647 	 */
1648 	if (exptilde(target, cp, sizeof(target)) == NULL)
1649 		return;
1650 	ptarget = target;
1651 	while (*ptarget)
1652 		ptarget++;
1653 
1654 	ack();
1655 }
1656 
1657 /*
1658  * Cleanup in preparation for exiting.
1659  */
1660 void
1661 cleanup(int dummy)
1662 {
1663 	/* We don't need to do anything */
1664 }
1665 
1666 /*
1667  * Server routine to read requests and process them.
1668  */
1669 void
1670 server(void)
1671 {
1672 	static char cmdbuf[BUFSIZ];
1673 	char *cp;
1674 	int n, proto_version;
1675 
1676 	if (setjmp(finish_jmpbuf))
1677 		return;
1678 	(void) signal(SIGHUP, sighandler);
1679 	(void) signal(SIGINT, sighandler);
1680 	(void) signal(SIGQUIT, sighandler);
1681 	(void) signal(SIGTERM, sighandler);
1682 	(void) signal(SIGPIPE, sighandler);
1683 	(void) umask(oumask = umask(0));
1684 	(void) strlcpy(tempname, _RDIST_TMP, sizeof(tempname));
1685 	if (fromhost) {
1686 		message(MT_SYSLOG, "Startup for %s", fromhost);
1687 #if 	defined(SETARGS)
1688 		setproctitle("Serving %s", fromhost);
1689 #endif	/* SETARGS */
1690 	}
1691 
1692 	/*
1693 	 * Let client know we want it to send it's version number
1694 	 */
1695 	(void) sendcmd(S_VERSION, NULL);
1696 
1697 	if (remline(cmdbuf, sizeof(cmdbuf), TRUE) < 0) {
1698 		error("server: expected control record");
1699 		return;
1700 	}
1701 
1702 	if (cmdbuf[0] != S_VERSION || !isdigit((unsigned char)cmdbuf[1])) {
1703 		error("Expected version command, received: \"%s\".", cmdbuf);
1704 		return;
1705 	}
1706 
1707 	proto_version = atoi(&cmdbuf[1]);
1708 	if (proto_version != VERSION) {
1709 		error("Protocol version %d is not supported.", proto_version);
1710 		return;
1711 	}
1712 
1713 	/* Version number is okay */
1714 	ack();
1715 
1716 	/*
1717 	 * Main command loop
1718 	 */
1719 	for ( ; ; ) {
1720 		n = remline(cp = cmdbuf, sizeof(cmdbuf), TRUE);
1721 		if (n == -1)		/* EOF */
1722 			return;
1723 		if (n == 0) {
1724 			error("server: expected control record");
1725 			continue;
1726 		}
1727 
1728 		switch (*cp++) {
1729 		case C_SETCONFIG:  	/* Configuration info */
1730 		        setconfig(cp);
1731 			ack();
1732 			continue;
1733 
1734 		case C_DIRTARGET:  	/* init target file/directory name */
1735 			settarget(cp, TRUE);
1736 			continue;
1737 
1738 		case C_TARGET:  	/* init target file/directory name */
1739 			settarget(cp, FALSE);
1740 			continue;
1741 
1742 		case C_RECVREG:  	/* Transfer a regular file. */
1743 			recvit(cp, S_IFREG);
1744 			continue;
1745 
1746 		case C_RECVDIR:  	/* Transfer a directory. */
1747 			recvit(cp, S_IFDIR);
1748 			continue;
1749 
1750 		case C_RECVSYMLINK:  	/* Transfer symbolic link. */
1751 			recvit(cp, S_IFLNK);
1752 			continue;
1753 
1754 		case C_RECVHARDLINK:  	/* Transfer hard link. */
1755 			hardlink(cp);
1756 			continue;
1757 
1758 		case C_END:  		/* End of transfer */
1759 			*ptarget = CNULL;
1760 			if (catname <= 0) {
1761 				error("server: too many '%c's", C_END);
1762 				continue;
1763 			}
1764 			ptarget = sptarget[--catname];
1765 			*ptarget = CNULL;
1766 			ack();
1767 			continue;
1768 
1769 		case C_CLEAN:  		/* Clean. Cleanup a directory */
1770 			clean(cp);
1771 			continue;
1772 
1773 		case C_QUERY:  		/* Query file/directory */
1774 			query(cp);
1775 			continue;
1776 
1777 		case C_SPECIAL:  	/* Special. Execute commands */
1778 			dospecial(cp);
1779 			continue;
1780 
1781 		case C_CMDSPECIAL:  	/* Cmd Special. Execute commands */
1782 			docmdspecial();
1783 			continue;
1784 
1785 	        case C_CHMOG:  		/* Set owner, group, mode */
1786 			dochmog(cp);
1787 			continue;
1788 
1789 		case C_ERRMSG:		/* Normal error message */
1790 			if (cp && *cp)
1791 				message(MT_NERROR|MT_NOREMOTE, "%s", cp);
1792 			continue;
1793 
1794 		case C_FERRMSG:		/* Fatal error message */
1795 			if (cp && *cp)
1796 				message(MT_FERROR|MT_NOREMOTE, "%s", cp);
1797 			return;
1798 
1799 		default:
1800 			error("server: unknown command '%s'", cp - 1);
1801 		case CNULL:
1802 			continue;
1803 		}
1804 	}
1805 }
1806