1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * John B. Roll Jr. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $ 35 * 36 * @(#) Copyright (c) 1990, 1993 The Regents of the University of California. All rights reserved. 37 * @(#)xargs.c 8.1 (Berkeley) 6/6/93 38 * $FreeBSD: head/usr.bin/xargs/xargs.c 359596 2020-04-03 14:03:58Z markj $ 39 */ 40 41 #include <sys/types.h> 42 #include <sys/wait.h> 43 #include <sys/time.h> 44 #include <sys/limits.h> 45 #include <sys/resource.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <langinfo.h> 50 #include <limits.h> 51 #include <locale.h> 52 #include <paths.h> 53 #include <regex.h> 54 #include <signal.h> 55 #include <stdint.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include "pathnames.h" 62 63 static void parse_input(int, char *[]); 64 static void prerun(int, char *[]); 65 #ifndef BOOTSTRAPPING 66 static int prompt(void); 67 #endif 68 static void run(char **); 69 static void usage(void); 70 void strnsubst(char **, const char *, const char *, size_t); 71 static pid_t xwait(int block, int *status); 72 static void xexit(const char *, const int); 73 static void waitchildren(const char *, int); 74 static void pids_init(void); 75 static int pids_empty(void); 76 static int pids_full(void); 77 static void pids_add(pid_t pid); 78 static int pids_remove(pid_t pid); 79 static int findslot(pid_t pid); 80 static int findfreeslot(void); 81 static void clearslot(int slot); 82 83 static char echo[] = _PATH_ECHO; 84 static char **av, **bxp, **ep, **endxp, **xp; 85 static char *argp, *bbp, *ebp, *inpline, *p, *replstr; 86 static const char *eofstr; 87 static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag; 88 static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag; 89 static int curprocs, maxprocs; 90 static pid_t *childpids; 91 92 static volatile int childerr; 93 94 extern char **environ; 95 96 int 97 main(int argc, char *argv[]) 98 { 99 long arg_max; 100 int ch, Jflag, nargs, nflag, nline; 101 size_t linelen; 102 struct rlimit rl; 103 char *endptr; 104 const char *errstr; 105 106 inpline = replstr = NULL; 107 ep = environ; 108 eofstr = ""; 109 Jflag = nflag = 0; 110 111 (void)setlocale(LC_ALL, ""); 112 113 /* 114 * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that 115 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given 116 * that the smallest argument is 2 bytes in length, this means that 117 * the number of arguments is limited to: 118 * 119 * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2. 120 * 121 * We arbitrarily limit the number of arguments to 5000. This is 122 * allowed by POSIX.2 as long as the resulting minimum exec line is 123 * at least LINE_MAX. Realloc'ing as necessary is possible, but 124 * probably not worthwhile. 125 */ 126 nargs = 5000; 127 if ((arg_max = sysconf(_SC_ARG_MAX)) == -1) 128 errx(1, "sysconf(_SC_ARG_MAX) failed"); 129 if (arg_max > INT32_MAX) { 130 /* cap arg_max to int32_t */ 131 arg_max = INT32_MAX; 132 } 133 nline = arg_max - 4 * 1024; 134 while (*ep != NULL) { 135 /* 1 byte for each '\0' */ 136 nline -= strlen(*ep++) + 1 + sizeof(*ep); 137 } 138 maxprocs = 1; 139 while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1) 140 switch (ch) { 141 case 'E': 142 eofstr = optarg; 143 break; 144 case 'I': 145 Jflag = 0; 146 Iflag = 1; 147 Lflag = 1; 148 replstr = optarg; 149 break; 150 case 'J': 151 Iflag = 0; 152 Jflag = 1; 153 replstr = optarg; 154 break; 155 case 'L': 156 Lflag = strtonum(optarg, 0, INT_MAX, &errstr); 157 if (errstr) 158 errx(1, "-L %s: %s", optarg, errstr); 159 break; 160 case 'n': 161 nflag = 1; 162 nargs = strtonum(optarg, 1, INT_MAX, &errstr); 163 if (errstr) 164 errx(1, "-n %s: %s", optarg, errstr); 165 break; 166 case 'o': 167 oflag = 1; 168 break; 169 case 'P': 170 maxprocs = strtonum(optarg, 0, INT_MAX, &errstr); 171 if (errstr) 172 errx(1, "-P %s: %s", optarg, errstr); 173 if (getrlimit(RLIMIT_NPROC, &rl) != 0) 174 errx(1, "getrlimit failed"); 175 if (maxprocs == 0 || maxprocs > rl.rlim_cur) 176 maxprocs = rl.rlim_cur; 177 break; 178 case 'p': 179 #ifndef BOOTSTRAPPING 180 pflag = 1; 181 #endif 182 break; 183 case 'R': 184 Rflag = strtol(optarg, &endptr, 10); 185 if (*endptr != '\0') 186 errx(1, "replacements must be a number"); 187 break; 188 case 'r': 189 /* GNU compatibility */ 190 break; 191 case 'S': 192 Sflag = strtoul(optarg, &endptr, 10); 193 if (*endptr != '\0') 194 errx(1, "replsize must be a number"); 195 break; 196 case 's': 197 nline = strtonum(optarg, 0, INT_MAX, &errstr); 198 if (errstr) 199 errx(1, "-s %s: %s", optarg, errstr); 200 break; 201 case 't': 202 tflag = 1; 203 break; 204 case 'x': 205 xflag = 1; 206 break; 207 case '0': 208 zflag = 1; 209 break; 210 case '?': 211 default: 212 usage(); 213 } 214 argc -= optind; 215 argv += optind; 216 217 if (!Iflag && Rflag) 218 usage(); 219 if (!Iflag && Sflag) 220 usage(); 221 if (Iflag && !Rflag) 222 Rflag = 5; 223 if (Iflag && !Sflag) 224 Sflag = 255; 225 if (xflag && !nflag) 226 usage(); 227 if (Iflag || Lflag) 228 xflag = 1; 229 if (replstr != NULL && *replstr == '\0') 230 errx(1, "replstr may not be empty"); 231 232 pids_init(); 233 234 /* 235 * Allocate pointers for the utility name, the utility arguments, 236 * the maximum arguments to be read from stdin and the trailing 237 * NULL. 238 */ 239 linelen = 1 + argc + nargs + 1; 240 if ((av = bxp = malloc(linelen * sizeof(char *))) == NULL) 241 errx(1, "malloc failed"); 242 243 /* 244 * Use the user's name for the utility as argv[0], just like the 245 * shell. Echo is the default. Set up pointers for the user's 246 * arguments. 247 */ 248 if (*argv == NULL) 249 cnt = strlen(*bxp++ = echo); 250 else { 251 do { 252 if (Jflag && strcmp(*argv, replstr) == 0) { 253 char **avj; 254 jfound = 1; 255 argv++; 256 for (avj = argv; *avj; avj++) 257 cnt += strlen(*avj) + 1; 258 break; 259 } 260 cnt += strlen(*bxp++ = *argv) + 1; 261 } while (*++argv != NULL); 262 } 263 264 /* 265 * Set up begin/end/traversing pointers into the array. The -n 266 * count doesn't include the trailing NULL pointer, so the malloc 267 * added in an extra slot. 268 */ 269 endxp = (xp = bxp) + nargs; 270 271 /* 272 * Allocate buffer space for the arguments read from stdin and the 273 * trailing NULL. Buffer space is defined as the default or specified 274 * space, minus the length of the utility name and arguments. Set up 275 * begin/end/traversing pointers into the array. The -s count does 276 * include the trailing NULL, so the malloc didn't add in an extra 277 * slot. 278 */ 279 nline -= cnt; 280 if (nline <= 0) 281 errx(1, "insufficient space for command"); 282 283 if ((bbp = malloc((size_t)(nline + 1))) == NULL) 284 errx(1, "malloc failed"); 285 ebp = (argp = p = bbp) + nline - 1; 286 for (;;) 287 parse_input(argc, argv); 288 } 289 290 static void 291 parse_input(int argc, char *argv[]) 292 { 293 int ch, foundeof; 294 char **avj; 295 296 foundeof = 0; 297 298 switch (ch = getchar()) { 299 case EOF: 300 /* No arguments since last exec. */ 301 if (p == bbp) 302 xexit(*av, rval); 303 goto arg1; 304 case ' ': 305 case '\t': 306 /* Quotes escape tabs and spaces. */ 307 if (insingle || indouble || zflag) 308 goto addch; 309 goto arg2; 310 case '\0': 311 if (zflag) { 312 /* 313 * Increment 'count', so that nulls will be treated 314 * as end-of-line, as well as end-of-argument. This 315 * is needed so -0 works properly with -I and -L. 316 */ 317 count++; 318 goto arg2; 319 } 320 goto addch; 321 case '\n': 322 if (zflag) 323 goto addch; 324 count++; /* Indicate end-of-line (used by -L) */ 325 326 /* Quotes do not escape newlines. */ 327 arg1: if (insingle || indouble) { 328 warnx("unterminated quote"); 329 xexit(*av, 1); 330 } 331 arg2: 332 foundeof = *eofstr != '\0' && 333 strncmp(argp, eofstr, p - argp) == 0; 334 335 /* Do not make empty args unless they are quoted */ 336 if ((argp != p || wasquoted) && !foundeof) { 337 *p++ = '\0'; 338 *xp++ = argp; 339 if (Iflag) { 340 size_t curlen; 341 342 if (inpline == NULL) 343 curlen = 0; 344 else { 345 /* 346 * If this string is not zero 347 * length, append a space for 348 * separation before the next 349 * argument. 350 */ 351 if ((curlen = strlen(inpline))) 352 strcat(inpline, " "); 353 } 354 curlen++; 355 /* 356 * Allocate enough to hold what we will 357 * be holding in a second, and to append 358 * a space next time through, if we have 359 * to. 360 */ 361 inpline = realloc(inpline, curlen + 2 + 362 strlen(argp)); 363 if (inpline == NULL) { 364 warnx("realloc failed"); 365 xexit(*av, 1); 366 } 367 if (curlen == 1) 368 strcpy(inpline, argp); 369 else 370 strcat(inpline, argp); 371 } 372 } 373 374 /* 375 * If max'd out on args or buffer, or reached EOF, 376 * run the command. If xflag and max'd out on buffer 377 * but not on args, object. Having reached the limit 378 * of input lines, as specified by -L is the same as 379 * maxing out on arguments. 380 */ 381 if (xp == endxp || p > ebp || ch == EOF || 382 (Lflag <= count && xflag) || foundeof) { 383 if (xflag && xp != endxp && p > ebp) { 384 warnx("insufficient space for arguments"); 385 xexit(*av, 1); 386 } 387 if (jfound) { 388 for (avj = argv; *avj; avj++) 389 *xp++ = *avj; 390 } 391 prerun(argc, av); 392 if (ch == EOF || foundeof) 393 xexit(*av, rval); 394 p = bbp; 395 xp = bxp; 396 count = 0; 397 } 398 argp = p; 399 wasquoted = 0; 400 break; 401 case '\'': 402 if (indouble || zflag) 403 goto addch; 404 insingle = !insingle; 405 wasquoted = 1; 406 break; 407 case '"': 408 if (insingle || zflag) 409 goto addch; 410 indouble = !indouble; 411 wasquoted = 1; 412 break; 413 case '\\': 414 if (zflag) 415 goto addch; 416 /* Backslash escapes anything, is escaped by quotes. */ 417 if (!insingle && !indouble && (ch = getchar()) == EOF) { 418 warnx("backslash at EOF"); 419 xexit(*av, 1); 420 } 421 /* FALLTHROUGH */ 422 default: 423 addch: if (p < ebp) { 424 *p++ = ch; 425 break; 426 } 427 428 /* If only one argument, not enough buffer space. */ 429 if (bxp == xp) { 430 warnx("insufficient space for argument"); 431 xexit(*av, 1); 432 } 433 /* Didn't hit argument limit, so if xflag object. */ 434 if (xflag) { 435 warnx("insufficient space for arguments"); 436 xexit(*av, 1); 437 } 438 439 if (jfound) { 440 for (avj = argv; *avj; avj++) 441 *xp++ = *avj; 442 } 443 prerun(argc, av); 444 xp = bxp; 445 cnt = ebp - argp; 446 memcpy(bbp, argp, (size_t)cnt); 447 p = (argp = bbp) + cnt; 448 *p++ = ch; 449 break; 450 } 451 } 452 453 /* 454 * Do things necessary before run()'ing, such as -I substitution, 455 * and then call run(). 456 */ 457 static void 458 prerun(int argc, char *argv[]) 459 { 460 char **tmp, **tmp2, **avj; 461 int repls; 462 463 repls = Rflag; 464 465 if (argc == 0 || repls == 0) { 466 *xp = NULL; 467 run(argv); 468 return; 469 } 470 471 avj = argv; 472 473 /* 474 * Allocate memory to hold the argument list, and 475 * a NULL at the tail. 476 */ 477 tmp = malloc((argc + 1) * sizeof(char *)); 478 if (tmp == NULL) { 479 warnx("malloc failed"); 480 xexit(*argv, 1); 481 } 482 tmp2 = tmp; 483 484 /* 485 * Save the first argument and iterate over it, we 486 * cannot do strnsubst() to it. 487 */ 488 if ((*tmp++ = strdup(*avj++)) == NULL) { 489 warnx("strdup failed"); 490 xexit(*argv, 1); 491 } 492 493 /* 494 * For each argument to utility, if we have not used up 495 * the number of replacements we are allowed to do, and 496 * if the argument contains at least one occurrence of 497 * replstr, call strnsubst(), else just save the string. 498 * Iterations over elements of avj and tmp are done 499 * where appropriate. 500 */ 501 while (--argc) { 502 *tmp = *avj++; 503 if (repls && strstr(*tmp, replstr) != NULL) { 504 strnsubst(tmp++, replstr, inpline, (size_t)Sflag); 505 if (repls > 0) 506 repls--; 507 } else { 508 if ((*tmp = strdup(*tmp)) == NULL) { 509 warnx("strdup failed"); 510 xexit(*argv, 1); 511 } 512 tmp++; 513 } 514 } 515 516 /* 517 * Run it. 518 */ 519 *tmp = NULL; 520 run(tmp2); 521 522 /* 523 * Walk from the tail to the head, free along the way. 524 */ 525 for (; tmp2 != tmp; tmp--) 526 free(*tmp); 527 /* 528 * Now free the list itself. 529 */ 530 free(tmp2); 531 532 /* 533 * Free the input line buffer, if we have one. 534 */ 535 if (inpline != NULL) { 536 free(inpline); 537 inpline = NULL; 538 } 539 } 540 541 static void 542 run(char **argv) 543 { 544 pid_t pid; 545 int fd; 546 char **avec; 547 548 /* 549 * If the user wants to be notified of each command before it is 550 * executed, notify them. If they want the notification to be 551 * followed by a prompt, then prompt them. 552 */ 553 if (tflag || pflag) { 554 (void)fprintf(stderr, "%s", *argv); 555 for (avec = argv + 1; *avec != NULL; ++avec) 556 (void)fprintf(stderr, " %s", *avec); 557 /* 558 * If the user has asked to be prompted, do so. 559 */ 560 #ifndef BOOTSTRAPPING 561 if (pflag) 562 /* 563 * If they asked not to exec, return without execution 564 * but if they asked to, go to the execution. If we 565 * could not open their tty, break the switch and drop 566 * back to -t behaviour. 567 */ 568 switch (prompt()) { 569 case 0: 570 return; 571 case 1: 572 goto exec; 573 case 2: 574 break; 575 } 576 #endif 577 (void)fprintf(stderr, "\n"); 578 (void)fflush(stderr); 579 } 580 #ifndef BOOTSTRAPPING 581 exec: 582 #endif 583 childerr = 0; 584 switch (pid = vfork()) { 585 case -1: 586 warn("vfork"); 587 xexit(*argv, 1); 588 break; 589 case 0: 590 if (oflag) { 591 if ((fd = open(_PATH_TTY, O_RDONLY)) == -1) 592 err(1, "can't open /dev/tty"); 593 } else { 594 fd = open(_PATH_DEVNULL, O_RDONLY); 595 } 596 if (fd > STDIN_FILENO) { 597 if (dup2(fd, STDIN_FILENO) != 0) 598 err(1, "can't dup2 to stdin"); 599 close(fd); 600 } 601 execvp(argv[0], argv); 602 childerr = errno; 603 _exit(1); 604 } 605 pids_add(pid); 606 waitchildren(*argv, 0); 607 } 608 609 /* 610 * Wait for a tracked child to exit and return its pid and exit status. 611 * 612 * Ignores (discards) all untracked child processes. 613 * Returns -1 and sets errno to ECHILD if no tracked children exist. 614 * If block is set, waits indefinitely for a child process to exit. 615 * If block is not set and no children have exited, returns 0 immediately. 616 */ 617 static pid_t 618 xwait(int block, int *status) { 619 pid_t pid; 620 621 if (pids_empty()) { 622 errno = ECHILD; 623 return (-1); 624 } 625 626 while ((pid = waitpid(-1, status, block ? 0 : WNOHANG)) > 0) 627 if (pids_remove(pid)) 628 break; 629 630 return (pid); 631 } 632 633 static void 634 xexit(const char *name, const int exit_code) { 635 waitchildren(name, 1); 636 exit(exit_code); 637 } 638 639 static void 640 waitchildren(const char *name, int waitall) 641 { 642 pid_t pid; 643 int status; 644 int cause_exit = 0; 645 646 while ((pid = xwait(waitall || pids_full(), &status)) > 0) { 647 /* 648 * If we couldn't invoke the utility or if utility exited 649 * because of a signal or with a value of 255, warn (per 650 * POSIX), and then wait until all other children have 651 * exited before exiting 1-125. POSIX requires us to stop 652 * reading if child exits because of a signal or with 255, 653 * but it does not require us to exit immediately; waiting 654 * is preferable to orphaning. 655 */ 656 if (childerr != 0 && cause_exit == 0) { 657 errno = childerr; 658 waitall = 1; 659 cause_exit = errno == ENOENT ? 127 : 126; 660 warn("%s", name); 661 } else if (WIFSIGNALED(status)) { 662 waitall = cause_exit = 1; 663 if (WTERMSIG(status) != SIGPIPE) { 664 if (WTERMSIG(status) < NSIG) 665 warnx("%s terminated by SIG%s", name, 666 sys_signame[WTERMSIG(status)]); 667 else 668 warnx("%s terminated by signal %d", 669 name, WTERMSIG(status)); 670 } 671 } else if (WEXITSTATUS(status) == 255) { 672 waitall = cause_exit = 1; 673 warnx("%s: exited with status 255; aborting", name); 674 } else if (WEXITSTATUS(status)) 675 rval = 1; 676 } 677 678 if (cause_exit) 679 exit(cause_exit); 680 if (pid == -1 && errno != ECHILD) 681 err(1, "waitpid"); 682 } 683 684 #define NOPID (0) 685 686 static void 687 pids_init(void) 688 { 689 int i; 690 691 if ((childpids = malloc(maxprocs * sizeof(*childpids))) == NULL) 692 errx(1, "malloc failed"); 693 694 for (i = 0; i < maxprocs; i++) 695 clearslot(i); 696 } 697 698 static int 699 pids_empty(void) 700 { 701 702 return (curprocs == 0); 703 } 704 705 static int 706 pids_full(void) 707 { 708 709 return (curprocs >= maxprocs); 710 } 711 712 static void 713 pids_add(pid_t pid) 714 { 715 int slot; 716 717 slot = findfreeslot(); 718 childpids[slot] = pid; 719 curprocs++; 720 } 721 722 static int 723 pids_remove(pid_t pid) 724 { 725 int slot; 726 727 if ((slot = findslot(pid)) < 0) 728 return (0); 729 730 clearslot(slot); 731 curprocs--; 732 return (1); 733 } 734 735 static int 736 findfreeslot(void) 737 { 738 int slot; 739 740 if ((slot = findslot(NOPID)) < 0) 741 errx(1, "internal error: no free pid slot"); 742 return (slot); 743 } 744 745 static int 746 findslot(pid_t pid) 747 { 748 int slot; 749 750 for (slot = 0; slot < maxprocs; slot++) 751 if (childpids[slot] == pid) 752 return (slot); 753 return (-1); 754 } 755 756 static void 757 clearslot(int slot) 758 { 759 760 childpids[slot] = NOPID; 761 } 762 763 /* 764 * Prompt the user about running a command. 765 */ 766 #ifndef BOOTSTRAPPING 767 static int 768 prompt(void) 769 { 770 regex_t cre; 771 size_t rsize; 772 int match; 773 char *response; 774 FILE *ttyfp; 775 776 if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL) 777 return (2); /* Indicate that the TTY failed to open. */ 778 (void)fprintf(stderr, "?..."); 779 (void)fflush(stderr); 780 if ((response = fgetln(ttyfp, &rsize)) == NULL || 781 regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) { 782 (void)fclose(ttyfp); 783 return (0); 784 } 785 response[rsize - 1] = '\0'; 786 match = regexec(&cre, response, 0, NULL, 0); 787 (void)fclose(ttyfp); 788 regfree(&cre); 789 return (match == 0); 790 } 791 #endif 792 793 static void 794 usage(void) 795 { 796 797 fprintf(stderr, 798 "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements] [-S replsize]]\n" 799 " [-J replstr] [-L number] [-n number [-x]] [-P maxprocs]\n" 800 " [-s size] [utility [argument ...]]\n"); 801 exit(1); 802 } 803