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