The implementation of posix_spawn on AIX 5.3..6.1 has yet another bug: it fails when asked to open a file whose name contains a '*'. Apparently the implementors (from a subcontractor of IBM, not IBM itself, I am being told) just took the primitive sample implementation from <http://www.opengroup.org/onlinepubs/000095399/xrat/xsh_chap03.html>
This patch adds a test against this bug. 2008-10-20 Bruno Haible <[EMAIL PROTECTED]> * m4/posix_spawn.m4 (gl_POSIX_SPAWN_WORKS): Test against another bug of posix_spawn on AIX 5.3. *** m4/posix_spawn.m4.orig 2008-10-20 13:09:09.000000000 +0200 --- m4/posix_spawn.m4 2008-10-20 13:09:03.000000000 +0200 *************** *** 48,57 **** ]) dnl Test whether posix_spawn actually works. ! dnl posix_spawn on AIX 5.3..6.1 has a bug: When it fails to execute the ! dnl program, the child process exits with exit() rather than _exit(), ! dnl which causes the stdio buffers to be flushed. Reported by Rainer Tammer. ! dnl posix_spawn on AIX 5.3..6.1 has also a second bug: It does not work dnl when POSIX threads are used. But we don't test against this bug here. AC_DEFUN([gl_POSIX_SPAWN_WORKS], [ --- 48,60 ---- ]) dnl Test whether posix_spawn actually works. ! dnl posix_spawn on AIX 5.3..6.1 has two bugs: ! dnl 1) When it fails to execute the program, the child process exits with ! dnl exit() rather than _exit(), which causes the stdio buffers to be ! dnl flushed. Reported by Rainer Tammer. ! dnl 2) The posix_spawn_file_actions_addopen function does not support file ! dnl names that contain a '*'. ! dnl posix_spawn on AIX 5.3..6.1 has also a third bug: It does not work dnl when POSIX threads are used. But we don't test against this bug here. AC_DEFUN([gl_POSIX_SPAWN_WORKS], [ *************** *** 199,204 **** --- 202,362 ---- gl_cv_func_posix_spawn_works=no fi], [gl_cv_func_posix_spawn_works=no]) + if test $gl_cv_func_posix_spawn_works = yes; then + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + /* Test whether posix_spawn_file_actions_addopen supports filename arguments + that contain special characters such as '*'. */ + + #include <errno.h> + #include <fcntl.h> + #include <signal.h> + #include <spawn.h> + #include <stdbool.h> + #include <stdio.h> + #include <string.h> + #include <unistd.h> + #include <sys/types.h> + #include <sys/wait.h> + + extern char **environ; + + #ifndef STDIN_FILENO + # define STDIN_FILENO 0 + #endif + #ifndef STDOUT_FILENO + # define STDOUT_FILENO 1 + #endif + #ifndef STDERR_FILENO + # define STDERR_FILENO 2 + #endif + + #ifndef WTERMSIG + # define WTERMSIG(x) ((x) & 0x7f) + #endif + #ifndef WIFEXITED + # define WIFEXITED(x) (WTERMSIG (x) == 0) + #endif + #ifndef WEXITSTATUS + # define WEXITSTATUS(x) (((x) >> 8) & 0xff) + #endif + + #define CHILD_PROGRAM_FILENAME "conftest" + #define DATA_FILENAME "conftest%=*#?" + + static int + parent_main (void) + { + FILE *fp; + char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL }; + posix_spawn_file_actions_t actions; + bool actions_allocated; + int err; + pid_t child; + int status; + int exitstatus; + + /* Create a data file with specific contents. */ + fp = fopen (DATA_FILENAME, "wb"); + if (fp == NULL) + { + perror ("cannot create data file"); + return 1; + } + fwrite ("Halle Potta", 1, 11, fp); + if (fflush (fp) || fclose (fp)) + { + perror ("cannot prepare data file"); + return 1; + } + + /* Avoid reading from our stdin, as it could block. */ + freopen ("/dev/null", "rb", stdin); + + /* Test whether posix_spawn_file_actions_addopen with this file name + actually works, but spawning a child that reads from this file. */ + actions_allocated = false; + if ((err = posix_spawn_file_actions_init (&actions)) != 0 + || (actions_allocated = true, + (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0 + || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0)) + { + if (actions_allocated) + posix_spawn_file_actions_destroy (&actions); + errno = err; + perror ("subprocess failed"); + return 1; + } + posix_spawn_file_actions_destroy (&actions); + status = 0; + while (waitpid (child, &status, 0) != child) + ; + if (!WIFEXITED (status)) + { + fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status); + return 1; + } + exitstatus = WEXITSTATUS (status); + if (exitstatus != 0) + { + fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus); + return 1; + } + return 0; + } + + static int + child_main (void) + { + char buf[1024]; + + /* See if reading from STDIN_FILENO yields the expected contents. */ + if (fread (buf, 1, sizeof (buf), stdin) == 11 + && memcmp (buf, "Halle Potta", 11) == 0) + return 0; + else + return 2; + } + + static void + cleanup_then_die (int sig) + { + /* Clean up data file. */ + unlink (DATA_FILENAME); + + /* Re-raise the signal and die from it. */ + signal (sig, SIG_DFL); + raise (sig); + } + + int + main (int argc, char *argv[]) + { + int exitstatus; + + if (!(argc > 1 && strcmp (argv[1], "-child") == 0)) + { + /* This is the parent process. */ + signal (SIGINT, cleanup_then_die); + signal (SIGTERM, cleanup_then_die); + #ifdef SIGHUP + signal (SIGHUP, cleanup_then_die); + #endif + + exitstatus = parent_main (); + } + else + { + /* This is the child process. */ + + exitstatus = child_main (); + } + unlink (DATA_FILENAME); + return exitstatus; + } + ]])], + [], + [gl_cv_func_posix_spawn_works=no]) + fi else case "$host_os" in aix*) gl_cv_func_posix_spawn_works="guessing no";;