]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Make the subprocess and pipe primitives more reliable and more flexible.
authorBruno Haible <bruno@clisp.org>
Wed, 24 Oct 2001 09:54:43 +0000 (09:54 +0000)
committerBruno Haible <bruno@clisp.org>
Wed, 24 Oct 2001 09:54:43 +0000 (09:54 +0000)
18 files changed:
lib/ChangeLog
lib/Makefile.am
lib/execute.c
lib/execute.h
lib/javacomp.c
lib/javaexec.c
lib/pipe-bidi.c
lib/pipe-in.c
lib/pipe-out.c
lib/pipe.h
lib/wait-process.c
lib/wait-process.h
m4/ChangeLog
m4/javacomp.m4
src/ChangeLog
src/msgexec.c
src/msggrep.c
src/read-java.c

index ce99523aff61e675e158af9766f9ffd5cd9f77d4..722f252f0466400c150d8c37c9d7c7880532bc73 100644 (file)
@@ -1,3 +1,25 @@
+2001-10-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * wait-process.h (wait_subprocess): New argument 'exit_on_error'.
+       * wait-process.c (wait_subprocess): Implement 'exit_on_error' handling.
+       Treat exitcode 127 like a failure to create the subprocess.
+       * execute.h (execute): New argument 'exit_on_error'.
+       * execute.c (execute): Implement 'exit_on_error' handling.
+       * pipe.h (create_pipe_out, create_pipe_in, create_pipe_bidi): New
+       arguments 'null_stderr' and 'exit_on_error'.
+       * pipe-in.c (create_pipe_in): Implement 'null_stderr' and
+       'exit_on_error' handling.
+       * pipe-out.c (create_pipe_out): Likewise.
+       * pipe-bidi.c (create_pipe_bidi): Likewise.
+       * javacomp.c: Include pipe.h, wait-process.h, safe-read.h.
+       (compile_java_class): Update for changed execute(). When testing for
+       gcj, ignore gcj version 2.xx, require at least gcj 3.0.
+       * javaexec.c (execute_java_class): Update for changed execute().
+       * Makefile.am (libnlsut_a_SOURCES): Add safe-read.c.
+       (libnlsut_a_HEADER): Add safe-read.h.
+       (UNUSED_SOURCE): Remove safe-read.c.
+       (UNUSED_HEADER): Remove safe-read.h.
+
 2001-09-25  Bruno Haible  <haible@clisp.cons.org>
 
        Upgrade to automake-1.5.
index 92d8ffa56b30107abaed25e17c930464aa900385..ed213bd048c7c78af799a1829ced974cb375f8bb 100644 (file)
@@ -26,13 +26,13 @@ noinst_LIBRARIES = libnlsut.a
 libnlsut_a_SOURCES = addext.c argmatch.c backupfile.c basename.c c-ctype.c \
 concatpath.c copy-file.c execute.c findprog.c fstrcmp.c full-write.c gcd.c \
 getopt.c getopt1.c hash.c javacomp.c javaexec.c linebreak.c localcharset.c \
-mbswidth.c obstack.c pipe-bidi.c pipe-in.c pipe-out.c progname.c sh-quote.c \
-tmpdir.c wait-process.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
+mbswidth.c obstack.c pipe-bidi.c pipe-in.c pipe-out.c progname.c safe-read.c \
+sh-quote.c tmpdir.c wait-process.c xerror.c xgetcwd.c xmalloc.c xstrdup.c
 
 libnlsut_a_HEADER = argmatch.h backupfile.h basename.h c-ctype.h copy-file.h \
 execute.h findprog.h fstrcmp.h full-write.h gcd.h getopt.h hash.h javacomp.h \
 javaexec.h lbrkprop.h linebreak.h mbswidth.h obstack.h pathmax.h pipe.h \
-progname.h sh-quote.h system.h tmpdir.h utf8-ucs4.h utf16-ucs4.h \
+progname.h safe-read.h sh-quote.h system.h tmpdir.h utf8-ucs4.h utf16-ucs4.h \
 wait-process.h xerror.h xmalloc.h
 
 # Sources that are compiled only on platforms that lack the functions.
@@ -45,9 +45,9 @@ LIBADD_HEADER = error.h getline.h mkdtemp.h setenv.h strpbrk.h strstr.h
 
 # Unused sources.
 
-UNUSED_SOURCE = memmove.c safe-read.c
+UNUSED_SOURCE = memmove.c
 
-UNUSED_HEADER = safe-read.h
+UNUSED_HEADER =
 
 libnlsut_a_LIBADD = @ALLOCA@ @LIBOBJS@
 
index 48cba72f765538c0aef2d79044c3065a6cd80dbb..0082959c353fb255977770ca2c95e612607cdd75 100644 (file)
@@ -107,19 +107,27 @@ nonintr_open (pathname, oflag, mode)
 
 
 /* Execute a command, optionally redirecting any of the three standard file
-   descriptors to /dev/null.  Exit if it didn't terminate correctly.
-   Otherwise return its exit code.  */
+   descriptors to /dev/null.  Return its exit code.
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
+   return 127.  */
 int
-execute (progname, prog_path, prog_argv, null_stdin, null_stdout, null_stderr)
+execute (progname, prog_path, prog_argv, null_stdin, null_stdout, null_stderr, exit_on_error)
      const char *progname;
      const char *prog_path;
      char **prog_argv;
      bool null_stdin;
      bool null_stdout;
      bool null_stderr;
+     bool exit_on_error;
 {
+  /* Note about 127: Some errors during posix_spawnp() cause the function
+     posix_spawnp() to return an error code; some other errors cause the
+     subprocess to exit with return code 127.  It is implementation
+     dependent which error is reported which way.  We treat both cases as
+     equivalent.  */
 #if HAVE_POSIX_SPAWN
   posix_spawn_file_actions_t actions;
+  bool actions_allocated;
   int err;
   pid_t child;
 #else
@@ -127,22 +135,38 @@ execute (progname, prog_path, prog_argv, null_stdin, null_stdout, null_stderr)
 #endif
 
 #if HAVE_POSIX_SPAWN
+  actions_allocated = false;
   if ((err = posix_spawn_file_actions_init (&actions)) != 0
-      || (null_stdin
-         && (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO,
-                                                     "/dev/null", O_RDONLY, 0))
-            != 0)
-      || (null_stdout
-         && (err = posix_spawn_file_actions_addopen (&actions, STDOUT_FILENO,
-                                                     "/dev/null", O_RDWR, 0))
-            != 0)
-      || (null_stderr
-         && (err = posix_spawn_file_actions_addopen (&actions, STDERR_FILENO,
-                                                     "/dev/null", O_RDWR, 0))
-            != 0)
-      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
-                             environ)) != 0)
-    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      || (actions_allocated = true,
+         (null_stdin
+           && (err = posix_spawn_file_actions_addopen (&actions,
+                                                       STDIN_FILENO,
+                                                       "/dev/null", O_RDONLY,
+                                                       0))
+              != 0)
+         || (null_stdout
+             && (err = posix_spawn_file_actions_addopen (&actions,
+                                                         STDOUT_FILENO,
+                                                         "/dev/null", O_RDWR,
+                                                         0))
+                != 0)
+         || (null_stderr
+             && (err = posix_spawn_file_actions_addopen (&actions,
+                                                         STDERR_FILENO,
+                                                         "/dev/null", O_RDWR,
+                                                         0))
+                != 0)
+         || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                                 environ))
+            != 0))
+    {
+      if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+      if (exit_on_error)
+       error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      else
+       return 127;
+    }
   posix_spawn_file_actions_destroy (&actions);
 #else
   /* Use vfork() instead of fork() for efficiency.  */
@@ -172,8 +196,13 @@ execute (progname, prog_path, prog_argv, null_stdin, null_stdout, null_stderr)
       _exit (-1);
     }
   if (child == -1)
-    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+      else
+       return 127;
+    }
 #endif
 
-  return wait_subprocess (child, progname);
+  return wait_subprocess (child, progname, exit_on_error);
 }
index 7a2cc491c9735f60a53131c7fe464b4807c54725..ac0fbeddbda5072c3e99a90495cdcbd016c6694d 100644 (file)
 #include <stdbool.h>
 
 /* Execute a command, optionally redirecting any of the three standard file
-   descriptors to /dev/null.  Exit if it didn't terminate correctly.
-   Otherwise return its exit code.  */
+   descriptors to /dev/null.  Return its exit code.
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
+   return 127.  */
 extern int execute PARAMS ((const char *progname,
                            const char *prog_path, char **prog_argv,
                            bool null_stdin,
-                           bool null_stdout, bool null_stderr));
+                           bool null_stdout, bool null_stderr,
+                           bool exit_on_error));
 
 #endif /* _EXECUTE_H */
index 04598a809cae8221dd1705611e61b6b2c5b9d0fb..556bffed851b0477c1e604253fd40949bd0019e6 100644 (file)
 #include <string.h>
 
 #include "execute.h"
+#include "pipe.h"
+#include "wait-process.h"
 #include "setenv.h"
 #include "sh-quote.h"
+#include "safe-read.h"
 #include "xmalloc.h"
 #include "error.h"
 #include "libgettext.h"
@@ -51,7 +54,7 @@
    Program  from        A  C               O  g  T
 
    $JAVAC   unknown     N  n/a            -O -g  true
-   gcj -C   GCC 3.0     Y  --classpath=P  -O -g  gcj --version >/dev/null
+   gcj -C   GCC 3.0     Y  --classpath=P  -O -g  gcj --version | grep '^[3-9]' >/dev/null
    javac    JDK 1.1.8   Y  -classpath P   -O -g  javac 2>/dev/null; test $? = 1
    javac    JDK 1.3.0   Y  -classpath P   -O -g  javac 2>/dev/null; test $? -le 2
    jikes    Jikes 1.14  N  -classpath P   -O -g  jikes 2>/dev/null; test $? = 1
@@ -163,7 +166,8 @@ compile_java_class (java_sources, java_sources_count,
        argv[1] = "-c";
        argv[2] = command;
        argv[3] = NULL;
-       exitstatus = execute (javac, "/bin/sh", argv, false, false, false);
+       exitstatus = execute (javac, "/bin/sh", argv, false, false, false,
+                             true);
        err = (exitstatus != 0);
 
        /* Reset CLASSPATH.  */
@@ -187,15 +191,38 @@ compile_java_class (java_sources, java_sources_count,
 
     if (!gcj_tested)
       {
-       /* Test for presence of gcj: "gcj --version > /dev/null"  */
+       /* Test for presence of gcj:
+          "gcj --version 2> /dev/null | grep '^[3-9]' > /dev/null"  */
        char *argv[3];
+       pid_t child;
+       int fd[1];
        int exitstatus;
 
        argv[0] = "gcj";
        argv[1] = "--version";
        argv[2] = NULL;
-       exitstatus = execute ("gcj", "gcj", argv, false, true, true);
-       gcj_present = (exitstatus == 0);
+       child = create_pipe_in ("gcj", "gcj", argv, "/dev/null", true, false,
+                               fd);
+       gcj_present = false;
+       if (child != -1)
+         {
+           /* Read the subprocess output, a single line, and test whether
+              it starts with a digit >= 3.  */
+           char c;
+
+           if (safe_read (fd[0], &c, 1) > 0)
+             gcj_present = (c >= '3' && c <= '9');
+           while (safe_read (fd[0], &c, 1) > 0)
+             ;
+
+           close (fd[0]);
+
+           /* Remove zombie process from process list, and retrieve exit
+              status.  */
+           exitstatus = wait_subprocess (child, "gcj", false);
+           if (exitstatus != 0)
+             gcj_present = false;
+         }
        gcj_tested = true;
       }
 
@@ -247,7 +274,7 @@ compile_java_class (java_sources, java_sources_count,
            free (command);
          }
 
-       exitstatus = execute ("gcj", "gcj", argv, false, false, false);
+       exitstatus = execute ("gcj", "gcj", argv, false, false, false, true);
        err = (exitstatus != 0);
 
        /* Reset CLASSPATH.  */
@@ -269,7 +296,8 @@ compile_java_class (java_sources, java_sources_count,
 
        argv[0] = "javac";
        argv[1] = NULL;
-       exitstatus = execute ("javac", "javac", argv, false, true, true);
+       exitstatus = execute ("javac", "javac", argv, false, true, true,
+                             false);
        javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2);
        javac_tested = true;
       }
@@ -320,7 +348,8 @@ compile_java_class (java_sources, java_sources_count,
            free (command);
          }
 
-       exitstatus = execute ("javac", "javac", argv, false, false, false);
+       exitstatus = execute ("javac", "javac", argv, false, false, false,
+                             true);
        err = (exitstatus != 0);
 
        /* Reset CLASSPATH.  */
@@ -342,7 +371,8 @@ compile_java_class (java_sources, java_sources_count,
 
        argv[0] = "jikes";
        argv[1] = NULL;
-       exitstatus = execute ("jikes", "jikes", argv, false, true, true);
+       exitstatus = execute ("jikes", "jikes", argv, false, true, true,
+                             false);
        jikes_present = (exitstatus == 0 || exitstatus == 1);
        jikes_tested = true;
       }
@@ -395,7 +425,8 @@ compile_java_class (java_sources, java_sources_count,
            free (command);
          }
 
-       exitstatus = execute ("jikes", "jikes", argv, false, false, false);
+       exitstatus = execute ("jikes", "jikes", argv, false, false, false,
+                             true);
        err = (exitstatus != 0);
 
        /* Reset CLASSPATH.  */
index 162685556db3d2c26dcd348d06daff5ccff48f53..4d473933bf428f7bcb8939aaa2300839ce083155 100644 (file)
@@ -179,7 +179,7 @@ execute_java_class (class_name,
        argv[0] = "gij";
        argv[1] = "--version";
        argv[2] = NULL;
-       exitstatus = execute ("gij", "gij", argv, false, true, true);
+       exitstatus = execute ("gij", "gij", argv, false, true, true, false);
        gij_present = (exitstatus == 0);
        gij_tested = true;
       }
@@ -229,7 +229,7 @@ execute_java_class (class_name,
        argv[0] = "java";
        argv[1] = "-version";
        argv[2] = NULL;
-       exitstatus = execute ("java", "java", argv, false, true, true);
+       exitstatus = execute ("java", "java", argv, false, true, true, false);
        java_present = (exitstatus == 0);
        java_tested = true;
       }
@@ -280,7 +280,7 @@ execute_java_class (class_name,
 
        argv[0] = "jre";
        argv[1] = NULL;
-       exitstatus = execute ("jre", "jre", argv, false, true, true);
+       exitstatus = execute ("jre", "jre", argv, false, true, true, false);
        jre_present = (exitstatus == 0 || exitstatus == 1);
        jre_tested = true;
       }
@@ -334,7 +334,8 @@ execute_java_class (class_name,
        argv[0] = "jview";
        argv[1] = "-?";
        argv[2] = NULL;
-       exitstatus = execute ("jview", "jview", argv, false, true, true);
+       exitstatus = execute ("jview", "jview", argv, false, true, true,
+                             false);
        jview_present = (exitstatus == 0 || exitstatus == 1);
        jview_tested = true;
       }
index e159f62f286df192840f5e71fe0dc03f892c48f1..95b4c3fc52460c80b026b619d5f211c3b58e1afe 100644 (file)
@@ -25,6 +25,7 @@
 #include "pipe.h"
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdlib.h>
 
 #ifdef HAVE_UNISTD_H
@@ -91,16 +92,19 @@ nonintr_close (fd)
  *
  */
 pid_t
-create_pipe_bidi (progname, prog_path, prog_argv, fd)
+create_pipe_bidi (progname, prog_path, prog_argv, null_stderr, exit_on_error, fd)
      const char *progname;
      const char *prog_path;
      char **prog_argv;
+     bool null_stderr;
+     bool exit_on_error;
      int fd[2];
 {
   int ifd[2];
   int ofd[2];
 #if HAVE_POSIX_SPAWN
   posix_spawn_file_actions_t actions;
+  bool actions_allocated;
   int err;
   pid_t child;
 #else
@@ -121,18 +125,40 @@ create_pipe_bidi (progname, prog_path, prog_argv, fd)
  */
 
 #if HAVE_POSIX_SPAWN
+  actions_allocated = false;
   if ((err = posix_spawn_file_actions_init (&actions)) != 0
-      || (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                 ofd[0], STDIN_FILENO)) != 0
-      || (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                 ifd[1], STDOUT_FILENO)) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
-      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
-                             environ)) != 0)
-    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      || (actions_allocated = true,
+         (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                  ofd[0], STDIN_FILENO)) != 0
+         || (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                     ifd[1], STDOUT_FILENO))
+            != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
+         || (null_stderr
+             && (err = posix_spawn_file_actions_addopen (&actions,
+                                                         STDERR_FILENO,
+                                                         "/dev/null", O_RDWR,
+                                                         0))
+                != 0)
+         || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                                 environ)) != 0))
+    {
+      if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+      if (exit_on_error)
+       error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ifd[0]);
+         close (ifd[1]);
+         close (ofd[0]);
+         close (ofd[1]);
+         return -1;
+       }
+    }
   posix_spawn_file_actions_destroy (&actions);
 #else
   /* Use vfork() instead of fork() for efficiency.  */
@@ -144,12 +170,28 @@ create_pipe_bidi (progname, prog_path, prog_argv, fd)
          && close (ofd[0]) >= 0
          && close (ifd[1]) >= 0
          && close (ofd[1]) >= 0
-         && close (ifd[0]) >= 0)
+         && close (ifd[0]) >= 0
+         && (!null_stderr
+             || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
+                 && (nulloutfd == STDERR_FILENO
+                     || (dup2 (nulloutfd, STDERR_FILENO) >= 0
+                         && close (nulloutfd) >= 0)))))
        execvp (prog_path, prog_argv);
       _exit (-1);
     }
   if (child == -1)
-    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ifd[0]);
+         close (ifd[1]);
+         close (ofd[0]);
+         close (ofd[1]);
+         return -1;
+       }
+    }
 #endif
   close (ofd[0]);
   close (ifd[1]);
index 8149f49347cf7701fb5792eba5208fd0c48f0aad..1c20963a4af03139bd1e8761177231e537a4f0f9 100644 (file)
@@ -109,16 +109,19 @@ nonintr_open (pathname, oflag, mode)
  *
  */
 pid_t
-create_pipe_in (progname, prog_path, prog_argv, prog_stdin, fd)
+create_pipe_in (progname, prog_path, prog_argv, prog_stdin, null_stderr, exit_on_error, fd)
      const char *progname;
      const char *prog_path;
      char **prog_argv;
      const char *prog_stdin;
+     bool null_stderr;
+     bool exit_on_error;
      int fd[1];
 {
   int ifd[2];
 #if HAVE_POSIX_SPAWN
   posix_spawn_file_actions_t actions;
+  bool actions_allocated;
   int err;
   pid_t child;
 #else
@@ -134,17 +137,37 @@ create_pipe_in (progname, prog_path, prog_argv, prog_stdin, fd)
  */
 
 #if HAVE_POSIX_SPAWN
+  actions_allocated = false;
   if ((err = posix_spawn_file_actions_init (&actions)) != 0
-      || (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                 ifd[1], STDOUT_FILENO)) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
-      || (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO,
-                                                 prog_stdin, O_RDONLY,
-                                                 0)) != 0
-      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
-                             environ)) != 0)
-    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      || (actions_allocated = true,
+         (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                  ifd[1], STDOUT_FILENO)) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
+         || (null_stderr
+             && (err = posix_spawn_file_actions_addopen (&actions,
+                                                         STDERR_FILENO,
+                                                         "/dev/null", O_RDWR,
+                                                         0))
+                != 0)
+         || (err = posix_spawn_file_actions_addopen (&actions,
+                                                     STDIN_FILENO,
+                                                     prog_stdin, O_RDONLY,
+                                                     0)) != 0
+         || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                                 environ)) != 0))
+    {
+      if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+      if (exit_on_error)
+       error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ifd[0]);
+         close (ifd[1]);
+         return -1;
+       }
+    }
   posix_spawn_file_actions_destroy (&actions);
 #else
   /* Use vfork() instead of fork() for efficiency.  */
@@ -152,10 +175,16 @@ create_pipe_in (progname, prog_path, prog_argv, prog_stdin, fd)
     {
       /* Child process code.  */
       int stdinfd;
+      int nulloutfd;
 
       if (dup2 (ifd[1], STDOUT_FILENO) >= 0
          && close (ifd[1]) >= 0
          && close (ifd[0]) >= 0
+         && (!null_stderr
+             || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
+                 && (nulloutfd == STDERR_FILENO
+                     || (dup2 (nulloutfd, STDERR_FILENO) >= 0
+                         && close (nulloutfd) >= 0))))
          && (stdinfd = open (prog_stdin, O_RDONLY, 0)) >= 0
          && (stdinfd == STDIN_FILENO
              || (dup2 (stdinfd, STDIN_FILENO) >= 0
@@ -164,7 +193,16 @@ create_pipe_in (progname, prog_path, prog_argv, prog_stdin, fd)
       _exit (-1);
     }
   if (child == -1)
-    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ifd[0]);
+         close (ifd[1]);
+         return -1;
+       }
+    }
 #endif
   close (ifd[1]);
 
index 60aab62b3619cc3137fc027a150c6c3951201e99..059df7f0dcf2b2ea73f4ed379aa12a99558f8c54 100644 (file)
@@ -109,16 +109,19 @@ nonintr_open (pathname, oflag, mode)
  *
  */
 pid_t
-create_pipe_out (progname, prog_path, prog_argv, prog_stdout, fd)
+create_pipe_out (progname, prog_path, prog_argv, prog_stdout, null_stderr, exit_on_error, fd)
      const char *progname;
      const char *prog_path;
      char **prog_argv;
      const char *prog_stdout;
+     bool null_stderr;
+     bool exit_on_error;
      int fd[1];
 {
   int ofd[2];
 #if HAVE_POSIX_SPAWN
   posix_spawn_file_actions_t actions;
+  bool actions_allocated;
   int err;
   pid_t child;
 #else
@@ -134,17 +137,37 @@ create_pipe_out (progname, prog_path, prog_argv, prog_stdout, fd)
  */
 
 #if HAVE_POSIX_SPAWN
+  actions_allocated = false;
   if ((err = posix_spawn_file_actions_init (&actions)) != 0
-      || (err = posix_spawn_file_actions_adddup2 (&actions,
-                                                 ofd[0], STDIN_FILENO)) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
-      || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
-      || (err = posix_spawn_file_actions_addopen (&actions, STDOUT_FILENO,
-                                                 prog_stdout, O_WRONLY,
-                                                 0)) != 0
-      || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
-                             environ)) != 0)
-    error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      || (actions_allocated = true,
+         (err = posix_spawn_file_actions_adddup2 (&actions,
+                                                  ofd[0], STDIN_FILENO)) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
+         || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
+         || (null_stderr
+             && (err = posix_spawn_file_actions_addopen (&actions,
+                                                         STDERR_FILENO,
+                                                         "/dev/null", O_RDWR,
+                                                         0))
+                != 0)
+         || (err = posix_spawn_file_actions_addopen (&actions,
+                                                     STDOUT_FILENO,
+                                                     prog_stdout, O_WRONLY,
+                                                     0)) != 0
+         || (err = posix_spawnp (&child, prog_path, &actions, NULL, prog_argv,
+                                 environ)) != 0))
+    {
+      if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+      if (exit_on_error)
+       error (EXIT_FAILURE, err, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ofd[0]);
+         close (ofd[1]);
+         return -1;
+       }
+    }
   posix_spawn_file_actions_destroy (&actions);
 #else
   /* Use vfork() instead of fork() for efficiency.  */
@@ -156,6 +179,11 @@ create_pipe_out (progname, prog_path, prog_argv, prog_stdout, fd)
       if (dup2 (ofd[0], STDIN_FILENO) >= 0
          && close (ofd[0]) >= 0
          && close (ofd[1]) >= 0
+         && (!null_stderr
+             || ((nulloutfd = open ("/dev/null", O_RDWR, 0)) >= 0
+                 && (nulloutfd == STDERR_FILENO
+                     || (dup2 (nulloutfd, STDERR_FILENO) >= 0
+                         && close (nulloutfd) >= 0))))
          && (stdoutfd = open (prog_stdout, O_WRONLY, 0)) >= 0
          && (stdoutfd == STDOUT_FILENO
              || (dup2 (stdoutfd, STDOUT_FILENO) >= 0
@@ -164,7 +192,16 @@ create_pipe_out (progname, prog_path, prog_argv, prog_stdout, fd)
       _exit (-1);
     }
   if (child == -1)
-    error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, errno, _("%s subprocess failed"), progname);
+      else
+       {
+         close (ifd[0]);
+         close (ifd[1]);
+         return -1;
+       }
+    }
 #endif
   close (ofd[0]);
 
index 6ee5f1600142e397252918e1bb0b5a69c8e64c5e..c972950a719d0f4a78453439cdad6aa7777c501c 100644 (file)
 #endif
 #include <sys/types.h>
 
+#include <stdbool.h>
+
+/* All these functions create a subprocess and don't wait for its termination.
+   They return the process id of the subprocess.  They also return in fd[]
+   one or two file descriptors for communication with the subprocess.
+   If the subprocess creation fails: if exit_on_error is true, the main
+   process exits with an error message; otherwise, -1 is returned and fd[]
+   remain uninitialized.
+
+   After finishing communication, the caller should call wait_subprocess()
+   to get rid of the subprocess in the process table.
+
+   If exit_on_error is false, a child process id of -1 should be treated the
+   same way as a subprocess which accepts no input, produces no output and
+   terminates with exit code 127.  Why?  Some errors during posix_spawnp()
+   cause the function posix_spawnp() to return an error code; some other
+   errors cause the subprocess to exit with return code 127.  It is
+   implementation dependent which error is reported which way.  The caller
+   must treat both cases as equivalent.  */
+
 /* Open a pipe for output to a child process.
  * The child's stdout goes to a file.
  *
@@ -35,7 +55,8 @@
  */
 extern pid_t create_pipe_out PARAMS ((const char *progname,
                                      const char *prog_path, char **prog_argv,
-                                     const char *prog_stdout,
+                                     const char *prog_stdout, bool null_stderr,
+                                     bool exit_on_error,
                                      int fd[1]));
 
 /* Open a pipe for input from a child process.
@@ -47,7 +68,8 @@ extern pid_t create_pipe_out PARAMS ((const char *progname,
  */
 extern pid_t create_pipe_in PARAMS ((const char *progname,
                                     const char *prog_path, char **prog_argv,
-                                    const char *prog_stdin,
+                                    const char *prog_stdin, bool null_stderr,
+                                    bool exit_on_error,
                                     int fd[1]));
 
 /* Open a bidirectional pipe.
@@ -60,6 +82,8 @@ extern pid_t create_pipe_in PARAMS ((const char *progname,
  */
 extern pid_t create_pipe_bidi PARAMS ((const char *progname,
                                       const char *prog_path, char **prog_argv,
+                                      bool null_stderr,
+                                      bool exit_on_error,
                                       int fd[2]));
 
 #endif /* _PIPE_H */
index 2dd9422dca2b3f305823a68e84c69e831d59cb8d..408117c745be893967281c577562ced98202bc55 100644 (file)
 
 
 int
-wait_subprocess (child, progname)
+wait_subprocess (child, progname, exit_on_error)
      pid_t child;
      const char *progname;
+     bool exit_on_error;
 {
   /* waitpid() is just as portable as wait() nowadays.  */
   WAIT_T status;
@@ -108,7 +109,10 @@ wait_subprocess (child, progname)
              break;
            }
 #endif
-         error (EXIT_FAILURE, errno, _("%s subprocess"), progname);
+         if (exit_on_error)
+           error (EXIT_FAILURE, errno, _("%s subprocess"), progname);
+         else
+           return 127;
        }
 
       if (!WIFSTOPPED (status))
@@ -116,6 +120,18 @@ wait_subprocess (child, progname)
     }
 
   if (WCOREDUMP (status) || WTERMSIG (status) != 0)
-    error (EXIT_FAILURE, 0, _("%s subprocess got fatal signal"), progname);
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, 0, _("%s subprocess got fatal signal"), progname);
+      else
+       return 127;
+    }
+  if (WEXITSTATUS (status) == 127)
+    {
+      if (exit_on_error)
+       error (EXIT_FAILURE, 0, _("%s subprocess failed"), progname);
+      else
+       return 127;
+    }
   return WEXITSTATUS (status);
 }
index 3d591a0cc61a7acc34a70fbefbcb353fa4254c10..509d73d61a644661e11a96e4cde9c9113c726376 100644 (file)
 #endif
 #include <sys/types.h>
 
-/* Wait for a subprocess to finish.  Exit if it didn't terminate
-   correctly.  Otherwise return its exit code.  */
-extern int wait_subprocess PARAMS ((pid_t child, const char *progname));
+#include <stdbool.h>
+
+/* Wait for a subprocess to finish.  Return its exit code.
+   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
+   return 127.  */
+extern int wait_subprocess PARAMS ((pid_t child, const char *progname,
+                                   bool exit_on_error));
 
 #endif /* _WAIT_PROCESS_H */
index e0180cb24d19dd4daeeeff3c2993353ff3ce2245..c6da425978d1b5ef2ad6244770c2eed957492be1 100644 (file)
@@ -1,3 +1,8 @@
+2001-10-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * javacomp.m4 (gt_JAVACOMP): Ignore gcj version 2.xx, require at least
+       gcj 3.0.
+
 2001-09-27  Bruno Haible  <haible@clisp.cons.org>
 
        * gettext.m4 (AM_GNU_GETTEXT): Inline AM_WITH_NLS call.
index df1d04405c0ac8e02ebac5e0bb420a15c2d4fbed..a7b4f07184c2bd3049e2a2f8d6cbd997670b6807 100644 (file)
@@ -15,7 +15,7 @@ AC_DEFUN([gt_JAVACOMP],
   if test -n "$JAVAC"; then
     ac_result="$JAVAC"
   else
-    if gcj --version >/dev/null 2>/dev/null; then
+    if gcj --version 2>/dev/null | grep '^[3-9]' >/dev/null; then
       HAVE_GCJ=1
       ac_result="gcj -C"
     else
index 9b5514a0abee7c5842daff0591035a93f98fa478..4f300e587a98c123a4f1114850a956308f2e3bc6 100644 (file)
@@ -1,3 +1,12 @@
+2001-10-10  Bruno Haible  <haible@clisp.cons.org>
+
+       * msgexec.c (process_string): Update for changed create_pipe_bidi(),
+       wait_subprocess().
+       * msggrep.c (is_string_selected): Update for changed create_pipe_out(),
+       wait_subprocess().
+       * read-java.c (execute_and_read_po_output): Update for changed
+       create_pipe_in(), wait_subprocess().
+
 2001-01-08  Bruno Haible  <haible@clisp.cons.org>
 
        * xgettext.c (remember_a_message): When the comment tag is seen,
index 1b54f5514d3d84679d7b5daf8bbfec1dde3d9f29..d6d98ee56f1da8e66f2d14d75c517064a8a48ead 100644 (file)
@@ -525,7 +525,7 @@ process_string (str, len, resultp, lengthp)
   int exitstatus;
 
   /* Open a bidirectional pipe to a subprocess.  */
-  child = create_pipe_bidi (sub_name, sub_path, sub_argv, fd);
+  child = create_pipe_bidi (sub_name, sub_path, sub_argv, false, true, fd);
      
   /* Enable non-blocking I/O.  This permits the read() and write() calls
      to return -1/EAGAIN without blocking; this is important for polling
@@ -636,7 +636,7 @@ process_string (str, len, resultp, lengthp)
   close (fd[0]);
 
   /* Remove zombie process from process list.  */
-  exitstatus = wait_subprocess (child, sub_name);
+  exitstatus = wait_subprocess (child, sub_name, true);
   if (exitstatus != 0)
     error (EXIT_FAILURE, 0, _("%s subprocess terminated with exit code %d"),
           sub_name, exitstatus);
index de1c07b26548da804e725b4a87c116adc62a5abf..da6aa6f37394f65697ed416009817560fa08d4d9 100644 (file)
@@ -502,7 +502,7 @@ is_string_selected (grep_pass, str, len)
 
       /* Open a pipe to a grep subprocess.  */
       child = create_pipe_out ("grep", grep_path, grep_argv[grep_pass],
-                              "/dev/null", fd);
+                              "/dev/null", false, true, fd);
 
       nwritten = full_write (fd[0], str, len);
       if (nwritten != (ssize_t) len)
@@ -512,7 +512,7 @@ is_string_selected (grep_pass, str, len)
       close (fd[0]);
 
       /* Remove zombie process from process list, and retrieve exit status.  */
-      exitstatus = wait_subprocess (child, "grep");
+      exitstatus = wait_subprocess (child, "grep", true);
       return (exitstatus == 0);
     }
   else
index a2f3dfc8767e6c5284aa3757288d20afce5bc516..f1be08001c83164f9db24a33d9c3c466c8646ed5 100644 (file)
@@ -72,7 +72,8 @@ execute_and_read_po_output (progname, prog_path, prog_argv, private_data)
   int exitstatus;
 
   /* Open a pipe to the JVM.  */
-  child = create_pipe_in (progname, prog_path, prog_argv, "/dev/null", fd);
+  child = create_pipe_in (progname, prog_path, prog_argv, "/dev/null", false,
+                         true, fd);
 
   fp = fdopen (fd[0], "r");
   if (fp == NULL)
@@ -84,7 +85,7 @@ execute_and_read_po_output (progname, prog_path, prog_argv, private_data)
   fclose (fp);
 
   /* Remove zombie process from process list, and retrieve exit status.  */
-  exitstatus = wait_subprocess (child, progname);
+  exitstatus = wait_subprocess (child, progname, true);
   if (exitstatus != 0)
     error (EXIT_FAILURE, 0, _("%s subprocess failed with exit code %d"),
           progname, exitstatus);