xref: /freebsd/usr.bin/xargs/xargs.c (revision 729362425c09cf6b362366aabc6fb547eee8035a)
1 /*-
2  * Copyright (c) 1990, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * John B. Roll Jr.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
37  */
38 
39 #ifndef lint
40 static const char copyright[] =
41 "@(#) Copyright (c) 1990, 1993\n\
42 	The Regents of the University of California.  All rights reserved.\n";
43 #endif /* not lint */
44 
45 #if 0
46 #ifndef lint
47 static char sccsid[] = "@(#)xargs.c	8.1 (Berkeley) 6/6/93";
48 #endif /* not lint */
49 #endif
50 
51 #include <sys/cdefs.h>
52 __FBSDID("$FreeBSD$");
53 
54 #include <sys/param.h>
55 #include <sys/wait.h>
56 
57 #include <err.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #if (__FreeBSD_version >= 450002 && __FreeBSD_version < 500000) || \
61     __FreeBSD_version >= 500017
62 #include <langinfo.h>
63 #endif
64 #include <locale.h>
65 #include <paths.h>
66 #include <regex.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71 
72 #include "pathnames.h"
73 
74 static void	parse_input(int, char *[]);
75 static void	prerun(int, char *[]);
76 static int	prompt(void);
77 static void	run(char **);
78 static void	usage(void);
79 void		strnsubst(char **, const char *, const char *, size_t);
80 static void	waitchildren(const char *, int);
81 
82 static char echo[] = _PATH_ECHO;
83 static char **av, **bxp, **ep, **exp, **xp;
84 static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
85 static const char *eofstr;
86 static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
87 static int cnt, Iflag, jfound, Lflag, wasquoted, xflag;
88 static int curprocs, maxprocs;
89 
90 static volatile int childerr;
91 
92 extern char **environ;
93 
94 int
95 main(int argc, char *argv[])
96 {
97 	long arg_max;
98 	int ch, Jflag, nargs, nflag, nline;
99 	size_t linelen;
100 	char *endptr;
101 
102 	inpline = replstr = NULL;
103 	ep = environ;
104 	eofstr = "";
105 	Jflag = nflag = 0;
106 
107 	(void)setlocale(LC_MESSAGES, "");
108 
109 	/*
110 	 * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
111 	 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
112 	 * that the smallest argument is 2 bytes in length, this means that
113 	 * the number of arguments is limited to:
114 	 *
115 	 *	 (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
116 	 *
117 	 * We arbitrarily limit the number of arguments to 5000.  This is
118 	 * allowed by POSIX.2 as long as the resulting minimum exec line is
119 	 * at least LINE_MAX.  Realloc'ing as necessary is possible, but
120 	 * probably not worthwhile.
121 	 */
122 	nargs = 5000;
123 	if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
124 		errx(1, "sysconf(_SC_ARG_MAX) failed");
125 	nline = arg_max - 4 * 1024;
126 	while (*ep != NULL) {
127 		/* 1 byte for each '\0' */
128 		nline -= strlen(*ep++) + 1 + sizeof(*ep);
129 	}
130 	maxprocs = 1;
131 	while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:s:tx")) != -1)
132 		switch(ch) {
133 		case 'E':
134 			eofstr = optarg;
135 			break;
136 		case 'I':
137 			Jflag = 0;
138 			Iflag = 1;
139 			Lflag = 1;
140 			replstr = optarg;
141 			break;
142 		case 'J':
143 			Iflag = 0;
144 			Jflag = 1;
145 			replstr = optarg;
146 			break;
147 		case 'L':
148 			Lflag = atoi(optarg);
149 			break;
150 		case 'n':
151 			nflag = 1;
152 			if ((nargs = atoi(optarg)) <= 0)
153 				errx(1, "illegal argument count");
154 			break;
155 		case 'o':
156 			oflag = 1;
157 			break;
158 		case 'P':
159 			if ((maxprocs = atoi(optarg)) <= 0)
160 				errx(1, "max. processes must be >0");
161 			break;
162 		case 'p':
163 			pflag = 1;
164 			break;
165 		case 'R':
166 			Rflag = strtol(optarg, &endptr, 10);
167 			if (*endptr != '\0')
168 				errx(1, "replacements must be a number");
169 			break;
170 		case 's':
171 			nline = atoi(optarg);
172 			break;
173 		case 't':
174 			tflag = 1;
175 			break;
176 		case 'x':
177 			xflag = 1;
178 			break;
179 		case '0':
180 			zflag = 1;
181 			break;
182 		case '?':
183 		default:
184 			usage();
185 	}
186 	argc -= optind;
187 	argv += optind;
188 
189 	if (!Iflag && Rflag)
190 		usage();
191 	if (Iflag && !Rflag)
192 		Rflag = 5;
193 	if (xflag && !nflag)
194 		usage();
195 	if (Iflag || Lflag)
196 		xflag = 1;
197 	if (replstr != NULL && *replstr == '\0')
198 		errx(1, "replstr may not be empty");
199 
200 	/*
201 	 * Allocate pointers for the utility name, the utility arguments,
202 	 * the maximum arguments to be read from stdin and the trailing
203 	 * NULL.
204 	 */
205 	linelen = 1 + argc + nargs + 1;
206 	if ((av = bxp = malloc(linelen * sizeof(char **))) == NULL)
207 		errx(1, "malloc failed");
208 
209 	/*
210 	 * Use the user's name for the utility as argv[0], just like the
211 	 * shell.  Echo is the default.  Set up pointers for the user's
212 	 * arguments.
213 	 */
214 	if (*argv == NULL)
215 		cnt = strlen(*bxp++ = echo);
216 	else {
217 		do {
218 			if (Jflag && strcmp(*argv, replstr) == 0) {
219 				char **avj;
220 				jfound = 1;
221 				argv++;
222 				for (avj = argv; *avj; avj++)
223 					cnt += strlen(*avj) + 1;
224 				break;
225 			}
226 			cnt += strlen(*bxp++ = *argv) + 1;
227 		} while (*++argv != NULL);
228 	}
229 
230 	/*
231 	 * Set up begin/end/traversing pointers into the array.  The -n
232 	 * count doesn't include the trailing NULL pointer, so the malloc
233 	 * added in an extra slot.
234 	 */
235 	exp = (xp = bxp) + nargs;
236 
237 	/*
238 	 * Allocate buffer space for the arguments read from stdin and the
239 	 * trailing NULL.  Buffer space is defined as the default or specified
240 	 * space, minus the length of the utility name and arguments.  Set up
241 	 * begin/end/traversing pointers into the array.  The -s count does
242 	 * include the trailing NULL, so the malloc didn't add in an extra
243 	 * slot.
244 	 */
245 	nline -= cnt;
246 	if (nline <= 0)
247 		errx(1, "insufficient space for command");
248 
249 	if ((bbp = malloc((size_t)(nline + 1))) == NULL)
250 		errx(1, "malloc failed");
251 	ebp = (argp = p = bbp) + nline - 1;
252 	for (;;)
253 		parse_input(argc, argv);
254 }
255 
256 static void
257 parse_input(int argc, char *argv[])
258 {
259 	int ch, foundeof;
260 	char **avj;
261 
262 	foundeof = 0;
263 
264 	switch(ch = getchar()) {
265 	case EOF:
266 		/* No arguments since last exec. */
267 		if (p == bbp) {
268 			waitchildren(*argv, 1);
269 			exit(rval);
270 		}
271 		goto arg1;
272 	case ' ':
273 	case '\t':
274 		/* Quotes escape tabs and spaces. */
275 		if (insingle || indouble || zflag)
276 			goto addch;
277 		goto arg2;
278 	case '\0':
279 		if (zflag)
280 			goto arg2;
281 		goto addch;
282 	case '\n':
283 		count++;
284 		if (zflag)
285 			goto addch;
286 
287 		/* Quotes do not escape newlines. */
288 arg1:		if (insingle || indouble)
289 			errx(1, "unterminated quote");
290 arg2:
291 		foundeof = *eofstr != '\0' &&
292 		    strcmp(argp, eofstr) == 0;
293 
294 		/* Do not make empty args unless they are quoted */
295 		if ((argp != p || wasquoted) && !foundeof) {
296 			*p++ = '\0';
297 			*xp++ = argp;
298 			if (Iflag) {
299 				size_t curlen;
300 
301 				if (inpline == NULL)
302 					curlen = 0;
303 				else {
304 					/*
305 					 * If this string is not zero
306 					 * length, append a space for
307 					 * separation before the next
308 					 * argument.
309 					 */
310 					if ((curlen = strlen(inpline)))
311 						strcat(inpline, " ");
312 				}
313 				curlen++;
314 				/*
315 				 * Allocate enough to hold what we will
316 				 * be holding in a second, and to append
317 				 * a space next time through, if we have
318 				 * to.
319 				 */
320 				inpline = realloc(inpline, curlen + 2 +
321 				    strlen(argp));
322 				if (inpline == NULL)
323 					errx(1, "realloc failed");
324 				if (curlen == 1)
325 					strcpy(inpline, argp);
326 				else
327 					strcat(inpline, argp);
328 			}
329 		}
330 
331 		/*
332 		 * If max'd out on args or buffer, or reached EOF,
333 		 * run the command.  If xflag and max'd out on buffer
334 		 * but not on args, object.  Having reached the limit
335 		 * of input lines, as specified by -L is the same as
336 		 * maxing out on arguments.
337 		 */
338 		if (xp == exp || p > ebp || ch == EOF ||
339 		    (Lflag <= count && xflag) || foundeof) {
340 			if (xflag && xp != exp && p > ebp)
341 				errx(1, "insufficient space for arguments");
342 			if (jfound) {
343 				for (avj = argv; *avj; avj++)
344 					*xp++ = *avj;
345 			}
346 			prerun(argc, av);
347 			if (ch == EOF || foundeof) {
348 				waitchildren(*argv, 1);
349 				exit(rval);
350 			}
351 			p = bbp;
352 			xp = bxp;
353 			count = 0;
354 		}
355 		argp = p;
356 		wasquoted = 0;
357 		break;
358 	case '\'':
359 		if (indouble || zflag)
360 			goto addch;
361 		insingle = !insingle;
362 		wasquoted = 1;
363 		break;
364 	case '"':
365 		if (insingle || zflag)
366 			goto addch;
367 		indouble = !indouble;
368 		wasquoted = 1;
369 		break;
370 	case '\\':
371 		if (zflag)
372 			goto addch;
373 		/* Backslash escapes anything, is escaped by quotes. */
374 		if (!insingle && !indouble && (ch = getchar()) == EOF)
375 			errx(1, "backslash at EOF");
376 		/* FALLTHROUGH */
377 	default:
378 addch:		if (p < ebp) {
379 			*p++ = ch;
380 			break;
381 		}
382 
383 		/* If only one argument, not enough buffer space. */
384 		if (bxp == xp)
385 			errx(1, "insufficient space for argument");
386 		/* Didn't hit argument limit, so if xflag object. */
387 		if (xflag)
388 			errx(1, "insufficient space for arguments");
389 
390 		if (jfound) {
391 			for (avj = argv; *avj; avj++)
392 				*xp++ = *avj;
393 		}
394 		prerun(argc, av);
395 		xp = bxp;
396 		cnt = ebp - argp;
397 		memcpy(bbp, argp, (size_t)cnt);
398 		p = (argp = bbp) + cnt;
399 		*p++ = ch;
400 		break;
401 	}
402 	return;
403 }
404 
405 /*
406  * Do things necessary before run()'ing, such as -I substitution,
407  * and then call run().
408  */
409 static void
410 prerun(int argc, char *argv[])
411 {
412 	char **tmp, **tmp2, **avj;
413 	int repls;
414 
415 	repls = Rflag;
416 
417 	if (argc == 0 || repls == 0) {
418 		*xp = NULL;
419 		run(argv);
420 		return;
421 	}
422 
423 	avj = argv;
424 
425 	/*
426 	 * Allocate memory to hold the argument list, and
427 	 * a NULL at the tail.
428 	 */
429 	tmp = malloc((argc + 1) * sizeof(char**));
430 	if (tmp == NULL)
431 		errx(1, "malloc failed");
432 	tmp2 = tmp;
433 
434 	/*
435 	 * Save the first argument and iterate over it, we
436 	 * cannot do strnsubst() to it.
437 	 */
438 	if ((*tmp++ = strdup(*avj++)) == NULL)
439 		errx(1, "strdup failed");
440 
441 	/*
442 	 * For each argument to utility, if we have not used up
443 	 * the number of replacements we are allowed to do, and
444 	 * if the argument contains at least one occurrence of
445 	 * replstr, call strnsubst(), else just save the string.
446 	 * Iterations over elements of avj and tmp are done
447 	 * where appropriate.
448 	 */
449 	while (--argc) {
450 		*tmp = *avj++;
451 		if (repls && strstr(*tmp, replstr) != NULL) {
452 			strnsubst(tmp++, replstr, inpline, (size_t)255);
453 			if (repls > 0)
454 				repls--;
455 		} else {
456 			if ((*tmp = strdup(*tmp)) == NULL)
457 				errx(1, "strdup failed");
458 			tmp++;
459 		}
460 	}
461 
462 	/*
463 	 * Run it.
464 	 */
465 	*tmp = NULL;
466 	run(tmp2);
467 
468 	/*
469 	 * Walk from the tail to the head, free along the way.
470 	 */
471 	for (; tmp2 != tmp; tmp--)
472 		free(*tmp);
473 	/*
474 	 * Now free the list itself.
475 	 */
476 	free(tmp2);
477 
478 	/*
479 	 * Free the input line buffer, if we have one.
480 	 */
481 	if (inpline != NULL) {
482 		free(inpline);
483 		inpline = NULL;
484 	}
485 }
486 
487 static void
488 run(char **argv)
489 {
490 	pid_t pid;
491 	char **avec;
492 
493 	/*
494 	 * If the user wants to be notified of each command before it is
495 	 * executed, notify them.  If they want the notification to be
496 	 * followed by a prompt, then prompt them.
497 	 */
498 	if (tflag || pflag) {
499 		(void)fprintf(stderr, "%s", *argv);
500 		for (avec = argv + 1; *avec != NULL; ++avec)
501 			(void)fprintf(stderr, " %s", *avec);
502 		/*
503 		 * If the user has asked to be prompted, do so.
504 		 */
505 		if (pflag)
506 			/*
507 			 * If they asked not to exec, return without execution
508 			 * but if they asked to, go to the execution.  If we
509 			 * could not open their tty, break the switch and drop
510 			 * back to -t behaviour.
511 			 */
512 			switch (prompt()) {
513 			case 0:
514 				return;
515 			case 1:
516 				goto exec;
517 			case 2:
518 				break;
519 			}
520 		(void)fprintf(stderr, "\n");
521 		(void)fflush(stderr);
522 	}
523 exec:
524 	childerr = 0;
525 	switch(pid = vfork()) {
526 	case -1:
527 		err(1, "vfork");
528 	case 0:
529 		close(0);
530 		if (oflag) {
531 			if (open("/dev/tty", O_RDONLY) == -1)
532 				err(1, "open /dev/tty");
533 		} else {
534 			if (open("/dev/null", O_RDONLY) == -1)
535 				err(1, "open /dev/null");
536 		}
537 		execvp(argv[0], argv);
538 		childerr = errno;
539 		_exit(1);
540 	}
541 	curprocs++;
542 	waitchildren(*argv, 0);
543 }
544 
545 static void
546 waitchildren(const char *name, int waitall)
547 {
548 	pid_t pid;
549 	int status;
550 
551 	while ((pid = wait3(&status, !waitall && curprocs < maxprocs ?
552 	    WNOHANG : 0, NULL)) > 0) {
553 		curprocs--;
554 		/* If we couldn't invoke the utility, exit. */
555 		if (childerr != 0) {
556 			errno = childerr;
557 			err(errno == ENOENT ? 127 : 126, "%s", name);
558 		}
559 		/*
560 		 * If utility signaled or exited with a value of 255,
561 		 * exit 1-125.
562 		 */
563 		if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
564 			exit(1);
565 		if (WEXITSTATUS(status))
566 			rval = 1;
567 	}
568 	if (pid == -1 && errno != ECHILD)
569 		err(1, "wait3");
570 }
571 
572 /*
573  * Prompt the user about running a command.
574  */
575 static int
576 prompt(void)
577 {
578 	regex_t cre;
579 	size_t rsize;
580 	int match;
581 	char *response;
582 	FILE *ttyfp;
583 
584 	if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
585 		return (2);	/* Indicate that the TTY failed to open. */
586 	(void)fprintf(stderr, "?...");
587 	(void)fflush(stderr);
588 	if ((response = fgetln(ttyfp, &rsize)) == NULL ||
589 	    regcomp(&cre,
590 #if (__FreeBSD_version >= 450002 && __FreeBSD_version < 500000) || \
591     __FreeBSD_version >= 500017
592 		nl_langinfo(YESEXPR),
593 #else
594 		"^[yY]",
595 #endif
596 		REG_BASIC) != 0) {
597 		(void)fclose(ttyfp);
598 		return (0);
599 	}
600 	match = regexec(&cre, response, 0, NULL, 0);
601 	(void)fclose(ttyfp);
602 	regfree(&cre);
603 	return (match == 0);
604 }
605 
606 static void
607 usage(void)
608 {
609 	fprintf(stderr,
610 "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
611 "             [-L number] [-n number [-x]] [-P maxprocs] [-s size]\n"
612 "             [utility [argument ...]]\n");
613 	exit(1);
614 }
615