install-reloc: Support multi-binary installation.
[gnulib.git] / m4 / posix_spawn.m4
index a6839ee..69eaf63 100644 (file)
@@ -1,5 +1,5 @@
-# posix_spawn.m4 serial 3
-dnl Copyright (C) 2008 Free Software Foundation, Inc.
+# posix_spawn.m4 serial 11
+dnl Copyright (C) 2008-2013 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.
@@ -13,9 +13,9 @@ AC_DEFUN([gl_POSIX_SPAWN],
 AC_DEFUN([gl_POSIX_SPAWN_BODY],
 [
   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
-  AC_CHECK_FUNCS_ONCE([posix_spawn])
-  dnl Assume that when the main function exists, all the others are
-  dnl available as well.
+  AC_REQUIRE([gl_HAVE_POSIX_SPAWN])
+  dnl Assume that when the main function exists, all the others,
+  dnl except posix_spawnattr_{get,set}sched*, are available as well.
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnp])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_init])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addclose])
@@ -27,10 +27,6 @@ AC_DEFUN([gl_POSIX_SPAWN_BODY],
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setflags])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getpgroup])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setpgroup])
-  dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
-  dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
-  dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
-  dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigdefault])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigdefault])
   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
@@ -39,19 +35,54 @@ AC_DEFUN([gl_POSIX_SPAWN_BODY],
   if test $ac_cv_func_posix_spawn = yes; then
     gl_POSIX_SPAWN_WORKS
     case "$gl_cv_func_posix_spawn_works" in
-      *yes) ;;
+      *yes)
+        AC_DEFINE([HAVE_WORKING_POSIX_SPAWN], [1],
+          [Define if you have the posix_spawn and posix_spawnp functions and
+           they work.])
+        dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
+        dnl evaluates to nonzero.
+        dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
+        dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
+        AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
+          [gl_cv_func_spawnattr_setschedpolicy],
+          [AC_EGREP_CPP([POSIX scheduling supported], [
+#include <spawn.h>
+#if POSIX_SPAWN_SETSCHEDULER
+ POSIX scheduling supported
+#endif
+],
+             [gl_cv_func_spawnattr_setschedpolicy=yes],
+             [gl_cv_func_spawnattr_setschedpolicy=no])
+          ])
+        dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
+        dnl evaluates to nonzero.
+        dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
+        dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
+        AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
+          [gl_cv_func_spawnattr_setschedparam],
+          [AC_EGREP_CPP([POSIX scheduling supported], [
+#include <spawn.h>
+#if POSIX_SPAWN_SETSCHEDPARAM
+ POSIX scheduling supported
+#endif
+],
+             [gl_cv_func_spawnattr_setschedparam=yes],
+             [gl_cv_func_spawnattr_setschedparam=no])
+          ])
+        ;;
       *) REPLACE_POSIX_SPAWN=1 ;;
     esac
-  else
-    HAVE_POSIX_SPAWN=0
   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 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],
 [
@@ -155,13 +186,18 @@ main ()
           || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, &attrs, argv, environ)) != 0))
     {
       if (actions_allocated)
-       posix_spawn_file_actions_destroy (&actions);
+        posix_spawn_file_actions_destroy (&actions);
       if (attrs_allocated)
-       posix_spawnattr_destroy (&attrs);
+        posix_spawnattr_destroy (&attrs);
       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
-      errno = err;
-      perror ("subprocess failed");
-      exit (1);
+      if (err == ENOENT)
+        return 0;
+      else
+        {
+          errno = err;
+          perror ("subprocess failed");
+          exit (1);
+        }
     }
   posix_spawn_file_actions_destroy (&actions);
   posix_spawnattr_destroy (&attrs);
@@ -194,6 +230,161 @@ main ()
             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 2;
+    }
+
+  /* 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 3;
+    }
+  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 4;
+    }
+  exitstatus = WEXITSTATUS (status);
+  if (exitstatus != 0)
+    {
+      fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
+      return 5;
+    }
+  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 8;
+}
+
+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";;
@@ -203,10 +394,134 @@ main ()
     ])
 ])
 
-AC_DEFUN([gl_POSIX_SPAWN_INTERNAL],
+# Prerequisites of lib/spawni.c.
+AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
 [
-  AC_LIBOBJ([spawni])
-  dnl Prerequisites of lib/spawni.c.
   AC_CHECK_HEADERS([paths.h])
   AC_CHECK_FUNCS([confstr sched_setparam sched_setscheduler setegid seteuid vfork])
 ])
+
+AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE],
+[
+  AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  gl_POSIX_SPAWN
+  if test $REPLACE_POSIX_SPAWN = 1; then
+    REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1
+  else
+    dnl On Solaris 11 2011-11, posix_spawn_file_actions_addclose succeeds even
+    dnl if the fd argument is out of range.
+    AC_CACHE_CHECK([whether posix_spawn_file_actions_addclose works],
+      [gl_cv_func_posix_spawn_file_actions_addclose_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+#include <spawn.h>
+int main ()
+{
+  posix_spawn_file_actions_t actions;
+  if (posix_spawn_file_actions_init (&actions) != 0)
+    return 1;
+  if (posix_spawn_file_actions_addclose (&actions, 10000000) == 0)
+    return 2;
+  return 0;
+}]])],
+         [gl_cv_func_posix_spawn_file_actions_addclose_works=yes],
+         [gl_cv_func_posix_spawn_file_actions_addclose_works=no],
+         [# Guess no on Solaris, yes otherwise.
+          case "$host_os" in
+            solaris*) gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no";;
+            *)        gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes";;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in
+      *yes) ;;
+      *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;;
+    esac
+  fi
+])
+
+AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2],
+[
+  AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  gl_POSIX_SPAWN
+  if test $REPLACE_POSIX_SPAWN = 1; then
+    REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1
+  else
+    dnl On Solaris 11 2011-11, posix_spawn_file_actions_adddup2 succeeds even
+    dnl if the fd argument is out of range.
+    AC_CACHE_CHECK([whether posix_spawn_file_actions_adddup2 works],
+      [gl_cv_func_posix_spawn_file_actions_adddup2_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+#include <spawn.h>
+int main ()
+{
+  posix_spawn_file_actions_t actions;
+  if (posix_spawn_file_actions_init (&actions) != 0)
+    return 1;
+  if (posix_spawn_file_actions_adddup2 (&actions, 10000000, 2) == 0)
+    return 2;
+  return 0;
+}]])],
+         [gl_cv_func_posix_spawn_file_actions_adddup2_works=yes],
+         [gl_cv_func_posix_spawn_file_actions_adddup2_works=no],
+         [# Guess no on Solaris, yes otherwise.
+          case "$host_os" in
+            solaris*) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
+            *)        gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in
+      *yes) ;;
+      *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;;
+    esac
+  fi
+])
+
+AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN],
+[
+  AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  gl_POSIX_SPAWN
+  if test $REPLACE_POSIX_SPAWN = 1; then
+    REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1
+  else
+    dnl On Solaris 11 2011-11, posix_spawn_file_actions_addopen succeeds even
+    dnl if the fd argument is out of range.
+    AC_CACHE_CHECK([whether posix_spawn_file_actions_addopen works],
+      [gl_cv_func_posix_spawn_file_actions_addopen_works],
+      [AC_RUN_IFELSE(
+         [AC_LANG_SOURCE([[
+#include <spawn.h>
+#include <fcntl.h>
+int main ()
+{
+  posix_spawn_file_actions_t actions;
+  if (posix_spawn_file_actions_init (&actions) != 0)
+    return 1;
+  if (posix_spawn_file_actions_addopen (&actions, 10000000, "foo", 0, O_RDONLY)
+      == 0)
+    return 2;
+  return 0;
+}]])],
+         [gl_cv_func_posix_spawn_file_actions_addopen_works=yes],
+         [gl_cv_func_posix_spawn_file_actions_addopen_works=no],
+         [# Guess no on Solaris, yes otherwise.
+          case "$host_os" in
+            solaris*) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
+            *)        gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";;
+          esac
+         ])
+      ])
+    case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in
+      *yes) ;;
+      *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;;
+    esac
+  fi
+])