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