maint: update copyright
[gnulib.git] / m4 / posix_spawn.m4
1 # posix_spawn.m4 serial 11
2 dnl Copyright (C) 2008-2014 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 ])