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