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