xinstall.c revision 318096
165543Scg/* 265543Scg * Copyright (c) 2012, 2013 SRI International 365543Scg * Copyright (c) 1987, 1993 465543Scg * The Regents of the University of California. All rights reserved. 565543Scg * 665543Scg * Redistribution and use in source and binary forms, with or without 765543Scg * modification, are permitted provided that the following conditions 865543Scg * are met: 965543Scg * 1. Redistributions of source code must retain the above copyright 1065543Scg * notice, this list of conditions and the following disclaimer. 1165543Scg * 2. Redistributions in binary form must reproduce the above copyright 1265543Scg * notice, this list of conditions and the following disclaimer in the 1365543Scg * documentation and/or other materials provided with the distribution. 1465543Scg * 4. Neither the name of the University nor the names of its contributors 1565543Scg * may be used to endorse or promote products derived from this software 1665543Scg * without specific prior written permission. 1765543Scg * 1865543Scg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1965543Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2065543Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2165543Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2265543Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2365543Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2465543Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2565543Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26137500Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2765543Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2865543Scg * SUCH DAMAGE. 2965543Scg */ 3065543Scg 3165543Scg#ifndef lint 3265543Scgstatic const char copyright[] = 3365543Scg"@(#) Copyright (c) 1987, 1993\n\ 3465543Scg The Regents of the University of California. All rights reserved.\n"; 3565543Scg#endif /* not lint */ 3665543Scg 3765543Scg#if 0 3865543Scg#ifndef lint 3965543Scgstatic char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93"; 4065543Scg#endif /* not lint */ 4165543Scg#endif 4265543Scg 4365543Scg#include <sys/cdefs.h> 44137500Sjulian__FBSDID("$FreeBSD: stable/10/usr.bin/xinstall/xinstall.c 318096 2017-05-09 19:14:26Z bdrewery $"); 45137500Sjulian 46137500Sjulian#include <sys/param.h> 4765543Scg#include <sys/mman.h> 4865543Scg#include <sys/mount.h> 4965543Scg#include <sys/stat.h> 50137500Sjulian#include <sys/time.h> 5165543Scg#include <sys/wait.h> 5265543Scg 5365543Scg#include <err.h> 5465543Scg#include <errno.h> 5565543Scg#include <fcntl.h> 5665543Scg#include <grp.h> 5765543Scg#include <libgen.h> 5865543Scg#include <md5.h> 5965543Scg#include <paths.h> 6065543Scg#include <pwd.h> 6165543Scg#include <ripemd.h> 6265543Scg#include <sha.h> 6365543Scg#include <sha256.h> 6465543Scg#include <sha512.h> 6565543Scg#include <stdint.h> 6665543Scg#include <stdio.h> 6765543Scg#include <stdlib.h> 6865543Scg#include <string.h> 6965543Scg#include <sysexits.h> 7065543Scg#include <unistd.h> 7165543Scg#include <vis.h> 7265543Scg 7365543Scg#include "mtree.h" 7465543Scg 7565543Scg/* Bootstrap aid - this doesn't exist in most older releases */ 7665543Scg#ifndef MAP_FAILED 7765543Scg#define MAP_FAILED ((void *)-1) /* from <sys/mman.h> */ 7865543Scg#endif 7965543Scg 8065543Scg#define MAX_CMP_SIZE (16 * 1024 * 1024) 8165543Scg 8265543Scg#define LN_ABSOLUTE 0x01 8365543Scg#define LN_RELATIVE 0x02 8465543Scg#define LN_HARD 0x04 8565543Scg#define LN_SYMBOLIC 0x08 8665543Scg#define LN_MIXED 0x10 8765543Scg 8865543Scg#define DIRECTORY 0x01 /* Tell install it's a directory. */ 8965543Scg#define SETFLAGS 0x02 /* Tell install to set flags. */ 9065543Scg#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 9165543Scg#define BACKUP_SUFFIX ".old" 9265543Scg 9365543Scgtypedef union { 9465543Scg MD5_CTX MD5; 9565543Scg RIPEMD160_CTX RIPEMD160; 9665543Scg SHA1_CTX SHA1; 9765543Scg SHA256_CTX SHA256; 9865543Scg SHA512_CTX SHA512; 9965543Scg} DIGEST_CTX; 10065543Scg 10165543Scgstatic enum { 10265543Scg DIGEST_NONE = 0, 10365543Scg DIGEST_MD5, 10465543Scg DIGEST_RIPEMD160, 10565543Scg DIGEST_SHA1, 10665543Scg DIGEST_SHA256, 10765543Scg DIGEST_SHA512, 10865543Scg} digesttype = DIGEST_NONE; 10965543Scg 11065543Scgstatic gid_t gid; 11165543Scgstatic uid_t uid; 11265543Scgstatic int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, 11365543Scg safecopy, verbose; 11465543Scgstatic int haveopt_f, haveopt_g, haveopt_m, haveopt_o; 11565543Scgstatic mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 11665543Scgstatic FILE *metafp; 11765543Scgstatic const char *group, *owner; 11865543Scgstatic const char *suffix = BACKUP_SUFFIX; 11965543Scgstatic char *destdir, *digest, *fflags, *metafile, *tags; 12065543Scg 12165543Scgstatic int compare(int, const char *, size_t, int, const char *, size_t, 12265543Scg char **); 12365543Scgstatic char *copy(int, const char *, int, const char *, off_t); 12465543Scgstatic int create_newfile(const char *, int, struct stat *); 12565543Scgstatic int create_tempfile(const char *, char *, size_t); 12665543Scgstatic char *quiet_mktemp(char *template); 12765543Scgstatic char *digest_file(const char *); 12865543Scgstatic void digest_init(DIGEST_CTX *); 12965543Scgstatic void digest_update(DIGEST_CTX *, const unsigned char *, size_t); 13065543Scgstatic char *digest_end(DIGEST_CTX *, char *); 13165543Scgstatic int do_link(const char *, const char *, const struct stat *); 13265543Scgstatic void do_symlink(const char *, const char *, const struct stat *); 13365543Scgstatic void makelink(const char *, const char *, const struct stat *); 13465543Scgstatic void install(const char *, const char *, u_long, u_int); 13565543Scgstatic void install_dir(char *); 13665543Scgstatic void metadata_log(const char *, const char *, struct timeval *, 13765543Scg const char *, const char *, off_t); 13865543Scgstatic int parseid(const char *, id_t *); 13965543Scgstatic void strip(const char *); 14065543Scgstatic int trymmap(int); 141137500Sjulianstatic void usage(void); 142137500Sjulian 143137500Sjulianint 14465543Scgmain(int argc, char *argv[]) 14565543Scg{ 14665543Scg struct stat from_sb, to_sb; 14765543Scg mode_t *set; 14870619Sjhb u_long fset; 149137500Sjulian int ch, no_target; 15070619Sjhb u_int iflags; 15170619Sjhb char *p; 15265543Scg const char *to_name; 15365543Scg 15465543Scg fset = 0; 15565543Scg iflags = 0; 15665543Scg group = owner = NULL; 15765543Scg while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != 15865543Scg -1) 15965543Scg switch((char)ch) { 16065543Scg case 'B': 16165543Scg suffix = optarg; 16265543Scg /* FALLTHROUGH */ 16365543Scg case 'b': 16465543Scg dobackup = 1; 16565543Scg break; 16665543Scg case 'C': 16765543Scg docompare = 1; 16865543Scg break; 16965543Scg case 'c': 17065543Scg /* For backwards compatibility. */ 17165543Scg break; 17265543Scg case 'D': 17365543Scg destdir = optarg; 17465543Scg break; 17565543Scg case 'd': 17665543Scg dodir = 1; 17765543Scg break; 17865543Scg case 'f': 17965543Scg haveopt_f = 1; 18065543Scg fflags = optarg; 18165543Scg break; 18265543Scg case 'g': 18365543Scg haveopt_g = 1; 18465543Scg group = optarg; 18565543Scg break; 18665543Scg case 'h': 18765543Scg digest = optarg; 18865543Scg break; 189137500Sjulian case 'l': 190137500Sjulian for (p = optarg; *p != '\0'; p++) 191137500Sjulian switch (*p) { 192137500Sjulian case 's': 193137500Sjulian dolink &= ~(LN_HARD|LN_MIXED); 194137500Sjulian dolink |= LN_SYMBOLIC; 195137500Sjulian break; 196137500Sjulian case 'h': 197137500Sjulian dolink &= ~(LN_SYMBOLIC|LN_MIXED); 19865543Scg dolink |= LN_HARD; 19965543Scg break; 20065543Scg case 'm': 20165543Scg dolink &= ~(LN_SYMBOLIC|LN_HARD); 20265543Scg dolink |= LN_MIXED; 20365543Scg break; 20465543Scg case 'a': 20565543Scg dolink &= ~LN_RELATIVE; 20665543Scg dolink |= LN_ABSOLUTE; 20765543Scg break; 20865543Scg case 'r': 20965543Scg dolink &= ~LN_ABSOLUTE; 21065543Scg dolink |= LN_RELATIVE; 21165543Scg break; 21265543Scg default: 21365543Scg errx(1, "%c: invalid link type", *p); 21465543Scg /* NOTREACHED */ 21565543Scg } 21665543Scg break; 21765543Scg case 'M': 21865543Scg metafile = optarg; 21965543Scg break; 22065543Scg case 'm': 22165543Scg haveopt_m = 1; 22265543Scg if (!(set = setmode(optarg))) 22365543Scg errx(EX_USAGE, "invalid file mode: %s", 22465543Scg optarg); 22565543Scg mode = getmode(set, 0); 22665543Scg free(set); 22765543Scg break; 22865543Scg case 'N': 22965543Scg if (!setup_getid(optarg)) 23065543Scg err(EX_OSERR, "Unable to use user and group " 23165543Scg "databases in `%s'", optarg); 23265543Scg break; 23365543Scg case 'o': 23465543Scg haveopt_o = 1; 23565543Scg owner = optarg; 23665543Scg break; 23765543Scg case 'p': 23865543Scg docompare = dopreserve = 1; 23965543Scg break; 24065543Scg case 'S': 24165543Scg safecopy = 1; 24265543Scg break; 24365543Scg case 's': 24465543Scg dostrip = 1; 24565543Scg break; 24665543Scg case 'T': 24765543Scg tags = optarg; 24865543Scg break; 24965543Scg case 'U': 25065543Scg dounpriv = 1; 25165543Scg break; 25265543Scg case 'v': 25365543Scg verbose = 1; 25465543Scg break; 25565543Scg case '?': 25665543Scg default: 25765543Scg usage(); 25865543Scg } 25965543Scg argc -= optind; 26065543Scg argv += optind; 26165543Scg 26265543Scg /* some options make no sense when creating directories */ 26365543Scg if (dostrip && dodir) { 26465543Scg warnx("-d and -s may not be specified together"); 26565543Scg usage(); 26665543Scg } 26765543Scg 26865543Scg if (getenv("DONTSTRIP") != NULL) { 26965543Scg warnx("DONTSTRIP set - will not strip installed binaries"); 27065543Scg dostrip = 0; 27165543Scg } 27265543Scg 27365543Scg /* must have at least two arguments, except when creating directories */ 27465543Scg if (argc == 0 || (argc == 1 && !dodir)) 27565543Scg usage(); 27665543Scg 27765543Scg if (digest != NULL) { 27865543Scg if (strcmp(digest, "none") == 0) { 27965543Scg digesttype = DIGEST_NONE; 28065543Scg } else if (strcmp(digest, "md5") == 0) { 28165543Scg digesttype = DIGEST_MD5; 28265543Scg } else if (strcmp(digest, "rmd160") == 0) { 28365543Scg digesttype = DIGEST_RIPEMD160; 28465543Scg } else if (strcmp(digest, "sha1") == 0) { 28565543Scg digesttype = DIGEST_SHA1; 28665543Scg } else if (strcmp(digest, "sha256") == 0) { 28765543Scg digesttype = DIGEST_SHA256; 28865543Scg } else if (strcmp(digest, "sha512") == 0) { 28965543Scg digesttype = DIGEST_SHA512; 29065543Scg } else { 29165543Scg warnx("unknown digest `%s'", digest); 29265543Scg usage(); 29365543Scg } 29465543Scg } 29565543Scg 29665543Scg /* need to make a temp copy so we can compare stripped version */ 29765543Scg if (docompare && dostrip) 29865543Scg safecopy = 1; 29965543Scg 30065543Scg /* get group and owner id's */ 30165543Scg if (group != NULL && !dounpriv) { 30265543Scg if (gid_from_group(group, &gid) == -1) { 30365543Scg id_t id; 30465543Scg if (!parseid(group, &id)) 30565543Scg errx(1, "unknown group %s", group); 30665543Scg gid = id; 30765543Scg } 30865543Scg } else 30965543Scg gid = (gid_t)-1; 31065543Scg 31165543Scg if (owner != NULL && !dounpriv) { 31265543Scg if (uid_from_user(owner, &uid) == -1) { 31365543Scg id_t id; 31465543Scg if (!parseid(owner, &id)) 31565543Scg errx(1, "unknown user %s", owner); 31665543Scg uid = id; 31765543Scg } 318137500Sjulian } else 319137500Sjulian uid = (uid_t)-1; 320137500Sjulian 321137500Sjulian if (fflags != NULL && !dounpriv) { 322137500Sjulian if (strtofflags(&fflags, &fset, NULL)) 323137500Sjulian errx(EX_USAGE, "%s: invalid flag", fflags); 324137500Sjulian iflags |= SETFLAGS; 325137500Sjulian } 326137500Sjulian 327137500Sjulian if (metafile != NULL) { 328137500Sjulian if ((metafp = fopen(metafile, "a")) == NULL) 329137500Sjulian warn("open %s", metafile); 330137500Sjulian } else 33165543Scg digesttype = DIGEST_NONE; 33265543Scg 33365543Scg if (dodir) { 33465543Scg for (; *argv != NULL; ++argv) 33565543Scg install_dir(*argv); 336137500Sjulian exit(EX_OK); 337137500Sjulian /* NOTREACHED */ 338137500Sjulian } 339137500Sjulian 340137500Sjulian to_name = argv[argc - 1]; 341137500Sjulian no_target = stat(to_name, &to_sb); 34265543Scg if (!no_target && S_ISDIR(to_sb.st_mode)) { 34365543Scg if (dolink & LN_SYMBOLIC) { 34465543Scg if (lstat(to_name, &to_sb) != 0) 34565543Scg err(EX_OSERR, "%s vanished", to_name); 34665543Scg if (S_ISLNK(to_sb.st_mode)) { 34765543Scg if (argc != 2) { 34865543Scg errno = ENOTDIR; 34965543Scg err(EX_USAGE, "%s", to_name); 35065543Scg } 35165543Scg install(*argv, to_name, fset, iflags); 35265543Scg exit(EX_OK); 35365543Scg } 35465543Scg } 35565543Scg for (; *argv != to_name; ++argv) 35665543Scg install(*argv, to_name, fset, iflags | DIRECTORY); 35765543Scg exit(EX_OK); 35865543Scg /* NOTREACHED */ 35965543Scg } 36065543Scg 36165543Scg /* can't do file1 file2 directory/file */ 36265543Scg if (argc != 2) { 36365543Scg if (no_target) 36465543Scg warnx("target directory `%s' does not exist", 36565543Scg argv[argc - 1]); 36665543Scg else 367137500Sjulian warnx("target `%s' is not a directory", 368137500Sjulian argv[argc - 1]); 369137500Sjulian usage(); 370137500Sjulian } 371137500Sjulian 372137500Sjulian if (!no_target && !dolink) { 37365543Scg if (stat(*argv, &from_sb)) 374137500Sjulian err(EX_OSERR, "%s", *argv); 375137500Sjulian if (!S_ISREG(to_sb.st_mode)) { 376137500Sjulian errno = EFTYPE; 377137500Sjulian err(EX_OSERR, "%s", to_name); 37865543Scg } 37965543Scg if (to_sb.st_dev == from_sb.st_dev && 38065543Scg to_sb.st_ino == from_sb.st_ino) 38165543Scg errx(EX_USAGE, 38265543Scg "%s and %s are the same file", *argv, to_name); 38365543Scg } 38465543Scg install(*argv, to_name, fset, iflags); 385 exit(EX_OK); 386 /* NOTREACHED */ 387} 388 389static char * 390digest_file(const char *name) 391{ 392 393 switch (digesttype) { 394 case DIGEST_MD5: 395 return (MD5File(name, NULL)); 396 case DIGEST_RIPEMD160: 397 return (RIPEMD160_File(name, NULL)); 398 case DIGEST_SHA1: 399 return (SHA1_File(name, NULL)); 400 case DIGEST_SHA256: 401 return (SHA256_File(name, NULL)); 402 case DIGEST_SHA512: 403 return (SHA512_File(name, NULL)); 404 default: 405 return (NULL); 406 } 407} 408 409static void 410digest_init(DIGEST_CTX *c) 411{ 412 413 switch (digesttype) { 414 case DIGEST_NONE: 415 break; 416 case DIGEST_MD5: 417 MD5Init(&(c->MD5)); 418 break; 419 case DIGEST_RIPEMD160: 420 RIPEMD160_Init(&(c->RIPEMD160)); 421 break; 422 case DIGEST_SHA1: 423 SHA1_Init(&(c->SHA1)); 424 break; 425 case DIGEST_SHA256: 426 SHA256_Init(&(c->SHA256)); 427 break; 428 case DIGEST_SHA512: 429 SHA512_Init(&(c->SHA512)); 430 break; 431 } 432} 433 434static void 435digest_update(DIGEST_CTX *c, const unsigned char *data, size_t len) 436{ 437 438 switch (digesttype) { 439 case DIGEST_NONE: 440 break; 441 case DIGEST_MD5: 442 MD5Update(&(c->MD5), data, len); 443 break; 444 case DIGEST_RIPEMD160: 445 RIPEMD160_Update(&(c->RIPEMD160), data, len); 446 break; 447 case DIGEST_SHA1: 448 SHA1_Update(&(c->SHA1), data, len); 449 break; 450 case DIGEST_SHA256: 451 SHA256_Update(&(c->SHA256), data, len); 452 break; 453 case DIGEST_SHA512: 454 SHA512_Update(&(c->SHA512), data, len); 455 break; 456 } 457} 458 459static char * 460digest_end(DIGEST_CTX *c, char *buf) 461{ 462 463 switch (digesttype) { 464 case DIGEST_MD5: 465 return (MD5End(&(c->MD5), buf)); 466 case DIGEST_RIPEMD160: 467 return (RIPEMD160_End(&(c->RIPEMD160), buf)); 468 case DIGEST_SHA1: 469 return (SHA1_End(&(c->SHA1), buf)); 470 case DIGEST_SHA256: 471 return (SHA256_End(&(c->SHA256), buf)); 472 case DIGEST_SHA512: 473 return (SHA512_End(&(c->SHA512), buf)); 474 default: 475 return (NULL); 476 } 477} 478 479/* 480 * parseid -- 481 * parse uid or gid from arg into id, returning non-zero if successful 482 */ 483static int 484parseid(const char *name, id_t *id) 485{ 486 char *ep; 487 errno = 0; 488 *id = (id_t)strtoul(name, &ep, 10); 489 if (errno || *ep != '\0') 490 return (0); 491 return (1); 492} 493 494/* 495 * quiet_mktemp -- 496 * mktemp implementation used mkstemp to avoid mktemp warnings. We 497 * really do need mktemp semantics here as we will be creating a link. 498 */ 499static char * 500quiet_mktemp(char *template) 501{ 502 int fd; 503 504 if ((fd = mkstemp(template)) == -1) 505 return (NULL); 506 close (fd); 507 if (unlink(template) == -1) 508 err(EX_OSERR, "unlink %s", template); 509 return (template); 510} 511 512/* 513 * do_link -- 514 * make a hard link, obeying dorename if set 515 * return -1 on failure 516 */ 517static int 518do_link(const char *from_name, const char *to_name, 519 const struct stat *target_sb) 520{ 521 char tmpl[MAXPATHLEN]; 522 int ret; 523 524 if (safecopy && target_sb != NULL) { 525 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 526 /* This usage is safe. */ 527 if (quiet_mktemp(tmpl) == NULL) 528 err(EX_OSERR, "%s: mktemp", tmpl); 529 ret = link(from_name, tmpl); 530 if (ret == 0) { 531 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == 532 -1) { 533 unlink(tmpl); 534 err(EX_OSERR, "%s", to_name); 535 } 536 if (target_sb->st_flags & NOCHANGEBITS) 537 (void)chflags(to_name, target_sb->st_flags & 538 ~NOCHANGEBITS); 539 if (verbose) 540 printf("install: link %s -> %s\n", 541 from_name, to_name); 542 ret = rename(tmpl, to_name); 543 /* 544 * If rename has posix semantics, then the temporary 545 * file may still exist when from_name and to_name point 546 * to the same file, so unlink it unconditionally. 547 */ 548 (void)unlink(tmpl); 549 } 550 return (ret); 551 } else { 552 if (verbose) 553 printf("install: link %s -> %s\n", 554 from_name, to_name); 555 return (link(from_name, to_name)); 556 } 557} 558 559/* 560 * do_symlink -- 561 * Make a symbolic link, obeying dorename if set. Exit on failure. 562 */ 563static void 564do_symlink(const char *from_name, const char *to_name, 565 const struct stat *target_sb) 566{ 567 char tmpl[MAXPATHLEN]; 568 569 if (safecopy && target_sb != NULL) { 570 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 571 /* This usage is safe. */ 572 if (quiet_mktemp(tmpl) == NULL) 573 err(EX_OSERR, "%s: mktemp", tmpl); 574 575 if (symlink(from_name, tmpl) == -1) 576 err(EX_OSERR, "symlink %s -> %s", from_name, tmpl); 577 578 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == -1) { 579 (void)unlink(tmpl); 580 err(EX_OSERR, "%s", to_name); 581 } 582 if (target_sb->st_flags & NOCHANGEBITS) 583 (void)chflags(to_name, target_sb->st_flags & 584 ~NOCHANGEBITS); 585 if (verbose) 586 printf("install: symlink %s -> %s\n", 587 from_name, to_name); 588 if (rename(tmpl, to_name) == -1) { 589 /* Remove temporary link before exiting. */ 590 (void)unlink(tmpl); 591 err(EX_OSERR, "%s: rename", to_name); 592 } 593 } else { 594 if (verbose) 595 printf("install: symlink %s -> %s\n", 596 from_name, to_name); 597 if (symlink(from_name, to_name) == -1) 598 err(EX_OSERR, "symlink %s -> %s", from_name, to_name); 599 } 600} 601 602/* 603 * makelink -- 604 * make a link from source to destination 605 */ 606static void 607makelink(const char *from_name, const char *to_name, 608 const struct stat *target_sb) 609{ 610 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; 611 struct stat to_sb; 612 613 /* Try hard links first. */ 614 if (dolink & (LN_HARD|LN_MIXED)) { 615 if (do_link(from_name, to_name, target_sb) == -1) { 616 if ((dolink & LN_HARD) || errno != EXDEV) 617 err(EX_OSERR, "link %s -> %s", from_name, to_name); 618 } else { 619 if (stat(to_name, &to_sb)) 620 err(EX_OSERR, "%s: stat", to_name); 621 if (S_ISREG(to_sb.st_mode)) { 622 /* 623 * XXX: hard links to anything other than 624 * plain files are not metalogged 625 */ 626 int omode; 627 const char *oowner, *ogroup; 628 char *offlags; 629 char *dres; 630 631 /* 632 * XXX: use underlying perms, unless 633 * overridden on command line. 634 */ 635 omode = mode; 636 if (!haveopt_m) 637 mode = (to_sb.st_mode & 0777); 638 oowner = owner; 639 if (!haveopt_o) 640 owner = NULL; 641 ogroup = group; 642 if (!haveopt_g) 643 group = NULL; 644 offlags = fflags; 645 if (!haveopt_f) 646 fflags = NULL; 647 dres = digest_file(from_name); 648 metadata_log(to_name, "file", NULL, NULL, 649 dres, to_sb.st_size); 650 free(dres); 651 mode = omode; 652 owner = oowner; 653 group = ogroup; 654 fflags = offlags; 655 } 656 return; 657 } 658 } 659 660 /* Symbolic links. */ 661 if (dolink & LN_ABSOLUTE) { 662 /* Convert source path to absolute. */ 663 if (realpath(from_name, src) == NULL) 664 err(EX_OSERR, "%s: realpath", from_name); 665 do_symlink(src, to_name, target_sb); 666 /* XXX: src may point outside of destdir */ 667 metadata_log(to_name, "link", NULL, src, NULL, 0); 668 return; 669 } 670 671 if (dolink & LN_RELATIVE) { 672 char *to_name_copy, *cp, *d, *s; 673 674 /* Resolve pathnames. */ 675 if (realpath(from_name, src) == NULL) 676 err(EX_OSERR, "%s: realpath", from_name); 677 678 /* 679 * The last component of to_name may be a symlink, 680 * so use realpath to resolve only the directory. 681 */ 682 to_name_copy = strdup(to_name); 683 if (to_name_copy == NULL) 684 err(EX_OSERR, "%s: strdup", to_name); 685 cp = dirname(to_name_copy); 686 if (realpath(cp, dst) == NULL) 687 err(EX_OSERR, "%s: realpath", cp); 688 /* .. and add the last component. */ 689 if (strcmp(dst, "/") != 0) { 690 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst)) 691 errx(1, "resolved pathname too long"); 692 } 693 strcpy(to_name_copy, to_name); 694 cp = basename(to_name_copy); 695 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst)) 696 errx(1, "resolved pathname too long"); 697 free(to_name_copy); 698 699 /* Trim common path components. */ 700 for (s = src, d = dst; *s == *d; s++, d++) 701 continue; 702 while (*s != '/') 703 s--, d--; 704 705 /* Count the number of directories we need to backtrack. */ 706 for (++d, lnk[0] = '\0'; *d; d++) 707 if (*d == '/') 708 (void)strlcat(lnk, "../", sizeof(lnk)); 709 710 (void)strlcat(lnk, ++s, sizeof(lnk)); 711 712 do_symlink(lnk, to_name, target_sb); 713 /* XXX: Link may point outside of destdir. */ 714 metadata_log(to_name, "link", NULL, lnk, NULL, 0); 715 return; 716 } 717 718 /* 719 * If absolute or relative was not specified, try the names the 720 * user provided. 721 */ 722 do_symlink(from_name, to_name, target_sb); 723 /* XXX: from_name may point outside of destdir. */ 724 metadata_log(to_name, "link", NULL, from_name, NULL, 0); 725} 726 727/* 728 * install -- 729 * build a path name and install the file 730 */ 731static void 732install(const char *from_name, const char *to_name, u_long fset, u_int flags) 733{ 734 struct stat from_sb, temp_sb, to_sb; 735 struct timeval tvb[2]; 736 int devnull, files_match, from_fd, serrno, target; 737 int tempcopy, temp_fd, to_fd; 738 char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; 739 char *digestresult; 740 741 files_match = 0; 742 from_fd = -1; 743 to_fd = -1; 744 745 /* If try to install NULL file to a directory, fails. */ 746 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { 747 if (!dolink) { 748 if (stat(from_name, &from_sb)) 749 err(EX_OSERR, "%s", from_name); 750 if (!S_ISREG(from_sb.st_mode)) { 751 errno = EFTYPE; 752 err(EX_OSERR, "%s", from_name); 753 } 754 } 755 /* Build the target path. */ 756 if (flags & DIRECTORY) { 757 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s", 758 to_name, 759 (p = strrchr(from_name, '/')) ? ++p : from_name); 760 to_name = pathbuf; 761 } 762 devnull = 0; 763 } else { 764 devnull = 1; 765 } 766 767 target = (lstat(to_name, &to_sb) == 0); 768 769 if (dolink) { 770 if (target && !safecopy) { 771 if (to_sb.st_mode & S_IFDIR && rmdir(to_name) == -1) 772 err(EX_OSERR, "%s", to_name); 773 if (to_sb.st_flags & NOCHANGEBITS) 774 (void)chflags(to_name, 775 to_sb.st_flags & ~NOCHANGEBITS); 776 unlink(to_name); 777 } 778 makelink(from_name, to_name, target ? &to_sb : NULL); 779 return; 780 } 781 782 if (target && !S_ISREG(to_sb.st_mode) && !S_ISLNK(to_sb.st_mode)) { 783 errno = EFTYPE; 784 warn("%s", to_name); 785 return; 786 } 787 788 /* Only copy safe if the target exists. */ 789 tempcopy = safecopy && target; 790 791 if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) 792 err(EX_OSERR, "%s", from_name); 793 794 /* If we don't strip, we can compare first. */ 795 if (docompare && !dostrip && target && S_ISREG(to_sb.st_mode)) { 796 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 797 err(EX_OSERR, "%s", to_name); 798 if (devnull) 799 files_match = to_sb.st_size == 0; 800 else 801 files_match = !(compare(from_fd, from_name, 802 (size_t)from_sb.st_size, to_fd, 803 to_name, (size_t)to_sb.st_size, &digestresult)); 804 805 /* Close "to" file unless we match. */ 806 if (!files_match) 807 (void)close(to_fd); 808 } 809 810 if (!files_match) { 811 if (tempcopy) { 812 to_fd = create_tempfile(to_name, tempfile, 813 sizeof(tempfile)); 814 if (to_fd < 0) 815 err(EX_OSERR, "%s", tempfile); 816 } else { 817 if ((to_fd = create_newfile(to_name, target, 818 &to_sb)) < 0) 819 err(EX_OSERR, "%s", to_name); 820 if (verbose) 821 (void)printf("install: %s -> %s\n", 822 from_name, to_name); 823 } 824 if (!devnull) 825 digestresult = copy(from_fd, from_name, to_fd, 826 tempcopy ? tempfile : to_name, from_sb.st_size); 827 else 828 digestresult = NULL; 829 } 830 831 if (dostrip) { 832 strip(tempcopy ? tempfile : to_name); 833 834 /* 835 * Re-open our fd on the target, in case we used a strip 836 * that does not work in-place -- like GNU binutils strip. 837 */ 838 close(to_fd); 839 to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0); 840 if (to_fd < 0) 841 err(EX_OSERR, "stripping %s", to_name); 842 } 843 844 /* 845 * Compare the stripped temp file with the target. 846 */ 847 if (docompare && dostrip && target && S_ISREG(to_sb.st_mode)) { 848 temp_fd = to_fd; 849 850 /* Re-open to_fd using the real target name. */ 851 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 852 err(EX_OSERR, "%s", to_name); 853 854 if (fstat(temp_fd, &temp_sb)) { 855 serrno = errno; 856 (void)unlink(tempfile); 857 errno = serrno; 858 err(EX_OSERR, "%s", tempfile); 859 } 860 861 if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd, 862 to_name, (size_t)to_sb.st_size, &digestresult) 863 == 0) { 864 /* 865 * If target has more than one link we need to 866 * replace it in order to snap the extra links. 867 * Need to preserve target file times, though. 868 */ 869 if (to_sb.st_nlink != 1) { 870 tvb[0].tv_sec = to_sb.st_atime; 871 tvb[0].tv_usec = 0; 872 tvb[1].tv_sec = to_sb.st_mtime; 873 tvb[1].tv_usec = 0; 874 (void)utimes(tempfile, tvb); 875 } else { 876 files_match = 1; 877 (void)unlink(tempfile); 878 } 879 (void) close(temp_fd); 880 } 881 } else if (dostrip) 882 digestresult = digest_file(tempfile); 883 884 /* 885 * Move the new file into place if doing a safe copy 886 * and the files are different (or just not compared). 887 */ 888 if (tempcopy && !files_match) { 889 /* Try to turn off the immutable bits. */ 890 if (to_sb.st_flags & NOCHANGEBITS) 891 (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS); 892 if (dobackup) { 893 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name, 894 suffix) != strlen(to_name) + strlen(suffix)) { 895 unlink(tempfile); 896 errx(EX_OSERR, "%s: backup filename too long", 897 to_name); 898 } 899 if (verbose) 900 (void)printf("install: %s -> %s\n", to_name, backup); 901 if (unlink(backup) < 0 && errno != ENOENT) { 902 serrno = errno; 903 if (to_sb.st_flags & NOCHANGEBITS) 904 (void)chflags(to_name, to_sb.st_flags); 905 unlink(tempfile); 906 errno = serrno; 907 err(EX_OSERR, "unlink: %s", backup); 908 } 909 if (link(to_name, backup) < 0) { 910 serrno = errno; 911 unlink(tempfile); 912 if (to_sb.st_flags & NOCHANGEBITS) 913 (void)chflags(to_name, to_sb.st_flags); 914 errno = serrno; 915 err(EX_OSERR, "link: %s to %s", to_name, 916 backup); 917 } 918 } 919 if (verbose) 920 (void)printf("install: %s -> %s\n", from_name, to_name); 921 if (rename(tempfile, to_name) < 0) { 922 serrno = errno; 923 unlink(tempfile); 924 errno = serrno; 925 err(EX_OSERR, "rename: %s to %s", 926 tempfile, to_name); 927 } 928 929 /* Re-open to_fd so we aren't hosed by the rename(2). */ 930 (void) close(to_fd); 931 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 932 err(EX_OSERR, "%s", to_name); 933 } 934 935 /* 936 * Preserve the timestamp of the source file if necessary. 937 */ 938 if (dopreserve && !files_match && !devnull) { 939 tvb[0].tv_sec = from_sb.st_atime; 940 tvb[0].tv_usec = 0; 941 tvb[1].tv_sec = from_sb.st_mtime; 942 tvb[1].tv_usec = 0; 943 (void)utimes(to_name, tvb); 944 } 945 946 if (fstat(to_fd, &to_sb) == -1) { 947 serrno = errno; 948 (void)unlink(to_name); 949 errno = serrno; 950 err(EX_OSERR, "%s", to_name); 951 } 952 953 /* 954 * Set owner, group, mode for target; do the chown first, 955 * chown may lose the setuid bits. 956 */ 957 if (!dounpriv && ((gid != (gid_t)-1 && gid != to_sb.st_gid) || 958 (uid != (uid_t)-1 && uid != to_sb.st_uid) || 959 (mode != (to_sb.st_mode & ALLPERMS)))) { 960 /* Try to turn off the immutable bits. */ 961 if (to_sb.st_flags & NOCHANGEBITS) 962 (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS); 963 } 964 965 if (!dounpriv & 966 (gid != (gid_t)-1 && gid != to_sb.st_gid) || 967 (uid != (uid_t)-1 && uid != to_sb.st_uid)) 968 if (fchown(to_fd, uid, gid) == -1) { 969 serrno = errno; 970 (void)unlink(to_name); 971 errno = serrno; 972 err(EX_OSERR,"%s: chown/chgrp", to_name); 973 } 974 975 if (mode != (to_sb.st_mode & ALLPERMS)) { 976 if (fchmod(to_fd, 977 dounpriv ? mode & (S_IRWXU|S_IRWXG|S_IRWXO) : mode)) { 978 serrno = errno; 979 (void)unlink(to_name); 980 errno = serrno; 981 err(EX_OSERR, "%s: chmod", to_name); 982 } 983 } 984 985 /* 986 * If provided a set of flags, set them, otherwise, preserve the 987 * flags, except for the dump flag. 988 * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just 989 * trying to turn off UF_NODUMP. If we're trying to set real flags, 990 * then warn if the fs doesn't support it, otherwise fail. 991 */ 992 if (!dounpriv & !devnull && (flags & SETFLAGS || 993 (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) && 994 fchflags(to_fd, 995 flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { 996 if (flags & SETFLAGS) { 997 if (errno == EOPNOTSUPP) 998 warn("%s: chflags", to_name); 999 else { 1000 serrno = errno; 1001 (void)unlink(to_name); 1002 errno = serrno; 1003 err(EX_OSERR, "%s: chflags", to_name); 1004 } 1005 } 1006 } 1007 1008 (void)close(to_fd); 1009 if (!devnull) 1010 (void)close(from_fd); 1011 1012 metadata_log(to_name, "file", tvb, NULL, digestresult, to_sb.st_size); 1013 free(digestresult); 1014} 1015 1016/* 1017 * compare -- 1018 * compare two files; non-zero means files differ 1019 */ 1020static int 1021compare(int from_fd, const char *from_name __unused, size_t from_len, 1022 int to_fd, const char *to_name __unused, size_t to_len, 1023 char **dresp) 1024{ 1025 char *p, *q; 1026 int rv; 1027 int done_compare; 1028 DIGEST_CTX ctx; 1029 1030 rv = 0; 1031 if (from_len != to_len) 1032 return 1; 1033 1034 if (from_len <= MAX_CMP_SIZE) { 1035 if (dresp != NULL) 1036 digest_init(&ctx); 1037 done_compare = 0; 1038 if (trymmap(from_fd) && trymmap(to_fd)) { 1039 p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 1040 from_fd, (off_t)0); 1041 if (p == (char *)MAP_FAILED) 1042 goto out; 1043 q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 1044 to_fd, (off_t)0); 1045 if (q == (char *)MAP_FAILED) { 1046 munmap(p, from_len); 1047 goto out; 1048 } 1049 1050 rv = memcmp(p, q, from_len); 1051 if (dresp != NULL) 1052 digest_update(&ctx, p, from_len); 1053 munmap(p, from_len); 1054 munmap(q, from_len); 1055 done_compare = 1; 1056 } 1057 out: 1058 if (!done_compare) { 1059 char buf1[MAXBSIZE]; 1060 char buf2[MAXBSIZE]; 1061 int n1, n2; 1062 1063 rv = 0; 1064 lseek(from_fd, 0, SEEK_SET); 1065 lseek(to_fd, 0, SEEK_SET); 1066 while (rv == 0) { 1067 n1 = read(from_fd, buf1, sizeof(buf1)); 1068 if (n1 == 0) 1069 break; /* EOF */ 1070 else if (n1 > 0) { 1071 n2 = read(to_fd, buf2, n1); 1072 if (n2 == n1) 1073 rv = memcmp(buf1, buf2, n1); 1074 else 1075 rv = 1; /* out of sync */ 1076 } else 1077 rv = 1; /* read failure */ 1078 digest_update(&ctx, buf1, n1); 1079 } 1080 lseek(from_fd, 0, SEEK_SET); 1081 lseek(to_fd, 0, SEEK_SET); 1082 } 1083 } else 1084 rv = 1; /* don't bother in this case */ 1085 1086 if (dresp != NULL) { 1087 if (rv == 0) 1088 *dresp = digest_end(&ctx, NULL); 1089 else 1090 (void)digest_end(&ctx, NULL); 1091 } 1092 1093 return rv; 1094} 1095 1096/* 1097 * create_tempfile -- 1098 * create a temporary file based on path and open it 1099 */ 1100static int 1101create_tempfile(const char *path, char *temp, size_t tsize) 1102{ 1103 char *p; 1104 1105 (void)strncpy(temp, path, tsize); 1106 temp[tsize - 1] = '\0'; 1107 if ((p = strrchr(temp, '/')) != NULL) 1108 p++; 1109 else 1110 p = temp; 1111 (void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p); 1112 temp[tsize - 1] = '\0'; 1113 return (mkstemp(temp)); 1114} 1115 1116/* 1117 * create_newfile -- 1118 * create a new file, overwriting an existing one if necessary 1119 */ 1120static int 1121create_newfile(const char *path, int target, struct stat *sbp) 1122{ 1123 char backup[MAXPATHLEN]; 1124 int saved_errno = 0; 1125 int newfd; 1126 1127 if (target) { 1128 /* 1129 * Unlink now... avoid ETXTBSY errors later. Try to turn 1130 * off the append/immutable bits -- if we fail, go ahead, 1131 * it might work. 1132 */ 1133 if (sbp->st_flags & NOCHANGEBITS) 1134 (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS); 1135 1136 if (dobackup) { 1137 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", 1138 path, suffix) != strlen(path) + strlen(suffix)) { 1139 saved_errno = errno; 1140 if (sbp->st_flags & NOCHANGEBITS) 1141 (void)chflags(path, sbp->st_flags); 1142 errno = saved_errno; 1143 errx(EX_OSERR, "%s: backup filename too long", 1144 path); 1145 } 1146 (void)snprintf(backup, MAXPATHLEN, "%s%s", 1147 path, suffix); 1148 if (verbose) 1149 (void)printf("install: %s -> %s\n", 1150 path, backup); 1151 if (rename(path, backup) < 0) { 1152 saved_errno = errno; 1153 if (sbp->st_flags & NOCHANGEBITS) 1154 (void)chflags(path, sbp->st_flags); 1155 errno = saved_errno; 1156 err(EX_OSERR, "rename: %s to %s", path, backup); 1157 } 1158 } else 1159 if (unlink(path) < 0) 1160 saved_errno = errno; 1161 } 1162 1163 newfd = open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); 1164 if (newfd < 0 && saved_errno != 0) 1165 errno = saved_errno; 1166 return newfd; 1167} 1168 1169/* 1170 * copy -- 1171 * copy from one file to another 1172 */ 1173static char * 1174copy(int from_fd, const char *from_name, int to_fd, const char *to_name, 1175 off_t size) 1176{ 1177 int nr, nw; 1178 int serrno; 1179 char *p, buf[MAXBSIZE]; 1180 int done_copy; 1181 DIGEST_CTX ctx; 1182 1183 /* Rewind file descriptors. */ 1184 if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1185 err(EX_OSERR, "lseek: %s", from_name); 1186 if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1187 err(EX_OSERR, "lseek: %s", to_name); 1188 1189 digest_init(&ctx); 1190 1191 /* 1192 * Mmap and write if less than 8M (the limit is so we don't totally 1193 * trash memory on big files. This is really a minor hack, but it 1194 * wins some CPU back. 1195 */ 1196 done_copy = 0; 1197 if (size <= 8 * 1048576 && trymmap(from_fd) && 1198 (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, 1199 from_fd, (off_t)0)) != (char *)MAP_FAILED) { 1200 nw = write(to_fd, p, size); 1201 if (nw != size) { 1202 serrno = errno; 1203 (void)unlink(to_name); 1204 if (nw >= 0) { 1205 errx(EX_OSERR, 1206 "short write to %s: %jd bytes written, %jd bytes asked to write", 1207 to_name, (uintmax_t)nw, (uintmax_t)size); 1208 } else { 1209 errno = serrno; 1210 err(EX_OSERR, "%s", to_name); 1211 } 1212 } 1213 digest_update(&ctx, p, size); 1214 (void)munmap(p, size); 1215 done_copy = 1; 1216 } 1217 if (!done_copy) { 1218 while ((nr = read(from_fd, buf, sizeof(buf))) > 0) { 1219 if ((nw = write(to_fd, buf, nr)) != nr) { 1220 serrno = errno; 1221 (void)unlink(to_name); 1222 if (nw >= 0) { 1223 errx(EX_OSERR, 1224 "short write to %s: %jd bytes written, %jd bytes asked to write", 1225 to_name, (uintmax_t)nw, 1226 (uintmax_t)size); 1227 } else { 1228 errno = serrno; 1229 err(EX_OSERR, "%s", to_name); 1230 } 1231 } 1232 digest_update(&ctx, buf, nr); 1233 } 1234 if (nr != 0) { 1235 serrno = errno; 1236 (void)unlink(to_name); 1237 errno = serrno; 1238 err(EX_OSERR, "%s", from_name); 1239 } 1240 } 1241 return (digest_end(&ctx, NULL)); 1242} 1243 1244/* 1245 * strip -- 1246 * use strip(1) to strip the target file 1247 */ 1248static void 1249strip(const char *to_name) 1250{ 1251 const char *stripbin; 1252 int serrno, status; 1253 1254 switch (fork()) { 1255 case -1: 1256 serrno = errno; 1257 (void)unlink(to_name); 1258 errno = serrno; 1259 err(EX_TEMPFAIL, "fork"); 1260 case 0: 1261 stripbin = getenv("STRIPBIN"); 1262 if (stripbin == NULL) 1263 stripbin = "strip"; 1264 execlp(stripbin, stripbin, to_name, (char *)NULL); 1265 err(EX_OSERR, "exec(%s)", stripbin); 1266 default: 1267 if (wait(&status) == -1 || status) { 1268 serrno = errno; 1269 (void)unlink(to_name); 1270 errc(EX_SOFTWARE, serrno, "wait"); 1271 /* NOTREACHED */ 1272 } 1273 } 1274} 1275 1276/* 1277 * install_dir -- 1278 * build directory hierarchy 1279 */ 1280static void 1281install_dir(char *path) 1282{ 1283 char *p; 1284 struct stat sb; 1285 int ch; 1286 1287 for (p = path;; ++p) 1288 if (!*p || (p != path && *p == '/')) { 1289 ch = *p; 1290 *p = '\0'; 1291 if (stat(path, &sb)) { 1292 if (errno != ENOENT || mkdir(path, 0755) < 0) { 1293 err(EX_OSERR, "mkdir %s", path); 1294 /* NOTREACHED */ 1295 } else if (verbose) 1296 (void)printf("install: mkdir %s\n", 1297 path); 1298 } else if (!S_ISDIR(sb.st_mode)) 1299 errx(EX_OSERR, "%s exists but is not a directory", path); 1300 if (!(*p = ch)) 1301 break; 1302 } 1303 1304 if (!dounpriv) { 1305 if ((gid != (gid_t)-1 || uid != (uid_t)-1) && 1306 chown(path, uid, gid)) 1307 warn("chown %u:%u %s", uid, gid, path); 1308 /* XXXBED: should we do the chmod in the dounpriv case? */ 1309 if (chmod(path, mode)) 1310 warn("chmod %o %s", mode, path); 1311 } 1312 metadata_log(path, "dir", NULL, NULL, NULL, 0); 1313} 1314 1315/* 1316 * metadata_log -- 1317 * if metafp is not NULL, output mtree(8) full path name and settings to 1318 * metafp, to allow permissions to be set correctly by other tools, 1319 * or to allow integrity checks to be performed. 1320 */ 1321static void 1322metadata_log(const char *path, const char *type, struct timeval *tv, 1323 const char *slink, const char *digestresult, off_t size) 1324{ 1325 static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; 1326 const char *p; 1327 char *buf; 1328 size_t destlen; 1329 struct flock metalog_lock; 1330 1331 if (!metafp) 1332 return; 1333 /* Buffer for strsvis(3). */ 1334 buf = (char *)malloc(4 * strlen(path) + 1); 1335 if (buf == NULL) { 1336 warnx("%s", strerror(ENOMEM)); 1337 return; 1338 } 1339 1340 /* Lock log file. */ 1341 metalog_lock.l_start = 0; 1342 metalog_lock.l_len = 0; 1343 metalog_lock.l_whence = SEEK_SET; 1344 metalog_lock.l_type = F_WRLCK; 1345 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { 1346 warn("can't lock %s", metafile); 1347 free(buf); 1348 return; 1349 } 1350 1351 /* Remove destdir. */ 1352 p = path; 1353 if (destdir) { 1354 destlen = strlen(destdir); 1355 if (strncmp(p, destdir, destlen) == 0 && 1356 (p[destlen] == '/' || p[destlen] == '\0')) 1357 p += destlen; 1358 } 1359 while (*p && *p == '/') 1360 p++; 1361 strsvis(buf, p, VIS_OCTAL, extra); 1362 p = buf; 1363 /* Print details. */ 1364 fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type); 1365 if (owner) 1366 fprintf(metafp, " uname=%s", owner); 1367 if (group) 1368 fprintf(metafp, " gname=%s", group); 1369 fprintf(metafp, " mode=%#o", mode); 1370 if (slink) { 1371 strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */ 1372 fprintf(metafp, " link=%s", buf); 1373 } 1374 if (*type == 'f') /* type=file */ 1375 fprintf(metafp, " size=%lld", (long long)size); 1376 if (tv != NULL && dopreserve) 1377 fprintf(metafp, " time=%lld.%ld", 1378 (long long)tv[1].tv_sec, (long)tv[1].tv_usec); 1379 if (digestresult && digest) 1380 fprintf(metafp, " %s=%s", digest, digestresult); 1381 if (fflags) 1382 fprintf(metafp, " flags=%s", fflags); 1383 if (tags) 1384 fprintf(metafp, " tags=%s", tags); 1385 fputc('\n', metafp); 1386 /* Flush line. */ 1387 fflush(metafp); 1388 1389 /* Unlock log file. */ 1390 metalog_lock.l_type = F_UNLCK; 1391 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) 1392 warn("can't unlock %s", metafile); 1393 free(buf); 1394} 1395 1396/* 1397 * usage -- 1398 * print a usage message and die 1399 */ 1400static void 1401usage(void) 1402{ 1403 (void)fprintf(stderr, 1404"usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" 1405" [-M log] [-D dest] [-h hash] [-T tags]\n" 1406" [-B suffix] [-l linkflags] [-N dbdir]\n" 1407" file1 file2\n" 1408" install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" 1409" [-M log] [-D dest] [-h hash] [-T tags]\n" 1410" [-B suffix] [-l linkflags] [-N dbdir]\n" 1411" file1 ... fileN directory\n" 1412" install -dU [-vU] [-g group] [-m mode] [-N dbdir] [-o owner]\n" 1413" [-M log] [-D dest] [-h hash] [-T tags]\n" 1414" directory ...\n"); 1415 exit(EX_USAGE); 1416 /* NOTREACHED */ 1417} 1418 1419/* 1420 * trymmap -- 1421 * return true (1) if mmap should be tried, false (0) if not. 1422 */ 1423static int 1424trymmap(int fd) 1425{ 1426/* 1427 * The ifdef is for bootstrapping - f_fstypename doesn't exist in 1428 * pre-Lite2-merge systems. 1429 */ 1430#ifdef MFSNAMELEN 1431 struct statfs stfs; 1432 1433 if (fstatfs(fd, &stfs) != 0) 1434 return (0); 1435 if (strcmp(stfs.f_fstypename, "ufs") == 0 || 1436 strcmp(stfs.f_fstypename, "cd9660") == 0) 1437 return (1); 1438#endif 1439 return (0); 1440} 1441