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