1/* $NetBSD: xinstall.c,v 1.114 2009/11/12 10:10:49 tron Exp $ */ 2 3/* 4 * Copyright (c) 1987, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#if HAVE_NBTOOL_CONFIG_H 33#include "nbtool_config.h" 34#else 35#define HAVE_FUTIMES 1 36#define HAVE_STRUCT_STAT_ST_FLAGS 1 37#endif 38 39#include <sys/cdefs.h> 40#if defined(__COPYRIGHT) && !defined(lint) 41__COPYRIGHT("@(#) Copyright (c) 1987, 1993\ 42 The Regents of the University of California. All rights reserved."); 43#endif /* not lint */ 44 45#if defined(__RCSID) && !defined(lint) 46#if 0 47static char sccsid[] = "@(#)xinstall.c 8.1 (Berkeley) 7/21/93"; 48#else 49__RCSID("$NetBSD: xinstall.c,v 1.114 2009/11/12 10:10:49 tron Exp $"); 50#endif 51#endif /* not lint */ 52 53#define __MKTEMP_OK__ /* All uses of mktemp have been checked */ 54#include <sys/param.h> 55#include <sys/mman.h> 56#include <sys/stat.h> 57#include <sys/wait.h> 58#include <sys/time.h> 59 60#include <ctype.h> 61#include <err.h> 62#include <errno.h> 63#include <fcntl.h> 64#include <grp.h> 65#include <libgen.h> 66#include <paths.h> 67#include <pwd.h> 68#include <stdio.h> 69#include <stdlib.h> 70#include <string.h> 71#include <unistd.h> 72#include <util.h> 73#include <vis.h> 74 75#include <md5.h> 76#include <rmd160.h> 77#include <sha1.h> 78#include <sha2.h> 79 80#include "pathnames.h" 81#include "mtree.h" 82 83#define STRIP_ARGS_MAX 32 84#define BACKUP_SUFFIX ".old" 85 86static int dobackup, dodir, dostrip, dolink, dopreserve, dorename, dounpriv; 87static int haveopt_f, haveopt_g, haveopt_m, haveopt_o; 88static int numberedbackup; 89static int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 90static char pathbuf[MAXPATHLEN]; 91static uid_t uid = -1; 92static gid_t gid = -1; 93static char *group, *owner, *fflags, *tags; 94static FILE *metafp; 95static char *metafile; 96static u_long fileflags; 97static char *stripArgs; 98static char *afterinstallcmd; 99static const char *suffix = BACKUP_SUFFIX; 100static char *destdir; 101 102enum { 103 DIGEST_NONE = 0, 104 DIGEST_MD5, 105 DIGEST_RMD160, 106 DIGEST_SHA1, 107 DIGEST_SHA256, 108 DIGEST_SHA384, 109 DIGEST_SHA512, 110} digesttype = DIGEST_NONE; 111 112static char *digest; 113 114#define LN_ABSOLUTE 0x01 115#define LN_RELATIVE 0x02 116#define LN_HARD 0x04 117#define LN_SYMBOLIC 0x08 118#define LN_MIXED 0x10 119 120#define DIRECTORY 0x01 /* Tell install it's a directory. */ 121#define SETFLAGS 0x02 /* Tell install to set flags. */ 122#define HASUID 0x04 /* Tell install the uid was given */ 123#define HASGID 0x08 /* Tell install the gid was given */ 124 125static void afterinstall(const char *, const char *, int); 126static void backup(const char *); 127static char *copy(int, char *, int, char *, off_t); 128static int do_link(char *, char *); 129static void do_symlink(char *, char *); 130static void install(char *, char *, u_int); 131static void install_dir(char *, u_int); 132static void makelink(char *, char *); 133static void metadata_log(const char *, const char *, struct timeval *, 134 const char *, const char *, off_t); 135static int parseid(char *, id_t *); 136static void strip(char *); 137__dead static void usage(void); 138static char *xbasename(char *); 139static char *xdirname(char *); 140 141int 142main(int argc, char *argv[]) 143{ 144 struct stat from_sb, to_sb; 145 void *set; 146 u_int iflags; 147 int ch, no_target; 148 char *p, *to_name; 149 150 setprogname(argv[0]); 151 152 iflags = 0; 153 while ((ch = getopt(argc, argv, "a:cbB:dD:f:g:h:l:m:M:N:o:prsS:T:U")) 154 != -1) 155 switch((char)ch) { 156 case 'a': 157 afterinstallcmd = strdup(optarg); 158 if (afterinstallcmd == NULL) 159 errx(1, "%s", strerror(ENOMEM)); 160 break; 161 case 'B': 162 suffix = optarg; 163 numberedbackup = 0; 164 { 165 /* Check if given suffix really generates 166 different suffixes - catch e.g. ".%" */ 167 char suffix_expanded0[FILENAME_MAX], 168 suffix_expanded1[FILENAME_MAX]; 169 (void)snprintf(suffix_expanded0, FILENAME_MAX, 170 suffix, 0); 171 (void)snprintf(suffix_expanded1, FILENAME_MAX, 172 suffix, 1); 173 if (strcmp(suffix_expanded0, suffix_expanded1) 174 != 0) 175 numberedbackup = 1; 176 } 177 /* fall through; -B implies -b */ 178 /*FALLTHROUGH*/ 179 case 'b': 180 dobackup = 1; 181 break; 182 case 'c': 183 /* ignored; was "docopy" which is now the default. */ 184 break; 185 case 'd': 186 dodir = 1; 187 break; 188 case 'D': 189 destdir = optarg; 190 break; 191#if ! HAVE_NBTOOL_CONFIG_H 192 case 'f': 193 haveopt_f = 1; 194 fflags = optarg; 195 break; 196#endif 197 case 'g': 198 haveopt_g = 1; 199 group = optarg; 200 break; 201 case 'h': 202 digest = optarg; 203 break; 204 case 'l': 205 for (p = optarg; *p; p++) 206 switch (*p) { 207 case 's': 208 dolink &= ~(LN_HARD|LN_MIXED); 209 dolink |= LN_SYMBOLIC; 210 break; 211 case 'h': 212 dolink &= ~(LN_SYMBOLIC|LN_MIXED); 213 dolink |= LN_HARD; 214 break; 215 case 'm': 216 dolink &= ~(LN_SYMBOLIC|LN_HARD); 217 dolink |= LN_MIXED; 218 break; 219 case 'a': 220 dolink &= ~LN_RELATIVE; 221 dolink |= LN_ABSOLUTE; 222 break; 223 case 'r': 224 dolink &= ~LN_ABSOLUTE; 225 dolink |= LN_RELATIVE; 226 break; 227 default: 228 errx(1, "%c: invalid link type", *p); 229 /* NOTREACHED */ 230 } 231 break; 232 case 'm': 233 haveopt_m = 1; 234 if (!(set = setmode(optarg))) 235 err(1, "Cannot set file mode `%s'", optarg); 236 mode = getmode(set, 0); 237 free(set); 238 break; 239 case 'M': 240 metafile = optarg; 241 break; 242 case 'N': 243 if (! setup_getid(optarg)) 244 errx(1, 245 "Unable to use user and group databases in `%s'", 246 optarg); 247 break; 248 case 'o': 249 haveopt_o = 1; 250 owner = optarg; 251 break; 252 case 'p': 253 dopreserve = 1; 254 break; 255 case 'r': 256 dorename = 1; 257 break; 258 case 'S': 259 stripArgs = strdup(optarg); 260 if (stripArgs == NULL) 261 errx(1, "%s", strerror(ENOMEM)); 262 /* fall through; -S implies -s */ 263 /*FALLTHROUGH*/ 264 case 's': 265 dostrip = 1; 266 break; 267 case 'T': 268 tags = optarg; 269 break; 270 case 'U': 271 dounpriv = 1; 272 break; 273 case '?': 274 default: 275 usage(); 276 } 277 argc -= optind; 278 argv += optind; 279 280 /* strip and link options make no sense when creating directories */ 281 if ((dostrip || dolink) && dodir) 282 usage(); 283 284 /* strip and flags make no sense with links */ 285 if ((dostrip || fflags) && dolink) 286 usage(); 287 288 /* must have at least two arguments, except when creating directories */ 289 if (argc < 2 && !dodir) 290 usage(); 291 292 if (digest) { 293 if (0) { 294 } else if (strcmp(digest, "none") == 0) { 295 digesttype = DIGEST_NONE; 296 } else if (strcmp(digest, "md5") == 0) { 297 digesttype = DIGEST_MD5; 298 } else if (strcmp(digest, "rmd160") == 0) { 299 digesttype = DIGEST_RMD160; 300 } else if (strcmp(digest, "sha1") == 0) { 301 digesttype = DIGEST_SHA1; 302 } else if (strcmp(digest, "sha256") == 0) { 303 digesttype = DIGEST_SHA256; 304 } else if (strcmp(digest, "sha384") == 0) { 305 digesttype = DIGEST_SHA384; 306 } else if (strcmp(digest, "sha512") == 0) { 307 digesttype = DIGEST_SHA512; 308 } else { 309 warnx("unknown digest `%s'", digest); 310 usage(); 311 } 312 } 313 314 /* get group and owner id's */ 315 if (group && !dounpriv) { 316 if (gid_from_group(group, &gid) == -1) { 317 id_t id; 318 if (!parseid(group, &id)) 319 errx(1, "unknown group %s", group); 320 gid = id; 321 } 322 iflags |= HASGID; 323 } 324 if (owner && !dounpriv) { 325 if (uid_from_user(owner, &uid) == -1) { 326 id_t id; 327 if (!parseid(owner, &id)) 328 errx(1, "unknown user %s", owner); 329 uid = id; 330 } 331 iflags |= HASUID; 332 } 333 334#if ! HAVE_NBTOOL_CONFIG_H 335 if (fflags && !dounpriv) { 336 if (string_to_flags(&fflags, &fileflags, NULL)) 337 errx(1, "%s: invalid flag", fflags); 338 /* restore fflags since string_to_flags() changed it */ 339 fflags = flags_to_string(fileflags, "-"); 340 iflags |= SETFLAGS; 341 } 342#endif 343 344 if (metafile) { 345 if ((metafp = fopen(metafile, "a")) == NULL) 346 warn("open %s", metafile); 347 } else 348 digesttype = DIGEST_NONE; 349 350 if (dodir) { 351 for (; *argv != NULL; ++argv) 352 install_dir(*argv, iflags); 353 exit (0); 354 } 355 356 no_target = stat(to_name = argv[argc - 1], &to_sb); 357 if (!no_target && S_ISDIR(to_sb.st_mode)) { 358 for (; *argv != to_name; ++argv) 359 install(*argv, to_name, iflags | DIRECTORY); 360 exit(0); 361 } 362 363 /* can't do file1 file2 directory/file */ 364 if (argc != 2) { 365 errx(EXIT_FAILURE, "the last argument (%s) " 366 "must name an existing directory", argv[argc - 1]); 367 /* NOTREACHED */ 368 } 369 370 if (!no_target) { 371 /* makelink() handles checks for links */ 372 if (!dolink) { 373 if (stat(*argv, &from_sb)) 374 err(1, "%s: stat", *argv); 375 if (!S_ISREG(to_sb.st_mode)) 376 errx(1, "%s: not a regular file", to_name); 377 if (to_sb.st_dev == from_sb.st_dev && 378 to_sb.st_ino == from_sb.st_ino) 379 errx(1, "%s and %s are the same file", *argv, 380 to_name); 381 } 382 /* 383 * Unlink now... avoid ETXTBSY errors later. Try and turn 384 * off the append/immutable bits -- if we fail, go ahead, 385 * it might work. 386 */ 387#if ! HAVE_NBTOOL_CONFIG_H 388#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND) 389 if (to_sb.st_flags & NOCHANGEBITS) 390 (void)chflags(to_name, 391 to_sb.st_flags & ~(NOCHANGEBITS)); 392#endif 393 if (dobackup) 394 backup(to_name); 395 else if (!dorename) 396 (void)unlink(to_name); 397 } 398 install(*argv, to_name, iflags); 399 exit(0); 400} 401 402/* 403 * parseid -- 404 * parse uid or gid from arg into id, returning non-zero if successful 405 */ 406static int 407parseid(char *name, id_t *id) 408{ 409 char *ep; 410 411 errno = 0; 412 *id = (id_t)strtoul(name, &ep, 10); 413 if (errno || *ep != '\0') 414 return (0); 415 return (1); 416} 417 418/* 419 * do_link -- 420 * make a hard link, obeying dorename if set 421 * return -1 on failure 422 */ 423static int 424do_link(char *from_name, char *to_name) 425{ 426 char tmpl[MAXPATHLEN]; 427 int ret; 428 429 if (dorename) { 430 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 431 /* This usage is safe. */ 432 if (mktemp(tmpl) == NULL) 433 err(1, "%s: mktemp", tmpl); 434 ret = link(from_name, tmpl); 435 if (ret == 0) { 436 ret = rename(tmpl, to_name); 437 /* If rename has posix semantics, then the temporary 438 * file may still exist when from_name and to_name point 439 * to the same file, so unlink it unconditionally. 440 */ 441 (void)unlink(tmpl); 442 } 443 return (ret); 444 } else 445 return (link(from_name, to_name)); 446} 447 448/* 449 * do_symlink -- 450 * make a symbolic link, obeying dorename if set 451 * exit on failure 452 */ 453static void 454do_symlink(char *from_name, char *to_name) 455{ 456 char tmpl[MAXPATHLEN]; 457 458 if (dorename) { 459 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 460 /* This usage is safe. */ 461 if (mktemp(tmpl) == NULL) 462 err(1, "%s: mktemp", tmpl); 463 464 if (symlink(from_name, tmpl) == -1) 465 err(1, "symlink %s -> %s", from_name, tmpl); 466 if (rename(tmpl, to_name) == -1) { 467 /* remove temporary link before exiting */ 468 (void)unlink(tmpl); 469 err(1, "%s: rename", to_name); 470 } 471 } else { 472 if (symlink(from_name, to_name) == -1) 473 err(1, "symlink %s -> %s", from_name, to_name); 474 } 475} 476 477/* 478 * makelink -- 479 * make a link from source to destination 480 */ 481static void 482makelink(char *from_name, char *to_name) 483{ 484 char src[MAXPATHLEN], dst[MAXPATHLEN], lnk[MAXPATHLEN]; 485 struct stat to_sb; 486 487 /* Try hard links first */ 488 if (dolink & (LN_HARD|LN_MIXED)) { 489 if (do_link(from_name, to_name) == -1) { 490 if ((dolink & LN_HARD) || errno != EXDEV) 491 err(1, "link %s -> %s", from_name, to_name); 492 } else { 493 if (stat(to_name, &to_sb)) 494 err(1, "%s: stat", to_name); 495 if (S_ISREG(to_sb.st_mode)) { 496 /* XXX: hard links to anything 497 * other than plain files are not 498 * metalogged 499 */ 500 int omode; 501 char *oowner, *ogroup, *offlags; 502 char *dres; 503 504 /* XXX: use underlying perms, 505 * unless overridden on command line. 506 */ 507 omode = mode; 508 if (!haveopt_m) 509 mode = (to_sb.st_mode & 0777); 510 oowner = owner; 511 if (!haveopt_o) 512 owner = NULL; 513 ogroup = group; 514 if (!haveopt_g) 515 group = NULL; 516 offlags = fflags; 517 if (!haveopt_f) 518 fflags = NULL; 519 switch (digesttype) { 520 case DIGEST_MD5: 521 dres = MD5File(from_name, NULL); 522 break; 523 case DIGEST_RMD160: 524 dres = RMD160File(from_name, NULL); 525 break; 526 case DIGEST_SHA1: 527 dres = SHA1File(from_name, NULL); 528 break; 529 case DIGEST_SHA256: 530 dres = SHA256_File(from_name, NULL); 531 break; 532 case DIGEST_SHA384: 533 dres = SHA384_File(from_name, NULL); 534 break; 535 case DIGEST_SHA512: 536 dres = SHA512_File(from_name, NULL); 537 break; 538 default: 539 dres = NULL; 540 } 541 metadata_log(to_name, "file", NULL, NULL, 542 dres, to_sb.st_size); 543 free(dres); 544 mode = omode; 545 owner = oowner; 546 group = ogroup; 547 fflags = offlags; 548 } 549 return; 550 } 551 } 552 553 /* Symbolic links */ 554 if (dolink & LN_ABSOLUTE) { 555 /* Convert source path to absolute */ 556 if (realpath(from_name, src) == NULL) 557 err(1, "%s: realpath", from_name); 558 do_symlink(src, to_name); 559 /* XXX: src may point outside of destdir */ 560 metadata_log(to_name, "link", NULL, src, NULL, 0); 561 return; 562 } 563 564 if (dolink & LN_RELATIVE) { 565 char *cp, *d, *s; 566 567 /* Resolve pathnames */ 568 if (realpath(from_name, src) == NULL) 569 err(1, "%s: realpath", from_name); 570 571 /* 572 * The last component of to_name may be a symlink, 573 * so use realpath to resolve only the directory. 574 */ 575 cp = xdirname(to_name); 576 if (realpath(cp, dst) == NULL) 577 err(1, "%s: realpath", cp); 578 /* .. and add the last component */ 579 if (strcmp(dst, "/") != 0) { 580 if (strlcat(dst, "/", sizeof(dst)) > sizeof(dst)) 581 errx(1, "resolved pathname too long"); 582 } 583 cp = xbasename(to_name); 584 if (strlcat(dst, cp, sizeof(dst)) > sizeof(dst)) 585 errx(1, "resolved pathname too long"); 586 587 /* trim common path components */ 588 for (s = src, d = dst; *s == *d; s++, d++) 589 continue; 590 while (*s != '/') 591 s--, d--; 592 593 /* count the number of directories we need to backtrack */ 594 for (++d, lnk[0] = '\0'; *d; d++) 595 if (*d == '/') 596 (void)strlcat(lnk, "../", sizeof(lnk)); 597 598 (void)strlcat(lnk, ++s, sizeof(lnk)); 599 600 do_symlink(lnk, to_name); 601 /* XXX: lnk may point outside of destdir */ 602 metadata_log(to_name, "link", NULL, lnk, NULL, 0); 603 return; 604 } 605 606 /* 607 * If absolute or relative was not specified, 608 * try the names the user provided 609 */ 610 do_symlink(from_name, to_name); 611 /* XXX: from_name may point outside of destdir */ 612 metadata_log(to_name, "link", NULL, from_name, NULL, 0); 613} 614 615/* 616 * install -- 617 * build a path name and install the file 618 */ 619static void 620install(char *from_name, char *to_name, u_int flags) 621{ 622 struct stat from_sb; 623 struct stat to_sb; 624 struct timeval tv[2]; 625 off_t size; 626 int devnull, from_fd, to_fd, serrno, tmpmode; 627 char *p, tmpl[MAXPATHLEN], *oto_name, *digestresult; 628 629 size = -1; 630 if (!dolink) { 631 /* ensure that from_sb & tv are sane if !dolink */ 632 if (stat(from_name, &from_sb)) 633 err(1, "%s: stat", from_name); 634 size = from_sb.st_size; 635#if BSD4_4 && !HAVE_NBTOOL_CONFIG_H 636 TIMESPEC_TO_TIMEVAL(&tv[0], &from_sb.st_atimespec); 637 TIMESPEC_TO_TIMEVAL(&tv[1], &from_sb.st_mtimespec); 638#else 639 tv[0].tv_sec = from_sb.st_atime; 640 tv[0].tv_usec = 0; 641 tv[1].tv_sec = from_sb.st_mtime; 642 tv[1].tv_usec = 0; 643#endif 644 } 645 646 if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL) != 0) { 647 devnull = 0; 648 if (!dolink) { 649 if (!S_ISREG(from_sb.st_mode)) 650 errx(1, "%s: not a regular file", from_name); 651 } 652 /* Build the target path. */ 653 if (flags & DIRECTORY) { 654 (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s", 655 to_name, 656 (p = strrchr(from_name, '/')) ? ++p : from_name); 657 to_name = pathbuf; 658 } 659 } else { 660 devnull = 1; 661 size = 0; 662#if HAVE_STRUCT_STAT_ST_FLAGS 663 from_sb.st_flags = 0; /* XXX */ 664#endif 665 } 666 667 /* 668 * Unlink now... avoid ETXTBSY errors later. Try and turn 669 * off the append/immutable bits -- if we fail, go ahead, 670 * it might work. 671 */ 672#if ! HAVE_NBTOOL_CONFIG_H 673 if (stat(to_name, &to_sb) == 0 && 674 to_sb.st_flags & (NOCHANGEBITS)) 675 (void)chflags(to_name, to_sb.st_flags & ~(NOCHANGEBITS)); 676#endif 677 if (dorename) { 678 (void)snprintf(tmpl, sizeof(tmpl), "%s.inst.XXXXXX", to_name); 679 oto_name = to_name; 680 to_name = tmpl; 681 } else { 682 oto_name = NULL; /* pacify gcc */ 683 if (dobackup) 684 backup(to_name); 685 else 686 (void)unlink(to_name); 687 } 688 689 if (dolink) { 690 makelink(from_name, dorename ? oto_name : to_name); 691 return; 692 } 693 694 /* Create target. */ 695 if (dorename) { 696 if ((to_fd = mkstemp(to_name)) == -1) 697 err(1, "%s: mkstemp", to_name); 698 } else { 699 if ((to_fd = open(to_name, 700 O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) 701 err(1, "%s: open", to_name); 702 } 703 digestresult = NULL; 704 if (!devnull) { 705 if ((from_fd = open(from_name, O_RDONLY, 0)) < 0) { 706 (void)unlink(to_name); 707 err(1, "%s: open", from_name); 708 } 709 digestresult = 710 copy(from_fd, from_name, to_fd, to_name, from_sb.st_size); 711 (void)close(from_fd); 712 } 713 714 if (dostrip) { 715 strip(to_name); 716 717 /* 718 * Re-open our fd on the target, in case we used a strip 719 * that does not work in-place -- like gnu binutils strip. 720 */ 721 close(to_fd); 722 if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0) 723 err(1, "stripping %s", to_name); 724 725 /* 726 * Recalculate size and digestresult after stripping. 727 */ 728 if (fstat(to_fd, &to_sb) != 0) 729 err(1, "%s: fstat", to_name); 730 size = to_sb.st_size; 731 digestresult = 732 copy(to_fd, to_name, -1, NULL, size); 733 734 } 735 736 if (afterinstallcmd != NULL) { 737 afterinstall(afterinstallcmd, to_name, 1); 738 739 /* 740 * Re-open our fd on the target, in case we used an 741 * after-install command that does not work in-place 742 */ 743 close(to_fd); 744 if ((to_fd = open(to_name, O_RDONLY, S_IRUSR | S_IWUSR)) < 0) 745 err(1, "running after install command on %s", to_name); 746 } 747 748 /* 749 * Set owner, group, mode for target; do the chown first, 750 * chown may lose the setuid bits. 751 */ 752 if (!dounpriv && 753 (flags & (HASUID | HASGID)) && fchown(to_fd, uid, gid) == -1) { 754 serrno = errno; 755 (void)unlink(to_name); 756 errx(1, "%s: chown/chgrp: %s", to_name, strerror(serrno)); 757 } 758 tmpmode = mode; 759 if (dounpriv) 760 tmpmode &= S_IRWXU|S_IRWXG|S_IRWXO; 761 if (fchmod(to_fd, tmpmode) == -1) { 762 serrno = errno; 763 (void)unlink(to_name); 764 errx(1, "%s: chmod: %s", to_name, strerror(serrno)); 765 } 766 767 /* 768 * Preserve the date of the source file. 769 */ 770 if (dopreserve) { 771#if HAVE_FUTIMES 772 if (futimes(to_fd, tv) == -1) 773 warn("%s: futimes", to_name); 774#else 775 if (utimes(to_name, tv) == -1) 776 warn("%s: utimes", to_name); 777#endif 778 } 779 780 (void)close(to_fd); 781 782 if (dorename) { 783 if (rename(to_name, oto_name) == -1) 784 err(1, "%s: rename", to_name); 785 to_name = oto_name; 786 } 787 788 /* 789 * If provided a set of flags, set them, otherwise, preserve the 790 * flags, except for the dump flag. 791 */ 792#if ! HAVE_NBTOOL_CONFIG_H 793 if (!dounpriv && chflags(to_name, 794 flags & SETFLAGS ? fileflags : from_sb.st_flags & ~UF_NODUMP) == -1) 795 { 796 if (errno != EOPNOTSUPP || (from_sb.st_flags & ~UF_NODUMP) != 0) 797 warn("%s: chflags", to_name); 798 } 799#endif 800 801 metadata_log(to_name, "file", tv, NULL, digestresult, size); 802 free(digestresult); 803} 804 805/* 806 * copy -- 807 * copy from one file to another, returning a digest. 808 * 809 * If to_fd < 0, just calculate a digest, don't copy. 810 */ 811static char * 812copy(int from_fd, char *from_name, int to_fd, char *to_name, off_t size) 813{ 814 ssize_t nr, nw; 815 int serrno; 816 u_char *p; 817 u_char buf[MAXBSIZE]; 818 MD5_CTX ctxMD5; 819 RMD160_CTX ctxRMD160; 820 SHA1_CTX ctxSHA1; 821 SHA256_CTX ctxSHA256; 822 SHA384_CTX ctxSHA384; 823 SHA512_CTX ctxSHA512; 824 825 switch (digesttype) { 826 case DIGEST_MD5: 827 MD5Init(&ctxMD5); 828 break; 829 case DIGEST_RMD160: 830 RMD160Init(&ctxRMD160); 831 break; 832 case DIGEST_SHA1: 833 SHA1Init(&ctxSHA1); 834 break; 835 case DIGEST_SHA256: 836 SHA256_Init(&ctxSHA256); 837 break; 838 case DIGEST_SHA384: 839 SHA384_Init(&ctxSHA384); 840 break; 841 case DIGEST_SHA512: 842 SHA512_Init(&ctxSHA512); 843 break; 844 case DIGEST_NONE: 845 if (to_fd < 0) 846 return NULL; /* no need to do anything */ 847 default: 848 break; 849 } 850 /* 851 * There's no reason to do anything other than close the file 852 * now if it's empty, so let's not bother. 853 */ 854 if (size > 0) { 855 856 /* 857 * Mmap and write if less than 8M (the limit is so we 858 * don't totally trash memory on big files). This is 859 * really a minor hack, but it wins some CPU back. 860 */ 861 862 if (size <= 8 * 1048576) { 863 if ((p = mmap(NULL, (size_t)size, PROT_READ, 864 MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) 865 == MAP_FAILED) { 866 goto mmap_failed; 867 } 868#if defined(MADV_SEQUENTIAL) && !defined(__APPLE__) 869 if (madvise(p, (size_t)size, MADV_SEQUENTIAL) == -1 870 && errno != EOPNOTSUPP) 871 warnx("madvise: %s", strerror(errno)); 872#endif 873 874 if (to_fd >= 0 && write(to_fd, p, size) != size) { 875 serrno = errno; 876 (void)unlink(to_name); 877 errx(1, "%s: write: %s", 878 to_name, strerror(serrno)); 879 } 880 switch (digesttype) { 881 case DIGEST_MD5: 882 MD5Update(&ctxMD5, p, size); 883 break; 884 case DIGEST_RMD160: 885 RMD160Update(&ctxRMD160, p, size); 886 break; 887 case DIGEST_SHA1: 888 SHA1Update(&ctxSHA1, p, size); 889 break; 890 case DIGEST_SHA256: 891 SHA256_Update(&ctxSHA256, p, size); 892 break; 893 case DIGEST_SHA384: 894 SHA384_Update(&ctxSHA384, p, size); 895 break; 896 case DIGEST_SHA512: 897 SHA512_Update(&ctxSHA512, p, size); 898 break; 899 default: 900 break; 901 } 902 (void)munmap(p, size); 903 } else { 904 mmap_failed: 905 while ((nr = read(from_fd, buf, sizeof(buf))) > 0) { 906 if (to_fd >= 0 && 907 (nw = write(to_fd, buf, nr)) != nr) { 908 serrno = errno; 909 (void)unlink(to_name); 910 errx(1, "%s: write: %s", to_name, 911 strerror(nw > 0 ? EIO : serrno)); 912 } 913 switch (digesttype) { 914 case DIGEST_MD5: 915 MD5Update(&ctxMD5, buf, nr); 916 break; 917 case DIGEST_RMD160: 918 RMD160Update(&ctxRMD160, buf, nr); 919 break; 920 case DIGEST_SHA1: 921 SHA1Update(&ctxSHA1, buf, nr); 922 break; 923 case DIGEST_SHA256: 924 SHA256_Update(&ctxSHA256, buf, nr); 925 break; 926 case DIGEST_SHA384: 927 SHA384_Update(&ctxSHA384, buf, nr); 928 break; 929 case DIGEST_SHA512: 930 SHA512_Update(&ctxSHA512, buf, nr); 931 break; 932 default: 933 break; 934 } 935 } 936 if (nr != 0) { 937 serrno = errno; 938 (void)unlink(to_name); 939 errx(1, "%s: read: %s", from_name, strerror(serrno)); 940 } 941 } 942 } 943 switch (digesttype) { 944 case DIGEST_MD5: 945 return MD5End(&ctxMD5, NULL); 946 case DIGEST_RMD160: 947 return RMD160End(&ctxRMD160, NULL); 948 case DIGEST_SHA1: 949 return SHA1End(&ctxSHA1, NULL); 950 case DIGEST_SHA256: 951 return SHA256_End(&ctxSHA256, NULL); 952 case DIGEST_SHA384: 953 return SHA384_End(&ctxSHA384, NULL); 954 case DIGEST_SHA512: 955 return SHA512_End(&ctxSHA512, NULL); 956 default: 957 return NULL; 958 } 959} 960 961/* 962 * strip -- 963 * use strip(1) to strip the target file 964 */ 965static void 966strip(char *to_name) 967{ 968 static const char exec_failure[] = ": exec of strip failed: "; 969 int serrno, status; 970 const char * volatile stripprog, *progname; 971 char *cmd; 972 973 if ((stripprog = getenv("STRIP")) == NULL || *stripprog == '\0') { 974#ifdef TARGET_STRIP 975 stripprog = TARGET_STRIP; 976#else 977 stripprog = _PATH_STRIP; 978#endif 979 } 980 981 cmd = NULL; 982 983 if (stripArgs) { 984 /* 985 * Build up a command line and let /bin/sh 986 * parse the arguments. 987 */ 988 int ret = asprintf(&cmd, "%s %s %s", stripprog, stripArgs, 989 to_name); 990 991 if (ret == -1 || cmd == NULL) 992 err(1, "asprintf failed"); 993 } 994 995 switch (vfork()) { 996 case -1: 997 serrno = errno; 998 (void)unlink(to_name); 999 errx(1, "vfork: %s", strerror(serrno)); 1000 /*NOTREACHED*/ 1001 case 0: 1002 1003 if (stripArgs) 1004 execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); 1005 else 1006 execlp(stripprog, "strip", to_name, NULL); 1007 1008 progname = getprogname(); 1009 write(STDERR_FILENO, progname, strlen(progname)); 1010 write(STDERR_FILENO, exec_failure, strlen(exec_failure)); 1011 write(STDERR_FILENO, stripprog, strlen(stripprog)); 1012 write(STDERR_FILENO, "\n", 1); 1013 _exit(1); 1014 /*NOTREACHED*/ 1015 default: 1016 if (wait(&status) == -1 || status) 1017 (void)unlink(to_name); 1018 } 1019 1020 free(cmd); 1021} 1022 1023/* 1024 * afterinstall -- 1025 * run provided command on the target file or directory after it's been 1026 * installed and stripped, but before permissions are set or it's renamed 1027 */ 1028static void 1029afterinstall(const char *command, const char *to_name, int errunlink) 1030{ 1031 int serrno, status; 1032 char *cmd; 1033 1034 switch (vfork()) { 1035 case -1: 1036 serrno = errno; 1037 if (errunlink) 1038 (void)unlink(to_name); 1039 errx(1, "vfork: %s", strerror(serrno)); 1040 /*NOTREACHED*/ 1041 case 0: 1042 /* 1043 * build up a command line and let /bin/sh 1044 * parse the arguments 1045 */ 1046 cmd = (char*)malloc(sizeof(char)* 1047 (2+strlen(command)+ 1048 strlen(to_name))); 1049 1050 if (cmd == NULL) 1051 errx(1, "%s", strerror(ENOMEM)); 1052 1053 sprintf(cmd, "%s %s", command, to_name); 1054 1055 execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); 1056 1057 warn("%s: exec of after install command", command); 1058 _exit(1); 1059 /*NOTREACHED*/ 1060 default: 1061 if ((wait(&status) == -1 || status) && errunlink) 1062 (void)unlink(to_name); 1063 } 1064} 1065 1066/* 1067 * backup -- 1068 * backup file "to_name" to to_name.suffix 1069 * if suffix contains a "%", it's taken as a printf(3) pattern 1070 * used for a numbered backup. 1071 */ 1072static void 1073backup(const char *to_name) 1074{ 1075 char bname[FILENAME_MAX]; 1076 1077 if (numberedbackup) { 1078 /* Do numbered backup */ 1079 int cnt; 1080 char suffix_expanded[FILENAME_MAX]; 1081 1082 cnt=0; 1083 do { 1084 (void)snprintf(suffix_expanded, FILENAME_MAX, suffix, 1085 cnt); 1086 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, 1087 suffix_expanded); 1088 cnt++; 1089 } while (access(bname, F_OK) == 0); 1090 } else { 1091 /* Do simple backup */ 1092 (void)snprintf(bname, FILENAME_MAX, "%s%s", to_name, suffix); 1093 } 1094 1095 (void)rename(to_name, bname); 1096} 1097 1098/* 1099 * install_dir -- 1100 * build directory hierarchy 1101 */ 1102static void 1103install_dir(char *path, u_int flags) 1104{ 1105 char *p; 1106 struct stat sb; 1107 int ch; 1108 1109 for (p = path;; ++p) 1110 if (!*p || (p != path && *p == '/')) { 1111 ch = *p; 1112 *p = '\0'; 1113 if (mkdir(path, 0777) < 0) { 1114 /* 1115 * Can't create; path exists or no perms. 1116 * stat() path to determine what's there now. 1117 */ 1118 int sverrno; 1119 sverrno = errno; 1120 if (stat(path, &sb) < 0) { 1121 /* Not there; use mkdir()s error */ 1122 errno = sverrno; 1123 err(1, "%s: mkdir", path); 1124 } 1125 if (!S_ISDIR(sb.st_mode)) { 1126 errx(1, 1127 "%s exists but is not a directory", 1128 path); 1129 } 1130 } 1131 if (!(*p = ch)) 1132 break; 1133 } 1134 1135 if (afterinstallcmd != NULL) 1136 afterinstall(afterinstallcmd, path, 0); 1137 1138 if (!dounpriv && ( 1139 ((flags & (HASUID | HASGID)) && chown(path, uid, gid) == -1) 1140 || chmod(path, mode) == -1 )) { 1141 warn("%s: chown/chmod", path); 1142 } 1143 metadata_log(path, "dir", NULL, NULL, NULL, 0); 1144} 1145 1146/* 1147 * metadata_log -- 1148 * if metafp is not NULL, output mtree(8) full path name and settings to 1149 * metafp, to allow permissions to be set correctly by other tools, 1150 * or to allow integrity checks to be performed. 1151 */ 1152static void 1153metadata_log(const char *path, const char *type, struct timeval *tv, 1154 const char *slink, const char *digestresult, off_t size) 1155{ 1156 static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; 1157 const char *p; 1158 char *buf; 1159 size_t destlen; 1160 struct flock metalog_lock; 1161 1162 if (!metafp) 1163 return; 1164 buf = (char *)malloc(4 * strlen(path) + 1); /* buf for strsvis(3) */ 1165 if (buf == NULL) { 1166 warnx("%s", strerror(ENOMEM)); 1167 return; 1168 } 1169 /* lock log file */ 1170 metalog_lock.l_start = 0; 1171 metalog_lock.l_len = 0; 1172 metalog_lock.l_whence = SEEK_SET; 1173 metalog_lock.l_type = F_WRLCK; 1174 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { 1175 warn("can't lock %s", metafile); 1176 free(buf); 1177 return; 1178 } 1179 1180 p = path; /* remove destdir */ 1181 if (destdir) { 1182 destlen = strlen(destdir); 1183 if (strncmp(p, destdir, destlen) == 0 && 1184 (p[destlen] == '/' || p[destlen] == '\0')) 1185 p += destlen; 1186 } 1187 while (*p && *p == '/') /* remove leading /s */ 1188 p++; 1189 strsvis(buf, p, VIS_CSTYLE, extra); /* encode name */ 1190 p = buf; 1191 /* print details */ 1192 fprintf(metafp, ".%s%s type=%s", *p ? "/" : "", p, type); 1193 if (owner) 1194 fprintf(metafp, " uname=%s", owner); 1195 if (group) 1196 fprintf(metafp, " gname=%s", group); 1197 fprintf(metafp, " mode=%#o", mode); 1198 if (slink) { 1199 strsvis(buf, slink, VIS_CSTYLE, extra); /* encode link */ 1200 fprintf(metafp, " link=%s", buf); 1201 } 1202 if (*type == 'f') /* type=file */ 1203 fprintf(metafp, " size=%lld", (long long)size); 1204 if (tv != NULL && dopreserve) 1205 fprintf(metafp, " time=%lld.%ld", 1206 (long long)tv[1].tv_sec, (long)tv[1].tv_usec); 1207 if (digestresult && digest) 1208 fprintf(metafp, " %s=%s", digest, digestresult); 1209 if (fflags) 1210 fprintf(metafp, " flags=%s", fflags); 1211 if (tags) 1212 fprintf(metafp, " tags=%s", tags); 1213 fputc('\n', metafp); 1214 fflush(metafp); /* flush output */ 1215 /* unlock log file */ 1216 metalog_lock.l_type = F_UNLCK; 1217 if (fcntl(fileno(metafp), F_SETLKW, &metalog_lock) == -1) { 1218 warn("can't unlock %s", metafile); 1219 } 1220 free(buf); 1221} 1222 1223/* 1224 * xbasename -- 1225 * libc basename(3) that returns a pointer to a static buffer 1226 * instead of overwriting that passed-in string. 1227 */ 1228static char * 1229xbasename(char *path) 1230{ 1231 static char tmp[MAXPATHLEN]; 1232 1233 (void)strlcpy(tmp, path, sizeof(tmp)); 1234 return (basename(tmp)); 1235} 1236 1237/* 1238 * xdirname -- 1239 * libc dirname(3) that returns a pointer to a static buffer 1240 * instead of overwriting that passed-in string. 1241 */ 1242static char * 1243xdirname(char *path) 1244{ 1245 static char tmp[MAXPATHLEN]; 1246 1247 (void)strlcpy(tmp, path, sizeof(tmp)); 1248 return (dirname(tmp)); 1249} 1250 1251/* 1252 * usage -- 1253 * print a usage message and die 1254 */ 1255static void 1256usage(void) 1257{ 1258 const char *prog; 1259 1260 prog = getprogname(); 1261 1262 (void)fprintf(stderr, 1263"usage: %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n" 1264" [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group] \n" 1265" [-l linkflags] [-h hash] [-S stripflags] file1 file2\n" 1266" %s [-Ubcprs] [-M log] [-D dest] [-T tags] [-B suffix]\n" 1267" [-a aftercmd] [-f flags] [-m mode] [-N dbdir] [-o owner] [-g group]\n" 1268" [-l linkflags] [-h hash] [-S stripflags] file1 ... fileN directory\n" 1269" %s -d [-Up] [-M log] [-D dest] [-T tags] [-a aftercmd] [-m mode]\n" 1270" [-N dbdir] [-o owner] [-g group] directory ...\n", 1271 prog, prog, prog); 1272 exit(1); 1273} 1274