From: Bruno Haible Date: Wed, 24 Oct 2001 09:54:43 +0000 (+0000) Subject: Make the subprocess and pipe primitives more reliable and more flexible. X-Git-Tag: v0.11~418 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=69206e1785592c25293f3edd7d78b7cd0bcd4668;p=thirdparty%2Fgettext.git Make the subprocess and pipe primitives more reliable and more flexible. --- diff --git a/lib/ChangeLog b/lib/ChangeLog index ce99523af..722f252f0 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,25 @@ +2001-10-10 Bruno Haible + + * 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 Upgrade to automake-1.5. diff --git a/lib/Makefile.am b/lib/Makefile.am index 92d8ffa56..ed213bd04 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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@ diff --git a/lib/execute.c b/lib/execute.c index 48cba72f7..0082959c3 100644 --- a/lib/execute.c +++ b/lib/execute.c @@ -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); } diff --git a/lib/execute.h b/lib/execute.h index 7a2cc491c..ac0fbeddb 100644 --- a/lib/execute.h +++ b/lib/execute.h @@ -22,11 +22,13 @@ #include /* 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 */ diff --git a/lib/javacomp.c b/lib/javacomp.c index 04598a809..556bffed8 100644 --- a/lib/javacomp.c +++ b/lib/javacomp.c @@ -28,8 +28,11 @@ #include #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. */ diff --git a/lib/javaexec.c b/lib/javaexec.c index 162685556..4d473933b 100644 --- a/lib/javaexec.c +++ b/lib/javaexec.c @@ -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; } diff --git a/lib/pipe-bidi.c b/lib/pipe-bidi.c index e159f62f2..95b4c3fc5 100644 --- a/lib/pipe-bidi.c +++ b/lib/pipe-bidi.c @@ -25,6 +25,7 @@ #include "pipe.h" #include +#include #include #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]); diff --git a/lib/pipe-in.c b/lib/pipe-in.c index 8149f4934..1c20963a4 100644 --- a/lib/pipe-in.c +++ b/lib/pipe-in.c @@ -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]); diff --git a/lib/pipe-out.c b/lib/pipe-out.c index 60aab62b3..059df7f0d 100644 --- a/lib/pipe-out.c +++ b/lib/pipe-out.c @@ -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]); diff --git a/lib/pipe.h b/lib/pipe.h index 6ee5f1600..c972950a7 100644 --- a/lib/pipe.h +++ b/lib/pipe.h @@ -26,6 +26,26 @@ #endif #include +#include + +/* 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 */ diff --git a/lib/wait-process.c b/lib/wait-process.c index 2dd9422dc..408117c74 100644 --- a/lib/wait-process.c +++ b/lib/wait-process.c @@ -81,9 +81,10 @@ 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); } diff --git a/lib/wait-process.h b/lib/wait-process.h index 3d591a0cc..509d73d61 100644 --- a/lib/wait-process.h +++ b/lib/wait-process.h @@ -26,8 +26,12 @@ #endif #include -/* 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 + +/* 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 */ diff --git a/m4/ChangeLog b/m4/ChangeLog index e0180cb24..c6da42597 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,8 @@ +2001-10-10 Bruno Haible + + * javacomp.m4 (gt_JAVACOMP): Ignore gcj version 2.xx, require at least + gcj 3.0. + 2001-09-27 Bruno Haible * gettext.m4 (AM_GNU_GETTEXT): Inline AM_WITH_NLS call. diff --git a/m4/javacomp.m4 b/m4/javacomp.m4 index df1d04405..a7b4f0718 100644 --- a/m4/javacomp.m4 +++ b/m4/javacomp.m4 @@ -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 diff --git a/src/ChangeLog b/src/ChangeLog index 9b5514a0a..4f300e587 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2001-10-10 Bruno Haible + + * 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 * xgettext.c (remember_a_message): When the comment tag is seen, diff --git a/src/msgexec.c b/src/msgexec.c index 1b54f5514..d6d98ee56 100644 --- a/src/msgexec.c +++ b/src/msgexec.c @@ -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); diff --git a/src/msggrep.c b/src/msggrep.c index de1c07b26..da6aa6f37 100644 --- a/src/msggrep.c +++ b/src/msggrep.c @@ -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 diff --git a/src/read-java.c b/src/read-java.c index a2f3dfc87..f1be08001 100644 --- a/src/read-java.c +++ b/src/read-java.c @@ -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);