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