Home | History | Annotate | Line # | Download | only in process
      1  1.1   jmmv // Copyright 2010 Google Inc.
      2  1.1   jmmv // All rights reserved.
      3  1.1   jmmv //
      4  1.1   jmmv // Redistribution and use in source and binary forms, with or without
      5  1.1   jmmv // modification, are permitted provided that the following conditions are
      6  1.1   jmmv // met:
      7  1.1   jmmv //
      8  1.1   jmmv // * Redistributions of source code must retain the above copyright
      9  1.1   jmmv //   notice, this list of conditions and the following disclaimer.
     10  1.1   jmmv // * Redistributions in binary form must reproduce the above copyright
     11  1.1   jmmv //   notice, this list of conditions and the following disclaimer in the
     12  1.1   jmmv //   documentation and/or other materials provided with the distribution.
     13  1.1   jmmv // * Neither the name of Google Inc. nor the names of its contributors
     14  1.1   jmmv //   may be used to endorse or promote products derived from this software
     15  1.1   jmmv //   without specific prior written permission.
     16  1.1   jmmv //
     17  1.1   jmmv // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18  1.1   jmmv // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19  1.1   jmmv // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20  1.1   jmmv // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21  1.1   jmmv // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22  1.1   jmmv // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23  1.1   jmmv // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  1.1   jmmv // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  1.1   jmmv // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  1.1   jmmv // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27  1.1   jmmv // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  1.1   jmmv 
     29  1.1   jmmv #include "utils/process/child.ipp"
     30  1.1   jmmv 
     31  1.1   jmmv extern "C" {
     32  1.1   jmmv #include <sys/stat.h>
     33  1.1   jmmv #include <sys/wait.h>
     34  1.1   jmmv 
     35  1.1   jmmv #include <fcntl.h>
     36  1.1   jmmv #include <signal.h>
     37  1.1   jmmv #include <unistd.h>
     38  1.1   jmmv }
     39  1.1   jmmv 
     40  1.1   jmmv #include <cassert>
     41  1.1   jmmv #include <cerrno>
     42  1.1   jmmv #include <cstdlib>
     43  1.1   jmmv #include <cstring>
     44  1.1   jmmv #include <iostream>
     45  1.1   jmmv #include <memory>
     46  1.1   jmmv 
     47  1.1   jmmv #include "utils/defs.hpp"
     48  1.1   jmmv #include "utils/format/macros.hpp"
     49  1.1   jmmv #include "utils/logging/macros.hpp"
     50  1.1   jmmv #include "utils/process/exceptions.hpp"
     51  1.1   jmmv #include "utils/process/fdstream.hpp"
     52  1.1   jmmv #include "utils/process/system.hpp"
     53  1.1   jmmv #include "utils/process/status.hpp"
     54  1.1   jmmv #include "utils/sanity.hpp"
     55  1.1   jmmv #include "utils/signals/interrupts.hpp"
     56  1.1   jmmv 
     57  1.1   jmmv 
     58  1.1   jmmv namespace utils {
     59  1.1   jmmv namespace process {
     60  1.1   jmmv 
     61  1.1   jmmv 
     62  1.1   jmmv /// Private implementation fields for child objects.
     63  1.1   jmmv struct child::impl {
     64  1.1   jmmv     /// The process identifier.
     65  1.1   jmmv     pid_t _pid;
     66  1.1   jmmv 
     67  1.1   jmmv     /// The input stream for the process' stdout and stderr.  May be NULL.
     68  1.2  lukem     std::unique_ptr< process::ifdstream > _output;
     69  1.1   jmmv 
     70  1.1   jmmv     /// Initializes private implementation data.
     71  1.1   jmmv     ///
     72  1.1   jmmv     /// \param pid The process identifier.
     73  1.1   jmmv     /// \param output The input stream.  Grabs ownership of the pointer.
     74  1.1   jmmv     impl(const pid_t pid, process::ifdstream* output) :
     75  1.1   jmmv         _pid(pid), _output(output) {}
     76  1.1   jmmv };
     77  1.1   jmmv 
     78  1.1   jmmv 
     79  1.1   jmmv }  // namespace process
     80  1.1   jmmv }  // namespace utils
     81  1.1   jmmv 
     82  1.1   jmmv 
     83  1.1   jmmv namespace fs = utils::fs;
     84  1.1   jmmv namespace process = utils::process;
     85  1.1   jmmv namespace signals = utils::signals;
     86  1.1   jmmv 
     87  1.1   jmmv 
     88  1.1   jmmv namespace {
     89  1.1   jmmv 
     90  1.1   jmmv 
     91  1.1   jmmv /// Exception-based version of dup(2).
     92  1.1   jmmv ///
     93  1.1   jmmv /// \param old_fd The file descriptor to duplicate.
     94  1.1   jmmv /// \param new_fd The file descriptor to use as the duplicate.  This is
     95  1.1   jmmv ///     closed if it was open before the copy happens.
     96  1.1   jmmv ///
     97  1.1   jmmv /// \throw process::system_error If the call to dup2(2) fails.
     98  1.1   jmmv static void
     99  1.1   jmmv safe_dup(const int old_fd, const int new_fd)
    100  1.1   jmmv {
    101  1.1   jmmv     if (process::detail::syscall_dup2(old_fd, new_fd) == -1) {
    102  1.1   jmmv         const int original_errno = errno;
    103  1.1   jmmv         throw process::system_error(F("dup2(%s, %s) failed") % old_fd % new_fd,
    104  1.1   jmmv                                     original_errno);
    105  1.1   jmmv     }
    106  1.1   jmmv }
    107  1.1   jmmv 
    108  1.1   jmmv 
    109  1.1   jmmv /// Exception-based version of open(2) to open (or create) a file for append.
    110  1.1   jmmv ///
    111  1.1   jmmv /// \param filename The file to open in append mode.
    112  1.1   jmmv ///
    113  1.1   jmmv /// \return The file descriptor for the opened or created file.
    114  1.1   jmmv ///
    115  1.1   jmmv /// \throw process::system_error If the call to open(2) fails.
    116  1.1   jmmv static int
    117  1.1   jmmv open_for_append(const fs::path& filename)
    118  1.1   jmmv {
    119  1.1   jmmv     const int fd = process::detail::syscall_open(
    120  1.1   jmmv         filename.c_str(), O_CREAT | O_WRONLY | O_APPEND,
    121  1.1   jmmv         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    122  1.1   jmmv     if (fd == -1) {
    123  1.1   jmmv         const int original_errno = errno;
    124  1.1   jmmv         throw process::system_error(F("Failed to create %s because open(2) "
    125  1.1   jmmv                                       "failed") % filename, original_errno);
    126  1.1   jmmv     }
    127  1.1   jmmv     return fd;
    128  1.1   jmmv }
    129  1.1   jmmv 
    130  1.1   jmmv 
    131  1.1   jmmv /// Exception-based, type-improved version of wait(2).
    132  1.1   jmmv ///
    133  1.1   jmmv /// Because we are waiting for the termination of a process, and because this is
    134  1.1   jmmv /// the canonical way to call wait(2) for this module, we ensure from here that
    135  1.1   jmmv /// any subprocess of the process we are killing is terminated.
    136  1.1   jmmv ///
    137  1.1   jmmv /// \param pid The identifier of the process to wait for.
    138  1.1   jmmv ///
    139  1.1   jmmv /// \return The termination status of the process.
    140  1.1   jmmv ///
    141  1.1   jmmv /// \throw process::system_error If the call to waitpid(2) fails.
    142  1.1   jmmv static process::status
    143  1.1   jmmv safe_wait(const pid_t pid)
    144  1.1   jmmv {
    145  1.1   jmmv     LD(F("Waiting for pid=%s") % pid);
    146  1.1   jmmv     int stat_loc;
    147  1.1   jmmv     if (process::detail::syscall_waitpid(pid, &stat_loc, 0) == -1) {
    148  1.1   jmmv         const int original_errno = errno;
    149  1.1   jmmv         throw process::system_error(F("Failed to wait for PID %s") % pid,
    150  1.1   jmmv                                     original_errno);
    151  1.1   jmmv     }
    152  1.1   jmmv     return process::status(pid, stat_loc);
    153  1.1   jmmv }
    154  1.1   jmmv 
    155  1.1   jmmv 
    156  1.1   jmmv /// Logs the execution of another program.
    157  1.1   jmmv ///
    158  1.1   jmmv /// \param program The binary to execute.
    159  1.1   jmmv /// \param args The arguments to pass to the binary, without the program name.
    160  1.1   jmmv static void
    161  1.1   jmmv log_exec(const fs::path& program, const process::args_vector& args)
    162  1.1   jmmv {
    163  1.1   jmmv     std::string plain_command = program.str();
    164  1.1   jmmv     for (process::args_vector::const_iterator iter = args.begin();
    165  1.1   jmmv          iter != args.end(); ++iter)
    166  1.1   jmmv         plain_command += F(" %s") % *iter;
    167  1.2  lukem     LD(F("Executing %s") % plain_command);
    168  1.1   jmmv }
    169  1.1   jmmv 
    170  1.1   jmmv 
    171  1.1   jmmv /// Maximum number of arguments supported by cxx_exec.
    172  1.1   jmmv ///
    173  1.1   jmmv /// We need this limit to avoid having to allocate dynamic memory in the child
    174  1.1   jmmv /// process to construct the arguments list, which would have side-effects in
    175  1.1   jmmv /// the parent's memory if we use vfork().
    176  1.1   jmmv #define MAX_ARGS 128
    177  1.1   jmmv 
    178  1.1   jmmv 
    179  1.1   jmmv static void cxx_exec(const fs::path& program, const process::args_vector& args)
    180  1.1   jmmv     throw() UTILS_NORETURN;
    181  1.1   jmmv 
    182  1.1   jmmv 
    183  1.1   jmmv /// Executes an external binary and replaces the current process.
    184  1.1   jmmv ///
    185  1.1   jmmv /// This function must not use any of the logging features, so that the output
    186  1.1   jmmv /// of the subprocess is not "polluted" by our own messages.
    187  1.1   jmmv ///
    188  1.1   jmmv /// This function must also not affect the global state of the current process
    189  1.1   jmmv /// as otherwise we would not be able to use vfork().  Only state stored in the
    190  1.1   jmmv /// stack can be touched.
    191  1.1   jmmv ///
    192  1.1   jmmv /// \param program The binary to execute.
    193  1.1   jmmv /// \param args The arguments to pass to the binary, without the program name.
    194  1.1   jmmv static void
    195  1.1   jmmv cxx_exec(const fs::path& program, const process::args_vector& args) throw()
    196  1.1   jmmv {
    197  1.1   jmmv     assert(args.size() < MAX_ARGS);
    198  1.1   jmmv     try {
    199  1.1   jmmv         const char* argv[MAX_ARGS + 1];
    200  1.1   jmmv 
    201  1.1   jmmv         argv[0] = program.c_str();
    202  1.1   jmmv         for (process::args_vector::size_type i = 0; i < args.size(); i++)
    203  1.1   jmmv             argv[1 + i] = args[i].c_str();
    204  1.1   jmmv         argv[1 + args.size()] = NULL;
    205  1.1   jmmv 
    206  1.1   jmmv         const int ret = ::execv(program.c_str(),
    207  1.1   jmmv                                 (char* const*)(unsigned long)(const void*)argv);
    208  1.1   jmmv         const int original_errno = errno;
    209  1.1   jmmv         assert(ret == -1);
    210  1.1   jmmv 
    211  1.1   jmmv         std::cerr << "Failed to execute " << program << ": "
    212  1.1   jmmv                   << std::strerror(original_errno) << "\n";
    213  1.1   jmmv         std::abort();
    214  1.1   jmmv     } catch (const std::runtime_error& error) {
    215  1.1   jmmv         std::cerr << "Failed to execute " << program << ": "
    216  1.1   jmmv                   << error.what() << "\n";
    217  1.1   jmmv         std::abort();
    218  1.1   jmmv     } catch (...) {
    219  1.1   jmmv         std::cerr << "Failed to execute " << program << "; got unexpected "
    220  1.1   jmmv             "exception during exec\n";
    221  1.1   jmmv         std::abort();
    222  1.1   jmmv     }
    223  1.1   jmmv }
    224  1.1   jmmv 
    225  1.1   jmmv 
    226  1.1   jmmv }  // anonymous namespace
    227  1.1   jmmv 
    228  1.1   jmmv 
    229  1.1   jmmv /// Creates a new child.
    230  1.1   jmmv ///
    231  1.1   jmmv /// \param implptr A dynamically-allocated impl object with the contents of the
    232  1.1   jmmv ///     new child.
    233  1.1   jmmv process::child::child(impl *implptr) :
    234  1.1   jmmv     _pimpl(implptr)
    235  1.1   jmmv {
    236  1.1   jmmv }
    237  1.1   jmmv 
    238  1.1   jmmv 
    239  1.1   jmmv /// Destructor for child.
    240  1.1   jmmv process::child::~child(void)
    241  1.1   jmmv {
    242  1.1   jmmv }
    243  1.1   jmmv 
    244  1.1   jmmv 
    245  1.1   jmmv /// Helper function for fork().
    246  1.1   jmmv ///
    247  1.1   jmmv /// Please note: if you update this function to change the return type or to
    248  1.1   jmmv /// raise different errors, do not forget to update fork() accordingly.
    249  1.1   jmmv ///
    250  1.1   jmmv /// \return In the case of the parent, a new child object returned as a
    251  1.1   jmmv /// dynamically-allocated object because children classes are unique and thus
    252  1.1   jmmv /// noncopyable.  In the case of the child, a NULL pointer.
    253  1.1   jmmv ///
    254  1.1   jmmv /// \throw process::system_error If the calls to pipe(2) or fork(2) fail.
    255  1.2  lukem std::unique_ptr< process::child >
    256  1.1   jmmv process::child::fork_capture_aux(void)
    257  1.1   jmmv {
    258  1.1   jmmv     std::cout.flush();
    259  1.1   jmmv     std::cerr.flush();
    260  1.1   jmmv 
    261  1.1   jmmv     int fds[2];
    262  1.1   jmmv     if (detail::syscall_pipe(fds) == -1)
    263  1.1   jmmv         throw process::system_error("pipe(2) failed", errno);
    264  1.1   jmmv 
    265  1.2  lukem     std::unique_ptr< signals::interrupts_inhibiter > inhibiter(
    266  1.1   jmmv         new signals::interrupts_inhibiter);
    267  1.1   jmmv     pid_t pid = detail::syscall_fork();
    268  1.1   jmmv     if (pid == -1) {
    269  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    270  1.1   jmmv         ::close(fds[0]);
    271  1.1   jmmv         ::close(fds[1]);
    272  1.1   jmmv         throw process::system_error("fork(2) failed", errno);
    273  1.1   jmmv     } else if (pid == 0) {
    274  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    275  1.1   jmmv         ::setpgid(::getpid(), ::getpid());
    276  1.1   jmmv 
    277  1.1   jmmv         try {
    278  1.1   jmmv             ::close(fds[0]);
    279  1.1   jmmv             safe_dup(fds[1], STDOUT_FILENO);
    280  1.1   jmmv             safe_dup(fds[1], STDERR_FILENO);
    281  1.1   jmmv             ::close(fds[1]);
    282  1.1   jmmv         } catch (const system_error& e) {
    283  1.1   jmmv             std::cerr << F("Failed to set up subprocess: %s\n") % e.what();
    284  1.1   jmmv             std::abort();
    285  1.1   jmmv         }
    286  1.2  lukem         return std::unique_ptr< process::child >();
    287  1.1   jmmv     } else {
    288  1.1   jmmv         ::close(fds[1]);
    289  1.1   jmmv         LD(F("Spawned process %s: stdout and stderr inherited") % pid);
    290  1.1   jmmv         signals::add_pid_to_kill(pid);
    291  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    292  1.2  lukem         return std::unique_ptr< process::child >(
    293  1.1   jmmv             new process::child(new impl(pid, new process::ifdstream(fds[0]))));
    294  1.1   jmmv     }
    295  1.1   jmmv }
    296  1.1   jmmv 
    297  1.1   jmmv 
    298  1.1   jmmv /// Helper function for fork().
    299  1.1   jmmv ///
    300  1.1   jmmv /// Please note: if you update this function to change the return type or to
    301  1.1   jmmv /// raise different errors, do not forget to update fork() accordingly.
    302  1.1   jmmv ///
    303  1.1   jmmv /// \param stdout_file The name of the file in which to store the stdout.
    304  1.1   jmmv ///     If this has the magic value /dev/stdout, then the parent's stdout is
    305  1.1   jmmv ///     reused without applying any redirection.
    306  1.1   jmmv /// \param stderr_file The name of the file in which to store the stderr.
    307  1.1   jmmv ///     If this has the magic value /dev/stderr, then the parent's stderr is
    308  1.1   jmmv ///     reused without applying any redirection.
    309  1.1   jmmv ///
    310  1.1   jmmv /// \return In the case of the parent, a new child object returned as a
    311  1.1   jmmv /// dynamically-allocated object because children classes are unique and thus
    312  1.1   jmmv /// noncopyable.  In the case of the child, a NULL pointer.
    313  1.1   jmmv ///
    314  1.1   jmmv /// \throw process::system_error If the call to fork(2) fails.
    315  1.2  lukem std::unique_ptr< process::child >
    316  1.1   jmmv process::child::fork_files_aux(const fs::path& stdout_file,
    317  1.1   jmmv                                const fs::path& stderr_file)
    318  1.1   jmmv {
    319  1.1   jmmv     std::cout.flush();
    320  1.1   jmmv     std::cerr.flush();
    321  1.1   jmmv 
    322  1.2  lukem     std::unique_ptr< signals::interrupts_inhibiter > inhibiter(
    323  1.1   jmmv         new signals::interrupts_inhibiter);
    324  1.1   jmmv     pid_t pid = detail::syscall_fork();
    325  1.1   jmmv     if (pid == -1) {
    326  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    327  1.1   jmmv         throw process::system_error("fork(2) failed", errno);
    328  1.1   jmmv     } else if (pid == 0) {
    329  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    330  1.1   jmmv         ::setpgid(::getpid(), ::getpid());
    331  1.1   jmmv 
    332  1.1   jmmv         try {
    333  1.1   jmmv             if (stdout_file != fs::path("/dev/stdout")) {
    334  1.1   jmmv                 const int stdout_fd = open_for_append(stdout_file);
    335  1.1   jmmv                 safe_dup(stdout_fd, STDOUT_FILENO);
    336  1.1   jmmv                 ::close(stdout_fd);
    337  1.1   jmmv             }
    338  1.1   jmmv             if (stderr_file != fs::path("/dev/stderr")) {
    339  1.1   jmmv                 const int stderr_fd = open_for_append(stderr_file);
    340  1.1   jmmv                 safe_dup(stderr_fd, STDERR_FILENO);
    341  1.1   jmmv                 ::close(stderr_fd);
    342  1.1   jmmv             }
    343  1.1   jmmv         } catch (const system_error& e) {
    344  1.1   jmmv             std::cerr << F("Failed to set up subprocess: %s\n") % e.what();
    345  1.1   jmmv             std::abort();
    346  1.1   jmmv         }
    347  1.2  lukem         return std::unique_ptr< process::child >();
    348  1.1   jmmv     } else {
    349  1.1   jmmv         LD(F("Spawned process %s: stdout=%s, stderr=%s") % pid % stdout_file %
    350  1.1   jmmv            stderr_file);
    351  1.1   jmmv         signals::add_pid_to_kill(pid);
    352  1.1   jmmv         inhibiter.reset(NULL);  // Unblock signals.
    353  1.2  lukem         return std::unique_ptr< process::child >(
    354  1.1   jmmv             new process::child(new impl(pid, NULL)));
    355  1.1   jmmv     }
    356  1.1   jmmv }
    357  1.1   jmmv 
    358  1.1   jmmv 
    359  1.1   jmmv /// Spawns a new binary and multiplexes and captures its stdout and stderr.
    360  1.1   jmmv ///
    361  1.1   jmmv /// If the subprocess cannot be completely set up for any reason, it attempts to
    362  1.1   jmmv /// dump an error message to its stderr channel and it then calls std::abort().
    363  1.1   jmmv ///
    364  1.1   jmmv /// \param program The binary to execute.
    365  1.1   jmmv /// \param args The arguments to pass to the binary, without the program name.
    366  1.1   jmmv ///
    367  1.1   jmmv /// \return A new child object, returned as a dynamically-allocated object
    368  1.1   jmmv /// because children classes are unique and thus noncopyable.
    369  1.1   jmmv ///
    370  1.1   jmmv /// \throw process::system_error If the process cannot be spawned due to a
    371  1.1   jmmv ///     system call error.
    372  1.2  lukem std::unique_ptr< process::child >
    373  1.1   jmmv process::child::spawn_capture(const fs::path& program, const args_vector& args)
    374  1.1   jmmv {
    375  1.2  lukem     std::unique_ptr< child > child = fork_capture_aux();
    376  1.1   jmmv     if (child.get() == NULL)
    377  1.1   jmmv         cxx_exec(program, args);
    378  1.1   jmmv     log_exec(program, args);
    379  1.1   jmmv     return child;
    380  1.1   jmmv }
    381  1.1   jmmv 
    382  1.1   jmmv 
    383  1.1   jmmv /// Spawns a new binary and redirects its stdout and stderr to files.
    384  1.1   jmmv ///
    385  1.1   jmmv /// If the subprocess cannot be completely set up for any reason, it attempts to
    386  1.1   jmmv /// dump an error message to its stderr channel and it then calls std::abort().
    387  1.1   jmmv ///
    388  1.1   jmmv /// \param program The binary to execute.
    389  1.1   jmmv /// \param args The arguments to pass to the binary, without the program name.
    390  1.1   jmmv /// \param stdout_file The name of the file in which to store the stdout.
    391  1.1   jmmv /// \param stderr_file The name of the file in which to store the stderr.
    392  1.1   jmmv ///
    393  1.1   jmmv /// \return A new child object, returned as a dynamically-allocated object
    394  1.1   jmmv /// because children classes are unique and thus noncopyable.
    395  1.1   jmmv ///
    396  1.1   jmmv /// \throw process::system_error If the process cannot be spawned due to a
    397  1.1   jmmv ///     system call error.
    398  1.2  lukem std::unique_ptr< process::child >
    399  1.1   jmmv process::child::spawn_files(const fs::path& program,
    400  1.1   jmmv                             const args_vector& args,
    401  1.1   jmmv                             const fs::path& stdout_file,
    402  1.1   jmmv                             const fs::path& stderr_file)
    403  1.1   jmmv {
    404  1.2  lukem     std::unique_ptr< child > child = fork_files_aux(stdout_file, stderr_file);
    405  1.1   jmmv     if (child.get() == NULL)
    406  1.1   jmmv         cxx_exec(program, args);
    407  1.1   jmmv     log_exec(program, args);
    408  1.1   jmmv     return child;
    409  1.1   jmmv }
    410  1.1   jmmv 
    411  1.1   jmmv 
    412  1.1   jmmv /// Returns the process identifier of this child.
    413  1.1   jmmv ///
    414  1.1   jmmv /// \return A process identifier.
    415  1.1   jmmv int
    416  1.1   jmmv process::child::pid(void) const
    417  1.1   jmmv {
    418  1.1   jmmv     return _pimpl->_pid;
    419  1.1   jmmv }
    420  1.1   jmmv 
    421  1.1   jmmv 
    422  1.1   jmmv /// Gets the input stream corresponding to the stdout and stderr of the child.
    423  1.1   jmmv ///
    424  1.1   jmmv /// \pre The child must have been started by fork_capture().
    425  1.1   jmmv ///
    426  1.1   jmmv /// \return A reference to the input stream connected to the output of the test
    427  1.1   jmmv /// case.
    428  1.1   jmmv std::istream&
    429  1.1   jmmv process::child::output(void)
    430  1.1   jmmv {
    431  1.1   jmmv     PRE(_pimpl->_output.get() != NULL);
    432  1.1   jmmv     return *_pimpl->_output;
    433  1.1   jmmv }
    434  1.1   jmmv 
    435  1.1   jmmv 
    436  1.1   jmmv /// Blocks to wait for completion.
    437  1.1   jmmv ///
    438  1.1   jmmv /// \return The termination status of the child process.
    439  1.1   jmmv ///
    440  1.1   jmmv /// \throw process::system_error If the call to waitpid(2) fails.
    441  1.1   jmmv process::status
    442  1.1   jmmv process::child::wait(void)
    443  1.1   jmmv {
    444  1.1   jmmv     const process::status status = safe_wait(_pimpl->_pid);
    445  1.1   jmmv     {
    446  1.1   jmmv         signals::interrupts_inhibiter inhibiter;
    447  1.1   jmmv         signals::remove_pid_to_kill(_pimpl->_pid);
    448  1.1   jmmv     }
    449  1.1   jmmv     return status;
    450  1.1   jmmv }
    451