* libguile/posix.c: Include spawn.h from Gnulib. (scm_spawn_process): New function. (scm_init_popen): Define spawn*. --- libguile/posix.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+)
diff --git a/libguile/posix.c b/libguile/posix.c index f4ca72d3e..5d287ff2a 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -32,6 +32,7 @@ #include <sys/types.h> #include <uniconv.h> #include <unistd.h> +#include <spawn.h> #ifdef HAVE_SCHED_H # include <sched.h> @@ -1472,6 +1473,75 @@ scm_piped_process (SCM prog, SCM args, SCM from, SCM to) } #undef FUNC_NAME +static SCM +scm_spawn_process (SCM prog, SCM args, SCM scm_in, SCM scm_out, SCM scm_err) +#define FUNC_NAME "spawn*" +{ + int in, out, err; + int pid; + char *exec_file; + char **exec_argv; + char **exec_env = NULL; + + posix_spawn_file_actions_t actions; + posix_spawnattr_t *attrp = NULL; + + exec_file = scm_to_locale_string (prog); + exec_argv = scm_i_allocate_string_pointers (args); + + in = scm_to_int (scm_in); + out = scm_to_int (scm_out); + err = scm_to_int (scm_err); + + int max_fd = 1024; + +#if defined (HAVE_GETRLIMIT) && defined (RLIMIT_NOFILE) + { + struct rlimit lim = { 0, 0 }; + if (getrlimit (RLIMIT_NOFILE, &lim) == 0) + max_fd = lim.rlim_cur; + } +#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); + + while (--max_fd > 2) + posix_spawn_file_actions_addclose (&actions, max_fd); + + if (posix_spawnp (&pid, exec_file, &actions, attrp, exec_argv, environ) != 0) + { + int errno_save = errno; + free (exec_file); + errno = errno_save; + SCM_SYSERROR; + } + + return scm_from_int (pid); +} +#undef FUNC_NAME + static void restore_sigaction (SCM pair) { @@ -2381,6 +2451,7 @@ static void scm_init_popen (void) { scm_c_define_gsubr ("piped-process", 2, 2, 0, scm_piped_process); + scm_c_define_gsubr ("spawn*", 5, 0, 0, scm_spawn_process); } #endif /* HAVE_START_CHILD */ -- 2.37.2