Home | History | Annotate | Download | only in m4
      1 # posix_spawn.m4 serial 11
      2 dnl Copyright (C) 2008-2012 Free Software Foundation, Inc.
      3 dnl This file is free software; the Free Software Foundation
      4 dnl gives unlimited permission to copy and/or distribute it,
      5 dnl with or without modifications, as long as this notice is preserved.
      6 
      7 dnl Tests whether the entire posix_spawn facility is available.
      8 AC_DEFUN([gl_POSIX_SPAWN],
      9 [
     10   AC_REQUIRE([gl_POSIX_SPAWN_BODY])
     11 ])
     12 
     13 AC_DEFUN([gl_POSIX_SPAWN_BODY],
     14 [
     15   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
     16   AC_REQUIRE([gl_HAVE_POSIX_SPAWN])
     17   dnl Assume that when the main function exists, all the others,
     18   dnl except posix_spawnattr_{get,set}sched*, are available as well.
     19   dnl AC_CHECK_FUNCS_ONCE([posix_spawnp])
     20   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_init])
     21   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addclose])
     22   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_adddup2])
     23   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addopen])
     24   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_destroy])
     25   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_init])
     26   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getflags])
     27   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setflags])
     28   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getpgroup])
     29   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setpgroup])
     30   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigdefault])
     31   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigdefault])
     32   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
     33   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigmask])
     34   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_destroy])
     35   if test $ac_cv_func_posix_spawn = yes; then
     36     gl_POSIX_SPAWN_WORKS
     37     case "$gl_cv_func_posix_spawn_works" in
     38       *yes)
     39         AC_DEFINE([HAVE_WORKING_POSIX_SPAWN], [1],
     40           [Define if you have the posix_spawn and posix_spawnp functions and
     41            they work.])
     42         dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
     43         dnl evaluates to nonzero.
     44         dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
     45         dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
     46         AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
     47           [gl_cv_func_spawnattr_setschedpolicy],
     48           [AC_EGREP_CPP([POSIX scheduling supported], [
     49 #include <spawn.h>
     50 #if POSIX_SPAWN_SETSCHEDULER
     51  POSIX scheduling supported
     52 #endif
     53 ],
     54              [gl_cv_func_spawnattr_setschedpolicy=yes],
     55              [gl_cv_func_spawnattr_setschedpolicy=no])
     56           ])
     57         dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
     58         dnl evaluates to nonzero.
     59         dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
     60         dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
     61         AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
     62           [gl_cv_func_spawnattr_setschedparam],
     63           [AC_EGREP_CPP([POSIX scheduling supported], [
     64 #include <spawn.h>
     65 #if POSIX_SPAWN_SETSCHEDPARAM
     66  POSIX scheduling supported
     67 #endif
     68 ],
     69              [gl_cv_func_spawnattr_setschedparam=yes],
     70              [gl_cv_func_spawnattr_setschedparam=no])
     71           ])
     72         ;;
     73       *) REPLACE_POSIX_SPAWN=1 ;;
     74     esac
     75   fi
     76 ])
     77 
     78 dnl Test whether posix_spawn actually works.
     79 dnl posix_spawn on AIX 5.3..6.1 has two bugs:
     80 dnl 1) When it fails to execute the program, the child process exits with
     81 dnl    exit() rather than _exit(), which causes the stdio buffers to be
     82 dnl    flushed. Reported by Rainer Tammer.
     83 dnl 2) The posix_spawn_file_actions_addopen function does not support file
     84 dnl    names that contain a '*'.
     85 dnl posix_spawn on AIX 5.3..6.1 has also a third bug: It does not work
     86 dnl when POSIX threads are used. But we don't test against this bug here.
     87 AC_DEFUN([gl_POSIX_SPAWN_WORKS],
     88 [
     89   AC_REQUIRE([AC_PROG_CC])
     90   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
     91   AC_CACHE_CHECK([whether posix_spawn works], [gl_cv_func_posix_spawn_works],
     92     [if test $cross_compiling = no; then
     93        AC_LINK_IFELSE([AC_LANG_SOURCE([[
     94 #include <errno.h>
     95 #include <fcntl.h>
     96 #include <signal.h>
     97 #include <spawn.h>
     98 #include <stdbool.h>
     99 #include <stdio.h>
    100 #include <stdlib.h>
    101 #include <string.h>
    102 #include <unistd.h>
    103 #include <sys/types.h>
    104 #include <sys/wait.h>
    105 
    106 extern char **environ;
    107 
    108 #ifndef STDIN_FILENO
    109 # define STDIN_FILENO 0
    110 #endif
    111 #ifndef STDOUT_FILENO
    112 # define STDOUT_FILENO 1
    113 #endif
    114 #ifndef STDERR_FILENO
    115 # define STDERR_FILENO 2
    116 #endif
    117 
    118 #ifndef WTERMSIG
    119 # define WTERMSIG(x) ((x) & 0x7f)
    120 #endif
    121 #ifndef WIFEXITED
    122 # define WIFEXITED(x) (WTERMSIG (x) == 0)
    123 #endif
    124 #ifndef WEXITSTATUS
    125 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
    126 #endif
    127 
    128 #define CHILD_PROGRAM_FILENAME "/non/exist/ent"
    129 
    130 static int
    131 fd_safer (int fd)
    132 {
    133   if (0 <= fd && fd <= 2)
    134     {
    135       int f = fd_safer (dup (fd));
    136       int e = errno;
    137       close (fd);
    138       errno = e;
    139       fd = f;
    140     }
    141 
    142   return fd;
    143 }
    144 
    145 int
    146 main ()
    147 {
    148   char *argv[2] = { CHILD_PROGRAM_FILENAME, NULL };
    149   int ofd[2];
    150   sigset_t blocked_signals;
    151   sigset_t fatal_signal_set;
    152   posix_spawn_file_actions_t actions;
    153   bool actions_allocated;
    154   posix_spawnattr_t attrs;
    155   bool attrs_allocated;
    156   int err;
    157   pid_t child;
    158   int status;
    159   int exitstatus;
    160 
    161   setvbuf (stdout, NULL, _IOFBF, 0);
    162   puts ("This should be seen only once.");
    163   if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
    164     {
    165       perror ("cannot create pipe");
    166       exit (1);
    167     }
    168   sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
    169   sigemptyset (&fatal_signal_set);
    170   sigaddset (&fatal_signal_set, SIGINT);
    171   sigaddset (&fatal_signal_set, SIGTERM);
    172   sigaddset (&fatal_signal_set, SIGHUP);
    173   sigaddset (&fatal_signal_set, SIGPIPE);
    174   sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
    175   actions_allocated = false;
    176   attrs_allocated = false;
    177   if ((err = posix_spawn_file_actions_init (&actions)) != 0
    178       || (actions_allocated = true,
    179           (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], STDIN_FILENO)) != 0
    180           || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
    181           || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
    182           || (err = posix_spawnattr_init (&attrs)) != 0
    183           || (attrs_allocated = true,
    184               (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
    185               || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
    186           || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, &attrs, argv, environ)) != 0))
    187     {
    188       if (actions_allocated)
    189         posix_spawn_file_actions_destroy (&actions);
    190       if (attrs_allocated)
    191         posix_spawnattr_destroy (&attrs);
    192       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
    193       if (err == ENOENT)
    194         return 0;
    195       else
    196         {
    197           errno = err;
    198           perror ("subprocess failed");
    199           exit (1);
    200         }
    201     }
    202   posix_spawn_file_actions_destroy (&actions);
    203   posix_spawnattr_destroy (&attrs);
    204   sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
    205   close (ofd[0]);
    206   close (ofd[1]);
    207   status = 0;
    208   while (waitpid (child, &status, 0) != child)
    209     ;
    210   if (!WIFEXITED (status))
    211     {
    212       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
    213       exit (1);
    214     }
    215   exitstatus = WEXITSTATUS (status);
    216   if (exitstatus != 127)
    217     {
    218       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
    219       exit (1);
    220     }
    221   return 0;
    222 }
    223 ]])],
    224          [if test -s conftest$ac_exeext \
    225              && ./conftest$ac_exeext > conftest.out \
    226              && echo 'This should be seen only once.' > conftest.ok \
    227              && cmp conftest.out conftest.ok > /dev/null; then
    228             gl_cv_func_posix_spawn_works=yes
    229           else
    230             gl_cv_func_posix_spawn_works=no
    231           fi],
    232          [gl_cv_func_posix_spawn_works=no])
    233        if test $gl_cv_func_posix_spawn_works = yes; then
    234          AC_RUN_IFELSE([AC_LANG_SOURCE([[
    235 /* Test whether posix_spawn_file_actions_addopen supports filename arguments
    236    that contain special characters such as '*'.  */
    237 
    238 #include <errno.h>
    239 #include <fcntl.h>
    240 #include <signal.h>
    241 #include <spawn.h>
    242 #include <stdbool.h>
    243 #include <stdio.h>
    244 #include <string.h>
    245 #include <unistd.h>
    246 #include <sys/types.h>
    247 #include <sys/wait.h>
    248 
    249 extern char **environ;
    250 
    251 #ifndef STDIN_FILENO
    252 # define STDIN_FILENO 0
    253 #endif
    254 #ifndef STDOUT_FILENO
    255 # define STDOUT_FILENO 1
    256 #endif
    257 #ifndef STDERR_FILENO
    258 # define STDERR_FILENO 2
    259 #endif
    260 
    261 #ifndef WTERMSIG
    262 # define WTERMSIG(x) ((x) & 0x7f)
    263 #endif
    264 #ifndef WIFEXITED
    265 # define WIFEXITED(x) (WTERMSIG (x) == 0)
    266 #endif
    267 #ifndef WEXITSTATUS
    268 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
    269 #endif
    270 
    271 #define CHILD_PROGRAM_FILENAME "conftest"
    272 #define DATA_FILENAME "conftest%=*#?"
    273 
    274 static int
    275 parent_main (void)
    276 {
    277   FILE *fp;
    278   char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL };
    279   posix_spawn_file_actions_t actions;
    280   bool actions_allocated;
    281   int err;
    282   pid_t child;
    283   int status;
    284   int exitstatus;
    285 
    286   /* Create a data file with specific contents.  */
    287   fp = fopen (DATA_FILENAME, "wb");
    288   if (fp == NULL)
    289     {
    290       perror ("cannot create data file");
    291       return 1;
    292     }
    293   fwrite ("Halle Potta", 1, 11, fp);
    294   if (fflush (fp) || fclose (fp))
    295     {
    296       perror ("cannot prepare data file");
    297       return 2;
    298     }
    299 
    300   /* Avoid reading from our stdin, as it could block.  */
    301   freopen ("/dev/null", "rb", stdin);
    302 
    303   /* Test whether posix_spawn_file_actions_addopen with this file name
    304      actually works, but spawning a child that reads from this file.  */
    305   actions_allocated = false;
    306   if ((err = posix_spawn_file_actions_init (&actions)) != 0
    307       || (actions_allocated = true,
    308           (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0
    309           || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0))
    310     {
    311       if (actions_allocated)
    312         posix_spawn_file_actions_destroy (&actions);
    313       errno = err;
    314       perror ("subprocess failed");
    315       return 3;
    316     }
    317   posix_spawn_file_actions_destroy (&actions);
    318   status = 0;
    319   while (waitpid (child, &status, 0) != child)
    320     ;
    321   if (!WIFEXITED (status))
    322     {
    323       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
    324       return 4;
    325     }
    326   exitstatus = WEXITSTATUS (status);
    327   if (exitstatus != 0)
    328     {
    329       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
    330       return 5;
    331     }
    332   return 0;
    333 }
    334 
    335 static int
    336 child_main (void)
    337 {
    338   char buf[1024];
    339 
    340   /* See if reading from STDIN_FILENO yields the expected contents.  */
    341   if (fread (buf, 1, sizeof (buf), stdin) == 11
    342       && memcmp (buf, "Halle Potta", 11) == 0)
    343     return 0;
    344   else
    345     return 8;
    346 }
    347 
    348 static void
    349 cleanup_then_die (int sig)
    350 {
    351   /* Clean up data file.  */
    352   unlink (DATA_FILENAME);
    353 
    354   /* Re-raise the signal and die from it.  */
    355   signal (sig, SIG_DFL);
    356   raise (sig);
    357 }
    358 
    359 int
    360 main (int argc, char *argv[])
    361 {
    362   int exitstatus;
    363 
    364   if (!(argc > 1 && strcmp (argv[1], "-child") == 0))
    365     {
    366       /* This is the parent process.  */
    367       signal (SIGINT, cleanup_then_die);
    368       signal (SIGTERM, cleanup_then_die);
    369       #ifdef SIGHUP
    370       signal (SIGHUP, cleanup_then_die);
    371       #endif
    372 
    373       exitstatus = parent_main ();
    374     }
    375   else
    376     {
    377       /* This is the child process.  */
    378 
    379       exitstatus = child_main ();
    380     }
    381   unlink (DATA_FILENAME);
    382   return exitstatus;
    383 }
    384 ]])],
    385            [],
    386            [gl_cv_func_posix_spawn_works=no])
    387        fi
    388      else
    389        case "$host_os" in
    390          aix*) gl_cv_func_posix_spawn_works="guessing no";;
    391          *)    gl_cv_func_posix_spawn_works="guessing yes";;
    392        esac
    393      fi
    394     ])
    395 ])
    396 
    397 # Prerequisites of lib/spawni.c.
    398 AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
    399 [
    400   AC_CHECK_HEADERS([paths.h])
    401   AC_CHECK_FUNCS([confstr sched_setparam sched_setscheduler setegid seteuid vfork])
    402 ])
    403 
    404 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE],
    405 [
    406   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
    407   AC_REQUIRE([AC_PROG_CC])
    408   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
    409   gl_POSIX_SPAWN
    410   if test $REPLACE_POSIX_SPAWN = 1; then
    411     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1
    412   else
    413     dnl On Solaris 11 2011-11, posix_spawn_file_actions_addclose succeeds even
    414     dnl if the fd argument is out of range.
    415     AC_CACHE_CHECK([whether posix_spawn_file_actions_addclose works],
    416       [gl_cv_func_posix_spawn_file_actions_addclose_works],
    417       [AC_RUN_IFELSE(
    418          [AC_LANG_SOURCE([[
    419 #include <spawn.h>
    420 int main ()
    421 {
    422   posix_spawn_file_actions_t actions;
    423   if (posix_spawn_file_actions_init (&actions) != 0)
    424     return 1;
    425   if (posix_spawn_file_actions_addclose (&actions, 10000000) == 0)
    426     return 2;
    427   return 0;
    428 }]])],
    429          [gl_cv_func_posix_spawn_file_actions_addclose_works=yes],
    430          [gl_cv_func_posix_spawn_file_actions_addclose_works=no],
    431          [# Guess no on Solaris, yes otherwise.
    432           case "$host_os" in
    433             solaris*) gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no";;
    434             *)        gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes";;
    435           esac
    436          ])
    437       ])
    438     case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in
    439       *yes) ;;
    440       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;;
    441     esac
    442   fi
    443 ])
    444 
    445 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2],
    446 [
    447   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
    448   AC_REQUIRE([AC_PROG_CC])
    449   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
    450   gl_POSIX_SPAWN
    451   if test $REPLACE_POSIX_SPAWN = 1; then
    452     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1
    453   else
    454     dnl On Solaris 11 2011-11, posix_spawn_file_actions_adddup2 succeeds even
    455     dnl if the fd argument is out of range.
    456     AC_CACHE_CHECK([whether posix_spawn_file_actions_adddup2 works],
    457       [gl_cv_func_posix_spawn_file_actions_adddup2_works],
    458       [AC_RUN_IFELSE(
    459          [AC_LANG_SOURCE([[
    460 #include <spawn.h>
    461 int main ()
    462 {
    463   posix_spawn_file_actions_t actions;
    464   if (posix_spawn_file_actions_init (&actions) != 0)
    465     return 1;
    466   if (posix_spawn_file_actions_adddup2 (&actions, 10000000, 2) == 0)
    467     return 2;
    468   return 0;
    469 }]])],
    470          [gl_cv_func_posix_spawn_file_actions_adddup2_works=yes],
    471          [gl_cv_func_posix_spawn_file_actions_adddup2_works=no],
    472          [# Guess no on Solaris, yes otherwise.
    473           case "$host_os" in
    474             solaris*) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
    475             *)        gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";;
    476           esac
    477          ])
    478       ])
    479     case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in
    480       *yes) ;;
    481       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;;
    482     esac
    483   fi
    484 ])
    485 
    486 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN],
    487 [
    488   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
    489   AC_REQUIRE([AC_PROG_CC])
    490   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
    491   gl_POSIX_SPAWN
    492   if test $REPLACE_POSIX_SPAWN = 1; then
    493     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1
    494   else
    495     dnl On Solaris 11 2011-11, posix_spawn_file_actions_addopen succeeds even
    496     dnl if the fd argument is out of range.
    497     AC_CACHE_CHECK([whether posix_spawn_file_actions_addopen works],
    498       [gl_cv_func_posix_spawn_file_actions_addopen_works],
    499       [AC_RUN_IFELSE(
    500          [AC_LANG_SOURCE([[
    501 #include <spawn.h>
    502 #include <fcntl.h>
    503 int main ()
    504 {
    505   posix_spawn_file_actions_t actions;
    506   if (posix_spawn_file_actions_init (&actions) != 0)
    507     return 1;
    508   if (posix_spawn_file_actions_addopen (&actions, 10000000, "foo", 0, O_RDONLY)
    509       == 0)
    510     return 2;
    511   return 0;
    512 }]])],
    513          [gl_cv_func_posix_spawn_file_actions_addopen_works=yes],
    514          [gl_cv_func_posix_spawn_file_actions_addopen_works=no],
    515          [# Guess no on Solaris, yes otherwise.
    516           case "$host_os" in
    517             solaris*) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
    518             *)        gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";;
    519           esac
    520          ])
    521       ])
    522     case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in
    523       *yes) ;;
    524       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;;
    525     esac
    526   fi
    527 ])
    528