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