xref: /freebsd/usr.bin/xargs/xargs.c (revision d411c1d6)
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 }
817