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