diff options
-rw-r--r-- | src/postfork.cpp | 474 | ||||
-rw-r--r-- | src/postfork.h | 74 |
2 files changed, 222 insertions, 326 deletions
diff --git a/src/postfork.cpp b/src/postfork.cpp index f2851eb0..cb0760b4 100644 --- a/src/postfork.cpp +++ b/src/postfork.cpp @@ -1,10 +1,6 @@ -/** \file postfork.cpp - - Functions that we may safely call after fork(). -*/ - -#include <fcntl.h> +// Functions that we may safely call after fork(). #include <errno.h> +#include <fcntl.h> #include <signal.h> #include <stdio.h> #include <string.h> @@ -15,67 +11,61 @@ #endif #include "common.h" -#include "proc.h" -#include "wutil.h" // IWYU pragma: keep -#include "signal.h" -#include "postfork.h" -#include "iothread.h" #include "exec.h" #include "io.h" +#include "iothread.h" +#include "postfork.h" +#include "proc.h" +#include "signal.h" +#include "wutil.h" // IWYU pragma: keep #ifndef JOIN_THREADS_BEFORE_FORK #define JOIN_THREADS_BEFORE_FORK 0 #endif -/** The number of times to try to call fork() before giving up */ +/// The number of times to try to call fork() before giving up. #define FORK_LAPS 5 -/** The number of nanoseconds to sleep between attempts to call fork() */ +/// The number of nanoseconds to sleep between attempts to call fork(). #define FORK_SLEEP_TIME 1000000 -/** Base open mode to pass to calls to open */ +/// Base open mode to pass to calls to open. #define OPEN_MASK 0666 -/** fork error message */ +/// Fork error message. #define FORK_ERROR "Could not create child process - exiting" -/** file redirection clobbering error message */ +/// File redirection clobbering error message. #define NOCLOB_ERROR "The file '%s' already exists" -/** file redirection error message */ +/// File redirection error message. #define FILE_ERROR "An error occurred while redirecting file '%s'" -/** file descriptor redirection error message */ -#define FD_ERROR "An error occurred while redirecting file descriptor %s" +/// File descriptor redirection error message. +#define FD_ERROR "An error occurred while redirecting file descriptor %s" -/** pipe error */ +/// Pipe error message. #define LOCAL_PIPE_ERROR "An error occurred while setting up pipe" static bool log_redirections = false; -/* Cover for debug_safe that can take an int. The format string should expect a %s */ -static void debug_safe_int(int level, const char *format, int val) -{ +/// Cover for debug_safe that can take an int. The format string should expect a %s. +static void debug_safe_int(int level, const char *format, int val) { char buff[128]; format_long_safe(buff, val); debug_safe(level, format, buff); } -int set_child_group(job_t *j, process_t *p, int print_errors) -{ +int set_child_group(job_t *j, process_t *p, int print_errors) { int res = 0; - if (job_get_flag(j, JOB_CONTROL)) - { - if (!j->pgid) - { + if (job_get_flag(j, JOB_CONTROL)) { + if (!j->pgid) { j->pgid = p->pid; } - if (setpgid(p->pid, j->pgid)) - { - if (getpgid(p->pid) != j->pgid && print_errors) - { + if (setpgid(p->pid, j->pgid)) { + if (getpgid(p->pid) != j->pgid && print_errors) { char pid_buff[128]; char job_id_buff[128]; char getpgid_buff[128]; @@ -90,29 +80,20 @@ int set_child_group(job_t *j, process_t *p, int print_errors) narrow_string_safe(argv0, p->argv0()); narrow_string_safe(command, j->command_wcstr()); - debug_safe(1, - "Could not send process %s, '%s' in job %s, '%s' from group %s to group %s", - pid_buff, - argv0, - job_id_buff, - command, - getpgid_buff, - job_pgid_buff); + debug_safe( + 1, "Could not send process %s, '%s' in job %s, '%s' from group %s to group %s", + pid_buff, argv0, job_id_buff, command, getpgid_buff, job_pgid_buff); safe_perror("setpgid"); res = -1; } } - } - else - { + } else { j->pgid = getpid(); } - if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND)) - { - if (tcsetpgrp(0, j->pgid) && print_errors) - { + if (job_get_flag(j, JOB_TERMINAL) && job_get_flag(j, JOB_FOREGROUND)) { + if (tcsetpgrp(0, j->pgid) && print_errors) { char job_id_buff[64]; char command_buff[64]; format_long_safe(job_id_buff, j->job_id); @@ -126,73 +107,51 @@ int set_child_group(job_t *j, process_t *p, int print_errors) return res; } -/** - Set up a childs io redirections. Should only be called by - setup_child_process(). Does the following: First it closes any open - file descriptors not related to the child by calling - close_unused_internal_pipes() and closing the universal variable - server file descriptor. It then goes on to perform all the - redirections described by \c io. - - \param io the list of IO redirections for the child - - \return 0 on sucess, -1 on failiure -*/ -static int handle_child_io(const io_chain_t &io_chain) -{ - for (size_t idx = 0; idx < io_chain.size(); idx++) - { +/// Set up a childs io redirections. Should only be called by setup_child_process(). Does the +/// following: First it closes any open file descriptors not related to the child by calling +/// close_unused_internal_pipes() and closing the universal variable server file descriptor. It then +/// goes on to perform all the redirections described by \c io. +/// +/// \param io the list of IO redirections for the child +/// +/// \return 0 on sucess, -1 on failure +static int handle_child_io(const io_chain_t &io_chain) { + for (size_t idx = 0; idx < io_chain.size(); idx++) { const io_data_t *io = io_chain.at(idx).get(); - if (io->io_mode == IO_FD && io->fd == static_cast<const io_fd_t*>(io)->old_fd) - { + if (io->io_mode == IO_FD && io->fd == static_cast<const io_fd_t *>(io)->old_fd) { continue; } - switch (io->io_mode) - { - case IO_CLOSE: - { + switch (io->io_mode) { + case IO_CLOSE: { if (log_redirections) fprintf(stderr, "%d: close %d\n", getpid(), io->fd); - if (close(io->fd)) - { + if (close(io->fd)) { debug_safe_int(0, "Failed to close file descriptor %s", io->fd); safe_perror("close"); } break; } - case IO_FILE: - { - // Here we definitely do not want to set CLO_EXEC because our child needs access + case IO_FILE: { + // Here we definitely do not want to set CLO_EXEC because our child needs access. CAST_INIT(const io_file_t *, io_file, io); int tmp = open(io_file->filename_cstr, io_file->flags, OPEN_MASK); - if (tmp < 0) - { - if ((io_file->flags & O_EXCL) && - (errno ==EEXIST)) - { + if (tmp < 0) { + if ((io_file->flags & O_EXCL) && (errno == EEXIST)) { debug_safe(1, NOCLOB_ERROR, io_file->filename_cstr); - } - else - { + } else { debug_safe(1, FILE_ERROR, io_file->filename_cstr); safe_perror("open"); } return -1; - } - else if (tmp != io->fd) - { - /* - This call will sometimes fail, but that is ok, - this is just a precausion. - */ + } else if (tmp != io->fd) { + // This call will sometimes fail, but that is ok, this is just a precausion. close(io->fd); - if (dup2(tmp, io->fd) == -1) - { - debug_safe_int(1, FD_ERROR, io->fd); + if (dup2(tmp, io->fd) == -1) { + debug_safe_int(1, FD_ERROR, io->fd); safe_perror("dup2"); exec_close(tmp); return -1; @@ -202,20 +161,15 @@ static int handle_child_io(const io_chain_t &io_chain) break; } - case IO_FD: - { + case IO_FD: { int old_fd = static_cast<const io_fd_t *>(io)->old_fd; - if (log_redirections) fprintf(stderr, "%d: fd dup %d to %d\n", getpid(), old_fd, io->fd); + if (log_redirections) + fprintf(stderr, "%d: fd dup %d to %d\n", getpid(), old_fd, io->fd); - /* - This call will sometimes fail, but that is ok, - this is just a precausion. - */ + // This call will sometimes fail, but that is ok, this is just a precausion. close(io->fd); - - if (dup2(old_fd, io->fd) == -1) - { + if (dup2(old_fd, io->fd) == -1) { debug_safe_int(1, FD_ERROR, io->fd); safe_perror("dup2"); return -1; @@ -224,88 +178,72 @@ static int handle_child_io(const io_chain_t &io_chain) } case IO_BUFFER: - case IO_PIPE: - { + case IO_PIPE: { CAST_INIT(const io_pipe_t *, io_pipe, io); - /* If write_pipe_idx is 0, it means we're connecting to the read end (first pipe fd). If it's 1, we're connecting to the write end (second pipe fd). */ + // If write_pipe_idx is 0, it means we're connecting to the read end (first pipe + // fd). If it's 1, we're connecting to the write end (second pipe fd). unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1); - /* - debug( 0, - L"%ls %ls on fd %d (%d %d)", - write_pipe?L"write":L"read", - (io->io_mode == IO_BUFFER)?L"buffer":L"pipe", - io->fd, - io->pipe_fd[0], - io->pipe_fd[1]); - */ - if (log_redirections) fprintf(stderr, "%d: %s dup %d to %d\n", getpid(), io->io_mode == IO_BUFFER ? "buffer" : "pipe", io_pipe->pipe_fd[write_pipe_idx], io->fd); - if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd) - { +#if 0 + debug( 0, L"%ls %ls on fd %d (%d %d)", write_pipe?L"write":L"read", + (io->io_mode == IO_BUFFER)?L"buffer":L"pipe", io->fd, io->pipe_fd[0], + io->pipe_fd[1]); +#endif + if (log_redirections) + fprintf(stderr, "%d: %s dup %d to %d\n", getpid(), + io->io_mode == IO_BUFFER ? "buffer" : "pipe", + io_pipe->pipe_fd[write_pipe_idx], io->fd); + if (dup2(io_pipe->pipe_fd[write_pipe_idx], io->fd) != io->fd) { debug_safe(1, LOCAL_PIPE_ERROR); safe_perror("dup2"); return -1; } - if (io_pipe->pipe_fd[0] >= 0) - exec_close(io_pipe->pipe_fd[0]); - if (io_pipe->pipe_fd[1] >= 0) - exec_close(io_pipe->pipe_fd[1]); + if (io_pipe->pipe_fd[0] >= 0) exec_close(io_pipe->pipe_fd[0]); + if (io_pipe->pipe_fd[1] >= 0) exec_close(io_pipe->pipe_fd[1]); break; } - } } return 0; - } +int setup_child_process(job_t *j, process_t *p, const io_chain_t &io_chain) { + bool ok = true; -int setup_child_process(job_t *j, process_t *p, const io_chain_t &io_chain) -{ - bool ok=true; - - if (p) - { + if (p) { ok = (0 == set_child_group(j, p, 1)); } - if (ok) - { + if (ok) { ok = (0 == handle_child_io(io_chain)); - if (p != 0 && ! ok) - { + if (p != 0 && !ok) { exit_without_destructors(1); } } - /* Set the handling for job control signals back to the default. */ - if (ok) - { + if (ok) { + // Set the handling for job control signals back to the default. signal_reset_handlers(); } - /* Remove all signal blocks */ - signal_unblock(); + signal_unblock(); // remove all signal blocks return ok ? 0 : -1; } int g_fork_count = 0; -/** - This function is a wrapper around fork. If the fork calls fails - with EAGAIN, it is retried FORK_LAPS times, with a very slight - delay between each lap. If fork fails even then, the process will - exit with an error message. -*/ -pid_t execute_fork(bool wait_for_threads_to_die) -{ +/// This function is a wrapper around fork. If the fork calls fails with EAGAIN, it is retried +/// FORK_LAPS times, with a very slight delay between each lap. If fork fails even then, the process +/// will exit with an error message. +pid_t execute_fork(bool wait_for_threads_to_die) { ASSERT_IS_MAIN_THREAD(); - if (wait_for_threads_to_die || JOIN_THREADS_BEFORE_FORK) - { - /* Make sure we have no outstanding threads before we fork. This is a pretty sketchy thing to do here, both because exec.cpp shouldn't have to know about iothreads, and because the completion handlers may do unexpected things. */ + if (wait_for_threads_to_die || JOIN_THREADS_BEFORE_FORK) { + // Make sure we have no outstanding threads before we fork. This is a pretty sketchy thing + // to do here, both because exec.cpp shouldn't have to know about iothreads, and because the + // completion handlers may do unexpected things. iothread_drain_all(); } @@ -315,28 +253,22 @@ pid_t execute_fork(bool wait_for_threads_to_die) g_fork_count++; - for (i=0; i<FORK_LAPS; i++) - { + for (i = 0; i < FORK_LAPS; i++) { pid = fork(); - if (pid >= 0) - { + if (pid >= 0) { return pid; } - if (errno != EAGAIN) - { + if (errno != EAGAIN) { break; } pollint.tv_sec = 0; pollint.tv_nsec = FORK_SLEEP_TIME; - /* - Don't sleep on the final lap - sleeping might change the - value of errno, which will break the error reporting below. - */ - if (i != FORK_LAPS-1) - { + // Don't sleep on the final lap - sleeping might change the value of errno, which will break + // the error reporting below. + if (i != FORK_LAPS - 1) { nanosleep(&pollint, NULL); } } @@ -348,238 +280,210 @@ pid_t execute_fork(bool wait_for_threads_to_die) } #if FISH_USE_POSIX_SPAWN -bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain) -{ - /* Initialize the output */ - if (posix_spawnattr_init(attr) != 0) - { +bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, + posix_spawn_file_actions_t *actions, job_t *j, process_t *p, + const io_chain_t &io_chain) { + // Initialize the output. + if (posix_spawnattr_init(attr) != 0) { return false; } - if (posix_spawn_file_actions_init(actions) != 0) - { + if (posix_spawn_file_actions_init(actions) != 0) { posix_spawnattr_destroy(attr); return false; } bool should_set_parent_group_id = false; int desired_parent_group_id = 0; - if (job_get_flag(j, JOB_CONTROL)) - { + if (job_get_flag(j, JOB_CONTROL)) { should_set_parent_group_id = true; - // PCA: I'm quite fuzzy on process groups, - // but I believe that the default value of 0 - // means that the process becomes its own - // group leader, which is what set_child_group did - // in this case. So we want this to be 0 if j->pgid is 0. + // PCA: I'm quite fuzzy on process groups, but I believe that the default value of 0 means + // that the process becomes its own group leader, which is what set_child_group did in this + // case. So we want this to be 0 if j->pgid is 0. desired_parent_group_id = j->pgid; } - /* Set the handling for job control signals back to the default. */ + // Set the handling for job control signals back to the default. bool reset_signal_handlers = true; - /* Remove all signal blocks */ + // Remove all signal blocks. bool reset_sigmask = true; - /* Set our flags */ + // Set our flags. short flags = 0; - if (reset_signal_handlers) - flags |= POSIX_SPAWN_SETSIGDEF; - if (reset_sigmask) - flags |= POSIX_SPAWN_SETSIGMASK; - if (should_set_parent_group_id) - flags |= POSIX_SPAWN_SETPGROUP; + if (reset_signal_handlers) flags |= POSIX_SPAWN_SETSIGDEF; + if (reset_sigmask) flags |= POSIX_SPAWN_SETSIGMASK; + if (should_set_parent_group_id) flags |= POSIX_SPAWN_SETPGROUP; int err = 0; - if (! err) - err = posix_spawnattr_setflags(attr, flags); + if (!err) err = posix_spawnattr_setflags(attr, flags); - if (! err && should_set_parent_group_id) + if (!err && should_set_parent_group_id) err = posix_spawnattr_setpgroup(attr, desired_parent_group_id); - /* Everybody gets default handlers */ - if (! err && reset_signal_handlers) - { + // Everybody gets default handlers. + if (!err && reset_signal_handlers) { sigset_t sigdefault; get_signals_with_handlers(&sigdefault); err = posix_spawnattr_setsigdefault(attr, &sigdefault); } - /* No signals blocked */ + // No signals blocked. sigset_t sigmask; sigemptyset(&sigmask); - if (! err && reset_sigmask) - err = posix_spawnattr_setsigmask(attr, &sigmask); - - for (size_t idx = 0; idx < io_chain.size(); idx++) - { + if (!err && reset_sigmask) err = posix_spawnattr_setsigmask(attr, &sigmask); + + for (size_t idx = 0; idx < io_chain.size(); idx++) { const shared_ptr<const io_data_t> io = io_chain.at(idx); - if (io->io_mode == IO_FD) - { + if (io->io_mode == IO_FD) { CAST_INIT(const io_fd_t *, io_fd, io.get()); - if (io->fd == io_fd->old_fd) - continue; + if (io->fd == io_fd->old_fd) continue; } - switch (io->io_mode) - { - case IO_CLOSE: - { - if (! err) - err = posix_spawn_file_actions_addclose(actions, io->fd); + switch (io->io_mode) { + case IO_CLOSE: { + if (!err) err = posix_spawn_file_actions_addclose(actions, io->fd); break; } - case IO_FILE: - { + case IO_FILE: { CAST_INIT(const io_file_t *, io_file, io.get()); - if (! err) - err = posix_spawn_file_actions_addopen(actions, io->fd, io_file->filename_cstr, io_file->flags /* mode */, OPEN_MASK); + if (!err) + err = posix_spawn_file_actions_addopen(actions, io->fd, io_file->filename_cstr, + io_file->flags /* mode */, OPEN_MASK); break; } - case IO_FD: - { + case IO_FD: { CAST_INIT(const io_fd_t *, io_fd, io.get()); - if (! err) - err = posix_spawn_file_actions_adddup2(actions, io_fd->old_fd /* from */, io->fd /* to */); + if (!err) + err = posix_spawn_file_actions_adddup2(actions, io_fd->old_fd /* from */, + io->fd /* to */); break; } case IO_BUFFER: - case IO_PIPE: - { + case IO_PIPE: { CAST_INIT(const io_pipe_t *, io_pipe, io.get()); unsigned int write_pipe_idx = (io_pipe->is_input ? 0 : 1); int from_fd = io_pipe->pipe_fd[write_pipe_idx]; int to_fd = io->fd; - if (! err) - err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd); - - - if (write_pipe_idx > 0) - { - if (! err) - err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); - if (! err) - err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[1]); - } - else - { - if (! err) - err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); + if (!err) err = posix_spawn_file_actions_adddup2(actions, from_fd, to_fd); + if (write_pipe_idx > 0) { + if (!err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); + if (!err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[1]); + } else { + if (!err) err = posix_spawn_file_actions_addclose(actions, io_pipe->pipe_fd[0]); } break; } } } - /* Clean up on error */ - if (err) - { + // Clean up on error. + if (err) { posix_spawnattr_destroy(attr); posix_spawn_file_actions_destroy(actions); } - return ! err; + return !err; } -#endif //FISH_USE_POSIX_SPAWN +#endif // FISH_USE_POSIX_SPAWN -void safe_report_exec_error(int err, const char *actual_cmd, const char * const *argv, const char *const *envv) -{ +void safe_report_exec_error(int err, const char *actual_cmd, const char *const *argv, + const char *const *envv) { debug_safe(0, "Failed to execute process '%s'. Reason:", actual_cmd); - switch (err) - { - - case E2BIG: - { + switch (err) { + case E2BIG: { char sz1[128], sz2[128]; long arg_max = -1; size_t sz = 0; - const char * const *p; - for (p=argv; *p; p++) - { - sz += strlen(*p)+1; + const char *const *p; + for (p = argv; *p; p++) { + sz += strlen(*p) + 1; } - for (p=envv; *p; p++) - { - sz += strlen(*p)+1; + for (p = envv; *p; p++) { + sz += strlen(*p) + 1; } format_size_safe(sz1, sz); arg_max = sysconf(_SC_ARG_MAX); - if (arg_max > 0) - { + if (arg_max > 0) { format_size_safe(sz2, static_cast<unsigned long long>(arg_max)); - debug_safe(0, "The total size of the argument and environment lists %s exceeds the operating system limit of %s.", sz1, sz2); - } - else - { - debug_safe(0, "The total size of the argument and environment lists (%s) exceeds the operating system limit.", sz1); + debug_safe(0, + "The total size of the argument and environment lists %s exceeds the " + "operating system limit of %s.", + sz1, sz2); + } else { + debug_safe(0, + "The total size of the argument and environment lists (%s) exceeds the " + "operating system limit.", + sz1); } debug_safe(0, "Try running the command again with fewer arguments."); break; } - case ENOEXEC: - { + case ENOEXEC: { const char *err = safe_strerror(errno); debug_safe(0, "exec: %s", err); - debug_safe(0, "The file '%s' is marked as an executable but could not be run by the operating system.", actual_cmd); + debug_safe(0, + "The file '%s' is marked as an executable but could not be run by the " + "operating system.", + actual_cmd); break; } - case ENOENT: - { - /* ENOENT is returned by exec() when the path fails, but also returned by posix_spawn if an open file action fails. These cases appear to be impossible to distinguish. We address this by not using posix_spawn for file redirections, so all the ENOENTs we find must be errors from exec(). */ + case ENOENT: { + // ENOENT is returned by exec() when the path fails, but also returned by posix_spawn if + // an open file action fails. These cases appear to be impossible to distinguish. We + // address this by not using posix_spawn for file redirections, so all the ENOENTs we + // find must be errors from exec(). char interpreter_buff[128] = {}, *interpreter; interpreter = get_interpreter(actual_cmd, interpreter_buff, sizeof interpreter_buff); - if (interpreter && 0 != access(interpreter, X_OK)) - { - debug_safe(0, "The file '%s' specified the interpreter '%s', which is not an executable command.", actual_cmd, interpreter); - } - else - { + if (interpreter && 0 != access(interpreter, X_OK)) { + debug_safe(0, + "The file '%s' specified the interpreter '%s', which is not an " + "executable command.", + actual_cmd, interpreter); + } else { debug_safe(0, "The file '%s' does not exist or could not be executed.", actual_cmd); } break; } - case ENOMEM: - { + case ENOMEM: { debug_safe(0, "Out of memory"); break; } - default: - { + default: { const char *err = safe_strerror(errno); debug_safe(0, "exec: %s", err); - // debug(0, L"The file '%ls' is marked as an executable but could not be run by the operating system.", p->actual_cmd); + // debug(0, L"The file '%ls' is marked as an executable but could not be run by the + // operating system.", p->actual_cmd); break; } } } -/** Perform output from builtins. May be called from a forked child, so don't do anything that may allocate memory, etc.. */ -bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errlen) -{ +/// Perform output from builtins. May be called from a forked child, so don't do anything that may +/// allocate memory, etc. +bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errlen) { bool success = true; - if (out && outlen) - { - if (write_loop(STDOUT_FILENO, out, outlen) < 0) - { + if (out && outlen) { + if (write_loop(STDOUT_FILENO, out, outlen) < 0) { int e = errno; debug_safe(0, "Error while writing to stdout"); safe_perror("write_loop"); @@ -588,10 +492,8 @@ bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errle } } - if (err && errlen) - { - if (write_loop(STDERR_FILENO, err, errlen) < 0) - { + if (err && errlen) { + if (write_loop(STDERR_FILENO, err, errlen) < 0) { success = false; } } diff --git a/src/postfork.h b/src/postfork.h index b2ef18ca..ed441de3 100644 --- a/src/postfork.h +++ b/src/postfork.h @@ -1,7 +1,5 @@ -/** \file postfork.h - - Functions that we may safely call after fork(), of which there are very few. In particular we cannot allocate memory, since we're insane enough to call fork from a multithreaded process. -*/ +// Functions that we may safely call after fork(), of which there are very few. In particular we +// cannot allocate memory, since we're insane enough to call fork from a multithreaded process. #ifndef FISH_POSTFORK_H #define FISH_POSTFORK_H @@ -20,52 +18,48 @@ class io_chain_t; class job_t; class process_t; -/** - This function should be called by both the parent process and the - child right after fork() has been called. If job control is - enabled, the child is put in the jobs group, and if the child is - also in the foreground, it is also given control of the - terminal. When called in the parent process, this function may - fail, since the child might have already finished and called - exit. The parent process may safely ignore the exit status of this - call. - - Returns 0 on sucess, -1 on failiure. -*/ +/// This function should be called by both the parent process and the child right after fork() has +/// been called. If job control is enabled, the child is put in the jobs group, and if the child is +/// also in the foreground, it is also given control of the terminal. When called in the parent +/// process, this function may fail, since the child might have already finished and called exit. +/// The parent process may safely ignore the exit status of this call. +/// +/// Returns 0 on sucess, -1 on failiure. int set_child_group(job_t *j, process_t *p, int print_errors); -/** - Initialize a new child process. This should be called right away - after forking in the child process. If job control is enabled for - this job, the process is put in the process group of the job, all - signal handlers are reset, signals are unblocked (this function may - only be called inside the exec function, which blocks all signals), - and all IO redirections and other file descriptor actions are - performed. - - \param j the job to set up the IO for - \param p the child process to set up - \param io_chain the IO chain to use - - \return 0 on sucess, -1 on failiure. When this function returns, - signals are always unblocked. On failiure, signal handlers, io - redirections and process group of the process is undefined. -*/ +/// Initialize a new child process. This should be called right away after forking in the child +/// process. If job control is enabled for this job, the process is put in the process group of the +/// job, all signal handlers are reset, signals are unblocked (this function may only be called +/// inside the exec function, which blocks all signals), and all IO redirections and other file +/// descriptor actions are performed. +/// +/// \param j the job to set up the IO for +/// \param p the child process to set up +/// \param io_chain the IO chain to use +/// +/// \return 0 on sucess, -1 on failiure. When this function returns, signals are always unblocked. +/// On failiure, signal handlers, io redirections and process group of the process is undefined. int setup_child_process(job_t *j, process_t *p, const io_chain_t &io_chain); -/* Call fork(), optionally waiting until we are no longer multithreaded. If the forked child doesn't do anything that could allocate memory, take a lock, etc. (like call exec), then it's not necessary to wait for threads to die. If the forked child may do those things, it should wait for threads to die. -*/ +/// Call fork(), optionally waiting until we are no longer multithreaded. If the forked child +/// doesn't do anything that could allocate memory, take a lock, etc. (like call exec), then it's +/// not necessary to wait for threads to die. If the forked child may do those things, it should +/// wait for threads to die. pid_t execute_fork(bool wait_for_threads_to_die); -/* Perform output from builtins. Returns true on success. */ +/// Perform output from builtins. Returns true on success. bool do_builtin_io(const char *out, size_t outlen, const char *err, size_t errlen); -/** Report an error from failing to exec or posix_spawn a command */ -void safe_report_exec_error(int err, const char *actual_cmd, const char * const *argv, const char * const *envv); +/// Report an error from failing to exec or posix_spawn a command. +void safe_report_exec_error(int err, const char *actual_cmd, const char *const *argv, + const char *const *envv); #if FISH_USE_POSIX_SPAWN -/* Initializes and fills in a posix_spawnattr_t; on success, the caller should destroy it via posix_spawnattr_destroy */ -bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, posix_spawn_file_actions_t *actions, job_t *j, process_t *p, const io_chain_t &io_chain); +/// Initializes and fills in a posix_spawnattr_t; on success, the caller should destroy it via +/// posix_spawnattr_destroy. +bool fork_actions_make_spawn_properties(posix_spawnattr_t *attr, + posix_spawn_file_actions_t *actions, job_t *j, process_t *p, + const io_chain_t &io_chain); #endif #endif |