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