bug#52835: [PATCH v5 2/3] Add spawn*.

Josselin Poiret via "Bug reports for GUILE, GNU's Ubiquitous Extension Language" <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <95dbb2e804221fc369203d38c75238a190d3ff6f.1662358976.git.dev@jpoiret.xyz>
* 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.