1 /* 2 * Copyright (c) 1987, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#) Copyright (c) 1987, 1993 The Regents of the University of California. All rights reserved. 30 * @(#)xinstall.c 8.1 (Berkeley) 7/21/93 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/wait.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <grp.h> 44 #include <libgen.h> 45 #include <paths.h> 46 #include <pwd.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <sysexits.h> 51 #include <unistd.h> 52 #include <utime.h> 53 #include <vis.h> 54 55 #include "mtree.h" 56 57 /* Bootstrap aid - this doesn't exist in most older releases */ 58 #ifndef MAP_FAILED 59 #define MAP_FAILED ((void *)-1) /* from <sys/mman.h> */ 60 #endif 61 #ifndef UF_NOHISTORY 62 #define UF_NOHISTORY 0 63 #endif 64 65 #define MAX_CMP_SIZE (16 * 1024 * 1024) 66 67 #define LN_ABSOLUTE 0x01 68 #define LN_RELATIVE 0x02 69 #define LN_HARD 0x04 70 #define LN_SYMBOLIC 0x08 71 #define LN_MIXED 0x10 72 73 #define DIRECTORY 0x01 /* Tell install it's a directory. */ 74 #define SETFLAGS 0x02 /* Tell install to set flags. */ 75 #define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 76 #define BACKUP_SUFFIX ".old" 77 78 static gid_t gid; 79 static uid_t uid; 80 static int dobackup, docompare, dodir, dolink, dopreserve, dostrip, dounpriv, 81 nommap, safecopy, verbose; 82 static int haveopt_f, haveopt_g, haveopt_m, haveopt_o; 83 static mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; 84 static const char *group, *owner; 85 static const char *suffix = BACKUP_SUFFIX; 86 static char *destdir, *fflags; 87 88 static int compare(int, const char *, size_t, int, const char *, size_t); 89 static void copy(int, const char *, int, const char *, off_t); 90 static int create_newfile(const char *, int, struct stat *); 91 static int create_tempfile(const char *, char *, size_t); 92 static int do_link(const char *, const char *, const struct stat *); 93 static void do_symlink(const char *, const char *, const struct stat *); 94 static void makelink(const char *, const char *, const struct stat *); 95 static void install(const char *, const char *, u_long, u_long, u_int); 96 static void install_dir(char *); 97 static int parseid(const char *, id_t *); 98 static void strip(const char *); 99 static int trymmap(int); 100 static void usage(void); 101 102 int 103 main(int argc, char *argv[]) 104 { 105 struct stat from_sb, to_sb; 106 mode_t *set; 107 u_long fset; 108 u_long fclr; 109 int ch, no_target; 110 u_int iflags; 111 char *p; 112 const char *to_name; 113 114 fclr = 0; 115 fset = 0; 116 iflags = 0; 117 group = NULL; 118 owner = NULL; 119 120 /* NOTE: please also update 'tools/install.sh' */ 121 while ((ch = getopt(argc, argv, "B:bCcD:df:g:L:l:M:m:N:o:pSsUv")) != -1) 122 switch((char)ch) { 123 case 'B': 124 suffix = optarg; 125 /* FALLTHROUGH */ 126 case 'b': 127 dobackup = 1; 128 break; 129 case 'C': 130 docompare = 1; 131 break; 132 case 'c': 133 /* For backwards compatibility. */ 134 break; 135 case 'D': 136 destdir = optarg; 137 break; 138 case 'd': 139 dodir = 1; 140 break; 141 case 'f': 142 #ifdef _ST_FLAGS_PRESENT_ 143 haveopt_f = 1; 144 fflags = optarg; 145 #endif 146 break; 147 case 'g': 148 haveopt_g = 1; 149 group = optarg; 150 break; 151 case 'l': 152 for (p = optarg; *p; p++) 153 switch (*p) { 154 case 's': 155 dolink &= ~(LN_HARD|LN_MIXED); 156 dolink |= LN_SYMBOLIC; 157 break; 158 case 'h': 159 dolink &= ~(LN_SYMBOLIC|LN_MIXED); 160 dolink |= LN_HARD; 161 break; 162 case 'm': 163 dolink &= ~(LN_SYMBOLIC|LN_HARD); 164 dolink |= LN_MIXED; 165 break; 166 case 'a': 167 dolink &= ~LN_RELATIVE; 168 dolink |= LN_ABSOLUTE; 169 break; 170 case 'r': 171 dolink &= ~LN_ABSOLUTE; 172 dolink |= LN_RELATIVE; 173 break; 174 default: 175 errx(EXIT_FAILURE, "%c: invalid link type", *p); 176 /* NOTREACHED */ 177 } 178 break; 179 case 'M': 180 nommap = 1; 181 break; 182 case 'm': 183 haveopt_m = 1; 184 if (!(set = setmode(optarg))) 185 errx(EX_USAGE, "invalid file mode: %s", 186 optarg); 187 mode = getmode(set, 0); 188 free(set); 189 break; 190 case 'L': 191 /* -L kept for compatibility with pre-5.4 DragonFly */ 192 warnx("Option -L is deprecated, use -N instead"); 193 /* FALLTHROUGH */ 194 case 'N': 195 if (!setup_getid(optarg)) 196 err(EX_OSERR, "Unable to use user and group " 197 "databases in `%s'", optarg); 198 break; 199 case 'o': 200 haveopt_o = 1; 201 owner = optarg; 202 break; 203 case 'p': 204 docompare = dopreserve = 1; 205 break; 206 case 'S': 207 safecopy = 1; 208 break; 209 case 's': 210 dostrip = 1; 211 break; 212 case 'U': 213 dounpriv = 1; 214 break; 215 case 'v': 216 verbose = 1; 217 break; 218 case '?': 219 default: 220 usage(); 221 } 222 argc -= optind; 223 argv += optind; 224 225 /* some options make no sense when creating directories */ 226 if (dostrip && dodir) { 227 warnx("-d and -s may not be specified together"); 228 usage(); 229 } 230 231 if (getenv("DONTSTRIP") != NULL) { 232 warnx("DONTSTRIP set - will not strip installed binaries"); 233 dostrip = 0; 234 } 235 236 /* must have at least two arguments, except when creating directories */ 237 if (argc == 0 || (argc == 1 && !dodir)) 238 usage(); 239 240 /* need to make a temp copy so we can compare stripped version */ 241 if (docompare && dostrip) 242 safecopy = 1; 243 244 /* get group and owner id's */ 245 if (group != NULL && !dounpriv) { 246 if (gid_from_group(group, &gid) == -1) { 247 id_t id; 248 if (!parseid(group, &id)) 249 errx(1, "unknown group %s", group); 250 gid = id; 251 } 252 } else 253 gid = (gid_t)-1; 254 255 if (owner != NULL && !dounpriv) { 256 if (uid_from_user(owner, &uid) == -1) { 257 id_t id; 258 if (!parseid(owner, &id)) 259 errx(1, "unknown user %s", owner); 260 uid = id; 261 } 262 } else 263 uid = (uid_t)-1; 264 265 #ifdef _ST_FLAGS_PRESENT_ 266 if (fflags != NULL && !dounpriv) { 267 if (strtofflags(&fflags, &fset, &fclr)) 268 errx(EX_USAGE, "%s: invalid flag", fflags); 269 iflags |= SETFLAGS; 270 } 271 #endif 272 273 if (dodir) { 274 for (; *argv != NULL; ++argv) 275 install_dir(*argv); 276 exit(EX_OK); 277 /* NOTREACHED */ 278 } 279 280 to_name = argv[argc - 1]; 281 no_target = stat(to_name, &to_sb); 282 if (!no_target && S_ISDIR(to_sb.st_mode)) { 283 if (dolink & LN_SYMBOLIC) { 284 if (lstat(to_name, &to_sb) != 0) 285 err(EX_OSERR, "%s vanished", to_name); 286 if (S_ISLNK(to_sb.st_mode)) { 287 if (argc != 2) { 288 errno = ENOTDIR; 289 err(EX_USAGE, "%s", to_name); 290 } 291 install(*argv, to_name, fset, fclr, iflags); 292 exit(EX_OK); 293 } 294 } 295 for (; *argv != to_name; ++argv) 296 install(*argv, to_name, fset, fclr, iflags | DIRECTORY); 297 exit(EX_OK); 298 /* NOTREACHED */ 299 } 300 301 /* can't do file1 file2 directory/file */ 302 if (argc != 2) { 303 if (no_target) 304 warnx("target directory `%s' does not exist", 305 argv[argc - 1]); 306 else 307 warnx("target `%s' is not a directory", 308 argv[argc - 1]); 309 usage(); 310 } 311 312 if (!no_target && !dolink) { 313 if (stat(*argv, &from_sb)) 314 err(EX_OSERR, "%s", *argv); 315 if (!S_ISREG(to_sb.st_mode)) { 316 errno = EFTYPE; 317 err(EX_OSERR, "%s", to_name); 318 } 319 if (to_sb.st_dev == from_sb.st_dev && 320 to_sb.st_ino == from_sb.st_ino) 321 errx(EX_USAGE, 322 "%s and %s are the same file", *argv, to_name); 323 } 324 install(*argv, to_name, fset, fclr, iflags); 325 exit(EX_OK); 326 /* NOTREACHED */ 327 } 328 329 /* 330 * parseid -- 331 * parse uid or gid from arg into id, returning non-zero if successful 332 */ 333 static int 334 parseid(const char *name, id_t *id) 335 { 336 char *ep; 337 errno = 0; 338 *id = (id_t)strtoul(name, &ep, 10); 339 if (errno || *ep != '\0') 340 return (0); 341 return (1); 342 } 343 344 /* 345 * quiet_mktemp -- 346 * mktemp implementation used mkstemp to avoid mktemp warnings. We 347 * really do need mktemp semantics here as we will be creating a link. 348 */ 349 static char * 350 quiet_mktemp(char *template) 351 { 352 int fd; 353 354 if ((fd = mkstemp(template)) == -1) 355 return (NULL); 356 close (fd); 357 if (unlink(template) == -1) 358 err(EX_OSERR, "unlink %s", template); 359 return (template); 360 } 361 362 /* 363 * do_link -- 364 * make a hard link, obeying dorename if set 365 * return -1 on failure 366 */ 367 static int 368 do_link(const char *from_name, const char *to_name, 369 const struct stat *target_sb) 370 { 371 char tmpl[MAXPATHLEN]; 372 int ret; 373 374 if (safecopy && target_sb != NULL) { 375 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 376 /* This usage is safe. */ 377 if (quiet_mktemp(tmpl) == NULL) 378 err(EX_OSERR, "%s: mktemp", tmpl); 379 ret = link(from_name, tmpl); 380 if (ret == 0) { 381 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == 382 -1) { 383 unlink(tmpl); 384 err(EX_OSERR, "%s", to_name); 385 } 386 #ifdef _ST_FLAGS_PRESENT_ 387 if (target_sb->st_flags & NOCHANGEBITS) 388 (void)chflags(to_name, target_sb->st_flags & 389 ~NOCHANGEBITS); 390 #endif 391 if (verbose) 392 printf("install: link %s -> %s\n", 393 from_name, to_name); 394 ret = rename(tmpl, to_name); 395 /* 396 * If rename has posix semantics, then the temporary 397 * file may still exist when from_name and to_name point 398 * to the same file, so unlink it unconditionally. 399 */ 400 (void)unlink(tmpl); 401 } 402 return (ret); 403 } else { 404 if (verbose) 405 printf("install: link %s -> %s\n", 406 from_name, to_name); 407 return (link(from_name, to_name)); 408 } 409 } 410 411 /* 412 * do_symlink -- 413 * Make a symbolic link, obeying dorename if set. Exit on failure. 414 */ 415 static void 416 do_symlink(const char *from_name, const char *to_name, 417 const struct stat *target_sb) 418 { 419 char tmpl[MAXPATHLEN]; 420 421 if (safecopy && target_sb != NULL) { 422 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 423 /* This usage is safe. */ 424 if (quiet_mktemp(tmpl) == NULL) 425 err(EX_OSERR, "%s: mktemp", tmpl); 426 427 if (symlink(from_name, tmpl) == -1) 428 err(EX_OSERR, "symlink %s -> %s", from_name, tmpl); 429 430 if (target_sb->st_mode & S_IFDIR && rmdir(to_name) == -1) { 431 (void)unlink(tmpl); 432 err(EX_OSERR, "%s", to_name); 433 } 434 #ifdef _ST_FLAGS_PRESENT_ 435 if (target_sb->st_flags & NOCHANGEBITS) 436 (void)chflags(to_name, target_sb->st_flags & 437 ~NOCHANGEBITS); 438 #endif 439 if (verbose) 440 printf("install: symlink %s -> %s\n", 441 from_name, to_name); 442 if (rename(tmpl, to_name) == -1) { 443 /* Remove temporary link before exiting. */ 444 (void)unlink(tmpl); 445 err(EX_OSERR, "%s: rename", to_name); 446 } 447 } else { 448 if (verbose) 449 printf("install: symlink %s -> %s\n", 450 from_name, to_name); 451 if (symlink(from_name, to_name) == -1) 452 err(EX_OSERR, "symlink %s -> %s", from_name, to_name); 453 } 454 } 455 456 /* 457 * makelink -- 458 * make a link from source to destination 459 */ 460 static void 461 makelink(const char *from_name, const char *to_name, 462 const struct stat *target_sb) 463 { 464 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; 465 struct stat to_sb; 466 467 /* Try hard links first. */ 468 if (dolink & (LN_HARD|LN_MIXED)) { 469 if (do_link(from_name, to_name, target_sb) == -1) { 470 if ((dolink & LN_HARD) || errno != EXDEV) 471 err(EX_OSERR, "link %s -> %s", from_name, to_name); 472 } else { 473 if (stat(to_name, &to_sb)) 474 err(EX_OSERR, "%s: stat", to_name); 475 if (S_ISREG(to_sb.st_mode)) { 476 /* 477 * XXX: hard links to anything other than 478 * plain files are not metalogged 479 */ 480 int omode; 481 const char *oowner, *ogroup; 482 char *offlags; 483 484 /* 485 * XXX: use underlying perms, unless 486 * overridden on command line. 487 */ 488 omode = mode; 489 if (!haveopt_m) 490 mode = (to_sb.st_mode & 0777); 491 oowner = owner; 492 if (!haveopt_o) 493 owner = NULL; 494 ogroup = group; 495 if (!haveopt_g) 496 group = NULL; 497 offlags = fflags; 498 if (!haveopt_f) 499 fflags = NULL; 500 mode = omode; 501 owner = oowner; 502 group = ogroup; 503 fflags = offlags; 504 } 505 return; 506 } 507 } 508 509 /* Symbolic links. */ 510 if (dolink & LN_ABSOLUTE) { 511 /* Convert source path to absolute. */ 512 if (realpath(from_name, src) == NULL) 513 err(EX_OSERR, "%s: realpath", from_name); 514 do_symlink(src, to_name, target_sb); 515 /* XXX: src may point outside of destdir */ 516 return; 517 } 518 519 if (dolink & LN_RELATIVE) { 520 char *to_name_copy, *cp, *d, *s; 521 522 if (*from_name != '/') { 523 /* this is already a relative link */ 524 do_symlink(from_name, to_name, target_sb); 525 /* XXX: from_name may point outside of destdir. */ 526 return; 527 } 528 529 /* Resolve pathnames. */ 530 if (realpath(from_name, src) == NULL) 531 err(EX_OSERR, "%s: realpath", from_name); 532 533 /* 534 * The last component of to_name may be a symlink, 535 * so use realpath to resolve only the directory. 536 */ 537 to_name_copy = strdup(to_name); 538 if (to_name_copy == NULL) 539 err(EX_OSERR, "%s: strdup", to_name); 540 cp = dirname(to_name_copy); 541 if (realpath(cp, dst) == NULL) 542 err(EX_OSERR, "%s: realpath", cp); 543 /* .. and add the last component. */ 544 if (strcmp(dst, "/") != 0) { 545 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst)) 546 errx(1, "resolved pathname too long"); 547 } 548 strcpy(to_name_copy, to_name); 549 cp = basename(to_name_copy); 550 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst)) 551 errx(1, "resolved pathname too long"); 552 free(to_name_copy); 553 554 /* Trim common path components. */ 555 for (s = src, d = dst; *s == *d; s++, d++) 556 continue; 557 while (*s != '/') 558 s--, d--; 559 560 /* Count the number of directories we need to backtrack. */ 561 for (++d, lnk[0] = '\0'; *d; d++) 562 if (*d == '/') 563 (void)strlcat(lnk, "../", sizeof(lnk)); 564 565 (void)strlcat(lnk, ++s, sizeof(lnk)); 566 567 do_symlink(lnk, to_name, target_sb); 568 /* XXX: Link may point outside of destdir. */ 569 return; 570 } 571 572 /* 573 * If absolute or relative was not specified, try the names the 574 * user provided. 575 */ 576 do_symlink(from_name, to_name, target_sb); 577 /* XXX: from_name may point outside of destdir. */ 578 } 579 580 /* 581 * install -- 582 * build a path name and install the file 583 */ 584 static void 585 install(const char *from_name, const char *to_name, u_long fset, u_long fclr, 586 u_int flags) 587 { 588 struct stat from_sb, temp_sb, to_sb; 589 struct utimbuf utb; 590 int devnull, files_match, from_fd, serrno, target; 591 int tempcopy, temp_fd, to_fd; 592 #ifdef _ST_FLAGS_PRESENT_ 593 u_long nfset; 594 #endif 595 char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN]; 596 597 files_match = 0; 598 from_fd = -1; 599 to_fd = -1; 600 601 /* If try to install NULL file to a directory, fails. */ 602 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) { 603 if (!dolink) { 604 if (stat(from_name, &from_sb)) 605 err(EX_OSERR, "%s", from_name); 606 if (!S_ISREG(from_sb.st_mode)) { 607 errno = EFTYPE; 608 err(EX_OSERR, "%s", from_name); 609 } 610 } 611 /* Build the target path. */ 612 if (flags & DIRECTORY) { 613 (void)snprintf(pathbuf, sizeof(pathbuf), "%s%s%s", 614 to_name, 615 to_name[strlen(to_name) - 1] == '/' ? "" : "/", 616 (p = strrchr(from_name, '/')) ? ++p : from_name); 617 to_name = pathbuf; 618 } 619 devnull = 0; 620 } else { 621 devnull = 1; 622 } 623 624 target = (lstat(to_name, &to_sb) == 0); 625 626 if (dolink) { 627 if (target && !safecopy) { 628 if (to_sb.st_mode & S_IFDIR && rmdir(to_name) == -1) 629 err(EX_OSERR, "%s", to_name); 630 #ifdef _ST_FLAGS_PRESENT_ 631 if (to_sb.st_flags & NOCHANGEBITS) 632 (void)chflags(to_name, 633 to_sb.st_flags & ~NOCHANGEBITS); 634 #endif 635 unlink(to_name); 636 } 637 makelink(from_name, to_name, target ? &to_sb : NULL); 638 return; 639 } 640 641 if (target && !S_ISREG(to_sb.st_mode) && !S_ISLNK(to_sb.st_mode)) { 642 errno = EFTYPE; 643 warn("%s", to_name); 644 return; 645 } 646 647 /* Only copy safe if the target exists. */ 648 tempcopy = safecopy && target; 649 650 if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0) 651 err(EX_OSERR, "%s", from_name); 652 653 /* If we don't strip, we can compare first. */ 654 if (docompare && !dostrip && target && S_ISREG(to_sb.st_mode)) { 655 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 656 err(EX_OSERR, "%s", to_name); 657 if (devnull) 658 files_match = to_sb.st_size == 0; 659 else 660 files_match = !(compare(from_fd, from_name, 661 (size_t)from_sb.st_size, to_fd, 662 to_name, (size_t)to_sb.st_size)); 663 664 /* Close "to" file unless we match. */ 665 if (!files_match) 666 (void)close(to_fd); 667 } 668 669 if (!files_match) { 670 if (tempcopy) { 671 to_fd = create_tempfile(to_name, tempfile, 672 sizeof(tempfile)); 673 if (to_fd < 0) 674 err(EX_OSERR, "%s", tempfile); 675 } else { 676 if ((to_fd = create_newfile(to_name, target, 677 &to_sb)) < 0) 678 err(EX_OSERR, "%s", to_name); 679 if (verbose) 680 (void)printf("install: %s -> %s\n", 681 from_name, to_name); 682 } 683 if (!devnull) 684 copy(from_fd, from_name, to_fd, 685 tempcopy ? tempfile : to_name, from_sb.st_size); 686 } 687 688 if (dostrip) { 689 strip(tempcopy ? tempfile : to_name); 690 691 /* 692 * Re-open our fd on the target, in case we used a strip 693 * that does not work in-place -- like GNU binutils strip. 694 */ 695 close(to_fd); 696 to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0); 697 if (to_fd < 0) 698 err(EX_OSERR, "stripping %s", to_name); 699 } 700 701 /* 702 * Compare the stripped temp file with the target. 703 */ 704 if (docompare && dostrip && target && S_ISREG(to_sb.st_mode)) { 705 temp_fd = to_fd; 706 707 /* Re-open to_fd using the real target name. */ 708 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 709 err(EX_OSERR, "%s", to_name); 710 711 if (fstat(temp_fd, &temp_sb)) { 712 serrno = errno; 713 (void)unlink(tempfile); 714 errno = serrno; 715 err(EX_OSERR, "%s", tempfile); 716 } 717 718 if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd, 719 to_name, (size_t)to_sb.st_size) == 0) { 720 /* 721 * If target has more than one link we need to 722 * replace it in order to snap the extra links. 723 * Need to preserve target file times, though. 724 */ 725 if (to_sb.st_nlink != 1) { 726 utb.actime = to_sb.st_atime; 727 utb.modtime = to_sb.st_mtime; 728 utime(tempfile, &utb); 729 } else { 730 files_match = 1; 731 (void)unlink(tempfile); 732 } 733 (void) close(temp_fd); 734 } 735 } 736 737 /* 738 * Move the new file into place if doing a safe copy 739 * and the files are different (or just not compared). 740 */ 741 if (tempcopy && !files_match) { 742 #ifdef _ST_FLAGS_PRESENT_ 743 /* Try to turn off the immutable bits. */ 744 if (to_sb.st_flags & NOCHANGEBITS) 745 (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS); 746 #endif 747 if (dobackup) { 748 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", to_name, 749 suffix) != strlen(to_name) + strlen(suffix)) { 750 unlink(tempfile); 751 errx(EX_OSERR, "%s: backup filename too long", 752 to_name); 753 } 754 if (verbose) 755 (void)printf("install: %s -> %s\n", to_name, backup); 756 if (rename(to_name, backup) < 0) { 757 serrno = errno; 758 unlink(tempfile); 759 errno = serrno; 760 err(EX_OSERR, "rename: %s to %s", to_name, 761 backup); 762 } 763 } 764 if (verbose) 765 (void)printf("install: %s -> %s\n", from_name, to_name); 766 if (rename(tempfile, to_name) < 0) { 767 serrno = errno; 768 unlink(tempfile); 769 errno = serrno; 770 err(EX_OSERR, "rename: %s to %s", 771 tempfile, to_name); 772 } 773 774 /* Re-open to_fd so we aren't hosed by the rename(2). */ 775 (void) close(to_fd); 776 if ((to_fd = open(to_name, O_RDONLY, 0)) < 0) 777 err(EX_OSERR, "%s", to_name); 778 } 779 780 /* 781 * Preserve the timestamp of the source file if necessary. 782 */ 783 if (dopreserve && !files_match && !devnull) { 784 utb.actime = from_sb.st_atime; 785 utb.modtime = from_sb.st_mtime; 786 utime(to_name, &utb); 787 } 788 789 if (fstat(to_fd, &to_sb) == -1) { 790 serrno = errno; 791 (void)unlink(to_name); 792 errno = serrno; 793 err(EX_OSERR, "%s", to_name); 794 } 795 796 /* 797 * Set owner, group, mode for target; do the chown first, 798 * chown may lose the setuid bits. 799 */ 800 #ifdef _ST_FLAGS_PRESENT_ 801 if (!dounpriv && ((gid != (gid_t)-1 && gid != to_sb.st_gid) || 802 (uid != (uid_t)-1 && uid != to_sb.st_uid) || 803 (mode != to_sb.st_mode))) { 804 /* Try to turn off the immutable bits. */ 805 if (to_sb.st_flags & NOCHANGEBITS) 806 (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS); 807 } 808 #endif 809 810 if (!dounpriv && ( 811 (gid != (gid_t)-1 && gid != to_sb.st_gid) || 812 (uid != (uid_t)-1 && uid != to_sb.st_uid))) 813 if (fchown(to_fd, uid, gid) == -1) { 814 serrno = errno; 815 (void)unlink(to_name); 816 errno = serrno; 817 err(EX_OSERR,"%s: chown/chgrp", to_name); 818 } 819 820 if (mode != to_sb.st_mode) { 821 if (fchmod(to_fd, 822 dounpriv ? mode & (S_IRWXU|S_IRWXG|S_IRWXO) : mode)) { 823 serrno = errno; 824 (void)unlink(to_name); 825 errno = serrno; 826 err(EX_OSERR, "%s: chmod", to_name); 827 } 828 } 829 830 /* 831 * If provided a set of flags, set them, otherwise, preserve the 832 * flags, except for the dump and history flags. The dump flag 833 * is left clear on the target while the history flag from when 834 * the target was created (which is inherited from the target's 835 * parent directory) is retained. 836 */ 837 #ifdef _ST_FLAGS_PRESENT_ 838 if (flags & SETFLAGS) { 839 nfset = (to_sb.st_flags | fset) & ~fclr; 840 } else { 841 nfset = (from_sb.st_flags & ~(UF_NODUMP | UF_NOHISTORY)) | 842 (to_sb.st_flags & UF_NOHISTORY); 843 } 844 845 /* 846 * NFS does not support flags. Ignore EOPNOTSUPP flags if we're just 847 * trying to turn off UF_NODUMP. If we're trying to set real flags, 848 * then warn if the fs doesn't support it, otherwise fail. 849 */ 850 if (!dounpriv && !devnull && fchflags(to_fd, nfset)) { 851 if (flags & SETFLAGS) { 852 if (errno == EOPNOTSUPP) 853 warn("%s: chflags", to_name); 854 else { 855 serrno = errno; 856 (void)unlink(to_name); 857 errno = serrno; 858 err(EX_OSERR, "%s: chflags", to_name); 859 } 860 } 861 } 862 #endif 863 864 (void)close(to_fd); 865 if (!devnull) 866 (void)close(from_fd); 867 } 868 869 /* 870 * compare -- 871 * compare two files; non-zero means files differ 872 */ 873 static int 874 compare(int from_fd, const char *from_name __unused, size_t from_len, 875 int to_fd, const char *to_name __unused, size_t to_len) 876 { 877 char *p, *q; 878 int rv; 879 int done_compare; 880 881 rv = 0; 882 if (from_len != to_len) 883 return 1; 884 885 if (from_len <= MAX_CMP_SIZE) { 886 done_compare = 0; 887 if (trymmap(from_fd) && trymmap(to_fd)) { 888 p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 889 from_fd, (off_t)0); 890 if (p == (char *)MAP_FAILED) 891 goto out; 892 q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, 893 to_fd, (off_t)0); 894 if (q == (char *)MAP_FAILED) { 895 munmap(p, from_len); 896 goto out; 897 } 898 899 rv = memcmp(p, q, from_len); 900 munmap(p, from_len); 901 munmap(q, from_len); 902 done_compare = 1; 903 } 904 out: 905 if (!done_compare) { 906 char buf1[MAXBSIZE]; 907 char buf2[MAXBSIZE]; 908 int n1, n2; 909 910 rv = 0; 911 lseek(from_fd, 0, SEEK_SET); 912 lseek(to_fd, 0, SEEK_SET); 913 while (rv == 0) { 914 n1 = read(from_fd, buf1, sizeof(buf1)); 915 if (n1 == 0) 916 break; /* EOF */ 917 else if (n1 > 0) { 918 n2 = read(to_fd, buf2, n1); 919 if (n2 == n1) 920 rv = memcmp(buf1, buf2, n1); 921 else 922 rv = 1; /* out of sync */ 923 } else 924 rv = 1; /* read failure */ 925 } 926 lseek(from_fd, 0, SEEK_SET); 927 lseek(to_fd, 0, SEEK_SET); 928 } 929 } else 930 rv = 1; /* don't bother in this case */ 931 932 return rv; 933 } 934 935 /* 936 * create_tempfile -- 937 * create a temporary file based on path and open it 938 */ 939 static int 940 create_tempfile(const char *path, char *temp, size_t tsize) 941 { 942 char *p; 943 944 (void)strncpy(temp, path, tsize); 945 temp[tsize - 1] = '\0'; 946 if ((p = strrchr(temp, '/')) != NULL) 947 p++; 948 else 949 p = temp; 950 (void)strncpy(p, "INS@XXXXXX", &temp[tsize - 1] - p); 951 temp[tsize - 1] = '\0'; 952 return (mkstemp(temp)); 953 } 954 955 /* 956 * create_newfile -- 957 * create a new file, overwriting an existing one if necessary 958 */ 959 static int 960 create_newfile(const char *path, int target, struct stat *sbp) 961 { 962 char backup[MAXPATHLEN]; 963 964 if (target) { 965 /* 966 * Unlink now... avoid ETXTBSY errors later. Try to turn 967 * off the append/immutable bits -- if we fail, go ahead, 968 * it might work. 969 */ 970 #ifdef _ST_FLAGS_PRESENT_ 971 if (sbp->st_flags & NOCHANGEBITS) 972 (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS); 973 #endif 974 975 if (dobackup) { 976 if ((size_t)snprintf(backup, MAXPATHLEN, "%s%s", 977 path, suffix) != strlen(path) + strlen(suffix)) 978 errx(EX_OSERR, "%s: backup filename too long", 979 path); 980 (void)snprintf(backup, MAXPATHLEN, "%s%s", 981 path, suffix); 982 if (verbose) 983 (void)printf("install: %s -> %s\n", 984 path, backup); 985 if (rename(path, backup) < 0) 986 err(EX_OSERR, "rename: %s to %s", path, backup); 987 } else 988 unlink(path); 989 } 990 991 return (open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)); 992 } 993 994 /* 995 * copy -- 996 * copy from one file to another 997 */ 998 static void 999 copy(int from_fd, const char *from_name, int to_fd, 1000 const char *to_name, off_t size) 1001 { 1002 int nr, nw; 1003 int serrno; 1004 char *p; 1005 char buf[MAXBSIZE]; 1006 int done_copy; 1007 1008 /* Rewind file descriptors. */ 1009 if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1010 err(EX_OSERR, "lseek: %s", from_name); 1011 if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) 1012 err(EX_OSERR, "lseek: %s", to_name); 1013 1014 /* 1015 * Mmap and write if less than 8M (the limit is so we don't totally 1016 * trash memory on big files. This is really a minor hack, but it 1017 * wins some CPU back. 1018 */ 1019 done_copy = 0; 1020 if (size <= 8 * 1048576 && trymmap(from_fd) && 1021 (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED, 1022 from_fd, (off_t)0)) != (char *)MAP_FAILED) { 1023 nw = write(to_fd, p, size); 1024 if (nw != size) { 1025 serrno = errno; 1026 (void)unlink(to_name); 1027 errno = nw > 0 ? EIO : serrno; 1028 err(EX_OSERR, "%s", to_name); 1029 } 1030 done_copy = 1; 1031 } 1032 if (!done_copy) { 1033 while ((nr = read(from_fd, buf, sizeof(buf))) > 0) { 1034 if ((nw = write(to_fd, buf, nr)) != nr) { 1035 serrno = errno; 1036 (void)unlink(to_name); 1037 errno = nw > 0 ? EIO : serrno; 1038 err(EX_OSERR, "%s", to_name); 1039 } 1040 } 1041 if (nr != 0) { 1042 serrno = errno; 1043 (void)unlink(to_name); 1044 errno = serrno; 1045 err(EX_OSERR, "%s", from_name); 1046 } 1047 } 1048 } 1049 1050 /* 1051 * strip -- 1052 * use strip(1) to strip the target file 1053 */ 1054 static void 1055 strip(const char *to_name) 1056 { 1057 const char *stripbin; 1058 int serrno, status; 1059 1060 switch (fork()) { 1061 case -1: 1062 serrno = errno; 1063 (void)unlink(to_name); 1064 errno = serrno; 1065 err(EX_TEMPFAIL, "fork"); 1066 case 0: 1067 stripbin = getenv("STRIPBIN"); 1068 if (stripbin == NULL) 1069 stripbin = "strip"; 1070 execlp(stripbin, stripbin, to_name, NULL); 1071 err(EX_OSERR, "exec(%s)", stripbin); 1072 default: 1073 if (wait(&status) == -1 || status) { 1074 serrno = errno; 1075 (void)unlink(to_name); 1076 errc(EX_SOFTWARE, serrno, "wait"); 1077 /* NOTREACHED */ 1078 } 1079 } 1080 } 1081 1082 /* 1083 * When doing a concurrent make -j N multiple install's can race the mkdir. 1084 */ 1085 static 1086 int 1087 mkdir_race(const char *path, int nmode) 1088 { 1089 int res; 1090 struct stat sb; 1091 1092 res = mkdir(path, nmode); 1093 if (res < 0 && errno == EEXIST) { 1094 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) 1095 return(0); 1096 res = mkdir(path, nmode); 1097 } 1098 return (res); 1099 } 1100 1101 /* 1102 * install_dir -- 1103 * build directory hierarchy 1104 */ 1105 static void 1106 install_dir(char *path) 1107 { 1108 char *p; 1109 struct stat sb; 1110 int ch; 1111 1112 for (p = path;; ++p) 1113 if (!*p || (p != path && *p == '/')) { 1114 ch = *p; 1115 *p = '\0'; 1116 if (stat(path, &sb)) { 1117 if (errno != ENOENT || 1118 mkdir_race(path, 0755) < 0) { 1119 err(EX_OSERR, "mkdir %s", path); 1120 /* NOTREACHED */ 1121 } else if (verbose) 1122 (void)printf("install: mkdir %s\n", 1123 path); 1124 } else if (!S_ISDIR(sb.st_mode)) 1125 errx(EX_OSERR, "%s exists but is not a directory", path); 1126 if (!(*p = ch)) 1127 break; 1128 } 1129 1130 if (!dounpriv) { 1131 if ((gid != (gid_t)-1 || uid != (uid_t)-1) && 1132 chown(path, uid, gid)) 1133 warn("chown %u:%u %s", uid, gid, path); 1134 /* XXXBED: should we do the chmod in the dounpriv case? */ 1135 if (chmod(path, mode)) 1136 warn("chmod %o %s", mode, path); 1137 } 1138 } 1139 1140 /* 1141 * usage -- 1142 * print a usage message and die 1143 */ 1144 static void 1145 usage(void) 1146 { 1147 fprintf(stderr, 1148 "usage: install [-bCcpSsUv] [-f flags] [-g group] [-m mode] [-o owner]\n" 1149 " [-D dest] [-h hash]\n" 1150 " [-B suffix] [-l linkflags] [-N dbdir]\n" 1151 " file1 file2\n" 1152 " install [-bCcpSsUv] [-B suffix] [-D dest] [-f flags] [-g group]\n" 1153 " [-N dbdir] [-m mode] [-o owner] file1 ... fileN directory\n" 1154 " install -d [-lUv] [-D dest] [-g group] [-m mode] [-N dbdir] [-o owner]\n" 1155 " directory ...\n"); 1156 exit(EX_USAGE); 1157 /* NOTREACHED */ 1158 } 1159 1160 /* 1161 * trymmap -- 1162 * return true (1) if mmap should be tried, false (0) if not. 1163 */ 1164 static int 1165 trymmap(int fd) 1166 { 1167 /* 1168 * The ifdef is for bootstrapping - f_fstypename doesn't exist in 1169 * pre-Lite2-merge systems. 1170 */ 1171 #ifdef MFSNAMELEN 1172 struct statfs stfs; 1173 1174 if (nommap || fstatfs(fd, &stfs) != 0) 1175 return (0); 1176 if (strcmp(stfs.f_fstypename, "ufs") == 0 || 1177 strcmp(stfs.f_fstypename, "cd9660") == 0) 1178 return (1); 1179 #endif 1180 return (0); 1181 } 1182