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