]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/xargs/xargs.c
Merge llvm-project main llvmorg-16-init-18548-gb0daacf58f41
[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         const char *errstr;
128
129         inpline = replstr = NULL;
130         ep = environ;
131         eofstr = "";
132         eoflen = 0;
133         Jflag = nflag = 0;
134
135         (void)setlocale(LC_ALL, "");
136
137         /*
138          * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
139          * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
140          * that the smallest argument is 2 bytes in length, this means that
141          * the number of arguments is limited to:
142          *
143          *       (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
144          *
145          * We arbitrarily limit the number of arguments to 5000.  This is
146          * allowed by POSIX.2 as long as the resulting minimum exec line is
147          * at least LINE_MAX.  Realloc'ing as necessary is possible, but
148          * probably not worthwhile.
149          */
150         nargs = 5000;
151         if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
152                 errx(1, "sysconf(_SC_ARG_MAX) failed");
153         nline = arg_max - 4 * 1024;
154         while (*ep != NULL) {
155                 /* 1 byte for each '\0' */
156                 nline -= strlen(*ep++) + 1 + sizeof(*ep);
157         }
158         maxprocs = 1;
159         while ((ch = getopt_long(argc, argv, optstr, long_options, NULL)) != -1)
160                 switch (ch) {
161                 case 'E':
162                         eofstr = optarg;
163                         eoflen = strlen(eofstr);
164                         break;
165                 case 'I':
166                         Jflag = 0;
167                         Iflag = 1;
168                         Lflag = 1;
169                         replstr = optarg;
170                         break;
171                 case 'J':
172                         Iflag = 0;
173                         Jflag = 1;
174                         replstr = optarg;
175                         break;
176                 case 'L':
177                         Lflag = (int)strtonum(optarg, 0, INT_MAX, &errstr);
178                         if (errstr)
179                                 errx(1, "-%c %s: %s", ch, optarg, errstr);
180                         break;
181                 case 'n':
182                         nflag = 1;
183                         nargs = (int)strtonum(optarg, 1, INT_MAX, &errstr);
184                         if (errstr)
185                                 errx(1, "-%c %s: %s", ch, optarg, errstr);
186                         break;
187                 case 'o':
188                         oflag = 1;
189                         break;
190                 case 'P':
191                         maxprocs = (int)strtonum(optarg, 0, INT_MAX, &errstr);
192                         if (errstr)
193                                 errx(1, "-%c %s: %s", ch, optarg, errstr);
194                         if (getrlimit(RLIMIT_NPROC, &rl) != 0)
195                                 errx(1, "getrlimit failed");
196                         if (maxprocs == 0 || maxprocs > rl.rlim_cur)
197                                 maxprocs = rl.rlim_cur;
198                         break;
199                 case 'p':
200                         pflag = 1;
201                         break;
202                 case 'R':
203                         Rflag = (int)strtonum(optarg, 0, INT_MAX, &errstr);
204                         if (errstr)
205                                 errx(1, "-%c %s: %s", ch, optarg, errstr);
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 + 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
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
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
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
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
655 xexit(const char *name, const int exit_code) {
656         waitchildren(name, 1);
657         exit(exit_code);
658 }
659
660 static void
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
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
714 pids_empty(void)
715 {
716
717         return (curprocs == 0);
718 }
719
720 static int
721 pids_full(void)
722 {
723
724         return (curprocs >= maxprocs);
725 }
726
727 static void
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
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
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
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
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
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
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 }