xref: /dragonfly/usr.bin/xargs/xargs.c (revision dca3c15d)
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  * @(#) Copyright (c) 1990, 1993 The Regents of the University of California.  All rights reserved.
39  * @(#)xargs.c	8.1 (Berkeley) 6/6/93
40  * $FreeBSD: src/usr.bin/xargs/xargs.c,v 1.9.2.6 2003/06/01 21:40:35 mux Exp $
41  * $DragonFly: src/usr.bin/xargs/xargs.c,v 1.3 2004/07/27 21:42:48 dillon Exp $
42  */
43 
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #ifndef BOOTSTRAPPING
51 #include <langinfo.h>
52 #endif
53 #include <locale.h>
54 #include <paths.h>
55 #include <regex.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60 
61 #include "pathnames.h"
62 
63 static void	parse_input(int, char *[]);
64 static void	prerun(int, char *[]);
65 static int	prompt(void);
66 static void	run(char **);
67 static void	usage(void);
68 void		strnsubst(char **, const char *, const char *, size_t);
69 
70 static char echo[] = _PATH_ECHO;
71 static char **av, **bxp, **ep, **expx, **xp;
72 static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
73 static const char *eofstr;
74 static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
75 static int cnt, Iflag, jfound, Lflag, wasquoted, xflag;
76 
77 extern char **environ;
78 
79 int
80 main(int argc, char *argv[])
81 {
82 	char *tmp;
83 	long arg_max;
84 	int ch, Jflag, nargs, nflag, nline;
85 	size_t linelen;
86 
87 	inpline = replstr = NULL;
88 	ep = environ;
89 	eofstr = "";
90 	Jflag = nflag = 0;
91 
92 	(void)setlocale(LC_MESSAGES, "");
93 
94 	/*
95 	 * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
96 	 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
97 	 * that the smallest argument is 2 bytes in length, this means that
98 	 * the number of arguments is limited to:
99 	 *
100 	 *	 (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
101 	 *
102 	 * We arbitrarily limit the number of arguments to 5000.  This is
103 	 * allowed by POSIX.2 as long as the resulting minimum exec line is
104 	 * at least LINE_MAX.  Realloc'ing as necessary is possible, but
105 	 * probably not worthwhile.
106 	 */
107 	nargs = 5000;
108 	if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
109 		errx(1, "sysconf(_SC_ARG_MAX) failed");
110 	nline = arg_max - 4 * 1024;
111 	while (*ep != NULL) {
112 		/* 1 byte for each '\0' */
113 		nline -= strlen(*ep++) + 1 + sizeof(*ep);
114 	}
115 	while ((ch = getopt(argc, argv, "0E:I:J:L:n:opR:s:tx")) != -1)
116 		switch(ch) {
117 		case 'E':
118 			eofstr = optarg;
119 			break;
120 		case 'I':
121 			Jflag = 0;
122 			Iflag = 1;
123 			Lflag = 1;
124 			replstr = optarg;
125 			break;
126 		case 'J':
127 			Iflag = 0;
128 			Jflag = 1;
129 			replstr = optarg;
130 			break;
131 		case 'L':
132 			Lflag = strtol(optarg, &tmp, 10);
133 			if (*tmp != 0 || *optarg == 0)
134 				errx(1, "illegal argument count");
135 			break;
136 		case 'n':
137 			nflag = 1;
138 			if ((nargs = atoi(optarg)) <= 0)
139 				errx(1, "illegal argument count");
140 			break;
141 		case 'o':
142 			oflag = 1;
143 			break;
144 		case 'p':
145 			pflag = 1;
146 			break;
147 		case 'R':
148 			if ((Rflag = atoi(optarg)) <= 0)
149 				errx(1, "illegal number of replacements");
150 			break;
151 		case 's':
152 			nline = atoi(optarg);
153 			break;
154 		case 't':
155 			tflag = 1;
156 			break;
157 		case 'x':
158 			xflag = 1;
159 			break;
160 		case '0':
161 			zflag = 1;
162 			break;
163 		case '?':
164 		default:
165 			usage();
166 	}
167 	argc -= optind;
168 	argv += optind;
169 
170 	if (!Iflag && Rflag)
171 		usage();
172 	if (Iflag && !Rflag)
173 		Rflag = 5;
174 	if (xflag && !nflag)
175 		usage();
176 	if (Iflag || Lflag)
177 		xflag = 1;
178 	if (replstr != NULL && *replstr == '\0')
179 		errx(1, "replstr may not be empty");
180 
181 	/*
182 	 * Allocate pointers for the utility name, the utility arguments,
183 	 * the maximum arguments to be read from stdin and the trailing
184 	 * NULL.
185 	 */
186 	linelen = 1 + argc + nargs + 1;
187 	if ((av = bxp = malloc(linelen * sizeof(char **))) == NULL)
188 		errx(1, "malloc failed");
189 
190 	/*
191 	 * Use the user's name for the utility as argv[0], just like the
192 	 * shell.  Echo is the default.  Set up pointers for the user's
193 	 * arguments.
194 	 */
195 	if (*argv == NULL)
196 		cnt = strlen(*bxp++ = echo);
197 	else {
198 		do {
199 			if (Jflag && strcmp(*argv, replstr) == 0) {
200 				char **avj;
201 				jfound = 1;
202 				argv++;
203 				for (avj = argv; *avj; avj++)
204 					cnt += strlen(*avj) + 1;
205 				break;
206 			}
207 			cnt += strlen(*bxp++ = *argv) + 1;
208 		} while (*++argv != NULL);
209 	}
210 
211 	/*
212 	 * Set up begin/end/traversing pointers into the array.  The -n
213 	 * count doesn't include the trailing NULL pointer, so the malloc
214 	 * added in an extra slot.
215 	 */
216 	expx = (xp = bxp) + nargs;
217 
218 	/*
219 	 * Allocate buffer space for the arguments read from stdin and the
220 	 * trailing NULL.  Buffer space is defined as the default or specified
221 	 * space, minus the length of the utility name and arguments.  Set up
222 	 * begin/end/traversing pointers into the array.  The -s count does
223 	 * include the trailing NULL, so the malloc didn't add in an extra
224 	 * slot.
225 	 */
226 	nline -= cnt;
227 	if (nline <= 0)
228 		errx(1, "insufficient space for command");
229 
230 	if ((bbp = malloc((size_t)(nline + 1))) == NULL)
231 		errx(1, "malloc failed");
232 	ebp = (argp = p = bbp) + nline - 1;
233 	for (;;)
234 		parse_input(argc, argv);
235 }
236 
237 static void
238 parse_input(int argc, char *argv[])
239 {
240 	int ch, foundeof;
241 	char **avj;
242 
243 	foundeof = 0;
244 
245 	switch(ch = getchar()) {
246 	case EOF:
247 		/* No arguments since last exec. */
248 		if (p == bbp)
249 			exit(rval);
250 		goto arg1;
251 	case ' ':
252 	case '\t':
253 		/* Quotes escape tabs and spaces. */
254 		if (insingle || indouble || zflag)
255 			goto addch;
256 		goto arg2;
257 	case '\0':
258 		if (zflag)
259 			goto arg2;
260 		goto addch;
261 	case '\n':
262 		count++;
263 		if (zflag)
264 			goto addch;
265 
266 		/* Quotes do not escape newlines. */
267 arg1:		if (insingle || indouble)
268 			errx(1, "unterminated quote");
269 arg2:
270 		foundeof = *eofstr != '\0' &&
271 		    strcmp(argp, eofstr) == 0;
272 
273 		/* Do not make empty args unless they are quoted */
274 		if ((argp != p || wasquoted) && !foundeof) {
275 			*p++ = '\0';
276 			*xp++ = argp;
277 			if (Iflag) {
278 				size_t curlen;
279 
280 				if (inpline == NULL)
281 					curlen = 0;
282 				else {
283 					/*
284 					 * If this string is not zero
285 					 * length, append a space for
286 					 * separation before the next
287 					 * argument.
288 					 */
289 					if ((curlen = strlen(inpline)))
290 						strcat(inpline, " ");
291 				}
292 				curlen++;
293 				/*
294 				 * Allocate enough to hold what we will
295 				 * be holding in a second, and to append
296 				 * a space next time through, if we have
297 				 * to.
298 				 */
299 				inpline = realloc(inpline, curlen + 2 +
300 				    strlen(argp));
301 				if (inpline == NULL)
302 					errx(1, "realloc failed");
303 				if (curlen == 1)
304 					strcpy(inpline, argp);
305 				else
306 					strcat(inpline, argp);
307 			}
308 		}
309 
310 		/*
311 		 * If max'd out on args or buffer, or reached EOF,
312 		 * run the command.  If xflag and max'd out on buffer
313 		 * but not on args, object.  Having reached the limit
314 		 * of input lines, as specified by -L is the same as
315 		 * maxing out on arguments.
316 		 */
317 		if (xp == expx || p > ebp || ch == EOF ||
318 		    (Lflag <= count && xflag) || foundeof) {
319 			if (xflag && xp != expx && p > ebp)
320 				errx(1, "insufficient space for arguments");
321 			if (jfound) {
322 				for (avj = argv; *avj; avj++)
323 					*xp++ = *avj;
324 			}
325 			prerun(argc, av);
326 			if (ch == EOF || foundeof)
327 				exit(rval);
328 			p = bbp;
329 			xp = bxp;
330 			count = 0;
331 		}
332 		argp = p;
333 		wasquoted = 0;
334 		break;
335 	case '\'':
336 		if (indouble || zflag)
337 			goto addch;
338 		insingle = !insingle;
339 		wasquoted = 1;
340 		break;
341 	case '"':
342 		if (insingle || zflag)
343 			goto addch;
344 		indouble = !indouble;
345 		wasquoted = 1;
346 		break;
347 	case '\\':
348 		if (zflag)
349 			goto addch;
350 		/* Backslash escapes anything, is escaped by quotes. */
351 		if (!insingle && !indouble && (ch = getchar()) == EOF)
352 			errx(1, "backslash at EOF");
353 		/* FALLTHROUGH */
354 	default:
355 addch:		if (p < ebp) {
356 			*p++ = ch;
357 			break;
358 		}
359 
360 		/* If only one argument, not enough buffer space. */
361 		if (bxp == xp)
362 			errx(1, "insufficient space for argument");
363 		/* Didn't hit argument limit, so if xflag object. */
364 		if (xflag)
365 			errx(1, "insufficient space for arguments");
366 
367 		if (jfound) {
368 			for (avj = argv; *avj; avj++)
369 				*xp++ = *avj;
370 		}
371 		prerun(argc, av);
372 		xp = bxp;
373 		cnt = ebp - argp;
374 		memcpy(bbp, argp, (size_t)cnt);
375 		p = (argp = bbp) + cnt;
376 		*p++ = ch;
377 		break;
378 	}
379 	return;
380 }
381 
382 /*
383  * Do things necessary before run()'ing, such as -I substitution,
384  * and then call run().
385  */
386 static void
387 prerun(int argc, char *argv[])
388 {
389 	char **tmp, **tmp2, **avj;
390 	int repls;
391 
392 	repls = Rflag;
393 
394 	if (argc == 0 || repls == 0) {
395 		*xp = NULL;
396 		run(argv);
397 		return;
398 	}
399 
400 	avj = argv;
401 
402 	/*
403 	 * Allocate memory to hold the argument list, and
404 	 * a NULL at the tail.
405 	 */
406 	tmp = malloc((argc + 1) * sizeof(char**));
407 	if (tmp == NULL)
408 		errx(1, "malloc failed");
409 	tmp2 = tmp;
410 
411 	/*
412 	 * Save the first argument and iterate over it, we
413 	 * cannot do strnsubst() to it.
414 	 */
415 	if ((*tmp++ = strdup(*avj++)) == NULL)
416 		errx(1, "strdup failed");
417 
418 	/*
419 	 * For each argument to utility, if we have not used up
420 	 * the number of replacements we are allowed to do, and
421 	 * if the argument contains at least one occurrence of
422 	 * replstr, call strnsubst(), else just save the string.
423 	 * Iterations over elements of avj and tmp are done
424 	 * where appropriate.
425 	 */
426 	while (--argc) {
427 		*tmp = *avj++;
428 		if (repls && strstr(*tmp, replstr) != NULL) {
429 			strnsubst(tmp++, replstr, inpline, (size_t)255);
430 			repls--;
431 		} else {
432 			if ((*tmp = strdup(*tmp)) == NULL)
433 				errx(1, "strdup failed");
434 			tmp++;
435 		}
436 	}
437 
438 	/*
439 	 * Run it.
440 	 */
441 	*tmp = NULL;
442 	run(tmp2);
443 
444 	/*
445 	 * Walk from the tail to the head, free along the way.
446 	 */
447 	for (; tmp2 != tmp; tmp--)
448 		free(*tmp);
449 	/*
450 	 * Now free the list itself.
451 	 */
452 	free(tmp2);
453 
454 	/*
455 	 * Free the input line buffer, if we have one.
456 	 */
457 	if (inpline != NULL) {
458 		free(inpline);
459 		inpline = NULL;
460 	}
461 }
462 
463 static void
464 run(char **argv)
465 {
466 	volatile int childerr;
467 	char **avec;
468 	pid_t pid;
469 	int status;
470 
471 	/*
472 	 * If the user wants to be notified of each command before it is
473 	 * executed, notify them.  If they want the notification to be
474 	 * followed by a prompt, then prompt them.
475 	 */
476 	if (tflag || pflag) {
477 		(void)fprintf(stderr, "%s", *argv);
478 		for (avec = argv + 1; *avec != NULL; ++avec)
479 			(void)fprintf(stderr, " %s", *avec);
480 		/*
481 		 * If the user has asked to be prompted, do so.
482 		 */
483 		if (pflag)
484 			/*
485 			 * If they asked not to exec, return without execution
486 			 * but if they asked to, go to the execution.  If we
487 			 * could not open their tty, break the switch and drop
488 			 * back to -t behaviour.
489 			 */
490 			switch (prompt()) {
491 			case 0:
492 				return;
493 			case 1:
494 				goto exec;
495 			case 2:
496 				break;
497 			}
498 		(void)fprintf(stderr, "\n");
499 		(void)fflush(stderr);
500 	}
501 exec:
502 	childerr = 0;
503 	switch(pid = vfork()) {
504 	case -1:
505 		err(1, "vfork");
506 	case 0:
507 		close(0);
508 		if (oflag) {
509 			if (open("/dev/tty", O_RDONLY) == -1)
510 				err(1, "open /dev/tty");
511 		} else {
512 			if (open("/dev/null", O_RDONLY) == -1)
513 				err(1, "open /dev/null");
514 		}
515 		execvp(argv[0], argv);
516 		childerr = errno;
517 		_exit(1);
518 	}
519 	pid = waitpid(pid, &status, 0);
520 	if (pid == -1)
521 		err(1, "waitpid");
522 	/* If we couldn't invoke the utility, exit. */
523 	if (childerr != 0)
524 		err(childerr == ENOENT ? 127 : 126, "%s", *argv);
525 	/* If utility signaled or exited with a value of 255, exit 1-125. */
526 	if (WIFSIGNALED(status) || WEXITSTATUS(status) == 255)
527 		exit(1);
528 	if (WEXITSTATUS(status))
529 		rval = 1;
530 }
531 
532 /*
533  * Prompt the user about running a command.
534  */
535 static int
536 prompt(void)
537 {
538 	regex_t cre;
539 	size_t rsize;
540 	int match;
541 	char *response;
542 	FILE *ttyfp;
543 
544 	if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
545 		return (2);	/* Indicate that the TTY failed to open. */
546 	(void)fprintf(stderr, "?...");
547 	(void)fflush(stderr);
548 	if ((response = fgetln(ttyfp, &rsize)) == NULL ||
549 	    regcomp(&cre,
550 #ifdef BOOTSTRAPPING
551 		"^[yY]",
552 #else
553 		nl_langinfo(YESEXPR),
554 #endif
555 		REG_BASIC) != 0) {
556 		(void)fclose(ttyfp);
557 		return (0);
558 	}
559 	match = regexec(&cre, response, 0, NULL, 0);
560 	(void)fclose(ttyfp);
561 	regfree(&cre);
562 	return (match == 0);
563 }
564 
565 static void
566 usage(void)
567 {
568 	fprintf(stderr,
569 "usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
570 "             [-L number] [-n number [-x] [-s size] [utility [argument ...]]\n");
571 	exit(1);
572 }
573