bug#52835: [PATCH v6 1/3] Add spawn*.

Josselin Poiret via "Bug reports for GUILE, GNU's Ubiquitous Extension Language" <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <93fe711248cf1ebe86a03bb273ae76e86342ddf8.1671710701.git.dev@jpoiret.xyz>
* 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
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.