git-merge-changelog: Improve last commit.
[gnulib.git] / m4 / posix_spawn.m4
blob7173ca3cf08d0aa04805e76219fc2c7651c1eafc
1 # posix_spawn.m4
2 # serial 25
3 dnl Copyright (C) 2008-2024 Free Software Foundation, Inc.
4 dnl This file is free software; the Free Software Foundation
5 dnl gives unlimited permission to copy and/or distribute it,
6 dnl with or without modifications, as long as this notice is preserved.
8 dnl Tests whether the entire posix_spawn facility is available.
9 AC_DEFUN([gl_POSIX_SPAWN],
11   AC_REQUIRE([gl_POSIX_SPAWN_BODY])
14 AC_DEFUN([gl_POSIX_SPAWN_BODY],
16   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
17   AC_REQUIRE([gl_HAVE_POSIX_SPAWN])
18   dnl Assume that when the main function exists, all the others,
19   dnl except posix_spawnattr_{get,set}sched*, are available as well.
20   dnl AC_CHECK_FUNCS_ONCE([posix_spawnp])
21   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_init])
22   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addclose])
23   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_adddup2])
24   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_addopen])
25   dnl AC_CHECK_FUNCS_ONCE([posix_spawn_file_actions_destroy])
26   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_init])
27   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getflags])
28   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setflags])
29   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getpgroup])
30   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setpgroup])
31   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigdefault])
32   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigdefault])
33   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getsigmask])
34   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setsigmask])
35   dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_destroy])
36   AC_CHECK_DECLS([posix_spawn], , , [[#include <spawn.h>]])
37   if test $ac_cv_func_posix_spawn = yes; then
38     m4_ifdef([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR],
39       [dnl Module 'posix_spawn_file_actions_addchdir' is present.
40        gl_CHECK_FUNCS_ANDROID([posix_spawn_file_actions_addchdir_np],
41          [[#include <spawn.h>]])
42        if test $ac_cv_func_posix_spawn_file_actions_addchdir_np = no; then
43          dnl In order to implement the posix_spawn_file_actions_addchdir
44          dnl function, we need to replace the entire posix_spawn facility.
45          REPLACE_POSIX_SPAWN=1
46        fi
47       ])
48     m4_ifdef([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR],
49       [dnl Module 'posix_spawn_file_actions_addfchdir' is present.
50        gl_CHECK_FUNCS_ANDROID([posix_spawn_file_actions_addfchdir_np],
51          [[#include <spawn.h>]])
52        if test $ac_cv_func_posix_spawn_file_actions_addfchdir_np = no; then
53          dnl In order to implement the posix_spawn_file_actions_addfchdir
54          dnl function, we need to replace the entire posix_spawn facility.
55          REPLACE_POSIX_SPAWN=1
56        fi
57       ])
58     if test $REPLACE_POSIX_SPAWN = 0; then
59       gl_POSIX_SPAWN_WORKS
60       case "$gl_cv_func_posix_spawn_works" in
61         *yes) ;;
62         *) REPLACE_POSIX_SPAWN=1 ;;
63       esac
64     fi
65     if test $REPLACE_POSIX_SPAWN = 0; then
66       gl_POSIX_SPAWN_SECURE
67       case "$gl_cv_func_posix_spawn_secure_exec" in
68         *yes) ;;
69         *) REPLACE_POSIX_SPAWN=1 ;;
70       esac
71       case "$gl_cv_func_posix_spawnp_secure_exec" in
72         *yes) ;;
73         *) REPLACE_POSIX_SPAWN=1 ;;
74       esac
75     fi
76     if test $REPLACE_POSIX_SPAWN = 0; then
77       dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
78       dnl evaluates to nonzero.
79       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
80       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
81       AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
82         [gl_cv_func_spawnattr_setschedpolicy],
83         [AC_EGREP_CPP([POSIX scheduling supported], [
84 #include <spawn.h>
85 #if POSIX_SPAWN_SETSCHEDULER
86  POSIX scheduling supported
87 #endif
89            [gl_cv_func_spawnattr_setschedpolicy=yes],
90            [gl_cv_func_spawnattr_setschedpolicy=no])
91         ])
92       dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
93       dnl evaluates to nonzero.
94       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
95       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
96       AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
97         [gl_cv_func_spawnattr_setschedparam],
98         [AC_EGREP_CPP([POSIX scheduling supported], [
99 #include <spawn.h>
100 #if POSIX_SPAWN_SETSCHEDPARAM
101  POSIX scheduling supported
102 #endif
104            [gl_cv_func_spawnattr_setschedparam=yes],
105            [gl_cv_func_spawnattr_setschedparam=no])
106         ])
107     fi
108   else
109     dnl The system does not have the main function. Therefore we have to
110     dnl provide our own implementation. This implies to define our own
111     dnl posix_spawn_file_actions_t and posix_spawnattr_t types.
112     if test $ac_cv_have_decl_posix_spawn = yes; then
113       dnl The system declares posix_spawn() already. This declaration uses
114       dnl the original posix_spawn_file_actions_t and posix_spawnattr_t types.
115       dnl But we need a declaration with our own posix_spawn_file_actions_t and
116       dnl posix_spawnattr_t types.
117       REPLACE_POSIX_SPAWN=1
118     fi
119   fi
120   if test $ac_cv_func_posix_spawn != yes || test $REPLACE_POSIX_SPAWN = 1; then
121     AC_DEFINE([REPLACE_POSIX_SPAWN], [1],
122       [Define if gnulib uses its own posix_spawn and posix_spawnp functions.])
123   fi
126 dnl Test whether posix_spawn actually works.
127 dnl posix_spawn on AIX 5.3..6.1 has two bugs:
128 dnl 1) When it fails to execute the program, the child process exits with
129 dnl    exit() rather than _exit(), which causes the stdio buffers to be
130 dnl    flushed. Reported by Rainer Tammer.
131 dnl 2) The posix_spawn_file_actions_addopen function does not support file
132 dnl    names that contain a '*'.
133 dnl posix_spawn on AIX 5.3..6.1 has also a third bug: It does not work
134 dnl when POSIX threads are used. But we don't test against this bug here.
135 AC_DEFUN([gl_POSIX_SPAWN_WORKS],
137   AC_REQUIRE([AC_PROG_CC])
138   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
139   AC_CACHE_CHECK([whether posix_spawn works], [gl_cv_func_posix_spawn_works],
140     [if test $cross_compiling = no; then
141        AC_LINK_IFELSE([AC_LANG_SOURCE([[
142 #include <errno.h>
143 #include <fcntl.h>
144 #include <signal.h>
145 #include <spawn.h>
146 #include <stdbool.h>
147 #include <stdio.h>
148 #include <stdlib.h>
149 #include <string.h>
150 #include <unistd.h>
151 #include <sys/types.h>
152 #include <sys/wait.h>
153 ]GL_MDA_DEFINES[
155 extern char **environ;
157 #ifndef STDIN_FILENO
158 # define STDIN_FILENO 0
159 #endif
160 #ifndef STDOUT_FILENO
161 # define STDOUT_FILENO 1
162 #endif
163 #ifndef STDERR_FILENO
164 # define STDERR_FILENO 2
165 #endif
167 #ifndef WTERMSIG
168 # define WTERMSIG(x) ((x) & 0x7f)
169 #endif
170 #ifndef WIFEXITED
171 # define WIFEXITED(x) (WTERMSIG (x) == 0)
172 #endif
173 #ifndef WEXITSTATUS
174 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
175 #endif
177 #define CHILD_PROGRAM_FILENAME "/non/exist/ent"
179 static int
180 fd_safer (int fd)
182   if (0 <= fd && fd <= 2)
183     {
184       int f = fd_safer (dup (fd));
185       int e = errno;
186       close (fd);
187       errno = e;
188       fd = f;
189     }
191   return fd;
195 main ()
197   char *argv[2] = { CHILD_PROGRAM_FILENAME, NULL };
198   int ofd[2];
199   sigset_t blocked_signals;
200   sigset_t fatal_signal_set;
201   posix_spawn_file_actions_t actions;
202   bool actions_allocated;
203   posix_spawnattr_t attrs;
204   bool attrs_allocated;
205   int err;
206   pid_t child;
207   int status;
208   int exitstatus;
210   setvbuf (stdout, NULL, _IOFBF, 0);
211   puts ("This should be seen only once.");
212   if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
213     {
214       perror ("cannot create pipe");
215       exit (1);
216     }
217   sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
218   sigemptyset (&fatal_signal_set);
219   sigaddset (&fatal_signal_set, SIGINT);
220   sigaddset (&fatal_signal_set, SIGTERM);
221   sigaddset (&fatal_signal_set, SIGHUP);
222   sigaddset (&fatal_signal_set, SIGPIPE);
223   sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
224   actions_allocated = false;
225   attrs_allocated = false;
226   if ((err = posix_spawn_file_actions_init (&actions)) != 0
227       || (actions_allocated = true,
228           (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], STDIN_FILENO)) != 0
229           || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
230           || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
231           || (err = posix_spawnattr_init (&attrs)) != 0
232           || (attrs_allocated = true,
233               (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
234               || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
235           || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, &attrs, argv, environ)) != 0))
236     {
237       if (actions_allocated)
238         posix_spawn_file_actions_destroy (&actions);
239       if (attrs_allocated)
240         posix_spawnattr_destroy (&attrs);
241       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
242       if (err == ENOENT)
243         return 0;
244       else
245         {
246           errno = err;
247           perror ("subprocess failed");
248           exit (1);
249         }
250     }
251   posix_spawn_file_actions_destroy (&actions);
252   posix_spawnattr_destroy (&attrs);
253   sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
254   close (ofd[0]);
255   close (ofd[1]);
256   status = 0;
257   while (waitpid (child, &status, 0) != child)
258     ;
259   if (!WIFEXITED (status))
260     {
261       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
262       exit (1);
263     }
264   exitstatus = WEXITSTATUS (status);
265   if (exitstatus != 127)
266     {
267       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
268       exit (1);
269     }
270   return 0;
272 ]])],
273          [if test -s conftest$ac_exeext \
274              && ./conftest$ac_exeext > conftest.out \
275              && echo 'This should be seen only once.' > conftest.ok \
276              && cmp conftest.out conftest.ok >/dev/null 2>&1; then
277             gl_cv_func_posix_spawn_works=yes
278           else
279             gl_cv_func_posix_spawn_works=no
280           fi],
281          [gl_cv_func_posix_spawn_works=no])
282        if test $gl_cv_func_posix_spawn_works = yes; then
283          AC_RUN_IFELSE([AC_LANG_SOURCE([[
284 /* Test whether posix_spawn_file_actions_addopen supports filename arguments
285    that contain special characters such as '*'.  */
287 #include <errno.h>
288 #include <fcntl.h>
289 #include <signal.h>
290 #include <spawn.h>
291 #include <stdbool.h>
292 #include <stdio.h>
293 #include <string.h>
294 #include <unistd.h>
295 #include <sys/types.h>
296 #include <sys/wait.h>
297 ]GL_MDA_DEFINES[
299 extern char **environ;
301 #ifndef STDIN_FILENO
302 # define STDIN_FILENO 0
303 #endif
304 #ifndef STDOUT_FILENO
305 # define STDOUT_FILENO 1
306 #endif
307 #ifndef STDERR_FILENO
308 # define STDERR_FILENO 2
309 #endif
311 #ifndef WTERMSIG
312 # define WTERMSIG(x) ((x) & 0x7f)
313 #endif
314 #ifndef WIFEXITED
315 # define WIFEXITED(x) (WTERMSIG (x) == 0)
316 #endif
317 #ifndef WEXITSTATUS
318 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
319 #endif
321 #define CHILD_PROGRAM_FILENAME "conftest"
322 #define DATA_FILENAME "conftest%=*#?"
324 static int
325 parent_main (void)
327   FILE *fp;
328   char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL };
329   posix_spawn_file_actions_t actions;
330   bool actions_allocated;
331   int err;
332   pid_t child;
333   int status;
334   int exitstatus;
336   /* Create a data file with specific contents.  */
337   fp = fopen (DATA_FILENAME, "wb");
338   if (fp == NULL)
339     {
340       perror ("cannot create data file");
341       return 1;
342     }
343   fwrite ("Halle Potta", 1, 11, fp);
344   if (fflush (fp) || fclose (fp))
345     {
346       perror ("cannot prepare data file");
347       return 2;
348     }
350   /* Avoid reading from our stdin, as it could block.  */
351   freopen ("/dev/null", "rb", stdin);
353   /* Test whether posix_spawn_file_actions_addopen with this file name
354      actually works, but spawning a child that reads from this file.  */
355   actions_allocated = false;
356   if ((err = posix_spawn_file_actions_init (&actions)) != 0
357       || (actions_allocated = true,
358           (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0
359           || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0))
360     {
361       if (actions_allocated)
362         posix_spawn_file_actions_destroy (&actions);
363       errno = err;
364       perror ("subprocess failed");
365       return 3;
366     }
367   posix_spawn_file_actions_destroy (&actions);
368   status = 0;
369   while (waitpid (child, &status, 0) != child)
370     ;
371   if (!WIFEXITED (status))
372     {
373       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
374       return 4;
375     }
376   exitstatus = WEXITSTATUS (status);
377   if (exitstatus != 0)
378     {
379       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
380       return 5;
381     }
382   return 0;
385 static int
386 child_main (void)
388   char buf[1024];
390   /* See if reading from STDIN_FILENO yields the expected contents.  */
391   if (fread (buf, 1, sizeof (buf), stdin) == 11
392       && memcmp (buf, "Halle Potta", 11) == 0)
393     return 0;
394   else
395     return 8;
398 static void
399 cleanup_then_die (int sig)
401   /* Clean up data file.  */
402   unlink (DATA_FILENAME);
404   /* Re-raise the signal and die from it.  */
405   signal (sig, SIG_DFL);
406   raise (sig);
410 main (int argc, char *argv[])
412   int exitstatus;
414   if (!(argc > 1 && strcmp (argv[1], "-child") == 0))
415     {
416       /* This is the parent process.  */
417       signal (SIGINT, cleanup_then_die);
418       signal (SIGTERM, cleanup_then_die);
419       #ifdef SIGHUP
420       signal (SIGHUP, cleanup_then_die);
421       #endif
423       exitstatus = parent_main ();
424     }
425   else
426     {
427       /* This is the child process.  */
429       exitstatus = child_main ();
430     }
431   unlink (DATA_FILENAME);
432   return exitstatus;
434 ]])],
435            [],
436            [gl_cv_func_posix_spawn_works=no])
437        fi
438      else
439        case "$host_os" in
440          aix*) gl_cv_func_posix_spawn_works="guessing no";;
441          *)    gl_cv_func_posix_spawn_works="guessing yes";;
442        esac
443      fi
444     ])
447 dnl Test whether posix_spawn and posix_spawnp are secure.
448 AC_DEFUN([gl_POSIX_SPAWN_SECURE],
450   AC_REQUIRE([AC_PROG_CC])
451   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
452   dnl On many platforms, posix_spawn or posix_spawnp allow executing a
453   dnl script without a '#!' marker as a shell script. This is unsecure.
454   AC_CACHE_CHECK([whether posix_spawn rejects scripts without shebang],
455     [gl_cv_func_posix_spawn_secure_exec],
456     [echo ':' > conftest.scr
457      chmod a+x conftest.scr
458      AC_RUN_IFELSE([AC_LANG_SOURCE([[
459        #include <errno.h>
460        #include <spawn.h>
461        #include <stddef.h>
462        #include <sys/types.h>
463        #include <sys/wait.h>
464        int
465        main ()
466        {
467          const char *prog_path = "./conftest.scr";
468          const char *prog_argv[2] = { prog_path, NULL };
469          const char *environment[2] = { "PATH=.", NULL };
470          pid_t child;
471          int status;
472          int err = posix_spawn (&child, prog_path, NULL, NULL,
473                                 (char **) prog_argv, (char **) environment);
474          if (err == ENOEXEC)
475            return 0;
476          if (err != 0)
477            return 1;
478          status = 0;
479          while (waitpid (child, &status, 0) != child)
480            ;
481          if (!WIFEXITED (status))
482            return 2;
483          if (WEXITSTATUS (status) != 127)
484            return 3;
485          return 0;
486        }
487        ]])],
488        [gl_cv_func_posix_spawn_secure_exec=yes],
489        [gl_cv_func_posix_spawn_secure_exec=no],
490        [case "$host_os" in
491           # Guess no on GNU/Hurd.
492           gnu*)
493             gl_cv_func_posix_spawn_secure_exec="guessing no" ;;
494           # Guess yes on all other platforms.
495           *)
496             gl_cv_func_posix_spawn_secure_exec="guessing yes" ;;
497         esac
498        ])
499      rm -f conftest.scr
500     ])
501   AC_CACHE_CHECK([whether posix_spawnp rejects scripts without shebang],
502     [gl_cv_func_posix_spawnp_secure_exec],
503     [echo ':' > conftest.scr
504      chmod a+x conftest.scr
505      AC_RUN_IFELSE([AC_LANG_SOURCE([[
506        #include <errno.h>
507        #include <spawn.h>
508        #include <stddef.h>
509        #include <sys/types.h>
510        #include <sys/wait.h>
511        int
512        main ()
513        {
514          const char *prog_path = "./conftest.scr";
515          const char *prog_argv[2] = { prog_path, NULL };
516          const char *environment[2] = { "PATH=.", NULL };
517          pid_t child;
518          int status;
519          int err = posix_spawnp (&child, prog_path, NULL, NULL,
520                                  (char **) prog_argv, (char **) environment);
521          if (err == ENOEXEC)
522            return 0;
523          if (err != 0)
524            return 1;
525          status = 0;
526          while (waitpid (child, &status, 0) != child)
527            ;
528          if (!WIFEXITED (status))
529            return 2;
530          if (WEXITSTATUS (status) != 127)
531            return 3;
532          return 0;
533        }
534        ]])],
535        [gl_cv_func_posix_spawnp_secure_exec=yes],
536        [gl_cv_func_posix_spawnp_secure_exec=no],
537        [case "$host_os" in
538           # Guess yes on glibc systems (glibc >= 2.15 actually) except GNU/Hurd,
539           # musl libc, NetBSD.
540           *-gnu* | *-musl* | midipix* | netbsd*)
541             gl_cv_func_posix_spawnp_secure_exec="guessing yes" ;;
542           # Guess no on GNU/Hurd, macOS, FreeBSD, OpenBSD, AIX, Solaris, Cygwin.
543           gnu* | darwin* | freebsd* | dragonfly* | midnightbsd* | openbsd* | \
544           aix* | solaris* | cygwin*)
545             gl_cv_func_posix_spawnp_secure_exec="guessing no" ;;
546           # If we don't know, obey --enable-cross-guesses.
547           *)
548             gl_cv_func_posix_spawnp_secure_exec="$gl_cross_guess_normal" ;;
549         esac
550        ])
551      rm -f conftest.scr
552     ])
555 # Prerequisites of lib/spawni.c.
556 AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
558   AC_CHECK_HEADERS([paths.h])
559   AC_CHECK_FUNCS([confstr sched_setparam sched_setscheduler setegid seteuid vfork])
562 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE],
564   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
565   AC_REQUIRE([AC_PROG_CC])
566   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
567   gl_POSIX_SPAWN
568   if test $REPLACE_POSIX_SPAWN = 1; then
569     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1
570   else
571     dnl On musl libc, posix_spawn_file_actions_addclose succeeds even if the fd
572     dnl argument is negative.
573     AC_CACHE_CHECK([whether posix_spawn_file_actions_addclose works],
574       [gl_cv_func_posix_spawn_file_actions_addclose_works],
575       [AC_RUN_IFELSE(
576          [AC_LANG_SOURCE([[
577 #include <spawn.h>
578 int main ()
580   posix_spawn_file_actions_t actions;
581   if (posix_spawn_file_actions_init (&actions) != 0)
582     return 1;
583   if (posix_spawn_file_actions_addclose (&actions, -5) == 0)
584     return 2;
585   return 0;
586 }]])],
587          [gl_cv_func_posix_spawn_file_actions_addclose_works=yes],
588          [gl_cv_func_posix_spawn_file_actions_addclose_works=no],
589          [# Guess no on musl libc and Solaris, yes otherwise.
590           case "$host_os" in
591             *-musl* | midipix*) gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
592             solaris*)           gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
593                                 # Guess no on native Windows.
594             mingw* | windows*)  gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
595             *)                  gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes" ;;
596           esac
597          ])
598       ])
599     case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in
600       *yes) ;;
601       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;;
602     esac
603   fi
606 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2],
608   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
609   AC_REQUIRE([AC_PROG_CC])
610   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
611   gl_POSIX_SPAWN
612   if test $REPLACE_POSIX_SPAWN = 1; then
613     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1
614   else
615     dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_adddup2
616     dnl succeeds even if the fd argument is out of range.
617     AC_CACHE_CHECK([whether posix_spawn_file_actions_adddup2 works],
618       [gl_cv_func_posix_spawn_file_actions_adddup2_works],
619       [AC_RUN_IFELSE(
620          [AC_LANG_SOURCE([[
621 #include <spawn.h>
622 int main ()
624   posix_spawn_file_actions_t actions;
625   if (posix_spawn_file_actions_init (&actions) != 0)
626     return 1;
627   if (posix_spawn_file_actions_adddup2 (&actions, 10000000, 2) == 0)
628     return 2;
629   return 0;
630 }]])],
631          [gl_cv_func_posix_spawn_file_actions_adddup2_works=yes],
632          [gl_cv_func_posix_spawn_file_actions_adddup2_works=no],
633          [# Guess no on musl libc and Solaris, yes otherwise.
634           case "$host_os" in
635             *-musl* | midipix*) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
636             solaris*)           gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
637                                 # Guess no on native Windows.
638             mingw* | windows*)  gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no" ;;
639             *)                  gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";;
640           esac
641          ])
642       ])
643     case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in
644       *yes) ;;
645       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;;
646     esac
647   fi
650 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN],
652   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
653   AC_REQUIRE([AC_PROG_CC])
654   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
655   gl_POSIX_SPAWN
656   if test $REPLACE_POSIX_SPAWN = 1; then
657     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1
658   else
659     dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_addopen
660     dnl succeeds even if the fd argument is out of range.
661     AC_CACHE_CHECK([whether posix_spawn_file_actions_addopen works],
662       [gl_cv_func_posix_spawn_file_actions_addopen_works],
663       [AC_RUN_IFELSE(
664          [AC_LANG_SOURCE([[
665 #include <spawn.h>
666 #include <fcntl.h>
667 int main ()
669   posix_spawn_file_actions_t actions;
670   if (posix_spawn_file_actions_init (&actions) != 0)
671     return 1;
672   if (posix_spawn_file_actions_addopen (&actions, 10000000, "foo", 0, O_RDONLY)
673       == 0)
674     return 2;
675   return 0;
676 }]])],
677          [gl_cv_func_posix_spawn_file_actions_addopen_works=yes],
678          [gl_cv_func_posix_spawn_file_actions_addopen_works=no],
679          [# Guess no on musl libc and Solaris, yes otherwise.
680           case "$host_os" in
681             *-musl* | midipix*) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
682             solaris*)           gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
683                                 # Guess no on native Windows.
684             mingw* | windows*)  gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no" ;;
685             *)                  gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";;
686           esac
687          ])
688       ])
689     case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in
690       *yes) ;;
691       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;;
692     esac
693   fi