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