]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/xargs/xargs.c
zfs: merge openzfs/zfs@ad0a55461
[FreeBSD/FreeBSD.git] / usr.bin / 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/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 }