1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2012, 2013 SRI International 5 * Copyright (c) 1987, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/mman.h> 35 #include <sys/mount.h> 36 #include <sys/stat.h> 37 #include <sys/time.h> 38 #include <sys/wait.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <grp.h> 44 #include <libgen.h> 45 #ifdef WITH_MD5 46 #include <md5.h> 47 #endif 48 #include <paths.h> 49 #include <pwd.h> 50 #ifdef WITH_RIPEMD160 51 #include <ripemd.h> 52 #endif 53 #include <sha.h> 54 #include <sha256.h> 55 #include <sha512.h> 56 #include <spawn.h> 57 #include <stdint.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <sysexits.h> 62 #include <unistd.h> 63 #include <vis.h> 64 65 #include "mtree.h" 66 67 /* 68 * Memory strategy threshold, in pages: if physmem is larger then this, use a 69 * large buffer. 70 */ 71 #define PHYSPAGES_THRESHOLD (32*1024) 72 73 /* Maximum buffer size in bytes - do not allow it to grow larger than this. */ 74 #define BUFSIZE_MAX (2*1024*1024) 75 76 /* 77 * Small (default) buffer size in bytes. It's inefficient for this to be 78 * smaller than MAXPHYS. 79 */ 80 #define BUFSIZE_SMALL (MAXPHYS) 81 82 /* 83 * We need to build xinstall during the bootstrap stage when building on a 84 * non-FreeBSD system. Linux does not have the st_flags and st_birthtime 85 * members in struct stat so we need to omit support for changing those fields. 86 */ 87 #ifdef UF_SETTABLE 88 #define HAVE_STRUCT_STAT_ST_FLAGS 1 89 #else 90 #define HAVE_STRUCT_STAT_ST_FLAGS 0 91 #endif 92 93 #define MAX_CMP_SIZE (16 * 1024 * 1024) 94 95 #define LN_ABSOLUTE 0x01 96 #define LN_RELATIVE 0x02 97 #define LN_HARD 0x04 98 #define LN_SYMBOLIC 0x08 99 #define LN_MIXED 0x10 100 101 #define DIRECTORY 0x01 /* Tell install it's a directory. */ 102 #define SETFLAGS 0x02 /* Tell install to set flags. */ 103 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 104 #define BACKUP_SUFFIX ".old" 105 106 typedef union { 107 #ifdef WITH_MD5 108 MD5_CTX MD5; 109 #endif 110 #ifdef WITH_RIPEMD160 111 RIPEMD160_CTX RIPEMD160; 112 #endif 113 SHA1_CTX SHA1; 114 SHA256_CTX SHA256; 115 SHA512_CTX SHA512; 116 } DIGEST_CTX; 117 118 static enum { 119 DIGEST_NONE = 0, 120 #ifdef WITH_MD5 121 DIGEST_MD5, 122 #endif 123 #ifdef WITH_RIPEMD160 124 DIGEST_RIPEMD160, 125 #endif 126 DIGEST_SHA1, 127 DIGEST_SHA256, 128 DIGEST_SHA512, 129 } digesttype = DIGEST_NONE; 130 131 extern char **environ; 132 133 static gid_t gid; 134 static uid_t uid; 135 static int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, 136 safecopy, verbose; 137 static int haveopt_f, haveopt_g, haveopt_m, haveopt_o; 138 static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 139 static FILE *metafp; 140 static const char *group, *owner; 141 static const char *suffix = BACKUP_SUFFIX; 142 static char *destdir, *digest, *fflags, *metafile, *tags; 143 144 static int compare(int, const char *, size_t, int, const char *, size_t, 145 char **); 146 static char *copy(int, const char *, int, const char *, off_t); 147 static int create_newfile(const char *, int, struct stat *); 148 static int create_tempfile(const char *, char *, size_t); 149 static char *quiet_mktemp(char *template); 150 static char *digest_file(const char *); 151 static void digest_init(DIGEST_CTX *); 152 static void digest_update(DIGEST_CTX *, const char *, size_t); 153 static char *digest_end(DIGEST_CTX *, char *); 154 static int do_link(const char *, const char *, const struct stat *); 155 static void do_symlink(const char *, const char *, const struct stat *); 156 static void makelink(const char *, const char *, const struct stat *); 157 static void install(const char *, const char *, u_long, u_int); 158 static void install_dir(char *); 159 static void metadata_log(const char *, const char *, struct timespec *, 160 const char *, const char *, off_t); 161 static int parseid(const char *, id_t *); 162 static int strip(const char *, int, const char *, char **); 163 static int trymmap(size_t); 164 static void usage(void); 165 166 int 167 main(int argc, char *argv[]) 168 { 169 struct stat from_sb, to_sb; 170 mode_t *set; 171 u_long fset; 172 int ch, no_target; 173 u_int iflags; 174 char *p; 175 const char *to_name; 176 177 fset = 0; 178 iflags = 0; 179 set = NULL; 180 group = owner = NULL; 181 while ((ch = getopt(argc, argv, "B:bCcD:df:g:h:l:M:m:N:o:pSsT:Uv")) != 182 -1) 183 switch((char)ch) { 184 case 'B': 185 suffix = optarg; 186 /* FALLTHROUGH */ 187 case 'b': 188 dobackup = 1; 189 break; 190 case 'C': 191 docompare = 1; 192 break; 193 case 'c': 194 /* For backwards compatibility. */ 195 break; 196 case 'D': 197 destdir = optarg; 198 break; 199 case 'd': 200 dodir = 1; 201 break; 202 case 'f': 203 haveopt_f = 1; 204 fflags = optarg; 205 break; 206 case 'g': 207 haveopt_g = 1; 208 group = optarg; 209 break; 210 case 'h': 211 digest = optarg; 212 break; 213 case 'l': 214 for (p = optarg; *p != '\0'; p++) 215 switch (*p) { 216 case 's': 217 dolink &= ~(LN_HARD|LN_MIXED); 218 dolink |= LN_SYMBOLIC; 219 break; 220 case 'h': 221 dolink &= ~(LN_SYMBOLIC|LN_MIXED); 222 dolink |= LN_HARD; 223 break; 224 case 'm': 225 dolink &= ~(LN_SYMBOLIC|LN_HARD); 226 dolink |= LN_MIXED; 227 break; 228 case 'a': 229 dolink &= ~LN_RELATIVE; 230 dolink |= LN_ABSOLUTE; 231 break; 232 case 'r': 233 dolink &= ~LN_ABSOLUTE; 234 dolink |= LN_RELATIVE; 235 break; 236 default: 237 errx(1, "%c: invalid link type", *p); 238 /* NOTREACHED */ 239 } 240 break; 241 case 'M': 242 metafile = optarg; 243 break; 244 case 'm': 245 haveopt_m = 1; 246 free(set); 247 if (!(set = setmode(optarg))) 248 errx(EX_USAGE, "invalid file mode: %s", 249 optarg); 250 break; 251 case 'N': 252 if (!setup_getid(optarg)) 253 err(EX_OSERR, "Unable to use user and group " 254 "databases in `%s'", optarg); 255 break; 256 case 'o': 257 haveopt_o = 1; 258 owner = optarg; 259 break; 260 case 'p': 261 docompare = dopreserve = 1; 262 break; 263 case 'S': 264 safecopy = 1; 265 break; 266 case 's': 267 dostrip = 1; 268 break; 269 case 'T': 270 tags = optarg; 271 break; 272 case 'U': 273 dounpriv = 1; 274 break; 275 case 'v': 276 verbose = 1; 277 break; 278 case '?': 279 default: 280 usage(); 281 } 282 argc -= optind; 283 argv += optind; 284 285 /* some options make no sense when creating directories */ 286 if (dostrip && dodir) { 287 warnx("-d and -s may not be specified together"); 288 usage(); 289 } 290 291 /* 292 * Default permissions based on whether we're a directory or not, since 293 * an +X may mean that we need to set the execute bit. 294 */ 295 if (set != NULL) 296 mode = getmode(set, dodir ? S_IFDIR : 0) & ~S_IFDIR; 297 free(set); 298 299 if (getenv("DONTSTRIP") != NULL) { 300 warnx("DONTSTRIP set - will not strip installed binaries"); 301 dostrip = 0; 302 } 303 304 /* must have at least two arguments, except when creating directories */ 305 if (argc == 0 || (argc == 1 && !dodir)) 306 usage(); 307 308 if (digest != NULL) { 309 if (strcmp(digest, "none") == 0) { 310 digesttype = DIGEST_NONE; 311 #ifdef WITH_MD5 312 } else if (strcmp(digest, "md5") == 0) { 313 digesttype = DIGEST_MD5; 314 #endif 315 #ifdef WITH_RIPEMD160 316 } else if (strcmp(digest, "rmd160") == 0) { 317 digesttype = DIGEST_RIPEMD160; 318 #endif 319 } else if (strcmp(digest, "sha1") == 0) { 320 digesttype = DIGEST_SHA1; 321 } else if (strcmp(digest, "sha256") == 0) { 322 digesttype = DIGEST_SHA256; 323 } else if (strcmp(digest, "sha512") == 0) { 324 digesttype = DIGEST_SHA512; 325 } else { 326 warnx("unknown digest `%s'", digest); 327 usage(); 328 } 329 } 330 331 /* need to make a temp copy so we can compare stripped version */ 332 if (docompare && dostrip) 333 safecopy = 1; 334 335 /* get group and owner id's */ 336 if (group != NULL && !dounpriv) { 337 if (gid_from_group(group, &gid) == -1) { 338 id_t id; 339 if (!parseid(group, &id)) 340 errx(1, "unknown group %s", group); 341 gid = id; 342 } 343 } else 344 gid = (gid_t)-1; 345 346 if (owner != NULL && !dounpriv) { 347 if (uid_from_user(owner, &uid) == -1) { 348 id_t id; 349 if (!parseid(owner, &id)) 350 errx(1, "unknown user %s", owner); 351 uid = id; 352 } 353 } else 354 uid = (uid_t)-1; 355 356 if (fflags != NULL && !dounpriv) { 357 if (strtofflags(&fflags, &fset, NULL)) 358 errx(EX_USAGE, "%s: invalid flag", fflags); 359 iflags |= SETFLAGS; 360 } 361 362 if (metafile != NULL) { 363 if ((metafp = fopen(metafile, "a")) == NULL) 364 warn("open %s", metafile); 365 } else 366 digesttype = DIGEST_NONE; 367 368 if (dodir) { 369 for (; *argv != NULL; ++argv) 370 install_dir(*argv); 371 exit(EX_OK); 372 /* NOTREACHED */ 373 } 374 375 to_name = argv[argc - 1]; 376 no_target = stat(to_name, &to_sb); 377 if (!no_target && S_ISDIR(to_sb.st_mode)) { 378 if (dolink & LN_SYMBOLIC) { 379 if (lstat(to_name, &to_sb) != 0) 380 err(EX_OSERR, "%s vanished", to_name); 381 if (S_ISLNK(to_sb.st_mode)) { 382 if (argc != 2) { 383 errno = ENOTDIR; 384 err(EX_USAGE, "%s", to_name); 385 } 386 install(*argv, to_name, fset, iflags); 387 exit(EX_OK); 388 } 389 } 390 for (; *argv != to_name; ++argv) 391 install(*argv, to_name, fset, iflags | DIRECTORY); 392 exit(EX_OK); 393 /* NOTREACHED */ 394 } 395 396 /* can't do file1 file2 directory/file */ 397 if (argc != 2) { 398 if (no_target) 399 warnx("target directory `%s' does not exist", 400 argv[argc - 1]); 401 else 402 warnx("target `%s' is not a directory", 403 argv[argc - 1]); 404 usage(); 405 } 406 407 if (!no_target && !dolink) { 408 if (stat(*argv, &from_sb)) 409 err(EX_OSERR, "%s", *argv); 410 if (!S_ISREG(to_sb.st_mode)) { 411 errno = EFTYPE; 412 err(EX_OSERR, "%s", to_name); 413 } 414 if (to_sb.st_dev == from_sb.st_dev && 415 to_sb.st_ino == from_sb.st_ino) 416 errx(EX_USAGE, 417 "%s and %s are the same file", *argv, to_name); 418 } 419 install(*argv, to_name, fset, iflags); 420 exit(EX_OK); 421 /* NOTREACHED */ 422 } 423 424 static char * 425 digest_file(const char *name) 426 { 427 428 switch (digesttype) { 429 #ifdef WITH_MD5 430 case DIGEST_MD5: 431 return (MD5File(name, NULL)); 432 #endif 433 #ifdef WITH_RIPEMD160 434 case DIGEST_RIPEMD160: 435 return (RIPEMD160_File(name, NULL)); 436 #endif 437 case DIGEST_SHA1: 438 return (SHA1_File(name, NULL)); 439 case DIGEST_SHA256: 440 return (SHA256_File(name, NULL)); 441 case DIGEST_SHA512: 442 return (SHA512_File(name, NULL)); 443 default: 444 return (NULL); 445 } 446 } 447 448 static void 449 digest_init(DIGEST_CTX *c) 450 { 451 452 switch (digesttype) { 453 case DIGEST_NONE: 454 break; 455 #ifdef WITH_MD5 456 case DIGEST_MD5: 457 MD5Init(&(c->MD5)); 458 break; 459 #endif 460 #ifdef WITH_RIPEMD160 461 case DIGEST_RIPEMD160: 462 RIPEMD160_Init(&(c->RIPEMD160)); 463 break; 464 #endif 465 case DIGEST_SHA1: 466 SHA1_Init(&(c->SHA1)); 467 break; 468 case DIGEST_SHA256: 469 SHA256_Init(&(c->SHA256)); 470 break; 471 case DIGEST_SHA512: 472 SHA512_Init(&(c->SHA512)); 473 break; 474 } 475 } 476 477 static void 478 digest_update(DIGEST_CTX *c, const char *data, size_t len) 479 { 480 481 switch (digesttype) { 482 case DIGEST_NONE: 483 break; 484 #ifdef WITH_MD5 485 case DIGEST_MD5: 486 MD5Update(&(c->MD5), data, len); 487 break; 488 #endif 489 #ifdef WITH_RIPEMD160 490 case DIGEST_RIPEMD160: 491 RIPEMD160_Update(&(c->RIPEMD160), data, len); 492 break; 493 #endif 494 case DIGEST_SHA1: 495 SHA1_Update(&(c->SHA1), data, len); 496 break; 497 case DIGEST_SHA256: 498 SHA256_Update(&(c->SHA256), data, len); 499 break; 500 case DIGEST_SHA512: 501 SHA512_Update(&(c->SHA512), data, len); 502 break; 503 } 504 } 505 506 static char * 507 digest_end(DIGEST_CTX *c, char *buf) 508 { 509 510 switch (digesttype) { 511 #ifdef WITH_MD5 512 case DIGEST_MD5: 513 return (MD5End(&(c->MD5), buf)); 514 #endif 515 #ifdef WITH_RIPEMD160 516 case DIGEST_RIPEMD160: 517 return (RIPEMD160_End(&(c->RIPEMD160), buf)); 518 #endif 519 case DIGEST_SHA1: 520 return (SHA1_End(&(c->SHA1), buf)); 521 case DIGEST_SHA256: 522 return (SHA256_End(&(c->SHA256), buf)); 523 case DIGEST_SHA512: 524 return (SHA512_End(&(c->SHA512), buf)); 525 default: 526 return (NULL); 527 } 528 } 529 530 /* 531 * parseid -- 532 * parse uid or gid from arg into id, returning non-zero if successful 533 */ 534 static int 535 parseid(const char *name, id_t *id) 536 { 537 char *ep; 538 errno = 0; 539 *id = (id_t)strtoul(name, &ep, 10); 540 if (errno || *ep != '\0') 541 return (0); 542 return (1); 543 } 544 545 /* 546 * quiet_mktemp -- 547 * mktemp implementation used mkstemp to avoid mktemp warnings. We 548 * really do need mktemp semantics here as we will be creating a link. 549 */ 550 static char * 551 quiet_mktemp(char *template) 552 { 553 int fd; 554 555 if ((fd = mkstemp(template)) == -1) 556 return (NULL); 557 close (fd); 558 if (unlink(template) == -1) 559 err(EX_OSERR, "unlink %s", template); 560 return (template); 561 } 562 563 /* 564 * do_link -- 565 * make a hard link, obeying dorename if set 566 * return -1 on failure 567 */ 568 static int 569 do_link(const char *from_name, const char *to_name, 570 const struct stat *target_sb) 571 { 572 char tmpl[MAXPATHLEN]; 573 int ret; 574 575 if (safecopy && target_sb != NULL) { 576 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 577 /* This usage is safe. */ 578 if (quiet_mktemp(tmpl) == NULL) 579 err(EX_OSERR, "%s: mktemp", tmpl); 580 ret = link(from_name, tmpl); 581 if (ret == 0) { 582 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == 583 -1) { 584 unlink(tmpl); 585 err(EX_OSERR, "%s", to_name); 586 } 587 #if HAVE_STRUCT_STAT_ST_FLAGS 588 if (target_sb->st_flags & NOCHANGEBITS) 589 (void)chflags(to_name, target_sb->st_flags & 590 ~NOCHANGEBITS); 591 #endif 592 if (verbose) 593 printf("install: link %s -> %s\n", 594 from_name, to_name); 595 ret = rename(tmpl, to_name); 596 /* 597 * If rename has posix semantics, then the temporary 598 * file may still exist when from_name and to_name point 599 * to the same file, so unlink it unconditionally. 600 */ 601 (void)unlink(tmpl); 602 } 603 return (ret); 604 } else { 605 if (verbose) 606 printf("install: link %s -> %s\n", 607 from_name, to_name); 608 return (link(from_name, to_name)); 609 } 610 } 611 612 /* 613 * do_symlink -- 614 * Make a symbolic link, obeying dorename if set. Exit on failure. 615 */ 616 static void 617 do_symlink(const char *from_name, const char *to_name, 618 const struct stat *target_sb) 619 { 620 char tmpl[MAXPATHLEN]; 621 622 if (safecopy && target_sb != NULL) { 623 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 624 /* This usage is safe. */ 625 if (quiet_mktemp(tmpl) == NULL) 626 err(EX_OSERR, "%s: mktemp", tmpl); 627 628 if (symlink(from_name, tmpl) == -1) 629 err(EX_OSERR, "symlink %s -> %s", from_name, tmpl); 630 631 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == -1) { 632 (void)unlink(tmpl); 633 err(EX_OSERR, "%s", to_name); 634 } 635 #if HAVE_STRUCT_STAT_ST_FLAGS 636 if (target_sb->st_flags & NOCHANGEBITS) 637 (void)chflags(to_name, target_sb->st_flags & 638 ~NOCHANGEBITS); 639 #endif 640 if (verbose) 641 printf("install: symlink %s -> %s\n", 642 from_name, to_name); 643 if (rename(tmpl, to_name) == -1) { 644 /* Remove temporary link before exiting. */ 645 (void)unlink(tmpl); 646 err(EX_OSERR, "%s: rename", to_name); 647 } 648 } else { 649 if (verbose) 650 printf("install: symlink %s -> %s\n", 651 from_name, to_name); 652 if (symlink(from_name, to_name) == -1) 653 err(EX_OSERR, "symlink %s -> %s", from_name, to_name); 654 } 655 } 656 657 /* 658 * makelink -- 659 * make a link from source to destination 660 */ 661 static void 662 makelink(const char *from_name, const char *to_name, 663 const struct stat *target_sb) 664 { 665 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; 666 struct stat to_sb; 667 668 /* Try hard links first. */ 669 if (dolink & (LN_HARD|LN_MIXED)) { 670 if (do_link(from_name, to_name, target_sb) == -1) { 671 if ((dolink & LN_HARD) || errno != EXDEV) 672 err(EX_OSERR, "link %s -> %s", from_name, to_name); 673 } else { 674 if (stat(to_name, &to_sb)) 675 err(EX_OSERR, "%s: stat", to_name); 676 if (S_ISREG(to_sb.st_mode)) { 677 /* 678 * XXX: hard links to anything other than 679 * plain files are not metalogged 680 */ 681 int omode; 682 const char *oowner, *ogroup; 683 char *offlags; 684 char *dres; 685 686 /* 687 * XXX: use underlying perms, unless 688 * overridden on command line. 689 */ 690 omode = mode; 691 if (!haveopt_m) 692 mode = (to_sb.st_mode & 0777); 693 oowner = owner; 694 if (!haveopt_o) 695 owner = NULL; 696 ogroup = group; 697 if (!haveopt_g) 698 group = NULL; 699 offlags = fflags; 700 if (!haveopt_f) 701 fflags = NULL; 702 dres = digest_file(from_name); 703 metadata_log(to_name, "file", NULL, NULL, 704 dres, to_sb.st_size); 705 free(dres); 706 mode = omode; 707 owner = oowner; 708 group = ogroup; 709 fflags = offlags; 710 } 711 return; 712 } 713 } 714 715 /* Symbolic links. */ 716 if (dolink & LN_ABSOLUTE) { 717 /* Convert source path to absolute. */ 718 if (realpath(from_name, src) == NULL) 719 err(EX_OSERR, "%s: realpath", from_name); 720 do_symlink(src, to_name, target_sb); 721 /* XXX: src may point outside of destdir */ 722 metadata_log(to_name, "link", NULL, src, NULL, 0); 723 return; 724 } 725 726 if (dolink & LN_RELATIVE) { 727 char *to_name_copy, *cp, *d, *ld, *ls, *s; 728 729 if (*from_name != '/') { 730 /* this is already a relative link */ 731 do_symlink(from_name, to_name, target_sb); 732 /* XXX: from_name may point outside of destdir. */ 733 metadata_log(to_name, "link", NULL, from_name, NULL, 0); 734 return; 735 } 736 737 /* Resolve pathnames. */ 738 if (realpath(from_name, src) == NULL) 739 err(EX_OSERR, "%s: realpath", from_name); 740 741 /* 742 * The last component of to_name may be a symlink, 743 * so use realpath to resolve only the directory. 744 */ 745 to_name_copy = strdup(to_name); 746 if (to_name_copy == NULL) 747 err(EX_OSERR, "%s: strdup", to_name); 748 cp = dirname(to_name_copy); 749 if (realpath(cp, dst) == NULL) 750 err(EX_OSERR, "%s: realpath", cp); 751 /* .. and add the last component. */ 752 if (strcmp(dst, "/") != 0) { 753 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst)) 754 errx(1, "resolved pathname too long"); 755 } 756 strcpy(to_name_copy, to_name); 757 cp = basename(to_name_copy); 758 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst)) 759 errx(1, "resolved pathname too long"); 760 free(to_name_copy); 761 762 /* Trim common path components. */ 763 ls = ld = NULL; 764 for (s = src, d = dst; *s == *d; ls = s, ld = d, s++, d++) 765 continue; 766 /* 767 * If we didn't end after a directory separator, then we've 768 * falsely matched the last component. For example, if one 769 * invoked install -lrs /lib/foo.so /libexec/ then the source 770 * would terminate just after the separator while the 771 * destination would terminate in the middle of 'libexec', 772 * leading to a full directory getting falsely eaten. 773 */ 774 if ((ls != NULL && *ls != '/') || (ld != NULL && *ld != '/')) 775 s--, d--; 776 while (*s != '/') 777 s--, d--; 778 779 /* Count the number of directories we need to backtrack. */ 780 for (++d, lnk[0] = '\0'; *d; d++) 781 if (*d == '/') 782 (void)strlcat(lnk, "../", sizeof(lnk)); 783 784 (void)strlcat(lnk, ++s, sizeof(lnk)); 785 786 do_symlink(lnk, to_name, target_sb); 787 /* XXX: Link may point outside of destdir. */ 788 metadata_log(to_name, "link", NULL, lnk, NULL, 0); 789 return; 790 } 791 792 /* 793 * If absolute or relative was not specified, try the names the 794 * user provided. 795 */ 796 do_symlink(from_name, to_name, target_sb); 797 /* XXX: from_name may point outside of destdir. */ 798 metadata_log(to_name, "link", NULL, from_name, NULL, 0); 799 } 800 801 /* 802 * install -- 803 * build a path name and install the file 804 */ 805 static void 806 install(const char *from_name, const char *to_name, u_long fset, u_int flags) 807 { 808 struct stat from_sb, temp_sb, to_sb; 809 struct timespec tsb[2]; 810 int devnull, files_match, from_fd, serrno, stripped, target; 811 int tempcopy, temp_fd, to_fd; 812 char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; 813 char *digestresult; 814 815 digestresult = NULL; 816 files_match = stripped = 0; 817 from_fd = -1; 818 to_fd = -1; 819 820 /* If try to install NULL file to a directory, fails. */ 821 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { 822 if (!dolink) { 823 if (stat(from_name, &from_sb)) 824 err(EX_OSERR, "%s", from_name); 825 if (!S_ISREG(from_sb.st_mode)) { 826 errno = EFTYPE; 827 err(EX_OSERR, "%s", from_name); 828 } 829 } 830 /* Build the target path. */ 831 if (flags & DIRECTORY) { 832 (void)snprintf(pathbuf, sizeof(pathbuf), "%s%s%s", 833 to_name, 834 to_name[strlen(to_name) - 1] == '/' ? "" : "/", 835 (p = strrchr(from_name, '/')) ? ++p : from_name); 836 to_name = pathbuf; 837 } 838 devnull = 0; 839 } else { 840 devnull = 1; 841 } 842 843 target = (lstat(to_name, &to_sb) == 0); 844 845 if (dolink) { 846 if (target && !safecopy) { 847 if (to_sb.st_mode & S_IFDIR && rmdir(to_name) == -1) 848 err(EX_OSERR, "%s", to_name); 849 #if HAVE_STRUCT_STAT_ST_FLAGS 850 if (to_sb.st_flags & NOCHANGEBITS) 851 (void)chflags(to_name, 852 to_sb.st_flags & ~NOCHANGEBITS); 853 #endif 854 unlink(to_name); 855 } 856 makelink(from_name, to_name, target ? &to_sb : NULL); 857 return; 858 } 859 860 if (target && !S_ISREG(to_sb.st_mode) && !S_ISLNK(to_sb.st_mode)) { 861 errno = EFTYPE; 862 warn("%s", to_name); 863 return; 864 } 865 866 /* Only copy safe if the target exists. */ 867 tempcopy = safecopy && target; 868 869 if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) 870 err(EX_OSERR, "%s", from_name); 871 872 /* If we don't strip, we can compare first. */ 873 if (docompare && !dostrip && target && S_ISREG(to_sb.st_mode)) { 874 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 875 err(EX_OSERR, "%s", to_name); 876 if (devnull) 877 files_match = to_sb.st_size == 0; 878 else 879 files_match = !(compare(from_fd, from_name, 880 (size_t)from_sb.st_size, to_fd, 881 to_name, (size_t)to_sb.st_size, &digestresult)); 882 883 /* Close "to" file unless we match. */ 884 if (!files_match) 885 (void)close(to_fd); 886 } 887 888 if (!files_match) { 889 if (tempcopy) { 890 to_fd = create_tempfile(to_name, tempfile, 891 sizeof(tempfile)); 892 if (to_fd < 0) 893 err(EX_OSERR, "%s", tempfile); 894 } else { 895 if ((to_fd = create_newfile(to_name, target, 896 &to_sb)) < 0) 897 err(EX_OSERR, "%s", to_name); 898 if (verbose) 899 (void)printf("install: %s -> %s\n", 900 from_name, to_name); 901 } 902 if (!devnull) { 903 if (dostrip) 904 stripped = strip(tempcopy ? tempfile : to_name, 905 to_fd, from_name, &digestresult); 906 if (!stripped) 907 digestresult = copy(from_fd, from_name, to_fd, 908 tempcopy ? tempfile : to_name, from_sb.st_size); 909 } 910 } 911 912 if (dostrip) { 913 if (!stripped) 914 (void)strip(tempcopy ? tempfile : to_name, to_fd, 915 NULL, &digestresult); 916 917 /* 918 * Re-open our fd on the target, in case 919 * we did not strip in-place. 920 */ 921 close(to_fd); 922 to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0); 923 if (to_fd < 0) 924 err(EX_OSERR, "stripping %s", to_name); 925 } 926 927 /* 928 * Compare the stripped temp file with the target. 929 */ 930 if (docompare && dostrip && target && S_ISREG(to_sb.st_mode)) { 931 temp_fd = to_fd; 932 933 /* Re-open to_fd using the real target name. */ 934 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 935 err(EX_OSERR, "%s", to_name); 936 937 if (fstat(temp_fd, &temp_sb)) { 938 serrno = errno; 939 (void)unlink(tempfile); 940 errno = serrno; 941 err(EX_OSERR, "%s", tempfile); 942 } 943 944 if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd, 945 to_name, (size_t)to_sb.st_size, &digestresult) 946 == 0) { 947 /* 948 * If target has more than one link we need to 949 * replace it in order to snap the extra links. 950 * Need to preserve target file times, though. 951 */ 952 if (to_sb.st_nlink != 1) { 953 tsb[0] = to_sb.st_atim; 954 tsb[1] = to_sb.st_mtim; 955 (void)utimensat(AT_FDCWD, tempfile, tsb, 0); 956 } else { 957 files_match = 1; 958 (void)unlink(tempfile); 959 } 960 (void) close(temp_fd); 961 } 962 } else if (dostrip) 963 digestresult = digest_file(tempfile); 964 965 /* 966 * Move the new file into place if doing a safe copy 967 * and the files are different (or just not compared). 968 */ 969 if (tempcopy && !files_match) { 970 #if HAVE_STRUCT_STAT_ST_FLAGS 971 /* Try to turn off the immutable bits. */ 972 if (to_sb.st_flags & NOCHANGEBITS) 973 (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS); 974 #endif 975 if (dobackup) { 976 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name, 977 suffix) != strlen(to_name) + strlen(suffix)) { 978 unlink(tempfile); 979 errx(EX_OSERR, "%s: backup filename too long", 980 to_name); 981 } 982 if (verbose) 983 (void)printf("install: %s -> %s\n", to_name, backup); 984 if (unlink(backup) < 0 && errno != ENOENT) { 985 serrno = errno; 986 #if HAVE_STRUCT_STAT_ST_FLAGS 987 if (to_sb.st_flags & NOCHANGEBITS) 988 (void)chflags(to_name, to_sb.st_flags); 989 #endif 990 unlink(tempfile); 991 errno = serrno; 992 err(EX_OSERR, "unlink: %s", backup); 993 } 994 if (link(to_name, backup) < 0) { 995 serrno = errno; 996 unlink(tempfile); 997 #if HAVE_STRUCT_STAT_ST_FLAGS 998 if (to_sb.st_flags & NOCHANGEBITS) 999 (void)chflags(to_name, to_sb.st_flags); 1000 #endif 1001 errno = serrno; 1002 err(EX_OSERR, "link: %s to %s", to_name, 1003 backup); 1004 } 1005 } 1006 if (verbose) 1007 (void)printf("install: %s -> %s\n", from_name, to_name); 1008 if (rename(tempfile, to_name) < 0) { 1009 serrno = errno; 1010 unlink(tempfile); 1011 errno = serrno; 1012 err(EX_OSERR, "rename: %s to %s", 1013 tempfile, to_name); 1014 } 1015 1016 /* Re-open to_fd so we aren't hosed by the rename(2). */ 1017 (void) close(to_fd); 1018 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 1019 err(EX_OSERR, "%s", to_name); 1020 } 1021 1022 /* 1023 * Preserve the timestamp of the source file if necessary. 1024 */ 1025 if (dopreserve && !files_match && !devnull) { 1026 tsb[0] = from_sb.st_atim; 1027 tsb[1] = from_sb.st_mtim; 1028 (void)utimensat(AT_FDCWD, to_name, tsb, 0); 1029 } 1030 1031 if (fstat(to_fd, &to_sb) == -1) { 1032 serrno = errno; 1033 (void)unlink(to_name); 1034 errno = serrno; 1035 err(EX_OSERR, "%s", to_name); 1036 } 1037 1038 /* 1039 * Set owner, group, mode for target; do the chown first, 1040 * chown may lose the setuid bits. 1041 */ 1042 if (!dounpriv && ((gid != (gid_t)-1 && gid != to_sb.st_gid) || 1043 (uid != (uid_t)-1 && uid != to_sb.st_uid) || 1044 (mode != (to_sb.st_mode & ALLPERMS)))) { 1045 #if HAVE_STRUCT_STAT_ST_FLAGS 1046 /* Try to turn off the immutable bits. */ 1047 if (to_sb.st_flags & NOCHANGEBITS) 1048 (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS); 1049 #endif 1050 } 1051 1052 if (!dounpriv && ((gid != (gid_t)-1 && gid != to_sb.st_gid) || 1053 (uid != (uid_t)-1 && uid != to_sb.st_uid))) { 1054 if (fchown(to_fd, uid, gid) == -1) { 1055 serrno = errno; 1056 (void)unlink(to_name); 1057 errno = serrno; 1058 err(EX_OSERR,"%s: chown/chgrp", to_name); 1059 } 1060 } 1061 if (mode != (to_sb.st_mode & ALLPERMS)) { 1062 if (fchmod(to_fd, 1063 dounpriv ? mode & (S_IRWXU|S_IRWXG|S_IRWXO) : mode)) { 1064 serrno = errno; 1065 (void)unlink(to_name); 1066 errno = serrno; 1067 err(EX_OSERR, "%s: chmod", to_name); 1068 } 1069 } 1070 #if HAVE_STRUCT_STAT_ST_FLAGS 1071 /* 1072 * If provided a set of flags, set them, otherwise, preserve the 1073 * flags, except for the dump flag. 1074 * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just 1075 * trying to turn off UF_NODUMP. If we're trying to set real flags, 1076 * then warn if the fs doesn't support it, otherwise fail. 1077 */ 1078 if (!dounpriv && !devnull && (flags & SETFLAGS || 1079 (from_sb.st_flags & ~UF_NODUMP) != to_sb.st_flags) && 1080 fchflags(to_fd, 1081 flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) { 1082 if (flags & SETFLAGS) { 1083 if (errno == EOPNOTSUPP) 1084 warn("%s: chflags", to_name); 1085 else { 1086 serrno = errno; 1087 (void)unlink(to_name); 1088 errno = serrno; 1089 err(EX_OSERR, "%s: chflags", to_name); 1090 } 1091 } 1092 } 1093 #endif 1094 1095 (void)close(to_fd); 1096 if (!devnull) 1097 (void)close(from_fd); 1098 1099 metadata_log(to_name, "file", tsb, NULL, digestresult, to_sb.st_size); 1100 free(digestresult); 1101 } 1102 1103 /* 1104 * compare -- 1105 * Compare two files; non-zero means files differ. 1106 * Compute digest and return its address in *dresp 1107 * unless it points to pre-computed digest. 1108 */ 1109 static int 1110 compare(int from_fd, const char *from_name __unused, size_t from_len, 1111 int to_fd, const char *to_name __unused, size_t to_len, 1112 char **dresp) 1113 { 1114 char *p, *q; 1115 int rv; 1116 int do_digest, done_compare; 1117 DIGEST_CTX ctx; 1118 1119 rv = 0; 1120 if (from_len != to_len) 1121 return 1; 1122 1123 do_digest = (digesttype != DIGEST_NONE && dresp != NULL && 1124 *dresp == NULL); 1125 if (from_len <= MAX_CMP_SIZE) { 1126 if (do_digest) 1127 digest_init(&ctx); 1128 done_compare = 0; 1129 if (trymmap(from_len) && trymmap(to_len)) { 1130 p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 1131 from_fd, (off_t)0); 1132 if (p == MAP_FAILED) 1133 goto out; 1134 q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 1135 to_fd, (off_t)0); 1136 if (q == MAP_FAILED) { 1137 munmap(p, from_len); 1138 goto out; 1139 } 1140 1141 rv = memcmp(p, q, from_len); 1142 if (do_digest) 1143 digest_update(&ctx, p, from_len); 1144 munmap(p, from_len); 1145 munmap(q, from_len); 1146 done_compare = 1; 1147 } 1148 out: 1149 if (!done_compare) { 1150 static char *buf, *buf1, *buf2; 1151 static size_t bufsize; 1152 int n1, n2; 1153 1154 if (buf == NULL) { 1155 /* 1156 * Note that buf and bufsize are static. If 1157 * malloc() fails, it will fail at the start 1158 * and not copy only some files. 1159 */ 1160 if (sysconf(_SC_PHYS_PAGES) > 1161 PHYSPAGES_THRESHOLD) 1162 bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 1163 else 1164 bufsize = BUFSIZE_SMALL; 1165 buf = malloc(bufsize * 2); 1166 if (buf == NULL) 1167 err(1, "Not enough memory"); 1168 buf1 = buf; 1169 buf2 = buf + bufsize; 1170 } 1171 rv = 0; 1172 lseek(from_fd, 0, SEEK_SET); 1173 lseek(to_fd, 0, SEEK_SET); 1174 while (rv == 0) { 1175 n1 = read(from_fd, buf1, bufsize); 1176 if (n1 == 0) 1177 break; /* EOF */ 1178 else if (n1 > 0) { 1179 n2 = read(to_fd, buf2, n1); 1180 if (n2 == n1) 1181 rv = memcmp(buf1, buf2, n1); 1182 else 1183 rv = 1; /* out of sync */ 1184 } else 1185 rv = 1; /* read failure */ 1186 if (do_digest) 1187 digest_update(&ctx, buf1, n1); 1188 } 1189 lseek(from_fd, 0, SEEK_SET); 1190 lseek(to_fd, 0, SEEK_SET); 1191 } 1192 } else 1193 rv = 1; /* don't bother in this case */ 1194 1195 if (do_digest) { 1196 if (rv == 0) 1197 *dresp = digest_end(&ctx, NULL); 1198 else 1199 (void)digest_end(&ctx, NULL); 1200 } 1201 1202 return rv; 1203 } 1204 1205 /* 1206 * create_tempfile -- 1207 * create a temporary file based on path and open it 1208 */ 1209 static int 1210 create_tempfile(const char *path, char *temp, size_t tsize) 1211 { 1212 char *p; 1213 1214 (void)strncpy(temp, path, tsize); 1215 temp[tsize - 1] = '\0'; 1216 if ((p = strrchr(temp, '/')) != NULL) 1217 p++; 1218 else 1219 p = temp; 1220 (void)strncpy(p, "INS@XXXXXX", &temp[tsize - 1] - p); 1221 temp[tsize - 1] = '\0'; 1222 return (mkstemp(temp)); 1223 } 1224 1225 /* 1226 * create_newfile -- 1227 * create a new file, overwriting an existing one if necessary 1228 */ 1229 static int 1230 create_newfile(const char *path, int target, struct stat *sbp) 1231 { 1232 char backup[MAXPATHLEN]; 1233 int saved_errno = 0; 1234 int newfd; 1235 1236 if (target) { 1237 /* 1238 * Unlink now... avoid ETXTBSY errors later. Try to turn 1239 * off the append/immutable bits -- if we fail, go ahead, 1240 * it might work. 1241 */ 1242 #if HAVE_STRUCT_STAT_ST_FLAGS 1243 if (sbp->st_flags & NOCHANGEBITS) 1244 (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS); 1245 #endif 1246 1247 if (dobackup) { 1248 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", 1249 path, suffix) != strlen(path) + strlen(suffix)) { 1250 saved_errno = errno; 1251 #if HAVE_STRUCT_STAT_ST_FLAGS 1252 if (sbp->st_flags & NOCHANGEBITS) 1253 (void)chflags(path, sbp->st_flags); 1254 #endif 1255 errno = saved_errno; 1256 errx(EX_OSERR, "%s: backup filename too long", 1257 path); 1258 } 1259 (void)snprintf(backup, MAXPATHLEN, "%s%s", 1260 path, suffix); 1261 if (verbose) 1262 (void)printf("install: %s -> %s\n", 1263 path, backup); 1264 if (rename(path, backup) < 0) { 1265 saved_errno = errno; 1266 #if HAVE_STRUCT_STAT_ST_FLAGS 1267 if (sbp->st_flags & NOCHANGEBITS) 1268 (void)chflags(path, sbp->st_flags); 1269 #endif 1270 errno = saved_errno; 1271 err(EX_OSERR, "rename: %s to %s", path, backup); 1272 } 1273 } else 1274 if (unlink(path) < 0) 1275 saved_errno = errno; 1276 } 1277 1278 newfd = open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR); 1279 if (newfd < 0 && saved_errno != 0) 1280 errno = saved_errno; 1281 return newfd; 1282 } 1283 1284 /* 1285 * copy -- 1286 * copy from one file to another 1287 */ 1288 static char * 1289 copy(int from_fd, const char *from_name, int to_fd, const char *to_name, 1290 off_t size) 1291 { 1292 static char *buf = NULL; 1293 static size_t bufsize; 1294 int nr, nw; 1295 int serrno; 1296 #ifndef BOOTSTRAP_XINSTALL 1297 ssize_t ret; 1298 #endif 1299 char *p; 1300 int done_copy; 1301 DIGEST_CTX ctx; 1302 1303 /* Rewind file descriptors. */ 1304 if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1305 err(EX_OSERR, "lseek: %s", from_name); 1306 if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1307 err(EX_OSERR, "lseek: %s", to_name); 1308 1309 #ifndef BOOTSTRAP_XINSTALL 1310 /* Try copy_file_range() if no digest is requested */ 1311 if (digesttype == DIGEST_NONE) { 1312 ret = 1; 1313 while (ret > 0) { 1314 ret = copy_file_range(from_fd, NULL, to_fd, NULL, 1315 SSIZE_MAX, 0); 1316 } 1317 if (ret == 0) { 1318 /* DIGEST_NONE always returns NULL */ 1319 return (NULL); 1320 } 1321 if (errno != EINVAL) { 1322 serrno = errno; 1323 (void)unlink(to_name); 1324 errno = serrno; 1325 err(EX_OSERR, "%s", to_name); 1326 } 1327 /* Fall back */ 1328 } 1329 1330 #endif 1331 digest_init(&ctx); 1332 1333 done_copy = 0; 1334 if (trymmap((size_t)size) && 1335 (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, 1336 from_fd, (off_t)0)) != MAP_FAILED) { 1337 nw = write(to_fd, p, size); 1338 if (nw != size) { 1339 serrno = errno; 1340 (void)unlink(to_name); 1341 if (nw >= 0) { 1342 errx(EX_OSERR, 1343 "short write to %s: %jd bytes written, %jd bytes asked to write", 1344 to_name, (uintmax_t)nw, (uintmax_t)size); 1345 } else { 1346 errno = serrno; 1347 err(EX_OSERR, "%s", to_name); 1348 } 1349 } 1350 digest_update(&ctx, p, size); 1351 (void)munmap(p, size); 1352 done_copy = 1; 1353 } 1354 if (!done_copy) { 1355 if (buf == NULL) { 1356 /* 1357 * Note that buf and bufsize are static. If 1358 * malloc() fails, it will fail at the start 1359 * and not copy only some files. 1360 */ 1361 if (sysconf(_SC_PHYS_PAGES) > 1362 PHYSPAGES_THRESHOLD) 1363 bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); 1364 else 1365 bufsize = BUFSIZE_SMALL; 1366 buf = malloc(bufsize); 1367 if (buf == NULL) 1368 err(1, "Not enough memory"); 1369 } 1370 while ((nr = read(from_fd, buf, bufsize)) > 0) { 1371 if ((nw = write(to_fd, buf, nr)) != nr) { 1372 serrno = errno; 1373 (void)unlink(to_name); 1374 if (nw >= 0) { 1375 errx(EX_OSERR, 1376 "short write to %s: %jd bytes written, %jd bytes asked to write", 1377 to_name, (uintmax_t)nw, 1378 (uintmax_t)size); 1379 } else { 1380 errno = serrno; 1381 err(EX_OSERR, "%s", to_name); 1382 } 1383 } 1384 digest_update(&ctx, buf, nr); 1385 } 1386 if (nr != 0) { 1387 serrno = errno; 1388 (void)unlink(to_name); 1389 errno = serrno; 1390 err(EX_OSERR, "%s", from_name); 1391 } 1392 } 1393 if (safecopy && fsync(to_fd) == -1) { 1394 serrno = errno; 1395 (void)unlink(to_name); 1396 errno = serrno; 1397 err(EX_OSERR, "fsync failed for %s", to_name); 1398 } 1399 return (digest_end(&ctx, NULL)); 1400 } 1401 1402 /* 1403 * strip -- 1404 * Use strip(1) to strip the target file. 1405 * Just invoke strip(1) on to_name if from_name is NULL, else try 1406 * to run "strip -o to_name from_name" and return 0 on failure. 1407 * Return 1 on success and assign result of digest_file(to_name) 1408 * to *dresp. 1409 */ 1410 static int 1411 strip(const char *to_name, int to_fd, const char *from_name, char **dresp) 1412 { 1413 const char *stripbin; 1414 const char *args[5]; 1415 char *prefixed_from_name; 1416 pid_t pid; 1417 int error, serrno, status; 1418 1419 prefixed_from_name = NULL; 1420 stripbin = getenv("STRIPBIN"); 1421 if (stripbin == NULL) 1422 stripbin = "strip"; 1423 args[0] = stripbin; 1424 if (from_name == NULL) { 1425 args[1] = to_name; 1426 args[2] = NULL; 1427 } else { 1428 args[1] = "-o"; 1429 args[2] = to_name; 1430 1431 /* Prepend './' if from_name begins with '-' */ 1432 if (from_name[0] == '-') { 1433 if (asprintf(&prefixed_from_name, "./%s", from_name) == -1) 1434 return (0); 1435 args[3] = prefixed_from_name; 1436 } else { 1437 args[3] = from_name; 1438 } 1439 args[4] = NULL; 1440 } 1441 error = posix_spawnp(&pid, stripbin, NULL, NULL, 1442 __DECONST(char **, args), environ); 1443 if (error != 0) { 1444 (void)unlink(to_name); 1445 errc(error == EAGAIN || error == EPROCLIM || error == ENOMEM ? 1446 EX_TEMPFAIL : EX_OSERR, error, "spawn %s", stripbin); 1447 } 1448 free(prefixed_from_name); 1449 if (waitpid(pid, &status, 0) == -1) { 1450 error = errno; 1451 (void)unlink(to_name); 1452 errc(EX_SOFTWARE, error, "wait"); 1453 /* NOTREACHED */ 1454 } 1455 if (status != 0) { 1456 if (from_name != NULL) 1457 return (0); 1458 (void)unlink(to_name); 1459 errx(EX_SOFTWARE, "strip command %s failed on %s", 1460 stripbin, to_name); 1461 } 1462 if (from_name != NULL && safecopy && fsync(to_fd) == -1) { 1463 serrno = errno; 1464 (void)unlink(to_name); 1465 errno = serrno; 1466 err(EX_OSERR, "fsync failed for %s", to_name); 1467 } 1468 if (dresp != NULL) 1469 *dresp = digest_file(to_name); 1470 return (1); 1471 } 1472 1473 /* 1474 * install_dir -- 1475 * build directory hierarchy 1476 */ 1477 static void 1478 install_dir(char *path) 1479 { 1480 char *p; 1481 struct stat sb; 1482 int ch, tried_mkdir; 1483 1484 for (p = path;; ++p) 1485 if (!*p || (p != path && *p == '/')) { 1486 tried_mkdir = 0; 1487 ch = *p; 1488 *p = '\0'; 1489 again: 1490 if (stat(path, &sb) != 0) { 1491 if (errno != ENOENT || tried_mkdir) 1492 err(EX_OSERR, "stat %s", path); 1493 if (mkdir(path, 0755) < 0) { 1494 tried_mkdir = 1; 1495 if (errno == EEXIST) 1496 goto again; 1497 err(EX_OSERR, "mkdir %s", path); 1498 } 1499 if (verbose) 1500 (void)printf("install: mkdir %s\n", 1501 path); 1502 } else if (!S_ISDIR(sb.st_mode)) 1503 errx(EX_OSERR, "%s exists but is not a directory", path); 1504 if (!(*p = ch)) 1505 break; 1506 } 1507 1508 if (!dounpriv) { 1509 if ((gid != (gid_t)-1 || uid != (uid_t)-1) && 1510 chown(path, uid, gid)) 1511 warn("chown %u:%u %s", uid, gid, path); 1512 /* XXXBED: should we do the chmod in the dounpriv case? */ 1513 if (chmod(path, mode)) 1514 warn("chmod %o %s", mode, path); 1515 } 1516 metadata_log(path, "dir", NULL, NULL, NULL, 0); 1517 } 1518 1519 /* 1520 * metadata_log -- 1521 * if metafp is not NULL, output mtree(8) full path name and settings to 1522 * metafp, to allow permissions to be set correctly by other tools, 1523 * or to allow integrity checks to be performed. 1524 */ 1525 static void 1526 metadata_log(const char *path, const char *type, struct timespec *ts, 1527 const char *slink, const char *digestresult, off_t size) 1528 { 1529 static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; 1530 const char *p; 1531 char *buf; 1532 size_t destlen; 1533 struct flock metalog_lock; 1534 1535 if (!metafp) 1536 return; 1537 /* Buffer for strsvis(3). */ 1538 buf = (char *)malloc(4 * strlen(path) + 1); 1539 if (buf == NULL) { 1540 warnx("%s", strerror(ENOMEM)); 1541 return; 1542 } 1543 1544 /* Lock log file. */ 1545 metalog_lock.l_start = 0; 1546 metalog_lock.l_len = 0; 1547 metalog_lock.l_whence = SEEK_SET; 1548 metalog_lock.l_type = F_WRLCK; 1549 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { 1550 warn("can't lock %s", metafile); 1551 free(buf); 1552 return; 1553 } 1554 1555 /* Remove destdir. */ 1556 p = path; 1557 if (destdir) { 1558 destlen = strlen(destdir); 1559 if (strncmp(p, destdir, destlen) == 0 && 1560 (p[destlen] == '/' || p[destlen] == '\0')) 1561 p += destlen; 1562 } 1563 while (*p && *p == '/') 1564 p++; 1565 strsvis(buf, p, VIS_OCTAL, extra); 1566 p = buf; 1567 /* Print details. */ 1568 fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type); 1569 if (owner) 1570 fprintf(metafp, " uname=%s", owner); 1571 if (group) 1572 fprintf(metafp, " gname=%s", group); 1573 fprintf(metafp, " mode=%#o", mode); 1574 if (slink) { 1575 strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */ 1576 fprintf(metafp, " link=%s", buf); 1577 } 1578 if (*type == 'f') /* type=file */ 1579 fprintf(metafp, " size=%lld", (long long)size); 1580 if (ts != NULL && dopreserve) 1581 fprintf(metafp, " time=%lld.%09ld", 1582 (long long)ts[1].tv_sec, ts[1].tv_nsec); 1583 if (digestresult && digest) 1584 fprintf(metafp, " %s=%s", digest, digestresult); 1585 if (fflags) 1586 fprintf(metafp, " flags=%s", fflags); 1587 if (tags) 1588 fprintf(metafp, " tags=%s", tags); 1589 fputc('\n', metafp); 1590 /* Flush line. */ 1591 fflush(metafp); 1592 1593 /* Unlock log file. */ 1594 metalog_lock.l_type = F_UNLCK; 1595 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) 1596 warn("can't unlock %s", metafile); 1597 free(buf); 1598 } 1599 1600 /* 1601 * usage -- 1602 * print a usage message and die 1603 */ 1604 static void 1605 usage(void) 1606 { 1607 (void)fprintf(stderr, 1608 "usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" 1609 " [-M log] [-D dest] [-h hash] [-T tags]\n" 1610 " [-B suffix] [-l linkflags] [-N dbdir]\n" 1611 " file1 file2\n" 1612 " install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" 1613 " [-M log] [-D dest] [-h hash] [-T tags]\n" 1614 " [-B suffix] [-l linkflags] [-N dbdir]\n" 1615 " file1 ... fileN directory\n" 1616 " install -dU [-vU] [-g group] [-m mode] [-N dbdir] [-o owner]\n" 1617 " [-M log] [-D dest] [-h hash] [-T tags]\n" 1618 " directory ...\n"); 1619 exit(EX_USAGE); 1620 /* NOTREACHED */ 1621 } 1622 1623 /* 1624 * trymmap -- 1625 * return true (1) if mmap should be tried, false (0) if not. 1626 */ 1627 static int 1628 trymmap(size_t filesize) 1629 { 1630 /* 1631 * This function existed to skip mmap() for NFS file systems whereas 1632 * nowadays mmap() should be perfectly safe. Nevertheless, using mmap() 1633 * only reduces the number of system calls if we need multiple read() 1634 * syscalls, i.e. if the file size is > MAXBSIZE. However, mmap() is 1635 * more expensive than read() so set the threshold at 4 fewer syscalls. 1636 * Additionally, for larger file size mmap() can significantly increase 1637 * the number of page faults, so avoid it in that case. 1638 * 1639 * Note: the 8MB limit is not based on any meaningful benchmarking 1640 * results, it is simply reusing the same value that was used before 1641 * and also matches bin/cp. 1642 * 1643 * XXX: Maybe we shouldn't bother with mmap() at all, since we use 1644 * MAXBSIZE the syscall overhead of read() shouldn't be too high? 1645 */ 1646 return (filesize > 4 * MAXBSIZE && filesize < 8 * 1024 * 1024); 1647 } 1648