From owner-svn-src-all@FreeBSD.ORG Fri Mar 16 16:41:29 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 7B016106566B; Fri, 16 Mar 2012 16:41:29 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 658F18FC12; Fri, 16 Mar 2012 16:41:29 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q2GGfTNs026079; Fri, 16 Mar 2012 16:41:29 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q2GGfTPA026076; Fri, 16 Mar 2012 16:41:29 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201203161641.q2GGfTPA026076@svn.freebsd.org> From: Jilles Tjoelker Date: Fri, 16 Mar 2012 16:41:29 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r233038 - head/usr.bin/xargs X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 16 Mar 2012 16:41:29 -0000 Author: jilles Date: Fri Mar 16 16:41:28 2012 New Revision: 233038 URL: http://svn.freebsd.org/changeset/base/233038 Log: 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 Modified: head/usr.bin/xargs/xargs.1 head/usr.bin/xargs/xargs.c Modified: head/usr.bin/xargs/xargs.1 ============================================================================== --- head/usr.bin/xargs/xargs.1 Fri Mar 16 16:29:21 2012 (r233037) +++ head/usr.bin/xargs/xargs.1 Fri Mar 16 16:41:28 2012 (r233038) @@ -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 Modified: head/usr.bin/xargs/xargs.c ============================================================================== --- head/usr.bin/xargs/xargs.c Fri Mar 16 16:29:21 2012 (r233037) +++ head/usr.bin/xargs/xargs.c Fri Mar 16 16:41:28 2012 (r233038) @@ -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"); }