diff options
-rw-r--r-- | SConstruct | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/config.h.cmake | 2 | ||||
-rw-r--r-- | src/fdevent.c | 99 | ||||
-rw-r--r-- | src/meson.build | 2 |
6 files changed, 112 insertions, 1 deletions
@@ -431,6 +431,8 @@ if 1: 'mmap', 'pipe2', 'poll', + 'posix_spawn', + 'posix_spawn_file_actions_addfchdir_np', 'pread', 'preadv', 'pwrite', diff --git a/configure.ac b/configure.ac index 02b1cdf6..331f95d2 100644 --- a/configure.ac +++ b/configure.ac @@ -1461,6 +1461,8 @@ AC_CHECK_FUNCS([\ mkostemp \ pipe2 \ poll \ + posix_spawn \ + posix_spawn_file_actions_addfchdir_np \ pread \ pwrite \ sendfile \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d469d75c..d8b1da3e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -209,6 +209,12 @@ check_include_files(sys/select.h HAVE_SYS_SELECT_H) check_function_exists(select HAVE_SELECT) endif() +check_include_files(spawn.h HAVE_SPAWN_H) +if(HAVE_SPAWN_H) +check_function_exists(posix_spawn HAVE_POSIX_SPAWN) +check_function_exists(posix_spawn_file_actions_addfchdir_np HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP) +endif() + set(CMAKE_EXTRA_INCLUDE_FILES time.h) check_function_exists(timegm HAVE_TIMEGM) set(CMAKE_EXTRA_INCLUDE_FILES) diff --git a/src/config.h.cmake b/src/config.h.cmake index 838792b4..99dfd954 100644 --- a/src/config.h.cmake +++ b/src/config.h.cmake @@ -178,6 +178,8 @@ #cmakedefine HAVE_MMAP #cmakedefine HAVE_PIPE2 #cmakedefine HAVE_POLL +#cmakedefine HAVE_POSIX_SPAWN +#cmakedefine HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP #cmakedefine HAVE_PORT_CREATE #cmakedefine HAVE_PREAD #cmakedefine HAVE_PREADV diff --git a/src/fdevent.c b/src/fdevent.c index 43d2622e..6fde8d97 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -432,6 +432,9 @@ int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr) { #include <stdio.h> /* perror() rename() */ #include <signal.h> /* signal() kill() */ +#ifdef HAVE_POSIX_SPAWN +#include <spawn.h> /* posix_spawn*() */ +#endif int fdevent_rename(const char *oldpath, const char *newpath) { @@ -440,7 +443,101 @@ int fdevent_rename(const char *oldpath, const char *newpath) { pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) { - #ifdef HAVE_FORK + #ifdef HAVE_POSIX_SPAWN + + /* Caller must ensure that all fd* args are >= 3, i.e. > STDERR_FILENO (2), + * unless fd* arg is -1, in which case we preserve existing target fd, or + * unless fd does not have FD_CLOEXEC set *and* is not being replaced, + * e.g. if fd 1 is open to /dev/null and fdout is -1 and fderr is 1 so + * that fd 1 (STDOUT_FILENO) to /dev/null is dup2() to fd 2 (STDERR_FILENO). + * Caller must handle so that if any dup() is required to make fd* >= 3, + * then the caller has access to the new fds. The reason fd* args >= 3 + * is required is that we set FD_CLOEXEC on all fds (thread-safety) and + * a dup2() in child is used for dup2() side effect of removing FD_CLOEXEC. + * (posix_spawn() provides posix_spawn_file_actions_adddup2() whereas + * it does not provide a means to use fcntl() to remove FD_CLOEXEC) */ + + sigset_t sigs; + posix_spawn_file_actions_t file_actions; + posix_spawnattr_t attr; + int rc; + pid_t pid = -1; + if (0 != (rc = posix_spawn_file_actions_init(&file_actions))) + return pid; + if (0 != (rc = posix_spawnattr_init(&attr))) { + posix_spawn_file_actions_destroy(&file_actions); + return pid; + } + if ( 0 == (rc = (fdin >= 0) + ? posix_spawn_file_actions_adddup2( + &file_actions, fdin, STDIN_FILENO) + : 0) + && 0 == (rc = (fdout >= 0) + ? posix_spawn_file_actions_adddup2( + &file_actions, fdout, STDOUT_FILENO) + : 0) + && 0 == (rc = (fderr >= 0) + ? posix_spawn_file_actions_adddup2( + &file_actions, fderr, STDERR_FILENO) + : 0) + #ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP + && 0 == (rc = (-1 != dfd) + ? posix_spawn_file_actions_addfchdir_np( + &file_actions, dfd) + : 0) + #endif + && 0 == (rc = posix_spawnattr_setflags( + &attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK)) + && 0 == (rc = sigemptyset(&sigs)) + && 0 == (rc = posix_spawnattr_setsigmask(&attr, &sigs)) + /*(force reset signals to SIG_DFL if server.c set to SIG_IGN)*/ + #ifdef SIGTTOU + && 0 == (rc = sigaddset(&sigs, SIGTTOU)) + #endif + #ifdef SIGTTIN + && 0 == (rc = sigaddset(&sigs, SIGTTIN)) + #endif + #ifdef SIGTSTP + && 0 == (rc = sigaddset(&sigs, SIGTSTP)) + #endif + && 0 == (rc = sigaddset(&sigs, SIGPIPE)) + && 0 == (rc = sigaddset(&sigs, SIGUSR1)) + && 0 == (rc = posix_spawnattr_setsigdefault(&attr, &sigs))) { + + #ifndef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP + /* not thread-safe, but ok since lighttpd not (currently) threaded + * (alternatively, check HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP + * along with HAVE_POSIX_SPAWN at top of block and use HAVE_FORK + * below if HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP not avail)*/ + if (-1 != dfd) { + int ndfd = dfd; + dfd = fdevent_open_dirname(".", 1); /* reuse dfd for cwd fd */ + if (-1 == dfd || 0 != fchdir(ndfd)) + rc = -1; /*(or could set to errno for posix consistency)*/ + } + if (0 == rc) + #endif + + rc = posix_spawn(&pid, name, &file_actions, &attr, + argv, envp ? envp : environ); + + if (0 != rc) + pid = -1; + + #ifndef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDFCHDIR_NP + if (-1 != dfd) { + if (0 != fchdir(dfd)) { /* ignore error; best effort */ + /*rc = errno;*/ + } + close(dfd); + } + #endif + } + posix_spawn_file_actions_destroy(&file_actions); + posix_spawnattr_destroy(&attr); + return pid; + + #elif defined(HAVE_FORK) pid_t pid = fork(); if (0 != pid) return pid; /* parent (pid > 0) or fork() error (-1 == pid) */ diff --git a/src/meson.build b/src/meson.build index 930d1cf5..db59f0f5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -136,6 +136,8 @@ functions = { 'mmap': 'sys/mman.h', 'pipe2': 'unistd.h', 'poll': 'poll.h', + 'posix_spawn': 'spawn.h', + 'posix_spawn_file_actions_addfchdir_np': 'spawn.h', 'pread': 'unistd.h', 'preadv': 'sys/uio.h', 'pwrite': 'unistd.h', |