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