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