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