summaryrefslogtreecommitdiff
path: root/libguile/posix.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2016-07-11 22:46:55 +0200
committerAndy Wingo <wingo@pobox.com>2016-07-25 11:24:55 +0200
commit10ae9cc60197562c72f3a8311bb64d62778df250 (patch)
treea9e363a900851ef3ce336b2ac9ebea4da8169371 /libguile/posix.c
parentf632d45c69d00156a63c162371e8a5ef36e1cabf (diff)
downloadguile-10ae9cc60197562c72f3a8311bb64d62778df250.tar.gz
Factor start_child out of open_process
* libguile/posix.c (start_child): Factor out from open_process. Based on initial work by Eli Zaretskii.
Diffstat (limited to 'libguile/posix.c')
-rw-r--r--libguile/posix.c188
1 files changed, 104 insertions, 84 deletions
diff --git a/libguile/posix.c b/libguile/posix.c
index 8aa0f3e60..8b3fabc03 100644
--- a/libguile/posix.c
+++ b/libguile/posix.c
@@ -1236,10 +1236,96 @@ SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
return scm_from_int (pid);
}
#undef FUNC_NAME
+#endif /* HAVE_FORK */
+#ifdef HAVE_FORK
+#define HAVE_START_CHILD 1
/* Since Guile uses threads, we have to be very careful to avoid calling
functions that are not async-signal-safe in the child. That's why
this function is implemented in C. */
+static pid_t
+start_child (const char *exec_file, char **exec_argv,
+ int reading, int c2p[2], int writing, int p2c[2],
+ int in, int out, int err)
+{
+ int pid;
+ 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
+
+ pid = fork ();
+
+ if (pid != 0)
+ /* The parent, with either and error (pid == -1), or the PID of the
+ child. Return directly in either case. */
+ return pid;
+
+ /* The child. */
+ if (reading)
+ close (c2p[0]);
+ if (writing)
+ close (p2c[1]);
+
+ /* Close all file descriptors in ports inherited from the parent
+ except for in, out, and err. Heavy-handed, but robust. */
+ while (max_fd--)
+ if (max_fd != in && max_fd != out && max_fd != err)
+ close (max_fd);
+
+ /* Ignore errors on these open() calls. */
+ if (in == -1)
+ in = open ("/dev/null", O_RDONLY);
+ if (out == -1)
+ out = open ("/dev/null", O_WRONLY);
+ if (err == -1)
+ err = open ("/dev/null", O_WRONLY);
+
+ if (in > 0)
+ {
+ if (out == 0)
+ do out = dup (out); while (errno == EINTR);
+ if (err == 0)
+ do err = dup (err); while (errno == EINTR);
+ do dup2 (in, 0); while (errno == EINTR);
+ close (in);
+ }
+ if (out > 1)
+ {
+ if (err == 1)
+ do err = dup (err); while (errno == EINTR);
+ do dup2 (out, 1); while (errno == EINTR);
+ close (out);
+ }
+ if (err > 2)
+ {
+ do dup2 (err, 2); while (errno == EINTR);
+ close (err);
+ }
+
+ execvp (exec_file, exec_argv);
+
+ /* The exec failed! There is nothing sensible to do. */
+ if (err > 0)
+ {
+ char *msg = strerror (errno);
+ fprintf (fdopen (err, "a"), "In execvp of %s: %s\n",
+ exec_file, msg);
+ }
+
+ _exit (EXIT_FAILURE);
+
+ /* Not reached. */
+ return -1;
+}
+#endif
+
+#ifdef HAVE_START_CHILD
static SCM
scm_open_process (SCM mode, SCM prog, SCM args)
#define FUNC_NAME "open-process"
@@ -1252,7 +1338,7 @@ scm_open_process (SCM mode, SCM prog, SCM args)
int pid;
char *exec_file;
char **exec_argv;
- int max_fd = 1024;
+ SCM read_port = SCM_BOOL_F, write_port = SCM_BOOL_F;
exec_file = scm_to_locale_string (prog);
exec_argv = scm_i_allocate_string_pointers (scm_cons (prog, args));
@@ -1301,15 +1387,8 @@ scm_open_process (SCM mode, SCM prog, SCM args)
in = SCM_FPORT_FDES (port);
}
-#if defined (HAVE_GETRLIMIT) && defined (RLIMIT_NOFILE)
- {
- struct rlimit lim = { 0, 0 };
- if (getrlimit (RLIMIT_NOFILE, &lim) == 0)
- max_fd = lim.rlim_cur;
- }
-#endif
-
- pid = fork ();
+ pid = start_child (exec_file, exec_argv, reading, c2p, writing, p2c,
+ in, out, err);
if (pid == -1)
{
@@ -1329,85 +1408,24 @@ scm_open_process (SCM mode, SCM prog, SCM args)
SCM_SYSERROR;
}
- if (pid)
- /* Parent. */
- {
- SCM read_port = SCM_BOOL_F, write_port = SCM_BOOL_F;
-
- /* There is no sense in catching errors on close(). */
- if (reading)
- {
- close (c2p[1]);
- read_port = scm_fdes_to_port (c2p[0], "r0", sym_read_pipe);
- }
- if (writing)
- {
- close (p2c[0]);
- write_port = scm_fdes_to_port (p2c[1], "w0", sym_write_pipe);
- }
-
- return scm_values
- (scm_list_3 (read_port, write_port, scm_from_int (pid)));
- }
-
- /* The child. */
+ /* There is no sense in catching errors on close(). */
if (reading)
- close (c2p[0]);
- if (writing)
- close (p2c[1]);
-
- /* Close all file descriptors in ports inherited from the parent
- except for in, out, and err. Heavy-handed, but robust. */
- while (max_fd--)
- if (max_fd != in && max_fd != out && max_fd != err)
- close (max_fd);
-
- /* Ignore errors on these open() calls. */
- if (in == -1)
- in = open ("/dev/null", O_RDONLY);
- if (out == -1)
- out = open ("/dev/null", O_WRONLY);
- if (err == -1)
- err = open ("/dev/null", O_WRONLY);
-
- if (in > 0)
{
- if (out == 0)
- do out = dup (out); while (errno == EINTR);
- if (err == 0)
- do err = dup (err); while (errno == EINTR);
- do dup2 (in, 0); while (errno == EINTR);
- close (in);
+ close (c2p[1]);
+ read_port = scm_fdes_to_port (c2p[0], "r0", sym_read_pipe);
}
- if (out > 1)
- {
- if (err == 1)
- do err = dup (err); while (errno == EINTR);
- do dup2 (out, 1); while (errno == EINTR);
- close (out);
- }
- if (err > 2)
- {
- do dup2 (err, 2); while (errno == EINTR);
- close (err);
- }
-
- execvp (exec_file, exec_argv);
-
- /* The exec failed! There is nothing sensible to do. */
- if (err > 0)
+ if (writing)
{
- char *msg = strerror (errno);
- fprintf (fdopen (err, "a"), "In execlp of %s: %s\n",
- exec_file, msg);
+ close (p2c[0]);
+ write_port = scm_fdes_to_port (p2c[1], "w0", sym_write_pipe);
}
- _exit (EXIT_FAILURE);
- /* Not reached. */
- return SCM_BOOL_F;
+ return scm_values (scm_list_3 (read_port,
+ write_port,
+ scm_from_int (pid)));
}
#undef FUNC_NAME
-#endif /* HAVE_FORK */
+#endif /* HAVE_START_CHILD */
#ifdef __MINGW32__
# include "win32-uname.h"
@@ -2215,13 +2233,13 @@ SCM_DEFINE (scm_gethostname, "gethostname", 0, 0, 0,
#endif /* HAVE_GETHOSTNAME */
-#ifdef HAVE_FORK
+#ifdef HAVE_START_CHILD
static void
scm_init_popen (void)
{
scm_c_define_gsubr ("open-process", 2, 0, 1, scm_open_process);
}
-#endif
+#endif /* HAVE_START_CHILD */
void
scm_init_posix ()
@@ -2320,11 +2338,13 @@ scm_init_posix ()
#ifdef HAVE_FORK
scm_add_feature ("fork");
+#endif /* HAVE_FORK */
+#ifdef HAVE_START_CHILD
scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
"scm_init_popen",
(scm_t_extension_init_func) scm_init_popen,
NULL);
-#endif /* HAVE_FORK */
+#endif /* HAVE_START_CHILD */
}
/*