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