civodul pushed a commit to branch wip-posix-spawn in repository guile. commit ab5afab476f12d1b8a539916a46467d4e8c237ae Author: Josselin Poiret <d...@jpoiret.xyz> AuthorDate: Mon Sep 5 08:48:14 2022 +0200
Add spawn*. * libguile/posix.c: Include spawn.h from Gnulib. (scm_spawn_process): New function. (scm_init_popen): Define spawn*. Signed-off-by: Ludovic Courtès <l...@gnu.org> --- libguile/posix.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/libguile/posix.c b/libguile/posix.c index b5352c2c4..dea5ca382 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> @@ -1500,6 +1501,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) { @@ -2421,6 +2491,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 */