libc-config: Fix __GNUC_PREREQ macro.
[gnulib.git] / m4 / posix_spawn.m4
blob40131dcddfe5156e778c5219cc14dff892480cba
1 # posix_spawn.m4 serial 12
2 dnl Copyright (C) 2008-2017 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.
7 dnl Tests whether the entire posix_spawn facility is available.
8 AC_DEFUN([gl_POSIX_SPAWN],
10   AC_REQUIRE([gl_POSIX_SPAWN_BODY])
13 AC_DEFUN([gl_POSIX_SPAWN_BODY],
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
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
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
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],
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>
106 extern char **environ;
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
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
128 #define CHILD_PROGRAM_FILENAME "/non/exist/ent"
130 static int
131 fd_safer (int fd)
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     }
142   return fd;
146 main ()
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;
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;
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 '*'.  */
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>
249 extern char **environ;
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
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
271 #define CHILD_PROGRAM_FILENAME "conftest"
272 #define DATA_FILENAME "conftest%=*#?"
274 static int
275 parent_main (void)
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;
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     }
300   /* Avoid reading from our stdin, as it could block.  */
301   freopen ("/dev/null", "rb", stdin);
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;
335 static int
336 child_main (void)
338   char buf[1024];
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;
348 static void
349 cleanup_then_die (int sig)
351   /* Clean up data file.  */
352   unlink (DATA_FILENAME);
354   /* Re-raise the signal and die from it.  */
355   signal (sig, SIG_DFL);
356   raise (sig);
360 main (int argc, char *argv[])
362   int exitstatus;
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
373       exitstatus = parent_main ();
374     }
375   else
376     {
377       /* This is the child process.  */
379       exitstatus = child_main ();
380     }
381   unlink (DATA_FILENAME);
382   return exitstatus;
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     ])
397 # Prerequisites of lib/spawni.c.
398 AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
400   AC_CHECK_HEADERS([paths.h])
401   AC_CHECK_FUNCS([confstr sched_setparam sched_setscheduler setegid seteuid vfork])
404 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE],
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 ()
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                       # Guess no on native Windows.
435             mingw*)   gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
436             *)        gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes" ;;
437           esac
438          ])
439       ])
440     case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in
441       *yes) ;;
442       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;;
443     esac
444   fi
447 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2],
449   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
450   AC_REQUIRE([AC_PROG_CC])
451   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
452   gl_POSIX_SPAWN
453   if test $REPLACE_POSIX_SPAWN = 1; then
454     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1
455   else
456     dnl On Solaris 11 2011-11, posix_spawn_file_actions_adddup2 succeeds even
457     dnl if the fd argument is out of range.
458     AC_CACHE_CHECK([whether posix_spawn_file_actions_adddup2 works],
459       [gl_cv_func_posix_spawn_file_actions_adddup2_works],
460       [AC_RUN_IFELSE(
461          [AC_LANG_SOURCE([[
462 #include <spawn.h>
463 int main ()
465   posix_spawn_file_actions_t actions;
466   if (posix_spawn_file_actions_init (&actions) != 0)
467     return 1;
468   if (posix_spawn_file_actions_adddup2 (&actions, 10000000, 2) == 0)
469     return 2;
470   return 0;
471 }]])],
472          [gl_cv_func_posix_spawn_file_actions_adddup2_works=yes],
473          [gl_cv_func_posix_spawn_file_actions_adddup2_works=no],
474          [# Guess no on Solaris, yes otherwise.
475           case "$host_os" in
476             solaris*) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
477                       # Guess no on native Windows.
478             mingw*)   gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no" ;;
479             *)        gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";;
480           esac
481          ])
482       ])
483     case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in
484       *yes) ;;
485       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;;
486     esac
487   fi
490 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN],
492   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
493   AC_REQUIRE([AC_PROG_CC])
494   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
495   gl_POSIX_SPAWN
496   if test $REPLACE_POSIX_SPAWN = 1; then
497     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1
498   else
499     dnl On Solaris 11 2011-11, posix_spawn_file_actions_addopen succeeds even
500     dnl if the fd argument is out of range.
501     AC_CACHE_CHECK([whether posix_spawn_file_actions_addopen works],
502       [gl_cv_func_posix_spawn_file_actions_addopen_works],
503       [AC_RUN_IFELSE(
504          [AC_LANG_SOURCE([[
505 #include <spawn.h>
506 #include <fcntl.h>
507 int main ()
509   posix_spawn_file_actions_t actions;
510   if (posix_spawn_file_actions_init (&actions) != 0)
511     return 1;
512   if (posix_spawn_file_actions_addopen (&actions, 10000000, "foo", 0, O_RDONLY)
513       == 0)
514     return 2;
515   return 0;
516 }]])],
517          [gl_cv_func_posix_spawn_file_actions_addopen_works=yes],
518          [gl_cv_func_posix_spawn_file_actions_addopen_works=no],
519          [# Guess no on Solaris, yes otherwise.
520           case "$host_os" in
521             solaris*) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
522                       # Guess no on native Windows.
523             mingw*)   gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no" ;;
524             *)        gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";;
525           esac
526          ])
527       ])
528     case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in
529       *yes) ;;
530       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;;
531     esac
532   fi