GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: xargs.c,v 1.31 2015/12/09 19:29:49 mmcc 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 |
2 |
{ |
|
78 |
long arg_max; |
||
79 |
int ch, Jflag, nargs, nflag, nline; |
||
80 |
size_t linelen; |
||
81 |
char *endptr; |
||
82 |
const char *errstr; |
||
83 |
|||
84 |
2 |
inpline = replstr = NULL; |
|
85 |
2 |
ep = environ; |
|
86 |
2 |
eofstr = ""; |
|
87 |
2 |
Jflag = nflag = 0; |
|
88 |
|||
89 |
2 |
(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 |
2 |
nargs = 5000; |
|
105 |
✗✓ | 2 |
if ((arg_max = sysconf(_SC_ARG_MAX)) == -1) |
106 |
errx(1, "sysconf(_SC_ARG_MAX) failed"); |
||
107 |
|||
108 |
✗✓ | 2 |
if (pledge("stdio rpath proc exec wpath cpath", NULL) == -1) |
109 |
err(1, "pledge"); |
||
110 |
|||
111 |
2 |
nline = arg_max - 4 * 1024; |
|
112 |
✓✓ | 42 |
while (*ep != NULL) { |
113 |
/* 1 byte for each '\0' */ |
||
114 |
38 |
nline -= strlen(*ep++) + 1 + sizeof(*ep); |
|
115 |
} |
||
116 |
2 |
maxprocs = 1; |
|
117 |
✗✓ | 4 |
while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:rs:tx")) != -1) |
118 |
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 |
Lflag = strtonum(optarg, 0, INT_MAX, &errstr); |
||
135 |
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 |
zflag = 1; |
||
176 |
break; |
||
177 |
case '?': |
||
178 |
default: |
||
179 |
usage(); |
||
180 |
} |
||
181 |
2 |
argc -= optind; |
|
182 |
2 |
argv += optind; |
|
183 |
|||
184 |
✓✗✗✓ |
2 |
if (!Iflag && Rflag) |
185 |
usage(); |
||
186 |
✗✓✗✗ |
2 |
if (Iflag && !Rflag) |
187 |
Rflag = 5; |
||
188 |
✗✓ | 2 |
if (xflag && !nflag) |
189 |
usage(); |
||
190 |
✓✗✗✓ |
2 |
if (Iflag || Lflag) |
191 |
xflag = 1; |
||
192 |
✗✓✗✗ |
2 |
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 |
2 |
linelen = 1 + argc + nargs + 1; |
|
201 |
✗✓ | 2 |
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 |
✗✓ | 2 |
if (*argv == NULL) |
210 |
cnt = strlen(*bxp++ = _PATH_ECHO); |
||
211 |
else { |
||
212 |
do { |
||
213 |
✗✓✗✗ |
2 |
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 |
2 |
cnt += strlen(*bxp++ = *argv) + 1; |
|
222 |
✗✓ | 2 |
} 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 |
2 |
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 |
2 |
nline -= cnt; |
|
241 |
✗✓ | 2 |
if (nline <= 0) |
242 |
errx(1, "insufficient space for command"); |
||
243 |
|||
244 |
✗✓ | 2 |
if ((bbp = malloc((size_t)(nline + 1))) == NULL) |
245 |
err(1, NULL); |
||
246 |
2 |
ebp = (argp = p = bbp) + nline - 1; |
|
247 |
for (;;) |
||
248 |
800 |
parse_input(argc, argv); |
|
249 |
} |
||
250 |
|||
251 |
static void |
||
252 |
parse_input(int argc, char *argv[]) |
||
253 |
800 |
{ |
|
254 |
800 |
int hasblank = 0; |
|
255 |
static int hadblank = 0; |
||
256 |
800 |
int ch, foundeof = 0; |
|
257 |
char **avj; |
||
258 |
|||
259 |
✓✗✓✓ |
800 |
ch = getchar(); |
260 |
✗✓ | 800 |
if (isblank(ch)) { |
261 |
/* Quotes escape tabs and spaces. */ |
||
262 |
if (insingle || indouble) |
||
263 |
goto addch; |
||
264 |
hasblank = 1; |
||
265 |
if (zflag) |
||
266 |
goto addch; |
||
267 |
goto arg2; |
||
268 |
} |
||
269 |
|||
270 |
✓✗✓✗ ✗✗✓ |
800 |
switch (ch) { |
271 |
case EOF: |
||
272 |
/* No arguments since last exec. */ |
||
273 |
✗✓ | 2 |
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 |
if (zflag) |
||
282 |
goto arg2; |
||
283 |
goto addch; |
||
284 |
case '\n': |
||
285 |
82 |
hasblank = 1; |
|
286 |
✓✗ | 82 |
if (hadblank == 0) |
287 |
82 |
count++; |
|
288 |
✗✓ | 82 |
if (zflag) |
289 |
goto addch; |
||
290 |
|||
291 |
/* Quotes do not escape newlines. */ |
||
292 |
✓✗✗✓ |
84 |
arg1: if (insingle || indouble) |
293 |
errx(1, "unterminated quote"); |
||
294 |
84 |
arg2: |
|
295 |
✗✓✗✗ |
84 |
foundeof = *eofstr != '\0' && |
296 |
strcmp(argp, eofstr) == 0; |
||
297 |
|||
298 |
/* Do not make empty args unless they are quoted */ |
||
299 |
✓✓✗✓ ✓✗ |
84 |
if ((argp != p || wasquoted) && !foundeof) { |
300 |
82 |
*p++ = '\0'; |
|
301 |
82 |
*xp++ = argp; |
|
302 |
✗✓ | 82 |
if (Iflag) { |
303 |
size_t curlen; |
||
304 |
|||
305 |
if (inpline == NULL) |
||
306 |
curlen = 0; |
||
307 |
else { |
||
308 |
/* |
||
309 |
* If this string is not zero |
||
310 |
* length, append a space for |
||
311 |
* separation before the next |
||
312 |
* argument. |
||
313 |
*/ |
||
314 |
if ((curlen = strlen(inpline))) |
||
315 |
strlcat(inpline, " ", inpsize); |
||
316 |
} |
||
317 |
curlen++; |
||
318 |
/* |
||
319 |
* Allocate enough to hold what we will |
||
320 |
* be holding in a second, and to append |
||
321 |
* a space next time through, if we have |
||
322 |
* to. |
||
323 |
*/ |
||
324 |
inpsize = curlen + 2 + strlen(argp); |
||
325 |
inpline = realloc(inpline, inpsize); |
||
326 |
if (inpline == NULL) |
||
327 |
errx(1, "realloc failed"); |
||
328 |
if (curlen == 1) |
||
329 |
strlcpy(inpline, argp, inpsize); |
||
330 |
else |
||
331 |
strlcat(inpline, argp, inpsize); |
||
332 |
} |
||
333 |
} |
||
334 |
|||
335 |
/* |
||
336 |
* If max'd out on args or buffer, or reached EOF, |
||
337 |
* run the command. If xflag and max'd out on buffer |
||
338 |
* but not on args, object. Having reached the limit |
||
339 |
* of input lines, as specified by -L is the same as |
||
340 |
* maxing out on arguments. |
||
341 |
*/ |
||
342 |
✓✗✓✓ ✓✗✓✗ ✗✓ |
84 |
if (xp == endxp || p > ebp || ch == EOF || |
343 |
(Lflag <= count && xflag) || foundeof) { |
||
344 |
✗✓✗✗ ✗✗ |
2 |
if (xflag && xp != endxp && p > ebp) |
345 |
errx(1, "insufficient space for arguments"); |
||
346 |
✗✓ | 2 |
if (jfound) { |
347 |
for (avj = argv; *avj; avj++) |
||
348 |
*xp++ = *avj; |
||
349 |
} |
||
350 |
2 |
prerun(argc, av); |
|
351 |
✓✗ | 1 |
if (ch == EOF || foundeof) { |
352 |
1 |
waitchildren(*argv, 1); |
|
353 |
1 |
exit(rval); |
|
354 |
} |
||
355 |
p = bbp; |
||
356 |
xp = bxp; |
||
357 |
count = 0; |
||
358 |
} |
||
359 |
82 |
argp = p; |
|
360 |
82 |
wasquoted = 0; |
|
361 |
82 |
break; |
|
362 |
case '\'': |
||
363 |
if (indouble || zflag) |
||
364 |
goto addch; |
||
365 |
insingle = !insingle; |
||
366 |
wasquoted = 1; |
||
367 |
break; |
||
368 |
case '"': |
||
369 |
if (insingle || zflag) |
||
370 |
goto addch; |
||
371 |
indouble = !indouble; |
||
372 |
wasquoted = 1; |
||
373 |
break; |
||
374 |
case '\\': |
||
375 |
if (zflag) |
||
376 |
goto addch; |
||
377 |
/* Backslash escapes anything, is escaped by quotes. */ |
||
378 |
if (!insingle && !indouble && (ch = getchar()) == EOF) |
||
379 |
errx(1, "backslash at EOF"); |
||
380 |
/* FALLTHROUGH */ |
||
381 |
default: |
||
382 |
✓✗ | 716 |
addch: if (p < ebp) { |
383 |
716 |
*p++ = ch; |
|
384 |
716 |
break; |
|
385 |
} |
||
386 |
|||
387 |
/* If only one argument, not enough buffer space. */ |
||
388 |
if (bxp == xp) |
||
389 |
errx(1, "insufficient space for argument"); |
||
390 |
/* Didn't hit argument limit, so if xflag object. */ |
||
391 |
if (xflag) |
||
392 |
errx(1, "insufficient space for arguments"); |
||
393 |
|||
394 |
if (jfound) { |
||
395 |
for (avj = argv; *avj; avj++) |
||
396 |
*xp++ = *avj; |
||
397 |
} |
||
398 |
prerun(argc, av); |
||
399 |
xp = bxp; |
||
400 |
cnt = ebp - argp; |
||
401 |
memcpy(bbp, argp, (size_t)cnt); |
||
402 |
p = (argp = bbp) + cnt; |
||
403 |
*p++ = ch; |
||
404 |
break; |
||
405 |
} |
||
406 |
798 |
hadblank = hasblank; |
|
407 |
798 |
} |
|
408 |
|||
409 |
/* |
||
410 |
* Do things necessary before run()'ing, such as -I substitution, |
||
411 |
* and then call run(). |
||
412 |
*/ |
||
413 |
static void |
||
414 |
prerun(int argc, char *argv[]) |
||
415 |
2 |
{ |
|
416 |
char **tmp, **tmp2, **avj; |
||
417 |
int repls; |
||
418 |
|||
419 |
2 |
repls = Rflag; |
|
420 |
2 |
runeof = 0; |
|
421 |
|||
422 |
✓✗ | 2 |
if (argc == 0 || repls == 0) { |
423 |
2 |
*xp = NULL; |
|
424 |
2 |
run(argv); |
|
425 |
1 |
return; |
|
426 |
} |
||
427 |
|||
428 |
avj = argv; |
||
429 |
|||
430 |
/* |
||
431 |
* Allocate memory to hold the argument list, and |
||
432 |
* a NULL at the tail. |
||
433 |
*/ |
||
434 |
tmp = calloc(argc + 1, sizeof(char**)); |
||
435 |
if (tmp == NULL) |
||
436 |
err(1, NULL); |
||
437 |
tmp2 = tmp; |
||
438 |
|||
439 |
/* |
||
440 |
* Save the first argument and iterate over it, we |
||
441 |
* cannot do strnsubst() to it. |
||
442 |
*/ |
||
443 |
if ((*tmp++ = strdup(*avj++)) == NULL) |
||
444 |
err(1, NULL); |
||
445 |
|||
446 |
/* |
||
447 |
* For each argument to utility, if we have not used up |
||
448 |
* the number of replacements we are allowed to do, and |
||
449 |
* if the argument contains at least one occurrence of |
||
450 |
* replstr, call strnsubst(), else just save the string. |
||
451 |
* Iterations over elements of avj and tmp are done |
||
452 |
* where appropriate. |
||
453 |
*/ |
||
454 |
while (--argc) { |
||
455 |
*tmp = *avj++; |
||
456 |
if (repls && strstr(*tmp, replstr) != NULL) { |
||
457 |
strnsubst(tmp++, replstr, inpline, (size_t)255); |
||
458 |
if (repls > 0) |
||
459 |
repls--; |
||
460 |
} else { |
||
461 |
if ((*tmp = strdup(*tmp)) == NULL) |
||
462 |
err(1, NULL); |
||
463 |
tmp++; |
||
464 |
} |
||
465 |
} |
||
466 |
|||
467 |
/* |
||
468 |
* Run it. |
||
469 |
*/ |
||
470 |
*tmp = NULL; |
||
471 |
run(tmp2); |
||
472 |
|||
473 |
/* |
||
474 |
* Walk from the tail to the head, free along the way. |
||
475 |
*/ |
||
476 |
for (; tmp2 != tmp; tmp--) |
||
477 |
free(*tmp); |
||
478 |
/* |
||
479 |
* Now free the list itself. |
||
480 |
*/ |
||
481 |
free(tmp2); |
||
482 |
|||
483 |
/* |
||
484 |
* Free the input line buffer, if we have one. |
||
485 |
*/ |
||
486 |
free(inpline); |
||
487 |
inpline = NULL; |
||
488 |
} |
||
489 |
|||
490 |
static void |
||
491 |
run(char **argv) |
||
492 |
2 |
{ |
|
493 |
pid_t pid; |
||
494 |
int fd; |
||
495 |
char **avec; |
||
496 |
|||
497 |
/* |
||
498 |
* If the user wants to be notified of each command before it is |
||
499 |
* executed, notify them. If they want the notification to be |
||
500 |
* followed by a prompt, then prompt them. |
||
501 |
*/ |
||
502 |
✓✗✗✓ |
2 |
if (tflag || pflag) { |
503 |
(void)fprintf(stderr, "%s", *argv); |
||
504 |
for (avec = argv + 1; *avec != NULL; ++avec) |
||
505 |
(void)fprintf(stderr, " %s", *avec); |
||
506 |
/* |
||
507 |
* If the user has asked to be prompted, do so. |
||
508 |
*/ |
||
509 |
if (pflag) |
||
510 |
/* |
||
511 |
* If they asked not to exec, return without execution |
||
512 |
* but if they asked to, go to the execution. If we |
||
513 |
* could not open their tty, break the switch and drop |
||
514 |
* back to -t behaviour. |
||
515 |
*/ |
||
516 |
switch (prompt()) { |
||
517 |
case 0: |
||
518 |
return; |
||
519 |
case 1: |
||
520 |
goto exec; |
||
521 |
case 2: |
||
522 |
break; |
||
523 |
} |
||
524 |
(void)fprintf(stderr, "\n"); |
||
525 |
(void)fflush(stderr); |
||
526 |
} |
||
527 |
2 |
exec: |
|
528 |
✗✓✓ | 2 |
switch (pid = vfork()) { |
529 |
case -1: |
||
530 |
err(1, "vfork"); |
||
531 |
case 0: |
||
532 |
✗✓ | 1 |
if (oflag) { |
533 |
if ((fd = open(_PATH_TTY, O_RDONLY)) == -1) { |
||
534 |
warn("can't open /dev/tty"); |
||
535 |
_exit(1); |
||
536 |
} |
||
537 |
} else { |
||
538 |
1 |
fd = open(_PATH_DEVNULL, O_RDONLY); |
|
539 |
} |
||
540 |
✓✗ | 1 |
if (fd > STDIN_FILENO) { |
541 |
✗✓ | 1 |
if (dup2(fd, STDIN_FILENO) != 0) { |
542 |
warn("can't dup2 to stdin"); |
||
543 |
_exit(1); |
||
544 |
} |
||
545 |
1 |
close(fd); |
|
546 |
} |
||
547 |
1 |
execvp(argv[0], argv); |
|
548 |
warn("%s", argv[0]); |
||
549 |
_exit(errno == ENOENT ? 127 : 126); |
||
550 |
} |
||
551 |
1 |
curprocs++; |
|
552 |
1 |
waitchildren(*argv, 0); |
|
553 |
} |
||
554 |
|||
555 |
static void |
||
556 |
waitchildren(const char *name, int waitall) |
||
557 |
2 |
{ |
|
558 |
pid_t pid; |
||
559 |
int status; |
||
560 |
|||
561 |
✓✓✓✓ ✓✓ |
5 |
while ((pid = waitpid(-1, &status, !waitall && curprocs < maxprocs ? |
562 |
WNOHANG : 0)) > 0) { |
||
563 |
1 |
curprocs--; |
|
564 |
/* |
||
565 |
* According to POSIX, we have to exit if the utility exits |
||
566 |
* with a 255 status, or is interrupted by a signal. |
||
567 |
* We are allowed to return any exit status between 1 and |
||
568 |
* 125 in these cases, but we'll use 124 and 125, the same |
||
569 |
* values used by GNU xargs. |
||
570 |
*/ |
||
571 |
✓✗ | 1 |
if (WIFEXITED(status)) { |
572 |
✗✓ | 1 |
if (WEXITSTATUS(status) == 255) { |
573 |
warnx("%s exited with status 255", name); |
||
574 |
exit(124); |
||
575 |
✗✓ | 1 |
} else if (WEXITSTATUS(status) == 127 || |
576 |
WEXITSTATUS(status) == 126) { |
||
577 |
exit(WEXITSTATUS(status)); |
||
578 |
✗✓ | 1 |
} else if (WEXITSTATUS(status) != 0) { |
579 |
rval = 123; |
||
580 |
} |
||
581 |
} else if (WIFSIGNALED(status)) { |
||
582 |
if (WTERMSIG(status) != SIGPIPE) { |
||
583 |
if (WTERMSIG(status) < NSIG) |
||
584 |
warnx("%s terminated by SIG%s", name, |
||
585 |
sys_signame[WTERMSIG(status)]); |
||
586 |
else |
||
587 |
warnx("%s terminated by signal %d", |
||
588 |
name, WTERMSIG(status)); |
||
589 |
} |
||
590 |
exit(125); |
||
591 |
} |
||
592 |
} |
||
593 |
✓✗✗✓ |
2 |
if (pid == -1 && errno != ECHILD) |
594 |
err(1, "waitpid"); |
||
595 |
2 |
} |
|
596 |
|||
597 |
/* |
||
598 |
* Prompt the user about running a command. |
||
599 |
*/ |
||
600 |
static int |
||
601 |
prompt(void) |
||
602 |
{ |
||
603 |
regex_t cre; |
||
604 |
size_t rsize; |
||
605 |
int match; |
||
606 |
char *response; |
||
607 |
FILE *ttyfp; |
||
608 |
|||
609 |
if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL) |
||
610 |
return (2); /* Indicate that the TTY failed to open. */ |
||
611 |
(void)fprintf(stderr, "?..."); |
||
612 |
(void)fflush(stderr); |
||
613 |
if ((response = fgetln(ttyfp, &rsize)) == NULL || |
||
614 |
regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) { |
||
615 |
(void)fclose(ttyfp); |
||
616 |
return (0); |
||
617 |
} |
||
618 |
response[rsize - 1] = '\0'; |
||
619 |
match = regexec(&cre, response, 0, NULL, 0); |
||
620 |
(void)fclose(ttyfp); |
||
621 |
regfree(&cre); |
||
622 |
return (match == 0); |
||
623 |
} |
||
624 |
|||
625 |
static void |
||
626 |
usage(void) |
||
627 |
{ |
||
628 |
fprintf(stderr, |
||
629 |
"usage: xargs [-0oprt] [-E eofstr] [-I replstr [-R replacements]] [-J replstr]\n" |
||
630 |
" [-L number] [-n number [-x]] [-P maxprocs] [-s size]\n" |
||
631 |
" [utility [argument ...]]\n"); |
||
632 |
exit(1); |
||
633 |
} |
Generated by: GCOVR (Version 3.3) |