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");
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to