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