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