fchmod-tests, fchmodat tests, lchmod tests: Add more tests.
[gnulib.git] / m4 / posix_spawn.m4
blob787336d7e71fb61cc819863f121db285e16eeab8
1 # posix_spawn.m4 serial 19
2 dnl Copyright (C) 2008-2021 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         *) REPLACE_POSIX_SPAWN=1 ;;
59       esac
60     fi
61     if test $REPLACE_POSIX_SPAWN = 0; then
62       gl_POSIX_SPAWN_SECURE
63       case "$gl_cv_func_posix_spawn_secure_exec" in
64         *yes) ;;
65         *) REPLACE_POSIX_SPAWN=1 ;;
66       esac
67       case "$gl_cv_func_posix_spawnp_secure_exec" in
68         *yes) ;;
69         *) REPLACE_POSIX_SPAWN=1 ;;
70       esac
71     fi
72     if test $REPLACE_POSIX_SPAWN = 0; then
73       dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDULER
74       dnl evaluates to nonzero.
75       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedpolicy])
76       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedpolicy])
77       AC_CACHE_CHECK([whether posix_spawnattr_setschedpolicy is supported],
78         [gl_cv_func_spawnattr_setschedpolicy],
79         [AC_EGREP_CPP([POSIX scheduling supported], [
80 #include <spawn.h>
81 #if POSIX_SPAWN_SETSCHEDULER
82  POSIX scheduling supported
83 #endif
85            [gl_cv_func_spawnattr_setschedpolicy=yes],
86            [gl_cv_func_spawnattr_setschedpolicy=no])
87         ])
88       dnl Assume that these functions are available if POSIX_SPAWN_SETSCHEDPARAM
89       dnl evaluates to nonzero.
90       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_getschedparam])
91       dnl AC_CHECK_FUNCS_ONCE([posix_spawnattr_setschedparam])
92       AC_CACHE_CHECK([whether posix_spawnattr_setschedparam is supported],
93         [gl_cv_func_spawnattr_setschedparam],
94         [AC_EGREP_CPP([POSIX scheduling supported], [
95 #include <spawn.h>
96 #if POSIX_SPAWN_SETSCHEDPARAM
97  POSIX scheduling supported
98 #endif
100            [gl_cv_func_spawnattr_setschedparam=yes],
101            [gl_cv_func_spawnattr_setschedparam=no])
102         ])
103     fi
104   fi
105   if test $ac_cv_func_posix_spawn != yes || test $REPLACE_POSIX_SPAWN = 1; then
106     AC_DEFINE([REPLACE_POSIX_SPAWN], [1],
107       [Define if gnulib uses its own posix_spawn and posix_spawnp functions.])
108   fi
111 dnl Test whether posix_spawn actually works.
112 dnl posix_spawn on AIX 5.3..6.1 has two bugs:
113 dnl 1) When it fails to execute the program, the child process exits with
114 dnl    exit() rather than _exit(), which causes the stdio buffers to be
115 dnl    flushed. Reported by Rainer Tammer.
116 dnl 2) The posix_spawn_file_actions_addopen function does not support file
117 dnl    names that contain a '*'.
118 dnl posix_spawn on AIX 5.3..6.1 has also a third bug: It does not work
119 dnl when POSIX threads are used. But we don't test against this bug here.
120 AC_DEFUN([gl_POSIX_SPAWN_WORKS],
122   AC_REQUIRE([AC_PROG_CC])
123   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
124   AC_CACHE_CHECK([whether posix_spawn works], [gl_cv_func_posix_spawn_works],
125     [if test $cross_compiling = no; then
126        AC_LINK_IFELSE([AC_LANG_SOURCE([[
127 #include <errno.h>
128 #include <fcntl.h>
129 #include <signal.h>
130 #include <spawn.h>
131 #include <stdbool.h>
132 #include <stdio.h>
133 #include <stdlib.h>
134 #include <string.h>
135 #include <unistd.h>
136 #include <sys/types.h>
137 #include <sys/wait.h>
138 ]GL_MDA_DEFINES[
140 extern char **environ;
142 #ifndef STDIN_FILENO
143 # define STDIN_FILENO 0
144 #endif
145 #ifndef STDOUT_FILENO
146 # define STDOUT_FILENO 1
147 #endif
148 #ifndef STDERR_FILENO
149 # define STDERR_FILENO 2
150 #endif
152 #ifndef WTERMSIG
153 # define WTERMSIG(x) ((x) & 0x7f)
154 #endif
155 #ifndef WIFEXITED
156 # define WIFEXITED(x) (WTERMSIG (x) == 0)
157 #endif
158 #ifndef WEXITSTATUS
159 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
160 #endif
162 #define CHILD_PROGRAM_FILENAME "/non/exist/ent"
164 static int
165 fd_safer (int fd)
167   if (0 <= fd && fd <= 2)
168     {
169       int f = fd_safer (dup (fd));
170       int e = errno;
171       close (fd);
172       errno = e;
173       fd = f;
174     }
176   return fd;
180 main ()
182   char *argv[2] = { CHILD_PROGRAM_FILENAME, NULL };
183   int ofd[2];
184   sigset_t blocked_signals;
185   sigset_t fatal_signal_set;
186   posix_spawn_file_actions_t actions;
187   bool actions_allocated;
188   posix_spawnattr_t attrs;
189   bool attrs_allocated;
190   int err;
191   pid_t child;
192   int status;
193   int exitstatus;
195   setvbuf (stdout, NULL, _IOFBF, 0);
196   puts ("This should be seen only once.");
197   if (pipe (ofd) < 0 || (ofd[1] = fd_safer (ofd[1])) < 0)
198     {
199       perror ("cannot create pipe");
200       exit (1);
201     }
202   sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
203   sigemptyset (&fatal_signal_set);
204   sigaddset (&fatal_signal_set, SIGINT);
205   sigaddset (&fatal_signal_set, SIGTERM);
206   sigaddset (&fatal_signal_set, SIGHUP);
207   sigaddset (&fatal_signal_set, SIGPIPE);
208   sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
209   actions_allocated = false;
210   attrs_allocated = false;
211   if ((err = posix_spawn_file_actions_init (&actions)) != 0
212       || (actions_allocated = true,
213           (err = posix_spawn_file_actions_adddup2 (&actions, ofd[0], STDIN_FILENO)) != 0
214           || (err = posix_spawn_file_actions_addclose (&actions, ofd[0])) != 0
215           || (err = posix_spawn_file_actions_addclose (&actions, ofd[1])) != 0
216           || (err = posix_spawnattr_init (&attrs)) != 0
217           || (attrs_allocated = true,
218               (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
219               || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0)
220           || (err = posix_spawnp (&child, CHILD_PROGRAM_FILENAME, &actions, &attrs, argv, environ)) != 0))
221     {
222       if (actions_allocated)
223         posix_spawn_file_actions_destroy (&actions);
224       if (attrs_allocated)
225         posix_spawnattr_destroy (&attrs);
226       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
227       if (err == ENOENT)
228         return 0;
229       else
230         {
231           errno = err;
232           perror ("subprocess failed");
233           exit (1);
234         }
235     }
236   posix_spawn_file_actions_destroy (&actions);
237   posix_spawnattr_destroy (&attrs);
238   sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
239   close (ofd[0]);
240   close (ofd[1]);
241   status = 0;
242   while (waitpid (child, &status, 0) != child)
243     ;
244   if (!WIFEXITED (status))
245     {
246       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
247       exit (1);
248     }
249   exitstatus = WEXITSTATUS (status);
250   if (exitstatus != 127)
251     {
252       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
253       exit (1);
254     }
255   return 0;
257 ]])],
258          [if test -s conftest$ac_exeext \
259              && ./conftest$ac_exeext > conftest.out \
260              && echo 'This should be seen only once.' > conftest.ok \
261              && cmp conftest.out conftest.ok >/dev/null 2>&1; then
262             gl_cv_func_posix_spawn_works=yes
263           else
264             gl_cv_func_posix_spawn_works=no
265           fi],
266          [gl_cv_func_posix_spawn_works=no])
267        if test $gl_cv_func_posix_spawn_works = yes; then
268          AC_RUN_IFELSE([AC_LANG_SOURCE([[
269 /* Test whether posix_spawn_file_actions_addopen supports filename arguments
270    that contain special characters such as '*'.  */
272 #include <errno.h>
273 #include <fcntl.h>
274 #include <signal.h>
275 #include <spawn.h>
276 #include <stdbool.h>
277 #include <stdio.h>
278 #include <string.h>
279 #include <unistd.h>
280 #include <sys/types.h>
281 #include <sys/wait.h>
282 ]GL_MDA_DEFINES[
284 extern char **environ;
286 #ifndef STDIN_FILENO
287 # define STDIN_FILENO 0
288 #endif
289 #ifndef STDOUT_FILENO
290 # define STDOUT_FILENO 1
291 #endif
292 #ifndef STDERR_FILENO
293 # define STDERR_FILENO 2
294 #endif
296 #ifndef WTERMSIG
297 # define WTERMSIG(x) ((x) & 0x7f)
298 #endif
299 #ifndef WIFEXITED
300 # define WIFEXITED(x) (WTERMSIG (x) == 0)
301 #endif
302 #ifndef WEXITSTATUS
303 # define WEXITSTATUS(x) (((x) >> 8) & 0xff)
304 #endif
306 #define CHILD_PROGRAM_FILENAME "conftest"
307 #define DATA_FILENAME "conftest%=*#?"
309 static int
310 parent_main (void)
312   FILE *fp;
313   char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL };
314   posix_spawn_file_actions_t actions;
315   bool actions_allocated;
316   int err;
317   pid_t child;
318   int status;
319   int exitstatus;
321   /* Create a data file with specific contents.  */
322   fp = fopen (DATA_FILENAME, "wb");
323   if (fp == NULL)
324     {
325       perror ("cannot create data file");
326       return 1;
327     }
328   fwrite ("Halle Potta", 1, 11, fp);
329   if (fflush (fp) || fclose (fp))
330     {
331       perror ("cannot prepare data file");
332       return 2;
333     }
335   /* Avoid reading from our stdin, as it could block.  */
336   freopen ("/dev/null", "rb", stdin);
338   /* Test whether posix_spawn_file_actions_addopen with this file name
339      actually works, but spawning a child that reads from this file.  */
340   actions_allocated = false;
341   if ((err = posix_spawn_file_actions_init (&actions)) != 0
342       || (actions_allocated = true,
343           (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0
344           || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0))
345     {
346       if (actions_allocated)
347         posix_spawn_file_actions_destroy (&actions);
348       errno = err;
349       perror ("subprocess failed");
350       return 3;
351     }
352   posix_spawn_file_actions_destroy (&actions);
353   status = 0;
354   while (waitpid (child, &status, 0) != child)
355     ;
356   if (!WIFEXITED (status))
357     {
358       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
359       return 4;
360     }
361   exitstatus = WEXITSTATUS (status);
362   if (exitstatus != 0)
363     {
364       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
365       return 5;
366     }
367   return 0;
370 static int
371 child_main (void)
373   char buf[1024];
375   /* See if reading from STDIN_FILENO yields the expected contents.  */
376   if (fread (buf, 1, sizeof (buf), stdin) == 11
377       && memcmp (buf, "Halle Potta", 11) == 0)
378     return 0;
379   else
380     return 8;
383 static void
384 cleanup_then_die (int sig)
386   /* Clean up data file.  */
387   unlink (DATA_FILENAME);
389   /* Re-raise the signal and die from it.  */
390   signal (sig, SIG_DFL);
391   raise (sig);
395 main (int argc, char *argv[])
397   int exitstatus;
399   if (!(argc > 1 && strcmp (argv[1], "-child") == 0))
400     {
401       /* This is the parent process.  */
402       signal (SIGINT, cleanup_then_die);
403       signal (SIGTERM, cleanup_then_die);
404       #ifdef SIGHUP
405       signal (SIGHUP, cleanup_then_die);
406       #endif
408       exitstatus = parent_main ();
409     }
410   else
411     {
412       /* This is the child process.  */
414       exitstatus = child_main ();
415     }
416   unlink (DATA_FILENAME);
417   return exitstatus;
419 ]])],
420            [],
421            [gl_cv_func_posix_spawn_works=no])
422        fi
423      else
424        case "$host_os" in
425          aix*) gl_cv_func_posix_spawn_works="guessing no";;
426          *)    gl_cv_func_posix_spawn_works="guessing yes";;
427        esac
428      fi
429     ])
432 dnl Test whether posix_spawn and posix_spawnp are secure.
433 AC_DEFUN([gl_POSIX_SPAWN_SECURE],
435   AC_REQUIRE([AC_PROG_CC])
436   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
437   dnl On many platforms, posix_spawn or posix_spawnp allow executing a
438   dnl script without a '#!' marker as a shell script. This is unsecure.
439   AC_CACHE_CHECK([whether posix_spawn rejects scripts without shebang],
440     [gl_cv_func_posix_spawn_secure_exec],
441     [echo ':' > conftest.scr
442      chmod a+x conftest.scr
443      AC_RUN_IFELSE([AC_LANG_SOURCE([[
444        #include <errno.h>
445        #include <spawn.h>
446        #include <stddef.h>
447        #include <sys/types.h>
448        #include <sys/wait.h>
449        int
450        main ()
451        {
452          const char *prog_path = "./conftest.scr";
453          const char *prog_argv[2] = { prog_path, NULL };
454          const char *environment[2] = { "PATH=.", NULL };
455          pid_t child;
456          int status;
457          int err = posix_spawn (&child, prog_path, NULL, NULL,
458                                 (char **) prog_argv, (char **) environment);
459          if (err == ENOEXEC)
460            return 0;
461          if (err != 0)
462            return 1;
463          status = 0;
464          while (waitpid (child, &status, 0) != child)
465            ;
466          if (!WIFEXITED (status))
467            return 2;
468          if (WEXITSTATUS (status) != 127)
469            return 3;
470          return 0;
471        }
472        ]])],
473        [gl_cv_func_posix_spawn_secure_exec=yes],
474        [gl_cv_func_posix_spawn_secure_exec=no],
475        [case "$host_os" in
476           # Guess no on GNU/Hurd.
477           gnu*)
478             gl_cv_func_posix_spawn_secure_exec="guessing no" ;;
479           # Guess yes on all other platforms.
480           *)
481             gl_cv_func_posix_spawn_secure_exec="guessing yes" ;;
482         esac
483        ])
484      rm -f conftest.scr
485     ])
486   AC_CACHE_CHECK([whether posix_spawnp rejects scripts without shebang],
487     [gl_cv_func_posix_spawnp_secure_exec],
488     [echo ':' > conftest.scr
489      chmod a+x conftest.scr
490      AC_RUN_IFELSE([AC_LANG_SOURCE([[
491        #include <errno.h>
492        #include <spawn.h>
493        #include <stddef.h>
494        #include <sys/types.h>
495        #include <sys/wait.h>
496        int
497        main ()
498        {
499          const char *prog_path = "./conftest.scr";
500          const char *prog_argv[2] = { prog_path, NULL };
501          const char *environment[2] = { "PATH=.", NULL };
502          pid_t child;
503          int status;
504          int err = posix_spawnp (&child, prog_path, NULL, NULL,
505                                  (char **) prog_argv, (char **) environment);
506          if (err == ENOEXEC)
507            return 0;
508          if (err != 0)
509            return 1;
510          status = 0;
511          while (waitpid (child, &status, 0) != child)
512            ;
513          if (!WIFEXITED (status))
514            return 2;
515          if (WEXITSTATUS (status) != 127)
516            return 3;
517          return 0;
518        }
519        ]])],
520        [gl_cv_func_posix_spawnp_secure_exec=yes],
521        [gl_cv_func_posix_spawnp_secure_exec=no],
522        [case "$host_os" in
523           # Guess yes on glibc systems (glibc >= 2.15 actually) except GNU/Hurd,
524           # musl libc, NetBSD.
525           *-gnu* | *-musl* | netbsd*)
526             gl_cv_func_posix_spawnp_secure_exec="guessing yes" ;;
527           # Guess no on GNU/Hurd, macOS, FreeBSD, OpenBSD, AIX, Solaris, Cygwin.
528           gnu* | darwin* | freebsd* | dragonfly* | openbsd* | aix* | solaris* | cygwin*)
529             gl_cv_func_posix_spawnp_secure_exec="guessing no" ;;
530           # If we don't know, obey --enable-cross-guesses.
531           *)
532             gl_cv_func_posix_spawnp_secure_exec="$gl_cross_guess_normal" ;;
533         esac
534        ])
535      rm -f conftest.scr
536     ])
539 # Prerequisites of lib/spawni.c.
540 AC_DEFUN([gl_PREREQ_POSIX_SPAWN_INTERNAL],
542   AC_CHECK_HEADERS([paths.h])
543   AC_CHECK_FUNCS([confstr sched_setparam sched_setscheduler setegid seteuid vfork])
546 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE],
548   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
549   AC_REQUIRE([AC_PROG_CC])
550   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
551   gl_POSIX_SPAWN
552   if test $REPLACE_POSIX_SPAWN = 1; then
553     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1
554   else
555     dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_addclose
556     dnl succeeds even if the fd argument is out of range.
557     AC_CACHE_CHECK([whether posix_spawn_file_actions_addclose works],
558       [gl_cv_func_posix_spawn_file_actions_addclose_works],
559       [AC_RUN_IFELSE(
560          [AC_LANG_SOURCE([[
561 #include <spawn.h>
562 int main ()
564   posix_spawn_file_actions_t actions;
565   if (posix_spawn_file_actions_init (&actions) != 0)
566     return 1;
567   if (posix_spawn_file_actions_addclose (&actions, 10000000) == 0)
568     return 2;
569   return 0;
570 }]])],
571          [gl_cv_func_posix_spawn_file_actions_addclose_works=yes],
572          [gl_cv_func_posix_spawn_file_actions_addclose_works=no],
573          [# Guess no on musl libc and Solaris, yes otherwise.
574           case "$host_os" in
575             *-musl*)  gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
576             solaris*) gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
577                       # Guess no on native Windows.
578             mingw*)   gl_cv_func_posix_spawn_file_actions_addclose_works="guessing no" ;;
579             *)        gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes" ;;
580           esac
581          ])
582       ])
583     case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in
584       *yes) ;;
585       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;;
586     esac
587   fi
590 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2],
592   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
593   AC_REQUIRE([AC_PROG_CC])
594   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
595   gl_POSIX_SPAWN
596   if test $REPLACE_POSIX_SPAWN = 1; then
597     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1
598   else
599     dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_adddup2
600     dnl succeeds even if the fd argument is out of range.
601     AC_CACHE_CHECK([whether posix_spawn_file_actions_adddup2 works],
602       [gl_cv_func_posix_spawn_file_actions_adddup2_works],
603       [AC_RUN_IFELSE(
604          [AC_LANG_SOURCE([[
605 #include <spawn.h>
606 int main ()
608   posix_spawn_file_actions_t actions;
609   if (posix_spawn_file_actions_init (&actions) != 0)
610     return 1;
611   if (posix_spawn_file_actions_adddup2 (&actions, 10000000, 2) == 0)
612     return 2;
613   return 0;
614 }]])],
615          [gl_cv_func_posix_spawn_file_actions_adddup2_works=yes],
616          [gl_cv_func_posix_spawn_file_actions_adddup2_works=no],
617          [# Guess no on musl libc and Solaris, yes otherwise.
618           case "$host_os" in
619             *-musl*)  gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
620             solaris*) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no";;
621                       # Guess no on native Windows.
622             mingw*)   gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing no" ;;
623             *)        gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";;
624           esac
625          ])
626       ])
627     case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in
628       *yes) ;;
629       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;;
630     esac
631   fi
634 AC_DEFUN([gl_FUNC_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN],
636   AC_REQUIRE([gl_SPAWN_H_DEFAULTS])
637   AC_REQUIRE([AC_PROG_CC])
638   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
639   gl_POSIX_SPAWN
640   if test $REPLACE_POSIX_SPAWN = 1; then
641     REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1
642   else
643     dnl On musl libc and Solaris 11.0, posix_spawn_file_actions_addopen
644     dnl succeeds even if the fd argument is out of range.
645     AC_CACHE_CHECK([whether posix_spawn_file_actions_addopen works],
646       [gl_cv_func_posix_spawn_file_actions_addopen_works],
647       [AC_RUN_IFELSE(
648          [AC_LANG_SOURCE([[
649 #include <spawn.h>
650 #include <fcntl.h>
651 int main ()
653   posix_spawn_file_actions_t actions;
654   if (posix_spawn_file_actions_init (&actions) != 0)
655     return 1;
656   if (posix_spawn_file_actions_addopen (&actions, 10000000, "foo", 0, O_RDONLY)
657       == 0)
658     return 2;
659   return 0;
660 }]])],
661          [gl_cv_func_posix_spawn_file_actions_addopen_works=yes],
662          [gl_cv_func_posix_spawn_file_actions_addopen_works=no],
663          [# Guess no on musl libc and Solaris, yes otherwise.
664           case "$host_os" in
665             *-musl*)  gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
666             solaris*) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no";;
667                       # Guess no on native Windows.
668             mingw*)   gl_cv_func_posix_spawn_file_actions_addopen_works="guessing no" ;;
669             *)        gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";;
670           esac
671          ])
672       ])
673     case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in
674       *yes) ;;
675       *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;;
676     esac
677   fi