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