* libguile/posix.c: Include spawn.h from Gnulib. (do_spawn, scm_spawn_process): New functions. --- libguile/posix.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ libguile/posix.h | 2 ++ 2 files changed, 83 insertions(+)
diff --git a/libguile/posix.c b/libguile/posix.c index b5352c2c4..e92625483 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -33,6 +33,7 @@ #include <sys/types.h> #include <uniconv.h> #include <unistd.h> +#include <spawn.h> #ifdef HAVE_SCHED_H # include <sched.h> @@ -1426,6 +1427,86 @@ start_child (const char *exec_file, char **exec_argv, } #endif +static int +do_spawn (char *exec_file, char **exec_argv, char **exec_env, int in, int out, int err) +{ + int pid = -1; + + posix_spawn_file_actions_t actions; + posix_spawnattr_t *attrp = NULL; + + 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) + return -1; + + return pid; +} + +SCM_DEFINE (scm_spawn_process, "spawn*", 5, 0, 0, + (SCM prog, SCM args, SCM in, SCM out, SCM err), +"Spawns a new child process executing @var{prog} with arguments\n" +"@var{args}, with its standard input, output and error file descriptors\n" +"set to @var{in}, @var{out}, @var{err}.") +#define FUNC_NAME s_scm_spawn_process +{ + int pid; + char *exec_file; + char **exec_argv; + char **exec_env = environ; + + exec_file = scm_to_locale_string (prog); + exec_argv = scm_i_allocate_string_pointers (args); + + pid = do_spawn (exec_file, exec_argv, exec_env, + scm_to_int (in), + scm_to_int (out), + scm_to_int (err)); + + free (exec_file); + + if (pid == -1) + SCM_SYSERROR; + + return scm_from_int (pid); +} +#undef FUNC_NAME + #ifdef HAVE_START_CHILD static SCM scm_piped_process (SCM prog, SCM args, SCM from, SCM to) diff --git a/libguile/posix.h b/libguile/posix.h index 6504eaea8..c2703f9ab 100644 --- a/libguile/posix.h +++ b/libguile/posix.h @@ -69,6 +69,8 @@ SCM_API SCM scm_tmpnam (void); SCM_API SCM scm_tmpfile (void); SCM_API SCM scm_open_pipe (SCM pipestr, SCM modes); SCM_API SCM scm_close_pipe (SCM port); +SCM_API SCM scm_spawn_process (SCM prog, SCM args, + SCM in, SCM out, SCM err); SCM_API SCM scm_system_star (SCM cmds); SCM_API SCM scm_utime (SCM object, SCM actime, SCM modtime, SCM actimens, SCM modtimens, SCM flags); -- 2.38.1