xref: /minix/usr.bin/xinstall/xinstall.c (revision 0a6a1f1d)
1 /*	$NetBSD: xinstall.c,v 1.124 2015/06/19 17:20:02 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1987, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #else
35 #define HAVE_FUTIMES 1
36 #define HAVE_STRUCT_STAT_ST_FLAGS 1
37 #endif
38 
39 #include <sys/cdefs.h>
40 #if defined(__COPYRIGHT) && !defined(lint)
41 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
42  The Regents of the University of California.  All rights reserved.");
43 #endif /* not lint */
44 
45 #if defined(__RCSID) && !defined(lint)
46 #if 0
47 static char sccsid[] = "@(#)xinstall.c	8.1 (Berkeley) 7/21/93";
48 #else
49 __RCSID("$NetBSD: xinstall.c,v 1.124 2015/06/19 17:20:02 christos Exp $");
50 #endif
51 #endif /* not lint */
52 
53 #define __MKTEMP_OK__	/* All uses of mktemp have been checked */
54 #include <sys/param.h>
55 #include <sys/mman.h>
56 #include <sys/stat.h>
57 #include <sys/wait.h>
58 #include <sys/time.h>
59 
60 #include <ctype.h>
61 #include <err.h>
62 #include <errno.h>
63 #include <fcntl.h>
64 #include <grp.h>
65 #include <libgen.h>
66 #include <paths.h>
67 #include <pwd.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include <util.h>
73 #include <vis.h>
74 
75 #ifdef HAVE_POSIX_SPAWN
76 #include <spawn.h>
77 #endif
78 
79 #include <md5.h>
80 #include <rmd160.h>
81 #include <sha1.h>
82 #include <sha2.h>
83 
84 #include "pathnames.h"
85 #include "mtree.h"
86 #include "metachar.h"
87 
88 #define BACKUP_SUFFIX ".old"
89 
90 static int	dobackup, dodir, dostrip, dolink, dopreserve, dorename, dounpriv;
91 static int	haveopt_f, haveopt_g, haveopt_m, haveopt_o;
92 static int	numberedbackup;
93 static int	mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
94 static char	pathbuf[MAXPATHLEN];
95 static uid_t	uid = -1;
96 static gid_t	gid = -1;
97 static char	*group, *owner, *fflags, *tags;
98 static FILE	*metafp;
99 static char	*metafile;
100 static u_long	fileflags;
101 static char	*stripArgs;
102 static char	*afterinstallcmd;
103 static const char *suffix = BACKUP_SUFFIX;
104 static char	*destdir;
105 
106 enum {
107 	DIGEST_NONE = 0,
108 	DIGEST_MD5,
109 	DIGEST_RMD160,
110 	DIGEST_SHA1,
111 	DIGEST_SHA256,
112 	DIGEST_SHA384,
113 	DIGEST_SHA512,
114 } digesttype = DIGEST_NONE;
115 
116 static char	*digest;
117 
118 #define LN_ABSOLUTE	0x01
119 #define LN_RELATIVE	0x02
120 #define LN_HARD		0x04
121 #define LN_SYMBOLIC	0x08
122 #define LN_MIXED	0x10
123 
124 #define	DIRECTORY	0x01		/* Tell install it's a directory. */
125 #define	SETFLAGS	0x02		/* Tell install to set flags. */
126 #define	HASUID		0x04		/* Tell install the uid was given */
127 #define	HASGID		0x08		/* Tell install the gid was given */
128 
129 static void	afterinstall(const char *, const char *, int);
130 static void	backup(const char *);
131 static char   *copy(int, char *, int, char *, off_t);
132 static int	do_link(char *, char *);
133 static void	do_symlink(char *, char *);
134 static void	install(char *, char *, u_int);
135 static void	install_dir(char *, u_int);
136 static void	makelink(char *, char *);
137 static void	metadata_log(const char *, const char *, struct timeval *,
138 	    const char *, const char *, off_t);
139 static int	parseid(char *, id_t *);
140 static void 	run(const char *, const char *, const char *, int);
141 static void	strip(const char *);
142 __dead static void	usage(void);
143 static char   *xbasename(char *);
144 static char   *xdirname(char *);
145 
146 int
main(int argc,char * argv[])147 main(int argc, char *argv[])
148 {
149 	struct stat	from_sb, to_sb;
150 	void		*set;
151 	u_int		iflags;
152 	int		ch, no_target;
153 	char		*p, *to_name;
154 
155 	setprogname(argv[0]);
156 
157 	iflags = 0;
158 	while ((ch = getopt(argc, argv, "a:cbB:dD:f:g:h:l:m:M:N:o:prsS:T:U"))
159 	    != -1)
160 		switch((char)ch) {
161 		case 'a':
162 			afterinstallcmd = strdup(optarg);
163 			if (afterinstallcmd == NULL)
164 				err(EXIT_FAILURE,
165 				    "Can't allocate after command");
166 			break;
167 		case 'B':
168 			suffix = optarg;
169 			numberedbackup = 0;
170 			{
171 				/* Check if given suffix really generates
172 				   different suffixes - catch e.g. ".%" */
173 				char suffix_expanded0[FILENAME_MAX],
174 				     suffix_expanded1[FILENAME_MAX];
175 				(void)snprintf(suffix_expanded0, FILENAME_MAX,
176 					       suffix, 0);
177 				(void)snprintf(suffix_expanded1, FILENAME_MAX,
178 					       suffix, 1);
179 				if (strcmp(suffix_expanded0, suffix_expanded1)
180 				    != 0)
181 					numberedbackup = 1;
182 			}
183 			/* fall through; -B implies -b */
184 			/*FALLTHROUGH*/
185 		case 'b':
186 			dobackup = 1;
187 			break;
188 		case 'c':
189 			/* ignored; was "docopy" which is now the default. */
190 			break;
191 		case 'd':
192 			dodir = 1;
193 			break;
194 		case 'D':
195 			destdir = optarg;
196 			break;
197 #if ! HAVE_NBTOOL_CONFIG_H
198 		case 'f':
199 			haveopt_f = 1;
200 			fflags = optarg;
201 			break;
202 #endif
203 		case 'g':
204 			haveopt_g = 1;
205 			group = optarg;
206 			break;
207 		case 'h':
208 			digest = optarg;
209 			break;
210 		case 'l':
211 			for (p = optarg; *p; p++)
212 				switch (*p) {
213 				case 's':
214 					dolink &= ~(LN_HARD|LN_MIXED);
215 					dolink |= LN_SYMBOLIC;
216 					break;
217 				case 'h':
218 					dolink &= ~(LN_SYMBOLIC|LN_MIXED);
219 					dolink |= LN_HARD;
220 					break;
221 				case 'm':
222 					dolink &= ~(LN_SYMBOLIC|LN_HARD);
223 					dolink |= LN_MIXED;
224 					break;
225 				case 'a':
226 					dolink &= ~LN_RELATIVE;
227 					dolink |= LN_ABSOLUTE;
228 					break;
229 				case 'r':
230 					dolink &= ~LN_ABSOLUTE;
231 					dolink |= LN_RELATIVE;
232 					break;
233 				default:
234 					errx(EXIT_FAILURE, "%c: invalid link type", *p);
235 					/* NOTREACHED */
236 				}
237 			break;
238 		case 'm':
239 			haveopt_m = 1;
240 			if (!(set = setmode(optarg)))
241 				err(EXIT_FAILURE, "Cannot set file mode `%s'", optarg);
242 			mode = getmode(set, 0);
243 			free(set);
244 			break;
245 		case 'M':
246 			metafile = optarg;
247 			break;
248 		case 'N':
249 			if (! setup_getid(optarg))
250 				errx(EXIT_FAILURE,
251 			    "Unable to use user and group databases in `%s'",
252 				    optarg);
253 			break;
254 		case 'o':
255 			haveopt_o = 1;
256 			owner = optarg;
257 			break;
258 		case 'p':
259 			dopreserve = 1;
260 			break;
261 		case 'r':
262 			dorename = 1;
263 			break;
264 		case 'S':
265 			stripArgs = strdup(optarg);
266 			if (stripArgs == NULL)
267 				err(EXIT_FAILURE, "Can't allocate options");
268 			/* fall through; -S implies -s */
269 			/*FALLTHROUGH*/
270 		case 's':
271 			dostrip = 1;
272 			break;
273 		case 'T':
274 			tags = optarg;
275 			break;
276 		case 'U':
277 			dounpriv = 1;
278 			break;
279 		case '?':
280 		default:
281 			usage();
282 		}
283 	argc -= optind;
284 	argv += optind;
285 
286 	/* strip and link options make no sense when creating directories */
287 	if ((dostrip || dolink) && dodir)
288 		usage();
289 
290 	/* strip and flags make no sense with links */
291 	if ((dostrip || fflags) && dolink)
292 		usage();
293 
294 	/* must have at least two arguments, except when creating directories */
295 	if (argc < 2 && !dodir)
296 		usage();
297 
298 	if (digest) {
299 		if (0) {
300 		} else if (strcmp(digest, "none") == 0) {
301 			digesttype = DIGEST_NONE;
302 		} else if (strcmp(digest, "md5") == 0) {
303 			digesttype = DIGEST_MD5;
304 		} else if (strcmp(digest, "rmd160") == 0) {
305 			digesttype = DIGEST_RMD160;
306 		} else if (strcmp(digest, "sha1") == 0) {
307 			digesttype = DIGEST_SHA1;
308 		} else if (strcmp(digest, "sha256") == 0) {
309 			digesttype = DIGEST_SHA256;
310 		} else if (strcmp(digest, "sha384") == 0) {
311 			digesttype = DIGEST_SHA384;
312 		} else if (strcmp(digest, "sha512") == 0) {
313 			digesttype = DIGEST_SHA512;
314 		} else {
315 			warnx("unknown digest `%s'", digest);
316 			usage();
317 		}
318 	}
319 
320 	/* get group and owner id's */
321 	if (group && !dounpriv) {
322 		if (gid_from_group(group, &gid) == -1) {
323 			id_t id;
324 			if (!parseid(group, &id))
325 				errx(EXIT_FAILURE, "unknown group %s", group);
326 			gid = id;
327 		}
328 		iflags |= HASGID;
329 	}
330 	if (owner && !dounpriv) {
331 		if (uid_from_user(owner, &uid) == -1) {
332 			id_t id;
333 			if (!parseid(owner, &id))
334 				errx(EXIT_FAILURE, "unknown user %s", owner);
335 			uid = id;
336 		}
337 		iflags |= HASUID;
338 	}
339 
340 #if ! HAVE_NBTOOL_CONFIG_H
341 	if (fflags && !dounpriv) {
342 		if (string_to_flags(&fflags, &fileflags, NULL))
343 			errx(EXIT_FAILURE, "%s: invalid flag", fflags);
344 		/* restore fflags since string_to_flags() changed it */
345 		fflags = flags_to_string(fileflags, "-");
346 		iflags |= SETFLAGS;
347 	}
348 #endif
349 
350 	if (metafile) {
351 		if ((metafp = fopen(metafile, "a")) == NULL)
352 			warn("open %s", metafile);
353 	} else
354 		digesttype = DIGEST_NONE;
355 
356 	if (dodir) {
357 		for (; *argv != NULL; ++argv)
358 			install_dir(*argv, iflags);
359 		exit (0);
360 	}
361 
362 	no_target = stat(to_name = argv[argc - 1], &to_sb);
363 	if (!no_target && S_ISDIR(to_sb.st_mode)) {
364 		for (; *argv != to_name; ++argv)
365 			install(*argv, to_name, iflags | DIRECTORY);
366 		exit(0);
367 	}
368 
369 	/* can't do file1 file2 directory/file */
370 	if (argc != 2) {
371 		errx(EXIT_FAILURE, "the last argument (%s) "
372 		    "must name an existing directory", argv[argc - 1]);
373 		/* NOTREACHED */
374 	}
375 
376 	if (!no_target) {
377 		/* makelink() handles checks for links */
378 		if (!dolink) {
379 			if (stat(*argv, &from_sb))
380 				err(EXIT_FAILURE, "%s: stat", *argv);
381 			if (!S_ISREG(to_sb.st_mode))
382 				errx(EXIT_FAILURE, "%s: not a regular file", to_name);
383 			if (to_sb.st_dev == from_sb.st_dev &&
384 			    to_sb.st_ino == from_sb.st_ino)
385 				errx(EXIT_FAILURE, "%s and %s are the same file", *argv,
386 				    to_name);
387 		}
388 		/*
389 		 * Unlink now... avoid ETXTBSY errors later.  Try and turn
390 		 * off the append/immutable bits -- if we fail, go ahead,
391 		 * it might work.
392 		 */
393 #if !defined(__minix)
394 #if ! HAVE_NBTOOL_CONFIG_H
395 #define	NOCHANGEBITS	(UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
396 		if (to_sb.st_flags & NOCHANGEBITS)
397 			(void)chflags(to_name,
398 			    to_sb.st_flags & ~(NOCHANGEBITS));
399 #endif
400 #endif /* !defined(__minix) */
401 		if (dobackup)
402 			backup(to_name);
403 		else if (!dorename)
404 			(void)unlink(to_name);
405 	}
406 	install(*argv, to_name, iflags);
407 	exit(0);
408 }
409 
410 /*
411  * parseid --
412  *	parse uid or gid from arg into id, returning non-zero if successful
413  */
414 static int
parseid(char * name,id_t * id)415 parseid(char *name, id_t *id)
416 {
417 	char	*ep;
418 
419 	errno = 0;
420 	*id = (id_t)strtoul(name, &ep, 10);
421 	if (errno || *ep != '\0')
422 		return (0);
423 	return (1);
424 }
425 
426 /*
427  * do_link --
428  *	make a hard link, obeying dorename if set
429  *	return -1 on failure
430  */
431 static int
do_link(char * from_name,char * to_name)432 do_link(char *from_name, char *to_name)
433 {
434 	char tmpl[MAXPATHLEN];
435 	int ret;
436 
437 	if (dorename) {
438 		(void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
439 		/* This usage is safe. */
440 		if (mktemp(tmpl) == NULL)
441 			err(EXIT_FAILURE, "%s: mktemp", tmpl);
442 		ret = link(from_name, tmpl);
443 		if (ret == 0) {
444 			ret = rename(tmpl, to_name);
445 			/* If rename has posix semantics, then the temporary
446 			 * file may still exist when from_name and to_name point
447 			 * to the same file, so unlink it unconditionally.
448 			 */
449 			(void)unlink(tmpl);
450 		}
451 		return (ret);
452 	} else
453 		return (link(from_name, to_name));
454 }
455 
456 /*
457  * do_symlink --
458  *	make a symbolic link, obeying dorename if set
459  *	exit on failure
460  */
461 static void
do_symlink(char * from_name,char * to_name)462 do_symlink(char *from_name, char *to_name)
463 {
464 	char tmpl[MAXPATHLEN];
465 
466 	if (dorename) {
467 		(void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
468 		/* This usage is safe. */
469 		if (mktemp(tmpl) == NULL)
470 			err(EXIT_FAILURE, "%s: mktemp", tmpl);
471 
472 		if (symlink(from_name, tmpl) == -1)
473 			err(EXIT_FAILURE, "symlink %s -> %s", from_name, tmpl);
474 		if (rename(tmpl, to_name) == -1) {
475 			/* remove temporary link before exiting */
476 			(void)unlink(tmpl);
477 			err(EXIT_FAILURE, "%s: rename", to_name);
478 		}
479 	} else {
480 		if (symlink(from_name, to_name) == -1)
481 			err(EXIT_FAILURE, "symlink %s -> %s", from_name, to_name);
482 	}
483 }
484 
485 /*
486  * makelink --
487  *	make a link from source to destination
488  */
489 static void
makelink(char * from_name,char * to_name)490 makelink(char *from_name, char *to_name)
491 {
492 	char	src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN];
493 	struct stat	to_sb;
494 
495 	/* Try hard links first */
496 	if (dolink & (LN_HARD|LN_MIXED)) {
497 		if (do_link(from_name, to_name) == -1) {
498 			if ((dolink & LN_HARD) || errno != EXDEV)
499 				err(EXIT_FAILURE, "link %s -> %s", from_name, to_name);
500 		} else {
501 			if (stat(to_name, &to_sb))
502 				err(EXIT_FAILURE, "%s: stat", to_name);
503 			if (S_ISREG(to_sb.st_mode)) {
504 					/* XXX: hard links to anything
505 					 * other than plain files are not
506 					 * metalogged
507 					 */
508 				int omode;
509 				char *oowner, *ogroup, *offlags;
510 				char *dres;
511 
512 					/* XXX: use underlying perms,
513 					 * unless overridden on command line.
514 					 */
515 				omode = mode;
516 				if (!haveopt_m)
517 					mode = (to_sb.st_mode & 0777);
518 				oowner = owner;
519 				if (!haveopt_o)
520 					owner = NULL;
521 				ogroup = group;
522 				if (!haveopt_g)
523 					group = NULL;
524 				offlags = fflags;
525 				if (!haveopt_f)
526 					fflags = NULL;
527 				switch (digesttype) {
528 				case DIGEST_MD5:
529 					dres = MD5File(from_name, NULL);
530 					break;
531 				case DIGEST_RMD160:
532 					dres = RMD160File(from_name, NULL);
533 					break;
534 				case DIGEST_SHA1:
535 					dres = SHA1File(from_name, NULL);
536 					break;
537 				case DIGEST_SHA256:
538 					dres = SHA256_File(from_name, NULL);
539 					break;
540 				case DIGEST_SHA384:
541 					dres = SHA384_File(from_name, NULL);
542 					break;
543 				case DIGEST_SHA512:
544 					dres = SHA512_File(from_name, NULL);
545 					break;
546 				default:
547 					dres = NULL;
548 				}
549 				metadata_log(to_name, "file", NULL, NULL,
550 				    dres, to_sb.st_size);
551 				free(dres);
552 				mode = omode;
553 				owner = oowner;
554 				group = ogroup;
555 				fflags = offlags;
556 			}
557 			return;
558 		}
559 	}
560 
561 	/* Symbolic links */
562 	if (dolink & LN_ABSOLUTE) {
563 		/* Convert source path to absolute */
564 		if (realpath(from_name, src) == NULL)
565 			err(EXIT_FAILURE, "%s: realpath", from_name);
566 		do_symlink(src, to_name);
567 			/* XXX: src may point outside of destdir */
568 		metadata_log(to_name, "link", NULL, src, NULL, 0);
569 		return;
570 	}
571 
572 	if (dolink & LN_RELATIVE) {
573 		char *cp, *d, *s;
574 
575 		/* Resolve pathnames */
576 		if (realpath(from_name, src) == NULL)
577 			err(EXIT_FAILURE, "%s: realpath", from_name);
578 
579 		/*
580 		 * The last component of to_name may be a symlink,
581 		 * so use realpath to resolve only the directory.
582 		 */
583 		cp = xdirname(to_name);
584 		if (realpath(cp, dst) == NULL)
585 			err(EXIT_FAILURE, "%s: realpath", cp);
586 		/* .. and add the last component */
587 		if (strcmp(dst, "/") != 0) {
588 			if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst))
589 				errx(EXIT_FAILURE, "resolved pathname too long");
590 		}
591 		cp = xbasename(to_name);
592 		if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst))
593 			errx(EXIT_FAILURE, "resolved pathname too long");
594 
595 		/* trim common path components */
596 		for (s = src, d = dst; *s == *d; s++, d++)
597 			continue;
598 		while (*s != '/')
599 			s--, d--;
600 
601 		/* count the number of directories we need to backtrack */
602 		for (++d, lnk[0] = '\0'; *d; d++)
603 			if (*d == '/')
604 				(void)strlcat(lnk, "../", sizeof(lnk));
605 
606 		(void)strlcat(lnk, ++s, sizeof(lnk));
607 
608 		do_symlink(lnk, to_name);
609 			/* XXX: lnk may point outside of destdir */
610 		metadata_log(to_name, "link", NULL, lnk, NULL, 0);
611 		return;
612 	}
613 
614 	/*
615 	 * If absolute or relative was not specified,
616 	 * try the names the user provided
617 	 */
618 	do_symlink(from_name, to_name);
619 		/* XXX: from_name may point outside of destdir */
620 	metadata_log(to_name, "link", NULL, from_name, NULL, 0);
621 }
622 
623 /*
624  * install --
625  *	build a path name and install the file
626  */
627 static void
install(char * from_name,char * to_name,u_int flags)628 install(char *from_name, char *to_name, u_int flags)
629 {
630 	struct stat	from_sb;
631 	struct stat	to_sb;
632 	struct timeval	tv[2];
633 	off_t		size;
634 	int		devnull, from_fd, to_fd, serrno, tmpmode;
635 	char		*p, tmpl[MAXPATHLEN], *oto_name, *digestresult;
636 
637 	size = -1;
638 	if (!dolink) {
639 			/* ensure that from_sb & tv are sane if !dolink */
640 		if (stat(from_name, &from_sb))
641 			err(EXIT_FAILURE, "%s: stat", from_name);
642 		size = from_sb.st_size;
643 #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
644 		TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec);
645 		TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec);
646 #else
647 		tv[0].tv_sec = from_sb.st_atime;
648 		tv[0].tv_usec = 0;
649 		tv[1].tv_sec = from_sb.st_mtime;
650 		tv[1].tv_usec = 0;
651 #endif
652 	}
653 
654 	if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL) != 0) {
655 		devnull = 0;
656 		if (!dolink) {
657 			if (!S_ISREG(from_sb.st_mode))
658 				errx(EXIT_FAILURE, "%s: not a regular file", from_name);
659 		}
660 		/* Build the target path. */
661 		if (flags & DIRECTORY) {
662 			(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
663 			    to_name,
664 			    (p = strrchr(from_name, '/')) ? ++p : from_name);
665 			to_name = pathbuf;
666 		}
667 	} else {
668 		devnull = 1;
669 		size = 0;
670 #if HAVE_STRUCT_STAT_ST_FLAGS
671 		from_sb.st_flags = 0;	/* XXX */
672 #endif
673 	}
674 
675 	/*
676 	 * Unlink now... avoid ETXTBSY errors later.  Try and turn
677 	 * off the append/immutable bits -- if we fail, go ahead,
678 	 * it might work.
679 	 */
680 #if !defined(__minix)
681 #if ! HAVE_NBTOOL_CONFIG_H
682 	if (stat(to_name, &to_sb) == 0 &&
683 	    to_sb.st_flags & (NOCHANGEBITS))
684 		(void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
685 #endif
686 #endif /* !defined(__minix) */
687 	if (dorename) {
688 		(void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name);
689 		oto_name = to_name;
690 		to_name = tmpl;
691 	} else {
692 		oto_name = NULL;	/* pacify gcc */
693 		if (dobackup)
694 			backup(to_name);
695 		else
696 			(void)unlink(to_name);
697 	}
698 
699 	if (dolink) {
700 		makelink(from_name, dorename ? oto_name : to_name);
701 		return;
702 	}
703 
704 	/* Create target. */
705 	if (dorename) {
706 		if ((to_fd = mkstemp(to_name)) == -1)
707 			err(EXIT_FAILURE, "%s: mkstemp", to_name);
708 	} else {
709 		if ((to_fd = open(to_name,
710 		    O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
711 			err(EXIT_FAILURE, "%s: open", to_name);
712 	}
713 	digestresult = NULL;
714 	if (!devnull) {
715 		if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
716 			(void)unlink(to_name);
717 			err(EXIT_FAILURE, "%s: open", from_name);
718 		}
719 		digestresult =
720 		    copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
721 		(void)close(from_fd);
722 	}
723 
724 	if (dostrip) {
725 		strip(to_name);
726 
727 		/*
728 		 * Re-open our fd on the target, in case we used a strip
729 		 *  that does not work in-place -- like gnu binutils strip.
730 		 */
731 		close(to_fd);
732 		if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
733 			err(EXIT_FAILURE, "stripping %s", to_name);
734 
735 		/*
736 		 * Recalculate size and digestresult after stripping.
737 		 */
738 		if (fstat(to_fd, &to_sb) != 0)
739 			err(EXIT_FAILURE, "%s: fstat", to_name);
740 		size = to_sb.st_size;
741 		digestresult =
742 		    copy(to_fd, to_name, -1, NULL, size);
743 
744 	}
745 
746 	if (afterinstallcmd != NULL) {
747 		afterinstall(afterinstallcmd, to_name, 1);
748 
749 		/*
750 		 * Re-open our fd on the target, in case we used an
751 		 * after-install command that does not work in-place
752 		 */
753 		close(to_fd);
754 		if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
755 			err(EXIT_FAILURE, "running after install command on %s", to_name);
756 	}
757 
758 	/*
759 	 * Set owner, group, mode for target; do the chown first,
760 	 * chown may lose the setuid bits.
761 	 */
762 	if (!dounpriv &&
763 	    (flags & (HASUID | HASGID)) && fchown(to_fd, uid, gid) == -1) {
764 		serrno = errno;
765 		(void)unlink(to_name);
766 		errc(EXIT_FAILURE, serrno, "%s: chown/chgrp", to_name);
767 	}
768 	tmpmode = mode;
769 	if (dounpriv)
770 		tmpmode &= S_IRWXU|S_IRWXG|S_IRWXO;
771 	if (fchmod(to_fd, tmpmode) == -1) {
772 		serrno = errno;
773 		(void)unlink(to_name);
774 		errc(EXIT_FAILURE, serrno, "%s: chmod", to_name);
775 	}
776 
777 	/*
778 	 * Preserve the date of the source file.
779 	 */
780 	if (dopreserve) {
781 #if HAVE_FUTIMES
782 		if (futimes(to_fd, tv) == -1)
783 			warn("%s: futimes", to_name);
784 #else
785 		if (utimes(to_name, tv) == -1)
786 			warn("%s: utimes", to_name);
787 #endif
788 	}
789 
790 	(void)close(to_fd);
791 
792 	if (dorename) {
793 		if (rename(to_name, oto_name) == -1)
794 			err(EXIT_FAILURE, "%s: rename", to_name);
795 		to_name = oto_name;
796 	}
797 
798 	/*
799 	 * If provided a set of flags, set them, otherwise, preserve the
800 	 * flags, except for the dump flag.
801 	 */
802 #if !defined(__minix)
803 #if ! HAVE_NBTOOL_CONFIG_H
804 	if (!dounpriv && chflags(to_name,
805 	    flags & SETFLAGS ? fileflags : from_sb.st_flags & ~UF_NODUMP) == -1)
806 	{
807 		if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
808 			warn("%s: chflags", to_name);
809 	}
810 #endif
811 #endif /* !defined(__minix) */
812 
813 	metadata_log(to_name, "file", tv, NULL, digestresult, size);
814 	free(digestresult);
815 }
816 
817 /*
818  * copy --
819  *	copy from one file to another, returning a digest.
820  *
821  *	If to_fd < 0, just calculate a digest, don't copy.
822  */
823 static char *
copy(int from_fd,char * from_name,int to_fd,char * to_name,off_t size)824 copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size)
825 {
826 	ssize_t	nr, nw;
827 	int	serrno;
828 	u_char	*p;
829 	u_char	buf[MAXBSIZE];
830 	MD5_CTX		ctxMD5;
831 	RMD160_CTX	ctxRMD160;
832 	SHA1_CTX	ctxSHA1;
833 	SHA256_CTX	ctxSHA256;
834 	SHA384_CTX	ctxSHA384;
835 	SHA512_CTX	ctxSHA512;
836 
837 	switch (digesttype) {
838 	case DIGEST_MD5:
839 		MD5Init(&ctxMD5);
840 		break;
841 	case DIGEST_RMD160:
842 		RMD160Init(&ctxRMD160);
843 		break;
844 	case DIGEST_SHA1:
845 		SHA1Init(&ctxSHA1);
846 		break;
847 	case DIGEST_SHA256:
848 		SHA256_Init(&ctxSHA256);
849 		break;
850 	case DIGEST_SHA384:
851 		SHA384_Init(&ctxSHA384);
852 		break;
853 	case DIGEST_SHA512:
854 		SHA512_Init(&ctxSHA512);
855 		break;
856 	case DIGEST_NONE:
857 		if (to_fd < 0)
858 			return NULL; /* no need to do anything */
859 	default:
860 		break;
861 	}
862 	/*
863 	 * There's no reason to do anything other than close the file
864 	 * now if it's empty, so let's not bother.
865 	 */
866 	if (size > 0) {
867 
868 		/*
869 		 * Mmap and write if less than 8M (the limit is so we
870 		 * don't totally trash memory on big files).  This is
871 		 * really a minor hack, but it wins some CPU back.
872 		 */
873 
874 		if (size <= 8 * 1048576) {
875 			if ((p = mmap(NULL, (size_t)size, PROT_READ,
876 			    MAP_FILE|MAP_SHARED, from_fd, (off_t)0))
877 			    == MAP_FAILED) {
878 				goto mmap_failed;
879 			}
880 #if defined(MADV_SEQUENTIAL) && !defined(__APPLE__) && !defined(__minix)
881 			if (madvise(p, (size_t)size, MADV_SEQUENTIAL) == -1
882 			    && errno != EOPNOTSUPP)
883 				warn("madvise");
884 #endif
885 
886 			if (to_fd >= 0 && write(to_fd, p, size) != size) {
887 				serrno = errno;
888 				(void)unlink(to_name);
889 				errc(EXIT_FAILURE, serrno, "%s: write",
890 				    to_name);
891 			}
892 			switch (digesttype) {
893 			case DIGEST_MD5:
894 				MD5Update(&ctxMD5, p, size);
895 				break;
896 			case DIGEST_RMD160:
897 				RMD160Update(&ctxRMD160, p, size);
898 				break;
899 			case DIGEST_SHA1:
900 				SHA1Update(&ctxSHA1, p, size);
901 				break;
902 			case DIGEST_SHA256:
903 				SHA256_Update(&ctxSHA256, p, size);
904 				break;
905 			case DIGEST_SHA384:
906 				SHA384_Update(&ctxSHA384, p, size);
907 				break;
908 			case DIGEST_SHA512:
909 				SHA512_Update(&ctxSHA512, p, size);
910 				break;
911 			default:
912 				break;
913 			}
914 			(void)munmap(p, size);
915 		} else {
916  mmap_failed:
917 			while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
918 				if (to_fd >= 0 &&
919 				    (nw = write(to_fd, buf, nr)) != nr) {
920 					serrno = errno;
921 					(void)unlink(to_name);
922 					errc(EXIT_FAILURE,
923 					    nw > 0 ? EIO : serrno,
924 					    "%s: write", to_name);
925 				}
926 				switch (digesttype) {
927 				case DIGEST_MD5:
928 					MD5Update(&ctxMD5, buf, nr);
929 					break;
930 				case DIGEST_RMD160:
931 					RMD160Update(&ctxRMD160, buf, nr);
932 					break;
933 				case DIGEST_SHA1:
934 					SHA1Update(&ctxSHA1, buf, nr);
935 					break;
936 				case DIGEST_SHA256:
937 					SHA256_Update(&ctxSHA256, buf, nr);
938 					break;
939 				case DIGEST_SHA384:
940 					SHA384_Update(&ctxSHA384, buf, nr);
941 					break;
942 				case DIGEST_SHA512:
943 					SHA512_Update(&ctxSHA512, buf, nr);
944 					break;
945 				default:
946 					break;
947 				}
948 			}
949 			if (nr != 0) {
950 				serrno = errno;
951 				(void)unlink(to_name);
952 				errc(EXIT_FAILURE, serrno, "%s: read",
953 				    from_name);
954 			}
955 		}
956 	}
957 	switch (digesttype) {
958 	case DIGEST_MD5:
959 		return MD5End(&ctxMD5, NULL);
960 	case DIGEST_RMD160:
961 		return RMD160End(&ctxRMD160, NULL);
962 	case DIGEST_SHA1:
963 		return SHA1End(&ctxSHA1, NULL);
964 	case DIGEST_SHA256:
965 		return SHA256_End(&ctxSHA256, NULL);
966 	case DIGEST_SHA384:
967 		return SHA384_End(&ctxSHA384, NULL);
968 	case DIGEST_SHA512:
969 		return SHA512_End(&ctxSHA512, NULL);
970 	default:
971 		return NULL;
972 	}
973 }
974 
975 static void
run(const char * command,const char * flags,const char * to_name,int errunlink)976 run(const char *command, const char *flags, const char *to_name, int errunlink)
977 {
978 	char	*args[4];
979 	char	*cmd;
980 	int	status;
981 	int	rv;
982 	size_t	i;
983 
984 	i = 1;
985 	status = 0;
986 
987 	if (needshell(command, 1)) {
988 		rv = asprintf(&cmd, "%s %s%s%s", command, flags ? flags : "",
989 		    flags ? " " : "", to_name);
990 		if (rv < 0) {
991 			warn("Cannot execute %s", command);
992 			goto out;
993 		}
994 		command = _PATH_BSHELL;
995 		flags = "-c";
996 	} else
997 		cmd = __UNCONST(to_name);
998 
999 	args[0] = __UNCONST(command);
1000 	if (flags)
1001 		args[i++] = __UNCONST(flags);
1002 	args[i++] = cmd;
1003 	args[i] = NULL;
1004 
1005 #ifdef HAVE_POSIX_SPAWN
1006 	if (*command == '/')
1007 		rv = posix_spawn(NULL, command, NULL, NULL, args, NULL);
1008 	else
1009 		rv = posix_spawnp(NULL, command, NULL, NULL, args, NULL);
1010 	if (rv != 0)
1011 		warnc(rv, "Cannot execute %s", command);
1012 	/*
1013 	 * the wait below will fail if we did not create a child it will
1014 	 * make rv negative.
1015 	 */
1016 #else
1017 	switch (vfork()) {
1018 	case -1:
1019 		rv = errno;
1020 		if (errunlink)
1021 			(void)unlink(to_name);
1022 		errc(EXIT_FAILURE, rv, "vfork");
1023 		/*NOTREACHED*/
1024 	case 0:
1025 		if (*command == '/')
1026 			execv(command, args);
1027 		else
1028 			execvp(command, args);
1029 		rv = errno;
1030 		const char *arr[] = {
1031 			getprogname(),
1032 			": exec failed for ",
1033 			command,
1034 			" (",
1035 			strerror(rv),
1036 			")\n",
1037 		};
1038 		for (i = 0; i < __arraycount(arr); i++)
1039 			write(STDERR_FILENO, arr[i], strlen(arr[i]));
1040 		_exit(1);
1041 		/*NOTREACHED*/
1042 	default:
1043 		break;
1044 	}
1045 #endif
1046 	rv = wait(&status);
1047 	if (cmd != to_name)
1048 		free(cmd);
1049 out:
1050 	if ((rv < 0 || status) && errunlink)
1051 		(void)unlink(to_name);
1052 }
1053 
1054 /*
1055  * strip --
1056  *	use strip(1) to strip the target file
1057  */
1058 static void
strip(const char * to_name)1059 strip(const char *to_name)
1060 {
1061 	const char *stripprog;
1062 
1063 	if ((stripprog = getenv("STRIP")) == NULL || *stripprog == '\0') {
1064 #ifdef TARGET_STRIP
1065 		stripprog = TARGET_STRIP;
1066 #else
1067 		stripprog = _PATH_STRIP;
1068 #endif
1069 	}
1070 	run(stripprog, stripArgs, to_name, 1);
1071 }
1072 
1073 /*
1074  * afterinstall --
1075  *	run provided command on the target file or directory after it's been
1076  *	installed and stripped, but before permissions are set or it's renamed
1077  */
1078 static void
afterinstall(const char * command,const char * to_name,int errunlink)1079 afterinstall(const char *command, const char *to_name, int errunlink)
1080 {
1081 	run(command, NULL, to_name, errunlink);
1082 }
1083 
1084 /*
1085  * backup --
1086  *	backup file "to_name" to to_name.suffix
1087  *	if suffix contains a "%", it's taken as a printf(3) pattern
1088  *	used for a numbered backup.
1089  */
1090 static void
backup(const char * to_name)1091 backup(const char *to_name)
1092 {
1093 	char	bname[FILENAME_MAX];
1094 
1095 	if (numberedbackup) {
1096 		/* Do numbered backup */
1097 		int cnt;
1098 		char suffix_expanded[FILENAME_MAX];
1099 
1100 		cnt=0;
1101 		do {
1102 			(void)snprintf(suffix_expanded, FILENAME_MAX, suffix,
1103 			    cnt);
1104 			(void)snprintf(bname, FILENAME_MAX, "%s%s", to_name,
1105 			    suffix_expanded);
1106 			cnt++;
1107 		} while (access(bname, F_OK) == 0);
1108 	} else {
1109 		/* Do simple backup */
1110 		(void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, suffix);
1111 	}
1112 
1113 	(void)rename(to_name, bname);
1114 }
1115 
1116 /*
1117  * install_dir --
1118  *	build directory hierarchy
1119  */
1120 static void
install_dir(char * path,u_int flags)1121 install_dir(char *path, u_int flags)
1122 {
1123 	char		*p;
1124 	struct stat	sb;
1125 	int		ch;
1126 
1127 	for (p = path;; ++p)
1128 		if (!*p || (p != path && *p  == '/')) {
1129 			ch = *p;
1130 			*p = '\0';
1131 			if (mkdir(path, 0777) < 0) {
1132 				/*
1133 				 * Can't create; path exists or no perms.
1134 				 * stat() path to determine what's there now.
1135 				 */
1136 				int sverrno;
1137 				sverrno = errno;
1138 				if (stat(path, &sb) < 0) {
1139 					/* Not there; use mkdir()s error */
1140 					errno = sverrno;
1141 					err(EXIT_FAILURE, "%s: mkdir", path);
1142 				}
1143 				if (!S_ISDIR(sb.st_mode)) {
1144 					errx(EXIT_FAILURE,
1145 					    "%s exists but is not a directory",
1146 					    path);
1147 				}
1148 			}
1149 			if (!(*p = ch))
1150 				break;
1151 		}
1152 
1153 	if (afterinstallcmd != NULL)
1154 		afterinstall(afterinstallcmd, path, 0);
1155 
1156 	if (!dounpriv && (
1157 	    ((flags & (HASUID | HASGID)) && chown(path, uid, gid) == -1)
1158 	    || chmod(path, mode) == -1 )) {
1159 		warn("%s: chown/chmod", path);
1160 	}
1161 	metadata_log(path, "dir", NULL, NULL, NULL, 0);
1162 }
1163 
1164 /*
1165  * metadata_log --
1166  *	if metafp is not NULL, output mtree(8) full path name and settings to
1167  *	metafp, to allow permissions to be set correctly by other tools,
1168  *	or to allow integrity checks to be performed.
1169  */
1170 static void
metadata_log(const char * path,const char * type,struct timeval * tv,const char * slink,const char * digestresult,off_t size)1171 metadata_log(const char *path, const char *type, struct timeval *tv,
1172 	const char *slink, const char *digestresult, off_t size)
1173 {
1174 	static const char	extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
1175 	const char	*p;
1176 	char		*buf;
1177 	size_t		destlen;
1178 	struct flock	metalog_lock;
1179 
1180 	if (!metafp)
1181 		return;
1182 	buf = malloc(4 * strlen(path) + 1);	/* buf for strsvis(3) */
1183 	if (buf == NULL) {
1184 		warn("Can't allocate metadata");
1185 		return;
1186 	}
1187 							/* lock log file */
1188 	metalog_lock.l_start = 0;
1189 	metalog_lock.l_len = 0;
1190 	metalog_lock.l_whence = SEEK_SET;
1191 	metalog_lock.l_type = F_WRLCK;
1192 	if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) {
1193 		warn("can't lock %s", metafile);
1194 		free(buf);
1195 		return;
1196 	}
1197 
1198 	p = path;					/* remove destdir */
1199 	if (destdir) {
1200 		destlen = strlen(destdir);
1201 		if (strncmp(p, destdir, destlen) == 0 &&
1202 		    (p[destlen] == '/' || p[destlen] == '\0'))
1203 			p += destlen;
1204 	}
1205 	while (*p && *p == '/')				/* remove leading /s */
1206 		p++;
1207 	strsvis(buf, p, VIS_CSTYLE, extra);		/* encode name */
1208 	p = buf;
1209 							/* print details */
1210 	fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type);
1211 	if (owner)
1212 		fprintf(metafp, " uname=%s", owner);
1213 	if (group)
1214 		fprintf(metafp, " gname=%s", group);
1215 	fprintf(metafp, " mode=%#o", mode);
1216 	if (slink) {
1217 		strsvis(buf, slink, VIS_CSTYLE, extra);	/* encode link */
1218 		fprintf(metafp, " link=%s", buf);
1219 	}
1220 	if (*type == 'f') /* type=file */
1221 		fprintf(metafp, " size=%lld", (long long)size);
1222 	if (tv != NULL && dopreserve)
1223 		fprintf(metafp, " time=%lld.%0*lld",
1224 			(long long)tv[1].tv_sec,
1225 			(tv[1].tv_usec == 0 ? 1 : 9),
1226 			(long long)tv[1].tv_usec * 1000);
1227 	if (digestresult && digest)
1228 		fprintf(metafp, " %s=%s", digest, digestresult);
1229 	if (fflags)
1230 		fprintf(metafp, " flags=%s", fflags);
1231 	if (tags)
1232 		fprintf(metafp, " tags=%s", tags);
1233 	fputc('\n', metafp);
1234 	fflush(metafp);					/* flush output */
1235 							/* unlock log file */
1236 	metalog_lock.l_type = F_UNLCK;
1237 	if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) {
1238 		warn("can't unlock %s", metafile);
1239 	}
1240 	free(buf);
1241 }
1242 
1243 /*
1244  * xbasename --
1245  *	libc basename(3) that returns a pointer to a static buffer
1246  *	instead of overwriting that passed-in string.
1247  */
1248 static char *
xbasename(char * path)1249 xbasename(char *path)
1250 {
1251 	static char tmp[MAXPATHLEN];
1252 
1253 	(void)strlcpy(tmp, path, sizeof(tmp));
1254 	return (basename(tmp));
1255 }
1256 
1257 /*
1258  * xdirname --
1259  *	libc dirname(3) that returns a pointer to a static buffer
1260  *	instead of overwriting that passed-in string.
1261  */
1262 static char *
xdirname(char * path)1263 xdirname(char *path)
1264 {
1265 	static char tmp[MAXPATHLEN];
1266 
1267 	(void)strlcpy(tmp, path, sizeof(tmp));
1268 	return (dirname(tmp));
1269 }
1270 
1271 /*
1272  * usage --
1273  *	print a usage message and die
1274  */
1275 static void
usage(void)1276 usage(void)
1277 {
1278 	const char *prog;
1279 
1280 	prog = getprogname();
1281 
1282 	(void)fprintf(stderr,
1283 "usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1284 "           [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n"
1285 "           [-l linkflags] [-h hash] [-S stripflags] file1 file2\n"
1286 "       %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n"
1287 "           [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n"
1288 "           [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n"
1289 "       %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n"
1290 "           [-N dbdir] [-o owner] [-g group] directory ...\n",
1291 	    prog, prog, prog);
1292 	exit(1);
1293 }
1294