Home | History | Annotate | Line # | Download | only in xinstall
xinstall.c revision 1.61
      1 /*	$NetBSD: xinstall.c,v 1.61 2001/11/23 16:14:51 simonb 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. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by the University of
     18  *	California, Berkeley and its contributors.
     19  * 4. Neither the name of the University nor the names of its contributors
     20  *    may be used to endorse or promote products derived from this software
     21  *    without specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  * SUCH DAMAGE.
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
     39 	The Regents of the University of California.  All rights reserved.\n");
     40 #endif /* not lint */
     41 
     42 #ifndef lint
     43 #if 0
     44 static char sccsid[] = "@(#)xinstall.c	8.1 (Berkeley) 7/21/93";
     45 #else
     46 __RCSID("$NetBSD: xinstall.c,v 1.61 2001/11/23 16:14:51 simonb Exp $");
     47 #endif
     48 #endif /* not lint */
     49 
     50 #include <sys/param.h>
     51 #include <sys/mman.h>
     52 #include <sys/stat.h>
     53 #include <sys/wait.h>
     54 
     55 #include <ctype.h>
     56 #include <err.h>
     57 #include <errno.h>
     58 #include <fcntl.h>
     59 #include <grp.h>
     60 #include <libgen.h>
     61 #include <paths.h>
     62 #include <pwd.h>
     63 #include <stdio.h>
     64 #include <stdlib.h>
     65 #include <string.h>
     66 #include <unistd.h>
     67 #include <vis.h>
     68 
     69 #include "pathnames.h"
     70 #include "stat_flags.h"
     71 
     72 #define STRIP_ARGS_MAX 32
     73 #define BACKUP_SUFFIX ".old"
     74 
     75 int	dobackup, docopy, dodir, dostrip, dolink, dopreserve, dorename,
     76 	    dounpriv;
     77 int	numberedbackup;
     78 int	mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
     79 char	pathbuf[MAXPATHLEN];
     80 uid_t	uid;
     81 gid_t	gid;
     82 char	*group, *owner, *fflags, *tags;
     83 FILE	*metafp;
     84 char	*metafile;
     85 u_long	fileflags;
     86 char	*stripArgs;
     87 char	*suffix = BACKUP_SUFFIX;
     88 
     89 #define LN_ABSOLUTE	0x01
     90 #define LN_RELATIVE	0x02
     91 #define LN_HARD		0x04
     92 #define LN_SYMBOLIC	0x08
     93 #define LN_MIXED	0x10
     94 
     95 #define	DIRECTORY	0x01		/* Tell install it's a directory. */
     96 #define	SETFLAGS	0x02		/* Tell install to set flags. */
     97 #define	HASUID		0x04		/* Tell install the uid was given */
     98 #define	HASGID		0x08		/* Tell install the gid was given */
     99 
    100 void	backup(const char *);
    101 void	copy(int, char *, int, char *, off_t);
    102 int	do_link(char *, char *);
    103 void	do_symlink(char *, char *);
    104 void	install(char *, char *, u_int);
    105 void	install_dir(char *, u_int);
    106 int	main(int, char *[]);
    107 void	makelink(char *, char *);
    108 void	metadata_log(const char *, const char *, struct timeval *, const char *);
    109 int	parseid(char *, id_t *);
    110 void	strip(char *);
    111 void	usage(void);
    112 char   *xbasename(char *);
    113 char   *xdirname(char *);
    114 
    115 int
    116 main(int argc, char *argv[])
    117 {
    118 	struct stat	from_sb, to_sb;
    119 	void		*set;
    120 	u_int		iflags;
    121 	int		ch, no_target;
    122 	char		*p, *to_name;
    123 
    124 	setprogname(argv[0]);
    125 
    126 	iflags = 0;
    127 	while ((ch = getopt(argc, argv, "cbB:df:g:l:m:M:o:prsS:T:U")) != -1)
    128 		switch((char)ch) {
    129 		case 'B':
    130 			suffix = optarg;
    131 			numberedbackup = 0;
    132 			{
    133 				/* Check if given suffix really generates
    134 				   different suffixes - catch e.g. ".%" */
    135 				char suffix_expanded0[FILENAME_MAX],
    136 				     suffix_expanded1[FILENAME_MAX];
    137 				(void)snprintf(suffix_expanded0, FILENAME_MAX,
    138 					       suffix, 0);
    139 				(void)snprintf(suffix_expanded1, FILENAME_MAX,
    140 					       suffix, 1);
    141 				if (strcmp(suffix_expanded0, suffix_expanded1)
    142 				    != 0)
    143 					numberedbackup = 1;
    144 			}
    145 			/* fall through; -B implies -b */
    146 			/*FALLTHROUGH*/
    147 		case 'b':
    148 			dobackup = 1;
    149 			break;
    150 		case 'c':
    151 			docopy = 1;
    152 			break;
    153 		case 'd':
    154 			dodir = 1;
    155 			break;
    156 		case 'f':
    157 			fflags = optarg;
    158 			break;
    159 		case 'g':
    160 			group = optarg;
    161 			break;
    162 		case 'l':
    163 			for (p = optarg; *p; p++)
    164 				switch (*p) {
    165 				case 's':
    166 					dolink &= ~(LN_HARD|LN_MIXED);
    167 					dolink |= LN_SYMBOLIC;
    168 					break;
    169 				case 'h':
    170 					dolink &= ~(LN_SYMBOLIC|LN_MIXED);
    171 					dolink |= LN_HARD;
    172 					break;
    173 				case 'm':
    174 					dolink &= ~(LN_SYMBOLIC|LN_HARD);
    175 					dolink |= LN_MIXED;
    176 					break;
    177 				case 'a':
    178 					dolink &= ~LN_RELATIVE;
    179 					dolink |= LN_ABSOLUTE;
    180 					break;
    181 				case 'r':
    182 					dolink &= ~LN_ABSOLUTE;
    183 					dolink |= LN_RELATIVE;
    184 					break;
    185 				default:
    186 					errx(1, "%c: invalid link type", *p);
    187 					/* NOTREACHED */
    188 				}
    189 			break;
    190 		case 'm':
    191 			if (!(set = setmode(optarg)))
    192 				errx(1, "%s: invalid file mode", optarg);
    193 			mode = getmode(set, 0);
    194 			free(set);
    195 			break;
    196 		case 'M':
    197 			metafile = optarg;
    198 			break;
    199 		case 'o':
    200 			owner = optarg;
    201 			break;
    202 		case 'p':
    203 			dopreserve = 1;
    204 			break;
    205 		case 'r':
    206 			dorename = 1;
    207 			break;
    208 		case 'S':
    209 			stripArgs = strdup(optarg);
    210 			if (stripArgs == NULL)
    211 				errx(1, "%s", strerror(ENOMEM));
    212 			/* fall through; -S implies -s */
    213 			/*FALLTHROUGH*/
    214 		case 's':
    215 			dostrip = 1;
    216 			break;
    217 		case 'T':
    218 			tags = optarg;
    219 			break;
    220 		case 'U':
    221 			dounpriv = 1;
    222 			break;
    223 		case '?':
    224 		default:
    225 			usage();
    226 		}
    227 	argc -= optind;
    228 	argv += optind;
    229 
    230 	/* strip and link options make no sense when creating directories */
    231 	if ((dostrip || dolink) && dodir)
    232 		usage();
    233 
    234 	/* strip and flags make no sense with links */
    235 	if ((dostrip || fflags) && dolink)
    236 		usage();
    237 
    238 	/* must have at least two arguments, except when creating directories */
    239 	if (argc < 2 && !dodir)
    240 		usage();
    241 
    242 	/* get group and owner id's */
    243 	if (group && !dounpriv) {
    244 		struct group *gp;
    245 
    246 		if ((gp = getgrnam(group)) != NULL)
    247 			gid = gp->gr_gid;
    248 		else if (! parseid(group, &gid))
    249 			errx(1, "unknown group %s", group);
    250 		iflags |= HASGID;
    251 	}
    252 	if (owner && !dounpriv) {
    253 		struct passwd *pp;
    254 
    255 		if ((pp = getpwnam(owner)) != NULL)
    256 			uid = pp->pw_uid;
    257 		else if (! parseid(owner, &uid))
    258 			errx(1, "unknown user %s", owner);
    259 		iflags |= HASUID;
    260 	}
    261 
    262 	if (fflags && !dounpriv) {
    263 		if (string_to_flags(&fflags, &fileflags, NULL))
    264 			errx(1, "%s: invalid flag", fflags);
    265 		iflags |= SETFLAGS;
    266 	}
    267 
    268 	if (metafile) {
    269 		if ((metafp = fopen(metafile, "a")) == NULL)
    270 			warn("open %s", metafile);
    271 	}
    272 
    273 	if (dodir) {
    274 		for (; *argv != NULL; ++argv)
    275 			install_dir(*argv, iflags);
    276 		exit (0);
    277 	}
    278 
    279 	no_target = stat(to_name = argv[argc - 1], &to_sb);
    280 	if (!no_target && S_ISDIR(to_sb.st_mode)) {
    281 		for (; *argv != to_name; ++argv)
    282 			install(*argv, to_name, iflags | DIRECTORY);
    283 		exit(0);
    284 	}
    285 
    286 	/* can't do file1 file2 directory/file */
    287 	if (argc != 2)
    288 		usage();
    289 
    290 	if (!no_target) {
    291 		/* makelink() handles checks for links */
    292 		if (!dolink) {
    293 			if (stat(*argv, &from_sb))
    294 				err(1, "%s", *argv);
    295 			if (!S_ISREG(to_sb.st_mode))
    296 				errx(1, "%s: not a regular file", to_name);
    297 			if (to_sb.st_dev == from_sb.st_dev &&
    298 			    to_sb.st_ino == from_sb.st_ino)
    299 				errx(1, "%s and %s are the same file", *argv,
    300 				    to_name);
    301 		}
    302 		/*
    303 		 * Unlink now... avoid ETXTBSY errors later.  Try and turn
    304 		 * off the append/immutable bits -- if we fail, go ahead,
    305 		 * it might work.
    306 		 */
    307 #define	NOCHANGEBITS	(UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
    308 		if (to_sb.st_flags & NOCHANGEBITS)
    309 			(void)chflags(to_name,
    310 			    to_sb.st_flags & ~(NOCHANGEBITS));
    311 		if (dobackup)
    312 			backup(to_name);
    313 		else if (!dorename)
    314 			(void)unlink(to_name);
    315 	}
    316 	install(*argv, to_name, iflags);
    317 	exit(0);
    318 }
    319 
    320 /*
    321  * parseid --
    322  *	parse uid or gid from arg into id, returning non-zero if successful
    323  */
    324 int
    325 parseid(char *name, id_t *id)
    326 {
    327 	char	*ep;
    328 
    329 	errno = 0;
    330 	*id = (id_t)strtoul(name, &ep, 10);
    331 	if (errno || *ep != '\0')
    332 		return (0);
    333 	return (1);
    334 }
    335 
    336 /*
    337  * do_link --
    338  *	make a hard link, obeying dorename if set
    339  *	return -1 on failure
    340  */
    341 int
    342 do_link(char *from_name, char *to_name)
    343 {
    344 	char tmpl[MAXPATHLEN];
    345 	int ret;
    346 
    347 	if (dorename) {
    348 		(void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
    349 		    xdirname(to_name));
    350 		if (mktemp(tmpl) == NULL)
    351 			err(1, "%s", tmpl);
    352 		ret = link(from_name, tmpl);
    353 		if (ret == 0) {
    354 			ret = rename(tmpl, to_name);
    355 			if (ret < 0)
    356 				/* remove temporary link before exiting */
    357 				(void)unlink(tmpl);
    358 		}
    359 		return (ret);
    360 	} else
    361 		return (link(from_name, to_name));
    362 }
    363 
    364 /*
    365  * do_symlink --
    366  *	make a symbolic link, obeying dorename if set
    367  *	exit on failure
    368  */
    369 void
    370 do_symlink(char *from_name, char *to_name)
    371 {
    372 	char tmpl[MAXPATHLEN];
    373 
    374 	if (dorename) {
    375 		(void)snprintf(tmpl, sizeof(tmpl), "%s/inst.XXXXXX",
    376 		    xdirname(to_name));
    377 		if (mktemp(tmpl) == NULL)
    378 			err(1, "%s", tmpl);
    379 
    380 		if (symlink(from_name, tmpl) == -1)
    381 			err(1, "symlink %s -> %s", from_name, tmpl);
    382 		if (rename(tmpl, to_name) == -1) {
    383 			/* remove temporary link before exiting */
    384 			(void)unlink(tmpl);
    385 			err(1, "%s: rename", to_name);
    386 		}
    387 	} else {
    388 		if (symlink(from_name, to_name) == -1)
    389 			err(1, "symlink %s -> %s", from_name, to_name);
    390 	}
    391 }
    392 
    393 /*
    394  * makelink --
    395  *	make a link from source to destination
    396  */
    397 void
    398 makelink(char *from_name, char *to_name)
    399 {
    400 	char	src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN];
    401 
    402 	/* Try hard links first */
    403 	if (dolink & (LN_HARD|LN_MIXED)) {
    404 		if (do_link(from_name, to_name) == -1) {
    405 			if ((dolink & LN_HARD) || errno != EXDEV)
    406 				err(1, "link %s -> %s", from_name, to_name);
    407 		}
    408 		else {
    409 			metadata_log(to_name, "hlink", NULL, from_name);
    410 			return;
    411 		}
    412 	}
    413 
    414 	/* Symbolic links */
    415 	if (dolink & LN_ABSOLUTE) {
    416 		/* Convert source path to absolute */
    417 		if (realpath(from_name, src) == NULL)
    418 			err(1, "%s", from_name);
    419 		do_symlink(src, to_name);
    420 		metadata_log(to_name, "link", NULL, src);
    421 		return;
    422 	}
    423 
    424 	if (dolink & LN_RELATIVE) {
    425 		char *cp, *d, *s;
    426 
    427 		/* Resolve pathnames */
    428 		if (realpath(from_name, src) == NULL)
    429 			err(1, "%s", from_name);
    430 
    431 		/*
    432 		 * The last component of to_name may be a symlink,
    433 		 * so use realpath to resolve only the directory.
    434 		 */
    435 		cp = dirname(to_name);
    436 		if (realpath(cp, dst) == NULL)
    437 			err(1, "%s", cp);
    438 		/* .. and add the last component */
    439 		if (strcmp(dst, "/") != 0) {
    440 			if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst))
    441 				errx(1, "resolved pathname too long");
    442 		}
    443 		cp = xbasename(to_name);
    444 		if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst))
    445 			errx(1, "resolved pathname too long");
    446 
    447 		/* trim common path components */
    448 		for (s = src, d = dst; *s == *d; s++, d++)
    449 			continue;
    450 		while (*s != '/')
    451 			s--, d--;
    452 
    453 		/* count the number of directories we need to backtrack */
    454 		for (++d, lnk[0] = '\0'; *d; d++)
    455 			if (*d == '/')
    456 				(void)strcat(lnk, "../");
    457 
    458 		(void)strcat(lnk, ++s);
    459 
    460 		do_symlink(lnk, dst);
    461 		metadata_log(dst, "link", NULL, lnk);
    462 		return;
    463 	}
    464 
    465 	/*
    466 	 * If absolute or relative was not specified,
    467 	 * try the names the user provided
    468 	 */
    469 	do_symlink(from_name, to_name);
    470 	metadata_log(to_name, "link", NULL, from_name);
    471 }
    472 
    473 /*
    474  * install --
    475  *	build a path name and install the file
    476  */
    477 void
    478 install(char *from_name, char *to_name, u_int flags)
    479 {
    480 	struct stat	from_sb, to_sb;
    481 	struct timeval	tv[2];
    482 	int		devnull, from_fd, to_fd, serrno, tmpmode;
    483 	char		*p, tmpl[MAXPATHLEN], *oto_name;
    484 
    485 	if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
    486 		if (!dolink) {
    487 			if (stat(from_name, &from_sb))
    488 				err(1, "%s", from_name);
    489 			if (!S_ISREG(from_sb.st_mode))
    490 				errx(1, "%s: not a regular file", from_name);
    491 		}
    492 		/* Build the target path. */
    493 		if (flags & DIRECTORY) {
    494 			(void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
    495 			    to_name,
    496 			    (p = strrchr(from_name, '/')) ? ++p : from_name);
    497 			to_name = pathbuf;
    498 		}
    499 		devnull = 0;
    500 	} else {
    501 		from_sb.st_flags = 0;	/* XXX */
    502 		devnull = 1;
    503 	}
    504 
    505 	/*
    506 	 * Unlink now... avoid ETXTBSY errors later.  Try and turn
    507 	 * off the append/immutable bits -- if we fail, go ahead,
    508 	 * it might work.
    509 	 */
    510 	if (stat(to_name, &to_sb) == 0 &&
    511 	    to_sb.st_flags & (NOCHANGEBITS))
    512 		(void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS));
    513 	if (dorename) {
    514 		(void)snprintf(tmpl, sizeof(tmpl), "%sinst.XXXXXX",
    515 		    xdirname(to_name));
    516 		oto_name = to_name;
    517 		to_name = tmpl;
    518 	} else {
    519 		oto_name = NULL;	/* pacify gcc */
    520 		if (dobackup)
    521 			backup(to_name);
    522 		else
    523 			(void)unlink(to_name);
    524 	}
    525 
    526 	if (dolink) {
    527 		makelink(from_name, dorename ? oto_name : to_name);
    528 		return;
    529 	}
    530 
    531 	/* Create target. */
    532 	if (dorename) {
    533 		if ((to_fd = mkstemp(to_name)) == -1)
    534 			err(1, "%s", to_name);
    535 	} else {
    536 		if ((to_fd = open(to_name,
    537 		    O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0)
    538 			err(1, "%s", to_name);
    539 	}
    540 	if (!devnull) {
    541 		if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) {
    542 			(void)unlink(to_name);
    543 			err(1, "%s", from_name);
    544 		}
    545 		copy(from_fd, from_name, to_fd, to_name, from_sb.st_size);
    546 		(void)close(from_fd);
    547 	}
    548 
    549 	if (dostrip) {
    550 		strip(to_name);
    551 
    552 		/*
    553 		 * Re-open our fd on the target, in case we used a strip
    554 		 *  that does not work in-place -- like gnu binutils strip.
    555 		 */
    556 		close(to_fd);
    557 		if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0)
    558 		  err(1, "stripping %s", to_name);
    559 	}
    560 
    561 	/*
    562 	 * Set owner, group, mode for target; do the chown first,
    563 	 * chown may lose the setuid bits.
    564 	 */
    565 	if (!dounpriv &&
    566 	    (flags & (HASUID | HASGID)) && fchown(to_fd, uid, gid) == -1) {
    567 		serrno = errno;
    568 		(void)unlink(to_name);
    569 		errx(1, "%s: chown/chgrp: %s", to_name, strerror(serrno));
    570 	}
    571 	tmpmode = mode;
    572 	if (dounpriv)
    573 		tmpmode &= S_IRWXU|S_IRWXG|S_IRWXO;
    574 	if (fchmod(to_fd, tmpmode) == -1) {
    575 		serrno = errno;
    576 		(void)unlink(to_name);
    577 		errx(1, "%s: chmod: %s", to_name, strerror(serrno));
    578 	}
    579 
    580 	/*
    581 	 * Preserve the date of the source file.
    582 	 */
    583 	if (dopreserve) {
    584 #ifdef BSD4_4
    585 		TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec);
    586 		TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec);
    587 #else
    588 		tv[0].tv_sec = from_sb.st_atime;
    589 		tv[0].tv_usec = 0;
    590 		tv[1].tv_sec = from_sb.st_mtime;
    591 		tv[1].tv_usec = 0;
    592 #endif
    593 		if (!dounpriv && futimes(to_fd, tv) == -1)
    594 			warn("%s: futimes", to_name);
    595 	}
    596 
    597 	(void)close(to_fd);
    598 
    599 	if (dorename) {
    600 		if (rename(to_name, oto_name) == -1)
    601 			err(1, "%s: rename", to_name);
    602 		to_name = oto_name;
    603 	}
    604 
    605 	if (!docopy && !devnull && unlink(from_name))
    606 		err(1, "%s", from_name);
    607 
    608 	/*
    609 	 * If provided a set of flags, set them, otherwise, preserve the
    610 	 * flags, except for the dump flag.
    611 	 */
    612 	if (!dounpriv && chflags(to_name,
    613 	    flags & SETFLAGS ? fileflags : from_sb.st_flags & ~UF_NODUMP) == -1)
    614 	{
    615 		if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0)
    616 			warn("%s: chflags", to_name);
    617 	}
    618 
    619 	metadata_log(to_name, "file", tv, NULL);
    620 }
    621 
    622 /*
    623  * copy --
    624  *	copy from one file to another
    625  */
    626 void
    627 copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size)
    628 {
    629 	ssize_t	nr, nw;
    630 	int	serrno;
    631 	char	*p;
    632 	char	buf[MAXBSIZE];
    633 
    634 	/*
    635 	 * There's no reason to do anything other than close the file
    636 	 * now if it's empty, so let's not bother.
    637 	 */
    638 	if (size > 0) {
    639 
    640 		/*
    641 		 * Mmap and write if less than 8M (the limit is so we
    642 		 * don't totally trash memory on big files).  This is
    643 		 * really a minor hack, but it wins some CPU back.
    644 		 */
    645 
    646 		if (size <= 8 * 1048576) {
    647 			if ((p = mmap(NULL, (size_t)size, PROT_READ,
    648 			    MAP_FILE|MAP_SHARED, from_fd, (off_t)0))
    649 			    == MAP_FAILED) {
    650 				goto mmap_failed;
    651 			}
    652 #ifdef MADV_SEQUENTIAL
    653 			if (madvise(p, (size_t)size, MADV_SEQUENTIAL) == -1
    654 			    && errno != EOPNOTSUPP)
    655 				warnx("madvise: %s", strerror(errno));
    656 #endif
    657 
    658 			if (write(to_fd, p, size) != size) {
    659 				serrno = errno;
    660 				(void)unlink(to_name);
    661 				errx(1, "%s: %s",
    662 				    to_name, strerror(serrno));
    663 			}
    664 		} else {
    665 mmap_failed:
    666 			while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
    667 				if ((nw = write(to_fd, buf, nr)) != nr) {
    668 					serrno = errno;
    669 					(void)unlink(to_name);
    670 					errx(1, "%s: %s", to_name,
    671 					    strerror(nw > 0 ? EIO : serrno));
    672 				}
    673 			}
    674 			if (nr != 0) {
    675 				serrno = errno;
    676 				(void)unlink(to_name);
    677 				errx(1, "%s: %s", from_name, strerror(serrno));
    678 			}
    679 		}
    680 	}
    681 }
    682 
    683 /*
    684  * strip --
    685  *	use strip(1) to strip the target file
    686  */
    687 void
    688 strip(char *to_name)
    689 {
    690 	int	serrno, status;
    691 	char	*stripprog;
    692 
    693 	switch (vfork()) {
    694 	case -1:
    695 		serrno = errno;
    696 		(void)unlink(to_name);
    697 		errx(1, "vfork: %s", strerror(serrno));
    698 		/*NOTREACHED*/
    699 	case 0:
    700 		stripprog = getenv("STRIP");
    701 		if (stripprog == NULL)
    702 			stripprog = _PATH_STRIP;
    703 
    704 		if (stripArgs) {
    705 			/*
    706 			 * build up a command line and let /bin/sh
    707 			 * parse the arguments
    708 			 */
    709 			char* cmd = (char*)malloc(sizeof(char)*
    710 						  (3+strlen(stripprog)+
    711 						     strlen(stripArgs)+
    712 						     strlen(to_name)));
    713 
    714 			if (cmd == NULL)
    715 				errx(1, "%s", strerror(ENOMEM));
    716 
    717 			sprintf(cmd, "%s %s %s", stripprog, stripArgs, to_name);
    718 
    719 			execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
    720 		} else
    721 			execlp(stripprog, "strip", to_name, NULL);
    722 
    723 		warn("%s", stripprog);
    724 		_exit(1);
    725 		/*NOTREACHED*/
    726 	default:
    727 		if (wait(&status) == -1 || status)
    728 			(void)unlink(to_name);
    729 	}
    730 }
    731 
    732 /*
    733  * backup --
    734  *	backup file "to_name" to to_name.suffix
    735  *	if suffix contains a "%", it's taken as a printf(3) pattern
    736  *	used for a numbered backup.
    737  */
    738 void
    739 backup(const char *to_name)
    740 {
    741 	char	bname[FILENAME_MAX];
    742 
    743 	if (numberedbackup) {
    744 		/* Do numbered backup */
    745 		int cnt;
    746 		char suffix_expanded[FILENAME_MAX];
    747 
    748 		cnt=0;
    749 		do {
    750 			(void)snprintf(suffix_expanded, FILENAME_MAX, suffix,
    751 			    cnt);
    752 			(void)snprintf(bname, FILENAME_MAX, "%s%s", to_name,
    753 			    suffix_expanded);
    754 			cnt++;
    755 		} while (access(bname, F_OK) == 0);
    756 	} else {
    757 		/* Do simple backup */
    758 		(void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, suffix);
    759 	}
    760 
    761 	(void)rename(to_name, bname);
    762 }
    763 
    764 /*
    765  * install_dir --
    766  *	build directory hierarchy
    767  */
    768 void
    769 install_dir(char *path, u_int flags)
    770 {
    771         char		*p;
    772         struct stat	sb;
    773         int		ch;
    774 
    775         for (p = path;; ++p)
    776                 if (!*p || (p != path && *p  == '/')) {
    777                         ch = *p;
    778                         *p = '\0';
    779                         if (stat(path, &sb)) {
    780                                 if (errno != ENOENT || mkdir(path, 0777) < 0) {
    781 					err(1, "%s", path);
    782                                 }
    783                         }
    784                         if (!(*p = ch))
    785 				break;
    786                 }
    787 
    788 	if (!dounpriv && (
    789 	    ((flags & (HASUID | HASGID)) && chown(path, uid, gid) == -1)
    790 	    || chmod(path, mode) == -1 )) {
    791                 warn("%s", path);
    792 	}
    793 	metadata_log(path, "dir", NULL, NULL);
    794 }
    795 
    796 /*
    797  * metadata_log --
    798  *	if metafp is not NULL, output mtree(8) full path name and settings to
    799  *	metafp, to allow permissions to be set correctly by other tools.
    800  */
    801 void
    802 metadata_log(const char *path, const char *type, struct timeval *tv,
    803 	const char *link)
    804 {
    805 	const char	extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
    806 	char		*buf;
    807 
    808 	if (!metafp)
    809 		return;
    810 	buf = (char *)malloc(4 * strlen(path) + 1);	/* buf for strsvis(3) */
    811 	if (buf == NULL) {
    812 		warnx("%s", strerror(ENOMEM));
    813 		return;
    814 	}
    815 	if (flock(fileno(metafp), LOCK_EX) == -1) {	/* lock log file */
    816 		warn("can't lock %s", metafile);
    817 		return;
    818 	}
    819 
    820 	strsvis(buf, path, VIS_CSTYLE, extra);		/* encode name */
    821 	fprintf(metafp, ".%s%s type=%s mode=%#o",	/* print details */
    822 	    buf[0] == '/' ? "" : "/", buf, type, mode);
    823 	if (link)
    824 		fprintf(metafp, " link=%s", link);
    825 	if (owner)
    826 		fprintf(metafp, " uname=%s", owner);
    827 	if (group)
    828 		fprintf(metafp, " gname=%s", group);
    829 	if (fflags)
    830 		fprintf(metafp, " flags=%s", fflags);
    831 	if (tags)
    832 		fprintf(metafp, " tags=%s", tags);
    833 	if (tv != NULL && dopreserve)
    834 		fprintf(metafp, " time=%ld.%ld", tv[1].tv_sec, tv[1].tv_usec);
    835 	fputc('\n', metafp);
    836 	fflush(metafp);					/* flush output */
    837 	if (flock(fileno(metafp), LOCK_UN) == -1) {	/* unlock log file */
    838 		warn("can't unlock %s", metafile);
    839 	}
    840 	free(buf);
    841 }
    842 
    843 /*
    844  * xbasename --
    845  *	libc basename(3) that returns a pointer to a static buffer
    846  *	instead of overwriting that passed-in string.
    847  */
    848 char *
    849 xbasename(char *path)
    850 {
    851 	static char tmp[MAXPATHLEN];
    852 
    853 	(void)strlcpy(tmp, path, sizeof(tmp));
    854 	return (basename(tmp));
    855 }
    856 
    857 /*
    858  * xdirname --
    859  *	libc dirname(3) that returns a pointer to a static buffer
    860  *	instead of overwriting that passed-in string.
    861  */
    862 char *
    863 xdirname(char *path)
    864 {
    865 	static char tmp[MAXPATHLEN];
    866 
    867 	(void)strlcpy(tmp, path, sizeof(tmp));
    868 	return (dirname(tmp));
    869 }
    870 
    871 /*
    872  * usage --
    873  *	print a usage message and die
    874  */
    875 void
    876 usage(void)
    877 {
    878 
    879 	(void)fprintf(stderr, "\
    880 usage: install [-Ubcprs] [-M log] [-T tags] [-B suffix] [-f flags] [-m mode]\n\
    881 	    [-o owner] [-g group] [-l linkflags] [-S stripflags] file1 file2\n\
    882        install [-Ubcprs] [-M log] [-T tags] [-B suffix] [-f flags] [-m mode]\n\
    883 	    [-o owner] [-g group] [-l linkflags] [-S stripflags]\n\
    884 	    file1 ... fileN directory\n\
    885        install [-Up] [-M log] [-T tags] -d [-m mode]\n\
    886 	    [-o owner] [-g group] directory ...\n");
    887 	exit(1);
    888 }
    889