GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/xargs/xargs.c Lines: 112 266 42.1 %
Date: 2017-11-13 Branches: 84 216 38.9 %

Line Branch Exec Source
1
/*	$OpenBSD: xargs.c,v 1.33 2017/10/16 13:10:50 anton Exp $	*/
2
/*	$FreeBSD: xargs.c,v 1.51 2003/05/03 19:09:11 obrien Exp $	*/
3
4
/*-
5
 * Copyright (c) 1990, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * This code is derived from software contributed to Berkeley by
9
 * John B. Roll Jr.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 * 3. Neither the name of the University nor the names of its contributors
20
 *    may be used to endorse or promote products derived from this software
21
 *    without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 *
35
 * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
36
 */
37
38
#include <sys/wait.h>
39
40
#include <ctype.h>
41
#include <err.h>
42
#include <errno.h>
43
#include <fcntl.h>
44
#include <langinfo.h>
45
#include <locale.h>
46
#include <paths.h>
47
#include <regex.h>
48
#include <signal.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <unistd.h>
53
#include <limits.h>
54
55
#include "pathnames.h"
56
57
static void	parse_input(int, char *[]);
58
static void	prerun(int, char *[]);
59
static int	prompt(void);
60
static void	run(char **);
61
static void	usage(void);
62
void		strnsubst(char **, const char *, const char *, size_t);
63
static void	waitchildren(const char *, int);
64
65
static char **av, **bxp, **ep, **endxp, **xp;
66
static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
67
static const char *eofstr;
68
static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
69
static int cnt, Iflag, jfound, Lflag, wasquoted, xflag, runeof = 1;
70
static int curprocs, maxprocs;
71
static size_t inpsize;
72
73
extern char **environ;
74
75
int
76
main(int argc, char *argv[])
77
{
78
	long arg_max;
79
	int ch, Jflag, nargs, nflag, nline;
80
	size_t linelen;
81
428
	char *endptr;
82
214
	const char *errstr;
83
84
214
	inpline = replstr = NULL;
85
214
	ep = environ;
86
214
	eofstr = "";
87
	Jflag = nflag = 0;
88
89
214
	(void)setlocale(LC_MESSAGES, "");
90
91
	/*
92
	 * POSIX.2 limits the exec line length to ARG_MAX - 2K.  Running that
93
	 * caused some E2BIG errors, so it was changed to ARG_MAX - 4K.  Given
94
	 * that the smallest argument is 2 bytes in length, this means that
95
	 * the number of arguments is limited to:
96
	 *
97
	 *	 (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
98
	 *
99
	 * We arbitrarily limit the number of arguments to 5000.  This is
100
	 * allowed by POSIX.2 as long as the resulting minimum exec line is
101
	 * at least LINE_MAX.  Realloc'ing as necessary is possible, but
102
	 * probably not worthwhile.
103
	 */
104
	nargs = 5000;
105
214
	if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
106
		errx(1, "sysconf(_SC_ARG_MAX) failed");
107
108
214
	if (pledge("stdio rpath proc exec flock cpath wpath", NULL) == -1)
109
		err(1, "pledge");
110
111
214
	nline = arg_max - 4 * 1024;
112
10620
	while (*ep != NULL) {
113
		/* 1 byte for each '\0' */
114
5096
		nline -= strlen(*ep++) + 1 + sizeof(*ep);
115
	}
116
214
	maxprocs = 1;
117
836
	while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:rs:tx")) != -1)
118



204
		switch (ch) {
119
		case 'E':
120
			eofstr = optarg;
121
			break;
122
		case 'I':
123
			Jflag = 0;
124
			Iflag = 1;
125
			Lflag = 1;
126
			replstr = optarg;
127
			break;
128
		case 'J':
129
			Iflag = 0;
130
			Jflag = 1;
131
			replstr = optarg;
132
			break;
133
		case 'L':
134
102
			Lflag = strtonum(optarg, 0, INT_MAX, &errstr);
135
102
			if (errstr)
136
				errx(1, "-L %s: %s", optarg, errstr);
137
			break;
138
		case 'n':
139
			nflag = 1;
140
			nargs = strtonum(optarg, 1, INT_MAX, &errstr);
141
			if (errstr)
142
				errx(1, "-n %s: %s", optarg, errstr);
143
			break;
144
		case 'o':
145
			oflag = 1;
146
			break;
147
		case 'P':
148
			maxprocs = strtonum(optarg, 1, INT_MAX, &errstr);
149
			if (errstr)
150
				errx(1, "-P %s: %s", optarg, errstr);
151
			break;
152
		case 'p':
153
			pflag = 1;
154
			break;
155
		case 'r':
156
			runeof = 0;
157
			break;
158
		case 'R':
159
			Rflag = strtol(optarg, &endptr, 10);
160
			if (*endptr != '\0')
161
				errx(1, "replacements must be a number");
162
			break;
163
		case 's':
164
			nline = strtonum(optarg, 0, INT_MAX, &errstr);
165
			if (errstr)
166
				errx(1, "-s %s: %s", optarg, errstr);
167
			break;
168
		case 't':
169
			tflag = 1;
170
			break;
171
		case 'x':
172
			xflag = 1;
173
			break;
174
		case '0':
175
102
			zflag = 1;
176
102
			break;
177
		case '?':
178
		default:
179
			usage();
180
	}
181
214
	argc -= optind;
182
214
	argv += optind;
183
184
214
	if (!Iflag && Rflag)
185
		usage();
186
214
	if (Iflag && !Rflag)
187
		Rflag = 5;
188
214
	if (xflag && !nflag)
189
		usage();
190
214
	if (Iflag || Lflag)
191
102
		xflag = 1;
192

214
	if (replstr != NULL && *replstr == '\0')
193
		errx(1, "replstr may not be empty");
194
195
	/*
196
	 * Allocate pointers for the utility name, the utility arguments,
197
	 * the maximum arguments to be read from stdin and the trailing
198
	 * NULL.
199
	 */
200
214
	linelen = 1 + argc + nargs + 1;
201
214
	if ((av = bxp = calloc(linelen, sizeof(char **))) == NULL)
202
		err(1, NULL);
203
204
	/*
205
	 * Use the user's name for the utility as argv[0], just like the
206
	 * shell.  Echo is the default.  Set up pointers for the user's
207
	 * arguments.
208
	 */
209
214
	if (*argv == NULL)
210
4
		cnt = strlen(*bxp++ = _PATH_ECHO);
211
	else {
212
210
		do {
213

213
			if (Jflag && strcmp(*argv, replstr) == 0) {
214
				char **avj;
215
				jfound = 1;
216
				argv++;
217
				for (avj = argv; *avj; avj++)
218
					cnt += strlen(*avj) + 1;
219
				break;
220
			}
221
213
			cnt += strlen(*bxp++ = *argv) + 1;
222
213
		} while (*++argv != NULL);
223
	}
224
225
	/*
226
	 * Set up begin/end/traversing pointers into the array.  The -n
227
	 * count doesn't include the trailing NULL pointer, so the malloc
228
	 * added in an extra slot.
229
	 */
230
214
	endxp = (xp = bxp) + nargs;
231
232
	/*
233
	 * Allocate buffer space for the arguments read from stdin and the
234
	 * trailing NULL.  Buffer space is defined as the default or specified
235
	 * space, minus the length of the utility name and arguments.  Set up
236
	 * begin/end/traversing pointers into the array.  The -s count does
237
	 * include the trailing NULL, so the malloc didn't add in an extra
238
	 * slot.
239
	 */
240
214
	nline -= cnt;
241
214
	if (nline <= 0)
242
		errx(1, "insufficient space for command");
243
244
214
	if ((bbp = malloc((size_t)(nline + 1))) == NULL)
245
		err(1, NULL);
246
214
	ebp = (argp = p = bbp) + nline - 1;
247
1035092
	for (;;)
248
1034878
		parse_input(argc, argv);
249
}
250
251
static void
252
parse_input(int argc, char *argv[])
253
{
254
	int hasblank = 0;
255
	static int hadblank = 0;
256
	int ch, foundeof = 0;
257
	char **avj;
258
259

5174390
	ch = getchar();
260
1034878
	if (isblank(ch)) {
261
		/* Quotes escape tabs and spaces. */
262
174
		if (insingle || indouble)
263
			goto addch;
264
		hasblank = 1;
265
174
		if (zflag)
266
			goto addch;
267
		goto arg2;
268
	}
269
270

1035004
	switch (ch) {
271
	case EOF:
272
		/* No arguments since last exec. */
273
214
		if (p == bbp) {
274
			if (runeof)
275
				prerun(0, av);
276
			waitchildren(*argv, 1);
277
			exit(rval);
278
		}
279
		goto arg1;
280
	case '\0':
281
51
		if (zflag) {
282
			/*
283
			 * Increment 'count', so that nulls will be treated
284
			 * as end-of-line, as well as end-of-argument.  This
285
			 * is needed so -0 works properly with -I and -L.
286
			 */
287
51
			count++;
288
51
			goto arg2;
289
		}
290
		goto addch;
291
	case '\n':
292
350
		if (zflag)
293
			goto addch;
294
		hasblank = 1;
295
242
		if (hadblank == 0)
296
204
			count++;
297
298
		/* Quotes do not escape newlines. */
299
456
arg1:		if (insingle || indouble)
300
			errx(1, "unterminated quote");
301
arg2:
302
1170
		foundeof = *eofstr != '\0' &&
303
		    strcmp(argp, eofstr) == 0;
304
305
		/* Do not make empty args unless they are quoted */
306
585
		if ((argp != p || wasquoted) && !foundeof) {
307
513
			*p++ = '\0';
308
513
			*xp++ = argp;
309
513
			if (Iflag) {
310
				size_t curlen;
311
312
				if (inpline == NULL)
313
					curlen = 0;
314
				else {
315
					/*
316
					 * If this string is not zero
317
					 * length, append a space for
318
					 * separation before the next
319
					 * argument.
320
					 */
321
					if ((curlen = strlen(inpline)))
322
						strlcat(inpline, " ", inpsize);
323
				}
324
				curlen++;
325
				/*
326
				 * Allocate enough to hold what we will
327
				 * be holding in a second, and to append
328
				 * a space next time through, if we have
329
				 * to.
330
				 */
331
				inpsize = curlen + 2 + strlen(argp);
332
				inpline = realloc(inpline, inpsize);
333
				if (inpline == NULL)
334
					errx(1, "realloc failed");
335
				if (curlen == 1)
336
					strlcpy(inpline, argp, inpsize);
337
				else
338
					strlcat(inpline, argp, inpsize);
339
			}
340
		}
341
342
		/*
343
		 * If max'd out on args or buffer, or reached EOF,
344
		 * run the command.  If xflag and max'd out on buffer
345
		 * but not on args, object.  Having reached the limit
346
		 * of input lines, as specified by -L is the same as
347
		 * maxing out on arguments.
348
		 */
349

1170
		if (xp == endxp || p > ebp || ch == EOF ||
350
371
		    (Lflag <= count && xflag) || foundeof) {
351

634
			if (xflag && xp != endxp && p > ebp)
352
				errx(1, "insufficient space for arguments");
353
286
			if (jfound) {
354
				for (avj = argv; *avj; avj++)
355
					*xp++ = *avj;
356
			}
357
286
			prerun(argc, av);
358
286
			if (ch == EOF || foundeof) {
359
				waitchildren(*argv, 1);
360
				exit(rval);
361
			}
362
72
			p = bbp;
363
72
			xp = bxp;
364
72
			count = 0;
365
72
		}
366
371
		argp = p;
367
371
		wasquoted = 0;
368
371
		break;
369
	case '\'':
370
		if (indouble || zflag)
371
			goto addch;
372
		insingle = !insingle;
373
		wasquoted = 1;
374
		break;
375
	case '"':
376
		if (insingle || zflag)
377
			goto addch;
378
		indouble = !indouble;
379
		wasquoted = 1;
380
		break;
381
	case '\\':
382
96
		if (zflag)
383
			goto addch;
384
		/* Backslash escapes anything, is escaped by quotes. */
385


240
		if (!insingle && !indouble && (ch = getchar()) == EOF)
386
			errx(1, "backslash at EOF");
387
		/* FALLTHROUGH */
388
	default:
389
1034293
addch:		if (p < ebp) {
390
1034289
			*p++ = ch;
391
1034289
			break;
392
		}
393
394
		/* If only one argument, not enough buffer space. */
395
4
		if (bxp == xp)
396
			errx(1, "insufficient space for argument");
397
		/* Didn't hit argument limit, so if xflag object. */
398
4
		if (xflag)
399
			errx(1, "insufficient space for arguments");
400
401
4
		if (jfound) {
402
			for (avj = argv; *avj; avj++)
403
				*xp++ = *avj;
404
		}
405
4
		prerun(argc, av);
406
4
		xp = bxp;
407
4
		cnt = ebp - argp;
408
4
		memmove(bbp, argp, (size_t)cnt);
409
4
		p = (argp = bbp) + cnt;
410
4
		*p++ = ch;
411
4
		break;
412
	}
413
1034664
	hadblank = hasblank;
414
1034664
}
415
416
/*
417
 * Do things necessary before run()'ing, such as -I substitution,
418
 * and then call run().
419
 */
420
static void
421
prerun(int argc, char *argv[])
422
{
423
	char **tmp, **tmp2, **avj;
424
	int repls;
425
426
580
	repls = Rflag;
427
290
	runeof = 0;
428
429
290
	if (argc == 0 || repls == 0) {
430
290
		*xp = NULL;
431
290
		run(argv);
432
290
		return;
433
	}
434
435
	avj = argv;
436
437
	/*
438
	 * Allocate memory to hold the argument list, and
439
	 * a NULL at the tail.
440
	 */
441
	tmp = calloc(argc + 1, sizeof(char**));
442
	if (tmp == NULL)
443
		err(1, NULL);
444
	tmp2 = tmp;
445
446
	/*
447
	 * Save the first argument and iterate over it, we
448
	 * cannot do strnsubst() to it.
449
	 */
450
	if ((*tmp++ = strdup(*avj++)) == NULL)
451
		err(1, NULL);
452
453
	/*
454
	 * For each argument to utility, if we have not used up
455
	 * the number of replacements we are allowed to do, and
456
	 * if the argument contains at least one occurrence of
457
	 * replstr, call strnsubst(), else just save the string.
458
	 * Iterations over elements of avj and tmp are done
459
	 * where appropriate.
460
	 */
461
	while (--argc) {
462
		*tmp = *avj++;
463
		if (repls && strstr(*tmp, replstr) != NULL) {
464
			strnsubst(tmp++, replstr, inpline, (size_t)255);
465
			if (repls > 0)
466
				repls--;
467
		} else {
468
			if ((*tmp = strdup(*tmp)) == NULL)
469
				err(1, NULL);
470
			tmp++;
471
		}
472
	}
473
474
	/*
475
	 * Run it.
476
	 */
477
	*tmp = NULL;
478
	run(tmp2);
479
480
	/*
481
	 * Walk from the tail to the head, free along the way.
482
	 */
483
	for (; tmp2 != tmp; tmp--)
484
		free(*tmp);
485
	/*
486
	 * Now free the list itself.
487
	 */
488
	free(tmp2);
489
490
	/*
491
	 * Free the input line buffer, if we have one.
492
	 */
493
	free(inpline);
494
	inpline = NULL;
495
290
}
496
497
static void
498
run(char **argv)
499
{
500
	pid_t pid;
501
	int fd;
502
	char **avec;
503
504
	/*
505
	 * If the user wants to be notified of each command before it is
506
	 * executed, notify them.  If they want the notification to be
507
	 * followed by a prompt, then prompt them.
508
	 */
509
580
	if (tflag || pflag) {
510
		(void)fprintf(stderr, "%s", *argv);
511
		for (avec = argv + 1; *avec != NULL; ++avec)
512
			(void)fprintf(stderr, " %s", *avec);
513
		/*
514
		 * If the user has asked to be prompted, do so.
515
		 */
516
		if (pflag)
517
			/*
518
			 * If they asked not to exec, return without execution
519
			 * but if they asked to, go to the execution.  If we
520
			 * could not open their tty, break the switch and drop
521
			 * back to -t behaviour.
522
			 */
523
			switch (prompt()) {
524
			case 0:
525
				return;
526
			case 1:
527
				goto exec;
528
			case 2:
529
				break;
530
			}
531
		(void)fprintf(stderr, "\n");
532
		(void)fflush(stderr);
533
	}
534
exec:
535
290
	switch (pid = vfork()) {
536
	case -1:
537
		err(1, "vfork");
538
	case 0:
539
		if (oflag) {
540
			if ((fd = open(_PATH_TTY, O_RDONLY)) == -1) {
541
				warn("can't open /dev/tty");
542
				_exit(1);
543
			}
544
		} else {
545
			fd = open(_PATH_DEVNULL, O_RDONLY);
546
		}
547
		if (fd > STDIN_FILENO) {
548
			if (dup2(fd, STDIN_FILENO) != 0) {
549
				warn("can't dup2 to stdin");
550
				_exit(1);
551
			}
552
			close(fd);
553
		}
554
		execvp(argv[0], argv);
555
		warn("%s", argv[0]);
556
		_exit(errno == ENOENT ? 127 : 126);
557
	}
558
290
	curprocs++;
559
290
	waitchildren(*argv, 0);
560
580
}
561
562
static void
563
waitchildren(const char *name, int waitall)
564
{
565
	pid_t pid;
566
1008
	int status;
567
568

3756
	while ((pid = waitpid(-1, &status, !waitall && curprocs < maxprocs ?
569
794
	    WNOHANG : 0)) > 0) {
570
290
		curprocs--;
571
		/*
572
		 * According to POSIX, we have to exit if the utility exits
573
		 * with a 255 status, or is interrupted by a signal.
574
		 * We are allowed to return any exit status between 1 and
575
		 * 125 in these cases, but we'll use 124 and 125, the same
576
		 * values used by GNU xargs.
577
		 */
578
290
		if (WIFEXITED(status)) {
579
290
			if (WEXITSTATUS(status) == 255) {
580
				warnx("%s exited with status 255", name);
581
				exit(124);
582

580
			} else if (WEXITSTATUS(status) == 127 ||
583
290
			    WEXITSTATUS(status) == 126) {
584
				exit(WEXITSTATUS(status));
585
290
			} else if (WEXITSTATUS(status) != 0) {
586
				rval = 123;
587
			}
588
		} else if (WIFSIGNALED(status)) {
589
			if (WTERMSIG(status) != SIGPIPE) {
590
				if (WTERMSIG(status) < NSIG)
591
					warnx("%s terminated by SIG%s", name,
592
					    sys_signame[WTERMSIG(status)]);
593
				else
594
					warnx("%s terminated by signal %d",
595
					    name, WTERMSIG(status));
596
			}
597
			exit(125);
598
		}
599
	}
600

1008
	if (pid == -1 && errno != ECHILD)
601
		err(1, "waitpid");
602
504
}
603
604
/*
605
 * Prompt the user about running a command.
606
 */
607
static int
608
prompt(void)
609
{
610
	regex_t cre;
611
	size_t rsize;
612
	int match;
613
	char *response;
614
	FILE *ttyfp;
615
616
	if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
617
		return (2);	/* Indicate that the TTY failed to open. */
618
	(void)fprintf(stderr, "?...");
619
	(void)fflush(stderr);
620
	if ((response = fgetln(ttyfp, &rsize)) == NULL ||
621
	    regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) {
622
		(void)fclose(ttyfp);
623
		return (0);
624
	}
625
	response[rsize - 1] = '\0';
626
	match = regexec(&cre, response, 0, NULL, 0);
627
	(void)fclose(ttyfp);
628
	regfree(&cre);
629
	return (match == 0);
630
}
631
632
static void
633
usage(void)
634
{
635
	fprintf(stderr,
636
"usage: xargs [-0oprt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n"
637
"             [-L number] [-n number [-x]] [-P maxprocs] [-s size]\n"
638
"             [utility [argument ...]]\n");
639
	exit(1);
640
}