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