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