1# posix_spawn.m4 serial 11 2dnl Copyright (C) 2008-2012 Free Software Foundation, Inc. 3dnl This file is free software; the Free Software Foundation 4dnl gives unlimited permission to copy and/or distribute it, 5dnl with or without modifications, as long as this notice is preserved. 6 7dnl Tests whether the entire posix_spawn facility is available. 8AC_DEFUN([gl_POSIX_SPAWN], 9[ 10 AC_REQUIRE([gl_POSIX_SPAWN_BODY]) 11]) 12 13AC_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 78dnl Test whether posix_spawn actually works. 79dnl posix_spawn on AIX 5.3..6.1 has two bugs: 80dnl 1) When it fails to execute the program, the child process exits with 81dnl exit() rather than _exit(), which causes the stdio buffers to be 82dnl flushed. Reported by Rainer Tammer. 83dnl 2) The posix_spawn_file_actions_addopen function does not support file 84dnl names that contain a '*'. 85dnl posix_spawn on AIX 5.3..6.1 has also a third bug: It does not work 86dnl when POSIX threads are used. But we don't test against this bug here. 87AC_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 106extern 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 130static int 131fd_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 145int 146main () 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 249extern 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 274static int 275parent_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 335static int 336child_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 348static void 349cleanup_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 359int 360main (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. 398AC_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 404AC_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> 420int 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 445AC_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> 461int 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 486AC_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> 503int 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]) 528