Avoid the broken posix_spawn function on AIX 5.3 and 6.1.
authorBruno Haible <bruno@clisp.org>
Wed, 1 Oct 2008 23:26:13 +0000 (01:26 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 1 Oct 2008 23:26:13 +0000 (01:26 +0200)
ChangeLog
doc/posix-functions/posix_spawn.texi
doc/posix-functions/posix_spawnp.texi
m4/execute.m4
m4/pipe.m4
m4/posix_spawn.m4
modules/execute
modules/pipe

index 6bccdbd..022f932 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2008-10-01  Bruno Haible  <bruno@clisp.org>
+
+       Avoid the broken posix_spawn function on AIX 5.3 and 6.1.
+       * m4/posix_spawn.m4 (gl_POSIX_SPAWN_WORKS): New macro.
+       (gl_POSIX_SPAWN_BODY): Invoke it. Set REPLACE_POSIX_SPAWN if needed.
+       * doc/posix-functions/posix_spawn.texi: Mention the AIX bugs.
+       * doc/posix-functions/posix_spawnp.texi: Likewise.
+       * m4/execute.m4 (gl_EXECUTE): Invoke gl_POSIX_SPAWN_WORKS, to check
+       whether posix_spawn actually works.
+       * m4/pipe.m4 (gl_PIPE): Likewise.
+       * modules/execute (Files): Add m4/posix_spawn.m4.
+       * modules/pipe (Files): Add m4/posix_spawn.m4.
+       Reported and analyzed by Rainer Tammer <tammer@tammer.net>.
+
 2008-10-01  Jim Meyering  <meyering@redhat.com>
 
        remove trailing spaces
index e5fa25c..713d4be 100644 (file)
@@ -11,11 +11,15 @@ Portability problems fixed by Gnulib:
 @item
 This function is missing on some platforms:
 MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
+@item
+When this function fails, it causes the stdio buffer contents to be output
+twice on some platforms:
+AIX 6.1.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 This function does not work on some platforms:
-mingw.
+AIX 6.1 (under particular circumstances), mingw.
 @end itemize
index b1db88c..bb3c27e 100644 (file)
@@ -11,11 +11,15 @@ Portability problems fixed by Gnulib:
 @item
 This function is missing on some platforms:
 MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin, mingw, Interix 3.5, BeOS.
+@item
+When this function fails, it causes the stdio buffer contents to be output
+twice on some platforms:
+AIX 6.1.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 This function does not work on some platforms:
-mingw.
+AIX 6.1 (under particular circumstances), mingw.
 @end itemize
index 6221290..d376dc2 100644 (file)
@@ -1,5 +1,5 @@
-# execute.m4 serial 1
-dnl Copyright (C) 2003 Free Software Foundation, Inc.
+# execute.m4 serial 2
+dnl Copyright (C) 2003, 2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -11,5 +11,13 @@ AC_DEFUN([gl_EXECUTE],
   AC_REQUIRE([AC_TYPE_MODE_T])
   AC_CHECK_HEADERS_ONCE(unistd.h)
   AC_REQUIRE([AC_FUNC_FORK])
-  AC_CHECK_FUNCS(posix_spawn)
+  AC_CHECK_FUNC([posix_spawn],
+    [gl_POSIX_SPAWN_WORKS
+     case "$gl_cv_func_posix_spawn_works" in
+       *yes)
+         AC_DEFINE([HAVE_POSIX_SPAWN], 1,
+           [Define if you have the posix_spawn() function and it works.])
+         ;;
+     esac
+    ])
 ])
index 4da9115..12da48f 100644 (file)
@@ -1,5 +1,5 @@
-# pipe.m4 serial 1
-dnl Copyright (C) 2004 Free Software Foundation, Inc.
+# pipe.m4 serial 2
+dnl Copyright (C) 2004, 2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -12,5 +12,13 @@ AC_DEFUN([gl_PIPE],
   AC_REQUIRE([AC_C_INLINE])
   AC_REQUIRE([AC_TYPE_MODE_T])
   AC_REQUIRE([AC_FUNC_FORK])
-  AC_CHECK_FUNCS(posix_spawn)
+  AC_CHECK_FUNC([posix_spawn],
+    [gl_POSIX_SPAWN_WORKS
+     case "$gl_cv_func_posix_spawn_works" in
+       *yes)
+         AC_DEFINE([HAVE_POSIX_SPAWN], 1,
+           [Define if you have the posix_spawn() function and it works.])
+         ;;
+     esac
+    ])
 ])
index 9cd5a66..f0e84c9 100644 (file)
@@ -1,4 +1,4 @@
-# posix_spawn.m4 serial 1
+# posix_spawn.m4 serial 2
 dnl Copyright (C) 2008 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -36,15 +36,179 @@ AC_DEFUN([gl_POSIX_SPAWN_BODY],
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigmask])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_destroy])
-  if test $ac_cv_func_posix_spawn != yes; then
+  if test $ac_cv_func_posix_spawn = yes; then
+    gl_POSIX_SPAWN_WORKS
+    case "$gl_cv_func_posix_spawn_works" in
+      *yes) ;;
+      *) REPLACE_POSIX_SPAWN=1 ;;
+    esac
+  else
     HAVE_POSIX_SPAWN=0
-    dnl For now, assume that if posix_spawn exists, it also works.
-    if false; then
-      REPLACE_POSIX_SPAWN=1
-    fi
   fi
 ])
 
+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],
+[
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_CACHE_CHECK([whether posix_spawn works], [gl_cv_func_posix_spawn_works],
+    [if test $cross_compiling = no; then
+       AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.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 WCOREDUMP
+# define WCOREDUMP(x) ((x) & 0x80)
+#endif
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(x) (((x) >> 8) & 0xff)
+#endif
+#ifndef WIFSIGNALED
+# define WIFSIGNALED(x) (WTERMSIG (x) != 0 && WTERMSIG(x) != 0x7f)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(x) (WTERMSIG (x) == 0)
+#endif
+#ifndef WIFSTOPPED
+# define WIFSTOPPED(x) (WTERMSIG (x) == 0x7f)
+#endif
+
+#define CHILD_PROGRAM_FILENAME "/non/exist/ent"
+
+static int
+fd_safer (int fd)
+{
+  if (0 <= fd && fd <= 2)
+    {
+      int f = fd_safer (dup (fd));
+      int e = errno;
+      close (fd);
+      errno = e;
+      fd = f;
+    }
+
+  return fd;
+}  
+]],
+dnl Now comes the main() function.
+[[
+  char *argv[2] = { CHILD_PROGRAM_FILENAME, NULL };
+  int ofd[2];
+  sigset_t blocked_signals;
+  sigset_t fatal_signal_set;
+  posix_spawn_file_actions_t actions;
+  bool actions_allocated;
+  posix_spawnattr_t attrs;
+  bool attrs_allocated;
+  int err;
+  pid_t child;
+  int status;
+  int exitstatus;
+
+  setvbuf (stdout, NULL, _IOFBF, 0);
+  puts ("This should be seen only once.");
+  if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
+    {
+      perror ("cannot create pipe");
+      exit (1);
+    }
+  sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
+  sigemptyset (&fatal_signal_set);
+  sigaddset (&fatal_signal_set, SIGINT);
+  sigaddset (&fatal_signal_set, SIGTERM);
+  sigaddset (&fatal_signal_set, SIGHUP);
+  sigaddset (&fatal_signal_set, SIGPIPE);
+  sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
+  actions_allocated = false;
+  attrs_allocated = false;
+  if ((err = posix_spawn_file_actions_init (&actions)) != 0
+      || (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
+          || (err = posix_spawnattr_init (&attrs)) != 0
+          || (attrs_allocated = true,
+              (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
+              || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
+          || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, &attrs, argv, environ)) != 0))
+    {
+      if (actions_allocated)
+       posix_spawn_file_actions_destroy (&actions);
+      if (attrs_allocated)
+       posix_spawnattr_destroy (&attrs);
+      sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+      errno = err;
+      perror ("subprocess failed");
+      exit (1);
+    }
+  posix_spawn_file_actions_destroy (&actions);
+  posix_spawnattr_destroy (&attrs);
+  sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
+  close (ofd[0]);
+  close (ofd[1]);
+  status = 0;
+  while (waitpid (child, &status, 0) != child)
+    ;
+  if (!WIFEXITED (status))
+    {
+      fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
+      exit (1);
+    }
+  exitstatus = WEXITSTATUS (status);
+  if (exitstatus != 127)
+    {
+      fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
+      exit (1);
+    }
+]])],
+         [if test -s conftest$ac_exeext \
+             && ./conftest$ac_exeext > conftest.out \
+             && echo 'This should be seen only once.' > conftest.ok \
+             && cmp conftest.out conftest.ok > /dev/null; then
+            gl_cv_func_posix_spawn_works=yes
+          else
+            gl_cv_func_posix_spawn_works=no
+          fi],
+         [gl_cv_func_posix_spawn_works=no])
+     else
+       case "$host_os" in
+         aix*) gl_cv_func_posix_spawn_works="guessing no";;
+         *)    gl_cv_func_posix_spawn_works="guessing yes";;
+       esac
+     fi
+    ])
+])
+
 AC_DEFUN([gl_POSIX_SPAWN_INTERNAL],
 [
   AC_LIBOBJ([spawni])
index d5f6ce6..ecea798 100644 (file)
@@ -6,6 +6,7 @@ lib/execute.h
 lib/execute.c
 lib/w32spawn.h
 m4/execute.m4
+m4/posix_spawn.m4
 
 Depends-on:
 error
index 916794e..42e3b83 100644 (file)
@@ -6,6 +6,7 @@ lib/pipe.h
 lib/pipe.c
 lib/w32spawn.h
 m4/pipe.m4
+m4/posix_spawn.m4
 
 Depends-on:
 environ