xargs: Before exiting, wait for all invocations of the utility.
This only has an effect with -P, otherwise errors are only detected when the utility is not running. Submitted by: Matthew Story
This commit is contained in:
parent
c54c4cd884
commit
b984bc44ed
@ -33,7 +33,7 @@
|
||||
.\" $FreeBSD$
|
||||
.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
|
||||
.\"
|
||||
.Dd March 24, 2011
|
||||
.Dd March 16, 2012
|
||||
.Dt XARGS 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -294,17 +294,17 @@ Undefined behavior may occur if
|
||||
.Ar utility
|
||||
reads from the standard input.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility exits immediately (without processing any further input) if a
|
||||
command line cannot be assembled,
|
||||
.Ar utility
|
||||
cannot be invoked, an invocation of
|
||||
If a command line cannot be assembled, or
|
||||
cannot be invoked, or if an invocation of
|
||||
.Ar utility
|
||||
is terminated by a signal,
|
||||
or an invocation of
|
||||
.Ar utility
|
||||
exits with a value of 255.
|
||||
exits with a value of 255, the
|
||||
.Nm
|
||||
utility stops processing input and exits after all invocations of
|
||||
.Ar utility
|
||||
finish processing.
|
||||
.Sh EXIT STATUS
|
||||
The
|
||||
.Nm
|
||||
|
@ -70,6 +70,7 @@ static void run(char **);
|
||||
static void usage(void);
|
||||
void strnsubst(char **, const char *, const char *, size_t);
|
||||
static pid_t xwait(int block, int *status);
|
||||
static void xexit(const char *, const int);
|
||||
static void waitchildren(const char *, int);
|
||||
static void pids_init(void);
|
||||
static int pids_empty(void);
|
||||
@ -280,10 +281,8 @@ parse_input(int argc, char *argv[])
|
||||
switch (ch = getchar()) {
|
||||
case EOF:
|
||||
/* No arguments since last exec. */
|
||||
if (p == bbp) {
|
||||
waitchildren(*av, 1);
|
||||
exit(rval);
|
||||
}
|
||||
if (p == bbp)
|
||||
xexit(*av, rval);
|
||||
goto arg1;
|
||||
case ' ':
|
||||
case '\t':
|
||||
@ -308,8 +307,10 @@ parse_input(int argc, char *argv[])
|
||||
count++; /* Indicate end-of-line (used by -L) */
|
||||
|
||||
/* Quotes do not escape newlines. */
|
||||
arg1: if (insingle || indouble)
|
||||
errx(1, "unterminated quote");
|
||||
arg1: if (insingle || indouble) {
|
||||
warnx("unterminated quote");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
arg2:
|
||||
foundeof = *eofstr != '\0' &&
|
||||
strncmp(argp, eofstr, p - argp) == 0;
|
||||
@ -342,8 +343,10 @@ arg1: if (insingle || indouble)
|
||||
*/
|
||||
inpline = realloc(inpline, curlen + 2 +
|
||||
strlen(argp));
|
||||
if (inpline == NULL)
|
||||
errx(1, "realloc failed");
|
||||
if (inpline == NULL) {
|
||||
warnx("realloc failed");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
if (curlen == 1)
|
||||
strcpy(inpline, argp);
|
||||
else
|
||||
@ -360,17 +363,17 @@ arg1: if (insingle || indouble)
|
||||
*/
|
||||
if (xp == endxp || p > ebp || ch == EOF ||
|
||||
(Lflag <= count && xflag) || foundeof) {
|
||||
if (xflag && xp != endxp && p > ebp)
|
||||
errx(1, "insufficient space for arguments");
|
||||
if (xflag && xp != endxp && p > ebp) {
|
||||
warnx("insufficient space for arguments");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
if (jfound) {
|
||||
for (avj = argv; *avj; avj++)
|
||||
*xp++ = *avj;
|
||||
}
|
||||
prerun(argc, av);
|
||||
if (ch == EOF || foundeof) {
|
||||
waitchildren(*av, 1);
|
||||
exit(rval);
|
||||
}
|
||||
if (ch == EOF || foundeof)
|
||||
xexit(*av, rval);
|
||||
p = bbp;
|
||||
xp = bxp;
|
||||
count = 0;
|
||||
@ -394,8 +397,10 @@ arg1: if (insingle || indouble)
|
||||
if (zflag)
|
||||
goto addch;
|
||||
/* Backslash escapes anything, is escaped by quotes. */
|
||||
if (!insingle && !indouble && (ch = getchar()) == EOF)
|
||||
errx(1, "backslash at EOF");
|
||||
if (!insingle && !indouble && (ch = getchar()) == EOF) {
|
||||
warnx("backslash at EOF");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
addch: if (p < ebp) {
|
||||
@ -404,11 +409,15 @@ addch: if (p < ebp) {
|
||||
}
|
||||
|
||||
/* If only one argument, not enough buffer space. */
|
||||
if (bxp == xp)
|
||||
errx(1, "insufficient space for argument");
|
||||
if (bxp == xp) {
|
||||
warnx("insufficient space for argument");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
/* Didn't hit argument limit, so if xflag object. */
|
||||
if (xflag)
|
||||
errx(1, "insufficient space for arguments");
|
||||
if (xflag) {
|
||||
warnx("insufficient space for arguments");
|
||||
xexit(*av, 1);
|
||||
}
|
||||
|
||||
if (jfound) {
|
||||
for (avj = argv; *avj; avj++)
|
||||
@ -449,16 +458,20 @@ prerun(int argc, char *argv[])
|
||||
* a NULL at the tail.
|
||||
*/
|
||||
tmp = malloc((argc + 1) * sizeof(char**));
|
||||
if (tmp == NULL)
|
||||
errx(1, "malloc failed");
|
||||
if (tmp == NULL) {
|
||||
warnx("malloc failed");
|
||||
xexit(*argv, 1);
|
||||
}
|
||||
tmp2 = tmp;
|
||||
|
||||
/*
|
||||
* Save the first argument and iterate over it, we
|
||||
* cannot do strnsubst() to it.
|
||||
*/
|
||||
if ((*tmp++ = strdup(*avj++)) == NULL)
|
||||
errx(1, "strdup failed");
|
||||
if ((*tmp++ = strdup(*avj++)) == NULL) {
|
||||
warnx("strdup failed");
|
||||
xexit(*argv, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* For each argument to utility, if we have not used up
|
||||
@ -475,8 +488,10 @@ prerun(int argc, char *argv[])
|
||||
if (repls > 0)
|
||||
repls--;
|
||||
} else {
|
||||
if ((*tmp = strdup(*tmp)) == NULL)
|
||||
errx(1, "strdup failed");
|
||||
if ((*tmp = strdup(*tmp)) == NULL) {
|
||||
warnx("strdup failed");
|
||||
xexit(*argv, 1);
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
}
|
||||
@ -547,7 +562,8 @@ run(char **argv)
|
||||
childerr = 0;
|
||||
switch (pid = vfork()) {
|
||||
case -1:
|
||||
err(1, "vfork");
|
||||
warn("vfork");
|
||||
xexit(*argv, 1);
|
||||
case 0:
|
||||
if (oflag) {
|
||||
if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
|
||||
@ -592,27 +608,47 @@ xwait(int block, int *status) {
|
||||
return (pid);
|
||||
}
|
||||
|
||||
static void
|
||||
xexit(const char *name, const int exit_code) {
|
||||
waitchildren(name, 1);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
static void
|
||||
waitchildren(const char *name, int waitall)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
int cause_exit = 0;
|
||||
|
||||
while ((pid = xwait(waitall || pids_full(), &status)) > 0) {
|
||||
/* If we couldn't invoke the utility, exit. */
|
||||
if (childerr != 0) {
|
||||
/*
|
||||
* If we couldn't invoke the utility or if utility exited
|
||||
* because of a signal or with a value of 255, warn (per
|
||||
* POSIX), and then wait until all other children have
|
||||
* exited before exiting 1-125. POSIX requires us to stop
|
||||
* reading if child exits because of a signal or with 255,
|
||||
* but it does not require us to exit immediately; waiting
|
||||
* is preferable to orphaning.
|
||||
*/
|
||||
if (childerr != 0 && cause_exit == 0) {
|
||||
errno = childerr;
|
||||
err(errno == ENOENT ? 127 : 126, "%s", name);
|
||||
}
|
||||
if (WIFSIGNALED(status))
|
||||
errx(1, "%s: terminated with signal %d; aborting",
|
||||
waitall = 1;
|
||||
cause_exit = ENOENT ? 127 : 126;
|
||||
warn("%s", name);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
waitall = cause_exit = 1;
|
||||
warnx("%s: terminated with signal %d; aborting",
|
||||
name, WTERMSIG(status));
|
||||
if (WEXITSTATUS(status) == 255)
|
||||
errx(1, "%s: exited with status 255; aborting", name);
|
||||
if (WEXITSTATUS(status))
|
||||
rval = 1;
|
||||
} else if (WEXITSTATUS(status) == 255) {
|
||||
waitall = cause_exit = 1;
|
||||
warnx("%s: exited with status 255; aborting", name);
|
||||
} else if (WEXITSTATUS(status))
|
||||
rval = 1;
|
||||
}
|
||||
|
||||
if (cause_exit)
|
||||
exit(cause_exit);
|
||||
if (pid == -1 && errno != ECHILD)
|
||||
err(1, "waitpid");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user