Eric Blake wrote on 2008-06-02: > |> Does the execute module allow distinguishing exits due to signals from > |> regular exits? M4 is currently documented as treating the sysval macro > |> differently to allow the user to distinguish between signals, but it looks > |> like wait_subprocess collapses all non-fatal signals into 127 > | > | Currently the 'execute' module indeed does not allow to distinguish between > | launch failure and fatal signals. I could imagine to provide this info > through > | an optional parameter. But how do you want to treat the portability problem > | to mingw here? > > mingw doesn't have signals, so the optional parameter would never be > populated. > > | How does m4 treat mingw at all? Which shell does it use in 'syscmd' and > | 'esyscmd'? > > The m4 documentation currently mentions that syscmd uses whatever system() > provides (probably 'cmd.exe /c' for mingw); and that POSIX compliance is > only attempted for platforms where the m4 macro __unix__ is defined (mingw > defines __windows__, not __unix__). At any rate, on mingw, syscmd is > certainly nowhere near a POSIX-compliant command parser, and the m4 > testsuite intentionally skips all tests that try to do anything with a > shell metacharacter or other action that just won't work without /bin/sh > as the interpreter (syscmd still works for some things regardless of > shell, such as a recursive invocation of m4 with arguments that do not > contain shell metacharacters).
OK, if you are ready to accept a documented misfeature of 'm4' on mingw, I can also accept a documented misfeature of the execute() function on mingw. I added an optional output parameter for the termination signal. 2008-06-10 Bruno Haible <[EMAIL PROTECTED]> * lib/wait-process.h (wait_subprocess): Add termsigp argument. * lib/wait-process.c (wait_subprocess): Likewise. * lib/execute.h (execute): Add termsigp argument. * lib/execute.c (execute): Likewise. * lib/csharpcomp.c (compile_csharp_using_pnet, compile_csharp_using_mono, compile_csharp_using_sscli): Update. * lib/csharpexec.c (execute_csharp_using_pnet, execute_csharp_using_mono, execute_csharp_using_sscli): Update. * lib/javacomp.c (compile_using_envjavac, compile_using_gcj, compile_using_javac, compile_using_jikes, is_envjavac_gcj, is_envjavac_gcj43, is_gcj_present, is_gcj_43, is_javac_present, is_jikes_present): Update. * lib/javaexec.c (execute_java_class): Update. * lib/javaversion.c (execute_and_read_line): Update. * NEWS: Document the changes. Reported by Eric Blake. *** NEWS.orig 2008-06-10 17:25:45.000000000 +0200 --- NEWS 2008-06-10 14:19:56.000000000 +0200 *************** *** 6,11 **** --- 6,16 ---- Date Modules Changes + 2008-06-10 execute The execute function takes an additional termsigp + argument. Passing termsigp = NULL is ok. + wait-process The wait_subprocess function takes an additional + termsigp argument. Passing termsigp = NULL is ok. + 2008-05-10 linebreak The module is split into several modules unilbrk/*. The include file is changed from "linebreak.h" to "unilbrk.h". Two functions are renamed: *** lib/wait-process.h.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/wait-process.h 2008-06-10 14:00:12.000000000 +0200 *************** *** 1,5 **** /* Waiting for a subprocess to finish. ! Copyright (C) 2001-2003, 2006 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Waiting for a subprocess to finish. ! Copyright (C) 2001-2003, 2006, 2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify *************** *** 47,56 **** - slave_process should be set to true if the process has been launched as a slave process. - If exit_on_error is true, any error will cause the main process to exit ! with an error status. */ extern int wait_subprocess (pid_t child, const char *progname, bool ignore_sigpipe, bool null_stderr, ! bool slave_process, bool exit_on_error); /* Register a subprocess as being a slave process. This means that the subprocess will be terminated when its creator receives a catchable fatal --- 47,60 ---- - slave_process should be set to true if the process has been launched as a slave process. - If exit_on_error is true, any error will cause the main process to exit ! with an error status. ! - If termsigp is not NULL, *termsig will be set to the signal that ! terminated the subprocess (if supported by the platform: not on native ! Windows platforms), otherwise 0. */ extern int wait_subprocess (pid_t child, const char *progname, bool ignore_sigpipe, bool null_stderr, ! bool slave_process, bool exit_on_error, ! int *termsigp); /* Register a subprocess as being a slave process. This means that the subprocess will be terminated when its creator receives a catchable fatal *** lib/wait-process.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/wait-process.c 2008-06-10 14:12:39.000000000 +0200 *************** *** 250,256 **** int wait_subprocess (pid_t child, const char *progname, bool ignore_sigpipe, bool null_stderr, ! bool slave_process, bool exit_on_error) { #if HAVE_WAITID && defined WNOWAIT && 0 /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't --- 250,257 ---- int wait_subprocess (pid_t child, const char *progname, bool ignore_sigpipe, bool null_stderr, ! bool slave_process, bool exit_on_error, ! int *termsigp) { #if HAVE_WAITID && defined WNOWAIT && 0 /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't *************** *** 263,268 **** --- 264,272 ---- before unregister_slave_subprocess() - this process gets a fatal signal, it would kill the other totally unrelated process. */ siginfo_t info; + + if (termsigp != NULL) + *termsigp = 0; for (;;) { if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0)) *************** *** 317,322 **** --- 321,328 ---- { case CLD_KILLED: case CLD_DUMPED: + if (termsigp != NULL) + *termsigp = info.si_status; /* TODO: or info.si_signo? */ # ifdef SIGPIPE if (info.si_status == SIGPIPE && ignore_sigpipe) return 0; *************** *** 342,347 **** --- 348,355 ---- /* waitpid() is just as portable as wait() nowadays. */ WAIT_T status; + if (termsigp != NULL) + *termsigp = 0; *(int *) &status = 0; for (;;) { *************** *** 385,390 **** --- 393,400 ---- if (WIFSIGNALED (status)) { + if (termsigp != NULL) + *termsigp = WTERMSIG (status); # ifdef SIGPIPE if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe) return 0; *** lib/execute.h.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/execute.h 2008-06-10 14:18:51.000000000 +0200 *************** *** 1,5 **** /* Creation of autonomous subprocesses. ! Copyright (C) 2001-2003 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Creation of autonomous subprocesses. ! Copyright (C) 2001-2003, 2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify *************** *** 29,40 **** purpose is to write to standard output. If slave_process is true, the child process will be terminated when its creator receives a catchable fatal signal. It is recommended that no signal is blocked or ignored while execute() is called. See pipe.h for the reason. */ extern int execute (const char *progname, const char *prog_path, char **prog_argv, bool ignore_sigpipe, bool null_stdin, bool null_stdout, bool null_stderr, ! bool slave_process, bool exit_on_error); #endif /* _EXECUTE_H */ --- 29,44 ---- purpose is to write to standard output. If slave_process is true, the child process will be terminated when its creator receives a catchable fatal signal. + If termsigp is not NULL, *termsig will be set to the signal that terminated + the subprocess (if supported by the platform: not on native Windows + platforms), otherwise 0. It is recommended that no signal is blocked or ignored while execute() is called. See pipe.h for the reason. */ extern int execute (const char *progname, const char *prog_path, char **prog_argv, bool ignore_sigpipe, bool null_stdin, bool null_stdout, bool null_stderr, ! bool slave_process, bool exit_on_error, ! int *termsigp); #endif /* _EXECUTE_H */ *** lib/execute.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/execute.c 2008-06-10 14:22:48.000000000 +0200 *************** *** 117,123 **** const char *prog_path, char **prog_argv, bool ignore_sigpipe, bool null_stdin, bool null_stdout, bool null_stderr, ! bool slave_process, bool exit_on_error) { #if defined _MSC_VER || defined __MINGW32__ --- 117,124 ---- const char *prog_path, char **prog_argv, bool ignore_sigpipe, bool null_stdin, bool null_stdout, bool null_stderr, ! bool slave_process, bool exit_on_error, ! int *termsigp) { #if defined _MSC_VER || defined __MINGW32__ *************** *** 173,178 **** --- 174,182 ---- if (null_stdin) dup2 (orig_stdin, STDIN_FILENO), close (orig_stdin); + if (termsigp != NULL) + *termsigp = 0; + if (exitcode == -1) { if (exit_on_error || !null_stderr) *************** *** 251,256 **** --- 255,262 ---- posix_spawnattr_destroy (&attrs); if (slave_process) unblock_fatal_signals (); + if (termsigp != NULL) + *termsigp = 0; if (exit_on_error || !null_stderr) error (exit_on_error ? EXIT_FAILURE : 0, err, _("%s subprocess failed"), progname); *************** *** 293,298 **** --- 299,306 ---- { if (slave_process) unblock_fatal_signals (); + if (termsigp != NULL) + *termsigp = 0; if (exit_on_error || !null_stderr) error (exit_on_error ? EXIT_FAILURE : 0, errno, _("%s subprocess failed"), progname); *************** *** 306,312 **** } return wait_subprocess (child, progname, ignore_sigpipe, null_stderr, ! slave_process, exit_on_error); #endif } --- 314,320 ---- } return wait_subprocess (child, progname, ignore_sigpipe, null_stderr, ! slave_process, exit_on_error, termsigp); #endif } *** lib/csharpcomp.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/csharpcomp.c 2008-06-10 14:27:24.000000000 +0200 *************** *** 1,5 **** /* Compile a C# program. ! Copyright (C) 2003-2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2003. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Compile a C# program. ! Copyright (C) 2003-2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2003. This program is free software: you can redistribute it and/or modify *************** *** 83,89 **** argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("cscc", "cscc", argv, false, false, true, true, ! true, false); cscc_present = (exitstatus == 0); cscc_tested = true; } --- 83,89 ---- argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("cscc", "cscc", argv, false, false, true, true, ! true, false, NULL); cscc_present = (exitstatus == 0); cscc_tested = true; } *************** *** 151,157 **** } exitstatus = execute ("cscc", "cscc", argv, false, false, false, false, ! true, true); for (i = 0; i < sources_count; i++) if (argv[argc - sources_count + i] != sources[i]) --- 151,157 ---- } exitstatus = execute ("cscc", "cscc", argv, false, false, false, false, ! true, true, NULL); for (i = 0; i < sources_count; i++) if (argv[argc - sources_count + i] != sources[i]) *************** *** 219,225 **** /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "mcs", false, true, true, false); if (exitstatus != 0) mcs_present = false; } --- 219,225 ---- /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "mcs", false, true, true, false, NULL); if (exitstatus != 0) mcs_present = false; } *************** *** 332,338 **** fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = wait_subprocess (child, "mcs", false, false, true, true); for (i = 1 + (output_is_library ? 1 : 0); i < 1 + (output_is_library ? 1 : 0) --- 332,339 ---- fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = ! wait_subprocess (child, "mcs", false, false, true, true, NULL); for (i = 1 + (output_is_library ? 1 : 0); i < 1 + (output_is_library ? 1 : 0) *************** *** 408,414 **** /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "csc", false, true, true, false); if (exitstatus != 0) csc_present = false; } --- 409,415 ---- /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "csc", false, true, true, false, NULL); if (exitstatus != 0) csc_present = false; } *************** *** 486,492 **** } exitstatus = execute ("csc", "csc", argv, false, false, false, false, ! true, true); for (i = 2; i < 3 + libdirs_count + libraries_count; i++) freea (argv[i]); --- 487,493 ---- } exitstatus = execute ("csc", "csc", argv, false, false, false, false, ! true, true, NULL); for (i = 2; i < 3 + libdirs_count + libraries_count; i++) freea (argv[i]); *** lib/csharpexec.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/csharpexec.c 2008-06-10 14:27:45.000000000 +0200 *************** *** 1,5 **** /* Execute a C# program. ! Copyright (C) 2003-2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2003. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Execute a C# program. ! Copyright (C) 2003-2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2003. This program is free software: you can redistribute it and/or modify *************** *** 109,115 **** argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("ilrun", "ilrun", argv, false, false, true, true, ! true, false); ilrun_present = (exitstatus == 0); ilrun_tested = true; } --- 109,115 ---- argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("ilrun", "ilrun", argv, false, false, true, true, ! true, false, NULL); ilrun_present = (exitstatus == 0); ilrun_tested = true; } *************** *** 179,185 **** argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("mono", "mono", argv, false, false, true, true, ! true, false); mono_present = (exitstatus == 0); mono_tested = true; } --- 179,185 ---- argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("mono", "mono", argv, false, false, true, true, ! true, false, NULL); mono_present = (exitstatus == 0); mono_tested = true; } *************** *** 240,246 **** argv[0] = "clix"; argv[1] = NULL; exitstatus = execute ("clix", "clix", argv, false, false, true, true, ! true, false); clix_present = (exitstatus == 0 || exitstatus == 1); clix_tested = true; } --- 240,246 ---- argv[0] = "clix"; argv[1] = NULL; exitstatus = execute ("clix", "clix", argv, false, false, true, true, ! true, false, NULL); clix_present = (exitstatus == 0 || exitstatus == 1); clix_tested = true; } *** lib/javacomp.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/javacomp.c 2008-06-10 14:28:18.000000000 +0200 *************** *** 1,5 **** /* Compile a Java program. ! Copyright (C) 2001-2003, 2006-2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Compile a Java program. ! Copyright (C) 2001-2003, 2006-2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify *************** *** 268,274 **** argv[2] = command; argv[3] = NULL; exitstatus = execute (javac, "/bin/sh", argv, false, false, false, ! null_stderr, true, true); err = (exitstatus != 0); freea (command); --- 268,274 ---- argv[2] = command; argv[3] = NULL; exitstatus = execute (javac, "/bin/sh", argv, false, false, false, ! null_stderr, true, true, NULL); err = (exitstatus != 0); freea (command); *************** *** 350,356 **** } exitstatus = execute ("gcj", "gcj", argv, false, false, false, null_stderr, ! true, true); err = (exitstatus != 0); if (ftarget_arg != NULL) --- 350,356 ---- } exitstatus = execute ("gcj", "gcj", argv, false, false, false, null_stderr, ! true, true, NULL); err = (exitstatus != 0); if (ftarget_arg != NULL) *************** *** 421,427 **** } exitstatus = execute ("javac", "javac", argv, false, false, false, ! null_stderr, true, true); err = (exitstatus != 0); freea (argv); --- 421,427 ---- } exitstatus = execute ("javac", "javac", argv, false, false, false, ! null_stderr, true, true, NULL); err = (exitstatus != 0); freea (argv); *************** *** 476,482 **** } exitstatus = execute ("jikes", "jikes", argv, false, false, false, ! null_stderr, true, true); err = (exitstatus != 0); freea (argv); --- 476,482 ---- } exitstatus = execute ("jikes", "jikes", argv, false, false, false, ! null_stderr, true, true, NULL); err = (exitstatus != 0); freea (argv); *************** *** 605,611 **** fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = wait_subprocess (child, javac, true, true, true, false); if (exitstatus != 0) envjavac_gcj = false; --- 605,612 ---- fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = ! wait_subprocess (child, javac, true, true, true, false, NULL); if (exitstatus != 0) envjavac_gcj = false; *************** *** 689,695 **** fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = wait_subprocess (child, javac, true, true, true, false); if (exitstatus != 0) envjavac_gcj43 = false; --- 690,697 ---- fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = ! wait_subprocess (child, javac, true, true, true, false, NULL); if (exitstatus != 0) envjavac_gcj43 = false; *************** *** 1367,1373 **** /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "gcj", false, true, true, false); if (exitstatus != 0) gcj_present = false; } --- 1369,1375 ---- /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "gcj", false, true, true, false, NULL); if (exitstatus != 0) gcj_present = false; } *************** *** 1482,1488 **** /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "gcj", false, true, true, false); if (exitstatus != 0) gcj_43 = false; } --- 1484,1490 ---- /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = ! wait_subprocess (child, "gcj", false, true, true, false, NULL); if (exitstatus != 0) gcj_43 = false; } *************** *** 1791,1797 **** argv[0] = "javac"; argv[1] = NULL; exitstatus = execute ("javac", "javac", argv, false, false, true, true, ! true, false); javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2); javac_tested = true; } --- 1793,1799 ---- argv[0] = "javac"; argv[1] = NULL; exitstatus = execute ("javac", "javac", argv, false, false, true, true, ! true, false, NULL); javac_present = (exitstatus == 0 || exitstatus == 1 || exitstatus == 2); javac_tested = true; } *************** *** 2055,2061 **** argv[0] = "jikes"; argv[1] = NULL; exitstatus = execute ("jikes", "jikes", argv, false, false, true, true, ! true, false); jikes_present = (exitstatus == 0 || exitstatus == 1); jikes_tested = true; } --- 2057,2063 ---- argv[0] = "jikes"; argv[1] = NULL; exitstatus = execute ("jikes", "jikes", argv, false, false, true, true, ! true, false, NULL); jikes_present = (exitstatus == 0 || exitstatus == 1); jikes_tested = true; } *** lib/javaexec.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/javaexec.c 2008-06-10 14:28:44.000000000 +0200 *************** *** 1,5 **** /* Execute a Java program. ! Copyright (C) 2001-2003, 2006-2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Execute a Java program. ! Copyright (C) 2001-2003, 2006-2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2001. This program is free software: you can redistribute it and/or modify *************** *** 209,215 **** argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("gij", "gij", argv, false, false, true, true, ! true, false); gij_present = (exitstatus == 0); gij_tested = true; } --- 209,215 ---- argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("gij", "gij", argv, false, false, true, true, ! true, false, NULL); gij_present = (exitstatus == 0); gij_tested = true; } *************** *** 262,268 **** argv[1] = "-version"; argv[2] = NULL; exitstatus = execute ("java", "java", argv, false, false, true, true, ! true, false); java_present = (exitstatus == 0); java_tested = true; } --- 262,268 ---- argv[1] = "-version"; argv[2] = NULL; exitstatus = execute ("java", "java", argv, false, false, true, true, ! true, false, NULL); java_present = (exitstatus == 0); java_tested = true; } *************** *** 316,322 **** argv[0] = "jre"; argv[1] = NULL; exitstatus = execute ("jre", "jre", argv, false, false, true, true, ! true, false); jre_present = (exitstatus == 0 || exitstatus == 1); jre_tested = true; } --- 316,322 ---- argv[0] = "jre"; argv[1] = NULL; exitstatus = execute ("jre", "jre", argv, false, false, true, true, ! true, false, NULL); jre_present = (exitstatus == 0 || exitstatus == 1); jre_tested = true; } *************** *** 373,379 **** argv[1] = "-?"; argv[2] = NULL; exitstatus = execute ("jview", "jview", argv, false, false, true, true, ! true, false); jview_present = (exitstatus == 0 || exitstatus == 1); jview_tested = true; } --- 373,379 ---- argv[1] = "-?"; argv[2] = NULL; exitstatus = execute ("jview", "jview", argv, false, false, true, true, ! true, false, NULL); jview_present = (exitstatus == 0 || exitstatus == 1); jview_tested = true; } *** lib/javaversion.c.orig 2008-06-10 17:25:46.000000000 +0200 --- lib/javaversion.c 2008-06-10 14:24:25.000000000 +0200 *************** *** 1,5 **** /* Determine the Java version supported by javaexec. ! Copyright (C) 2006, 2007 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2006. This program is free software: you can redistribute it and/or modify --- 1,5 ---- /* Determine the Java version supported by javaexec. ! Copyright (C) 2006-2008 Free Software Foundation, Inc. Written by Bruno Haible <[EMAIL PROTECTED]>, 2006. This program is free software: you can redistribute it and/or modify *************** *** 90,96 **** fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = wait_subprocess (child, progname, true, false, true, false); if (exitstatus != 0) { free (line); --- 90,97 ---- fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ ! exitstatus = ! wait_subprocess (child, progname, true, false, true, false, NULL); if (exitstatus != 0) { free (line);