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