diff options
author | jilles <jilles@FreeBSD.org> | 2012-03-16 16:41:28 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2012-03-16 16:41:28 +0000 |
commit | b984bc44eda30371243a1c0a2180b9994c17bb04 (patch) | |
tree | 288aa85d576f0761599d4b53399c0c557089e577 | |
parent | c54c4cd884dadebbd9aa62993a50211a7f6ef365 (diff) | |
download | FreeBSD-src-b984bc44eda30371243a1c0a2180b9994c17bb04.zip FreeBSD-src-b984bc44eda30371243a1c0a2180b9994c17bb04.tar.gz |
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
-rw-r--r-- | usr.bin/xargs/xargs.1 | 16 | ||||
-rw-r--r-- | usr.bin/xargs/xargs.c | 110 |
2 files changed, 81 insertions, 45 deletions
diff --git a/usr.bin/xargs/xargs.1 b/usr.bin/xargs/xargs.1 index 32dfa3c..f3dabc1 100644 --- a/usr.bin/xargs/xargs.1 +++ b/usr.bin/xargs/xargs.1 @@ -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 diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c index d102ce6..e204528 100644 --- a/usr.bin/xargs/xargs.c +++ b/usr.bin/xargs/xargs.c @@ -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 @@ arg2: */ 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 @@ arg2: */ 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 @@ arg2: 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 @@ exec: 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) @@ -593,26 +609,46 @@ xwait(int block, int *status) { } 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"); } |