diff options
author | Andy Wingo <wingo@pobox.com> | 2016-07-11 22:46:55 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-07-25 11:24:55 +0200 |
commit | 10ae9cc60197562c72f3a8311bb64d62778df250 (patch) | |
tree | a9e363a900851ef3ce336b2ac9ebea4da8169371 /libguile/posix.c | |
parent | f632d45c69d00156a63c162371e8a5ef36e1cabf (diff) | |
download | guile-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.c | 188 |
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 */ } /* |