diff --git a/libguile/posix.c b/libguile/posix.c index 3a8be94e4..cde199888 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -1322,39 +1322,18 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0, #undef FUNC_NAME #endif /* HAVE_FORK */ -static void -close_inherited_fds_slow (posix_spawn_file_actions_t *actions, int max_fd) -{ - while (--max_fd > 2) - posix_spawn_file_actions_addclose (actions, max_fd); -} - static void close_inherited_fds (posix_spawn_file_actions_t *actions, int max_fd) { - DIR *dirp; - struct dirent *d; - int fd; - - /* Try to use the platform-specific list of open file descriptors, so - we don't need to use the brute force approach. */ - dirp = opendir ("/proc/self/fd"); - - if (dirp == NULL) - return close_inherited_fds_slow (actions, max_fd); - - while ((d = readdir (dirp)) != NULL) + while (--max_fd > 2) { - fd = atoi (d->d_name); - - /* Skip "." and "..", garbage entries, stdin/stdout/stderr. */ - if (fd <= 2) - continue; - - posix_spawn_file_actions_addclose (actions, fd); + /* Adding invalid file descriptors to an 'addclose' action leads + to 'posix_spawn' failures on some operating systems: + . Hence the extra check. */ + int flags = fcntl (max_fd, F_GETFD, NULL); + if ((flags >= 0) && ((flags & FD_CLOEXEC) == 0)) + posix_spawn_file_actions_addclose (actions, max_fd); } - - closedir (dirp); } static pid_t @@ -1366,6 +1345,26 @@ do_spawn (char *exec_file, char **exec_argv, char **exec_env, posix_spawn_file_actions_t actions; posix_spawnattr_t *attrp = NULL; + posix_spawn_file_actions_init (&actions); + + /* Duplicate IN, OUT, and ERR unconditionally to clear their + FD_CLOEXEC flag, if any. */ + posix_spawn_file_actions_adddup2 (&actions, in, STDIN_FILENO); + posix_spawn_file_actions_adddup2 (&actions, out, STDOUT_FILENO); + posix_spawn_file_actions_adddup2 (&actions, err, STDERR_FILENO); + + /* TODO: Use 'closefrom' where available. */ +#if 0 + /* Version 2.34 of the GNU libc provides this function. */ + posix_spawn_file_actions_addclosefrom_np (&actions, 3); +#else + if (in > 2) + posix_spawn_file_actions_addclose (&actions, in); + if (out > 2 && out != in) + posix_spawn_file_actions_addclose (&actions, out); + if (err > 2 && err != out && err != in) + posix_spawn_file_actions_addclose (&actions, err); + int max_fd = 1024; #if defined (HAVE_GETRLIMIT) && defined (RLIMIT_NOFILE) @@ -1376,31 +1375,8 @@ do_spawn (char *exec_file, char **exec_argv, char **exec_env, } #endif - posix_spawn_file_actions_init (&actions); - - int free_fd_slots = 0; - int fd_slot[3]; - - for (int fdnum = 3; free_fd_slots < 3 && fdnum < max_fd; fdnum++) - { - if (fdnum != in && fdnum != out && fdnum != err) - { - fd_slot[free_fd_slots] = fdnum; - free_fd_slots++; - } - } - - /* Move the fds out of the way, so that duplicate fds or fds equal - to 0, 1, 2 don't trample each other */ - - posix_spawn_file_actions_adddup2 (&actions, in, fd_slot[0]); - posix_spawn_file_actions_adddup2 (&actions, out, fd_slot[1]); - posix_spawn_file_actions_adddup2 (&actions, err, fd_slot[2]); - posix_spawn_file_actions_adddup2 (&actions, fd_slot[0], 0); - posix_spawn_file_actions_adddup2 (&actions, fd_slot[1], 1); - posix_spawn_file_actions_adddup2 (&actions, fd_slot[2], 2); - close_inherited_fds (&actions, max_fd); +#endif int res = -1; if (spawnp)