111be35a1SLionel Sambuc // Copyright 2010 Google Inc. 211be35a1SLionel Sambuc // All rights reserved. 311be35a1SLionel Sambuc // 411be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without 511be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are 611be35a1SLionel Sambuc // met: 711be35a1SLionel Sambuc // 811be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright 911be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer. 1011be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright 1111be35a1SLionel Sambuc // notice, this list of conditions and the following disclaimer in the 1211be35a1SLionel Sambuc // documentation and/or other materials provided with the distribution. 1311be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors 1411be35a1SLionel Sambuc // may be used to endorse or promote products derived from this software 1511be35a1SLionel Sambuc // without specific prior written permission. 1611be35a1SLionel Sambuc // 1711be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1811be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1911be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2011be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2111be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2211be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2311be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2411be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2511be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2611be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2711be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2811be35a1SLionel Sambuc 2911be35a1SLionel Sambuc #include "utils/process/child.ipp" 3011be35a1SLionel Sambuc 3111be35a1SLionel Sambuc extern "C" { 3211be35a1SLionel Sambuc #include <sys/stat.h> 3311be35a1SLionel Sambuc #include <sys/wait.h> 3411be35a1SLionel Sambuc 3511be35a1SLionel Sambuc #include <fcntl.h> 3611be35a1SLionel Sambuc #include <signal.h> 3711be35a1SLionel Sambuc #include <unistd.h> 3811be35a1SLionel Sambuc } 3911be35a1SLionel Sambuc 4011be35a1SLionel Sambuc #include <cassert> 4111be35a1SLionel Sambuc #include <cerrno> 4211be35a1SLionel Sambuc #include <cstdlib> 4311be35a1SLionel Sambuc #include <cstring> 4411be35a1SLionel Sambuc #include <iostream> 4511be35a1SLionel Sambuc #include <memory> 4611be35a1SLionel Sambuc 4711be35a1SLionel Sambuc #include "utils/defs.hpp" 4811be35a1SLionel Sambuc #include "utils/format/macros.hpp" 4911be35a1SLionel Sambuc #include "utils/logging/macros.hpp" 5011be35a1SLionel Sambuc #include "utils/process/exceptions.hpp" 5111be35a1SLionel Sambuc #include "utils/process/fdstream.hpp" 5211be35a1SLionel Sambuc #include "utils/process/system.hpp" 5311be35a1SLionel Sambuc #include "utils/process/status.hpp" 5411be35a1SLionel Sambuc #include "utils/sanity.hpp" 5511be35a1SLionel Sambuc #include "utils/signals/interrupts.hpp" 5611be35a1SLionel Sambuc 5711be35a1SLionel Sambuc 5811be35a1SLionel Sambuc namespace utils { 5911be35a1SLionel Sambuc namespace process { 6011be35a1SLionel Sambuc 6111be35a1SLionel Sambuc 6211be35a1SLionel Sambuc /// Private implementation fields for child objects. 6311be35a1SLionel Sambuc struct child::impl { 6411be35a1SLionel Sambuc /// The process identifier. 6511be35a1SLionel Sambuc pid_t _pid; 6611be35a1SLionel Sambuc 6711be35a1SLionel Sambuc /// The input stream for the process' stdout and stderr. May be NULL. 6811be35a1SLionel Sambuc std::auto_ptr< process::ifdstream > _output; 6911be35a1SLionel Sambuc 7011be35a1SLionel Sambuc /// Initializes private implementation data. 7111be35a1SLionel Sambuc /// 7211be35a1SLionel Sambuc /// \param pid The process identifier. 7311be35a1SLionel Sambuc /// \param output The input stream. Grabs ownership of the pointer. 7411be35a1SLionel Sambuc impl(const pid_t pid, process::ifdstream* output) : 7511be35a1SLionel Sambuc _pid(pid), _output(output) {} 7611be35a1SLionel Sambuc }; 7711be35a1SLionel Sambuc 7811be35a1SLionel Sambuc 7911be35a1SLionel Sambuc } // namespace process 8011be35a1SLionel Sambuc } // namespace utils 8111be35a1SLionel Sambuc 8211be35a1SLionel Sambuc 8311be35a1SLionel Sambuc namespace fs = utils::fs; 8411be35a1SLionel Sambuc namespace process = utils::process; 8511be35a1SLionel Sambuc namespace signals = utils::signals; 8611be35a1SLionel Sambuc 8711be35a1SLionel Sambuc 8811be35a1SLionel Sambuc namespace { 8911be35a1SLionel Sambuc 9011be35a1SLionel Sambuc 9111be35a1SLionel Sambuc /// Exception-based version of dup(2). 9211be35a1SLionel Sambuc /// 9311be35a1SLionel Sambuc /// \param old_fd The file descriptor to duplicate. 9411be35a1SLionel Sambuc /// \param new_fd The file descriptor to use as the duplicate. This is 9511be35a1SLionel Sambuc /// closed if it was open before the copy happens. 9611be35a1SLionel Sambuc /// 9711be35a1SLionel Sambuc /// \throw process::system_error If the call to dup2(2) fails. 9811be35a1SLionel Sambuc static void 9911be35a1SLionel Sambuc safe_dup(const int old_fd, const int new_fd) 10011be35a1SLionel Sambuc { 10111be35a1SLionel Sambuc if (process::detail::syscall_dup2(old_fd, new_fd) == -1) { 10211be35a1SLionel Sambuc const int original_errno = errno; 10311be35a1SLionel Sambuc throw process::system_error(F("dup2(%s, %s) failed") % old_fd % new_fd, 10411be35a1SLionel Sambuc original_errno); 10511be35a1SLionel Sambuc } 10611be35a1SLionel Sambuc } 10711be35a1SLionel Sambuc 10811be35a1SLionel Sambuc 10911be35a1SLionel Sambuc /// Exception-based version of open(2) to open (or create) a file for append. 11011be35a1SLionel Sambuc /// 11111be35a1SLionel Sambuc /// \param filename The file to open in append mode. 11211be35a1SLionel Sambuc /// 11311be35a1SLionel Sambuc /// \return The file descriptor for the opened or created file. 11411be35a1SLionel Sambuc /// 11511be35a1SLionel Sambuc /// \throw process::system_error If the call to open(2) fails. 11611be35a1SLionel Sambuc static int 11711be35a1SLionel Sambuc open_for_append(const fs::path& filename) 11811be35a1SLionel Sambuc { 11911be35a1SLionel Sambuc const int fd = process::detail::syscall_open( 12011be35a1SLionel Sambuc filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 12111be35a1SLionel Sambuc S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 12211be35a1SLionel Sambuc if (fd == -1) { 12311be35a1SLionel Sambuc const int original_errno = errno; 12411be35a1SLionel Sambuc throw process::system_error(F("Failed to create %s because open(2) " 12511be35a1SLionel Sambuc "failed") % filename, original_errno); 12611be35a1SLionel Sambuc } 12711be35a1SLionel Sambuc return fd; 12811be35a1SLionel Sambuc } 12911be35a1SLionel Sambuc 13011be35a1SLionel Sambuc 13111be35a1SLionel Sambuc /// Exception-based, type-improved version of wait(2). 13211be35a1SLionel Sambuc /// 13311be35a1SLionel Sambuc /// Because we are waiting for the termination of a process, and because this is 13411be35a1SLionel Sambuc /// the canonical way to call wait(2) for this module, we ensure from here that 13511be35a1SLionel Sambuc /// any subprocess of the process we are killing is terminated. 13611be35a1SLionel Sambuc /// 13711be35a1SLionel Sambuc /// \param pid The identifier of the process to wait for. 13811be35a1SLionel Sambuc /// 13911be35a1SLionel Sambuc /// \return The termination status of the process. 14011be35a1SLionel Sambuc /// 14111be35a1SLionel Sambuc /// \throw process::system_error If the call to waitpid(2) fails. 14211be35a1SLionel Sambuc static process::status 14311be35a1SLionel Sambuc safe_wait(const pid_t pid) 14411be35a1SLionel Sambuc { 14511be35a1SLionel Sambuc LD(F("Waiting for pid=%s") % pid); 14611be35a1SLionel Sambuc int stat_loc; 14711be35a1SLionel Sambuc if (process::detail::syscall_waitpid(pid, &stat_loc, 0) == -1) { 14811be35a1SLionel Sambuc const int original_errno = errno; 14911be35a1SLionel Sambuc throw process::system_error(F("Failed to wait for PID %s") % pid, 15011be35a1SLionel Sambuc original_errno); 15111be35a1SLionel Sambuc } 15211be35a1SLionel Sambuc return process::status(pid, stat_loc); 15311be35a1SLionel Sambuc } 15411be35a1SLionel Sambuc 15511be35a1SLionel Sambuc 15611be35a1SLionel Sambuc /// Logs the execution of another program. 15711be35a1SLionel Sambuc /// 15811be35a1SLionel Sambuc /// \param program The binary to execute. 15911be35a1SLionel Sambuc /// \param args The arguments to pass to the binary, without the program name. 16011be35a1SLionel Sambuc static void 16111be35a1SLionel Sambuc log_exec(const fs::path& program, const process::args_vector& args) 16211be35a1SLionel Sambuc { 16311be35a1SLionel Sambuc std::string plain_command = program.str(); 16411be35a1SLionel Sambuc for (process::args_vector::const_iterator iter = args.begin(); 16511be35a1SLionel Sambuc iter != args.end(); ++iter) 16611be35a1SLionel Sambuc plain_command += F(" %s") % *iter; 16711be35a1SLionel Sambuc LD(F("Executing %s") % plain_command); 16811be35a1SLionel Sambuc } 16911be35a1SLionel Sambuc 17011be35a1SLionel Sambuc 17111be35a1SLionel Sambuc /// Maximum number of arguments supported by cxx_exec. 17211be35a1SLionel Sambuc /// 17311be35a1SLionel Sambuc /// We need this limit to avoid having to allocate dynamic memory in the child 17411be35a1SLionel Sambuc /// process to construct the arguments list, which would have side-effects in 17511be35a1SLionel Sambuc /// the parent's memory if we use vfork(). 17611be35a1SLionel Sambuc #define MAX_ARGS 128 17711be35a1SLionel Sambuc 17811be35a1SLionel Sambuc 17911be35a1SLionel Sambuc static void cxx_exec(const fs::path& program, const process::args_vector& args) 18011be35a1SLionel Sambuc throw() UTILS_NORETURN; 18111be35a1SLionel Sambuc 18211be35a1SLionel Sambuc 18311be35a1SLionel Sambuc /// Executes an external binary and replaces the current process. 18411be35a1SLionel Sambuc /// 18511be35a1SLionel Sambuc /// This function must not use any of the logging features, so that the output 18611be35a1SLionel Sambuc /// of the subprocess is not "polluted" by our own messages. 18711be35a1SLionel Sambuc /// 18811be35a1SLionel Sambuc /// This function must also not affect the global state of the current process 18911be35a1SLionel Sambuc /// as otherwise we would not be able to use vfork(). Only state stored in the 19011be35a1SLionel Sambuc /// stack can be touched. 19111be35a1SLionel Sambuc /// 19211be35a1SLionel Sambuc /// \param program The binary to execute. 19311be35a1SLionel Sambuc /// \param args The arguments to pass to the binary, without the program name. 19411be35a1SLionel Sambuc static void 19511be35a1SLionel Sambuc cxx_exec(const fs::path& program, const process::args_vector& args) throw() 19611be35a1SLionel Sambuc { 19711be35a1SLionel Sambuc assert(args.size() < MAX_ARGS); 19811be35a1SLionel Sambuc try { 19911be35a1SLionel Sambuc const char* argv[MAX_ARGS + 1]; 20011be35a1SLionel Sambuc 20111be35a1SLionel Sambuc argv[0] = program.c_str(); 20211be35a1SLionel Sambuc for (process::args_vector::size_type i = 0; i < args.size(); i++) 20311be35a1SLionel Sambuc argv[1 + i] = args[i].c_str(); 20411be35a1SLionel Sambuc argv[1 + args.size()] = NULL; 20511be35a1SLionel Sambuc 206*3260d16fSLionel Sambuc #if defined(__minix) && !defined(NDEBUG) 207*3260d16fSLionel Sambuc const int ret = 208*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */ 209*3260d16fSLionel Sambuc ::execv(program.c_str(), 21011be35a1SLionel Sambuc (char* const*)(unsigned long)(const void*)argv); 21111be35a1SLionel Sambuc const int original_errno = errno; 21211be35a1SLionel Sambuc assert(ret == -1); 21311be35a1SLionel Sambuc 21411be35a1SLionel Sambuc std::cerr << "Failed to execute " << program << ": " 21511be35a1SLionel Sambuc << std::strerror(original_errno) << "\n"; 21611be35a1SLionel Sambuc std::abort(); 21711be35a1SLionel Sambuc } catch (const std::runtime_error& error) { 21811be35a1SLionel Sambuc std::cerr << "Failed to execute " << program << ": " 21911be35a1SLionel Sambuc << error.what() << "\n"; 22011be35a1SLionel Sambuc std::abort(); 22111be35a1SLionel Sambuc } catch (...) { 22211be35a1SLionel Sambuc std::cerr << "Failed to execute " << program << "; got unexpected " 22311be35a1SLionel Sambuc "exception during exec\n"; 22411be35a1SLionel Sambuc std::abort(); 22511be35a1SLionel Sambuc } 22611be35a1SLionel Sambuc } 22711be35a1SLionel Sambuc 22811be35a1SLionel Sambuc 22911be35a1SLionel Sambuc } // anonymous namespace 23011be35a1SLionel Sambuc 23111be35a1SLionel Sambuc 23211be35a1SLionel Sambuc /// Creates a new child. 23311be35a1SLionel Sambuc /// 23411be35a1SLionel Sambuc /// \param implptr A dynamically-allocated impl object with the contents of the 23511be35a1SLionel Sambuc /// new child. 23611be35a1SLionel Sambuc process::child::child(impl *implptr) : 23711be35a1SLionel Sambuc _pimpl(implptr) 23811be35a1SLionel Sambuc { 23911be35a1SLionel Sambuc } 24011be35a1SLionel Sambuc 24111be35a1SLionel Sambuc 24211be35a1SLionel Sambuc /// Destructor for child. 24311be35a1SLionel Sambuc process::child::~child(void) 24411be35a1SLionel Sambuc { 24511be35a1SLionel Sambuc } 24611be35a1SLionel Sambuc 24711be35a1SLionel Sambuc 24811be35a1SLionel Sambuc /// Helper function for fork(). 24911be35a1SLionel Sambuc /// 25011be35a1SLionel Sambuc /// Please note: if you update this function to change the return type or to 25111be35a1SLionel Sambuc /// raise different errors, do not forget to update fork() accordingly. 25211be35a1SLionel Sambuc /// 25311be35a1SLionel Sambuc /// \return In the case of the parent, a new child object returned as a 25411be35a1SLionel Sambuc /// dynamically-allocated object because children classes are unique and thus 25511be35a1SLionel Sambuc /// noncopyable. In the case of the child, a NULL pointer. 25611be35a1SLionel Sambuc /// 25711be35a1SLionel Sambuc /// \throw process::system_error If the calls to pipe(2) or fork(2) fail. 25811be35a1SLionel Sambuc std::auto_ptr< process::child > 25911be35a1SLionel Sambuc process::child::fork_capture_aux(void) 26011be35a1SLionel Sambuc { 26111be35a1SLionel Sambuc std::cout.flush(); 26211be35a1SLionel Sambuc std::cerr.flush(); 26311be35a1SLionel Sambuc 26411be35a1SLionel Sambuc int fds[2]; 26511be35a1SLionel Sambuc if (detail::syscall_pipe(fds) == -1) 26611be35a1SLionel Sambuc throw process::system_error("pipe(2) failed", errno); 26711be35a1SLionel Sambuc 26811be35a1SLionel Sambuc std::auto_ptr< signals::interrupts_inhibiter > inhibiter( 26911be35a1SLionel Sambuc new signals::interrupts_inhibiter); 27011be35a1SLionel Sambuc pid_t pid = detail::syscall_fork(); 27111be35a1SLionel Sambuc if (pid == -1) { 27211be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 27311be35a1SLionel Sambuc ::close(fds[0]); 27411be35a1SLionel Sambuc ::close(fds[1]); 27511be35a1SLionel Sambuc throw process::system_error("fork(2) failed", errno); 27611be35a1SLionel Sambuc } else if (pid == 0) { 27711be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 27811be35a1SLionel Sambuc #if !defined(__minix) 27911be35a1SLionel Sambuc ::setpgid(::getpid(), ::getpid()); 28011be35a1SLionel Sambuc #endif /* !defined(__minix) */ 28184d9c625SLionel Sambuc 28211be35a1SLionel Sambuc try { 28311be35a1SLionel Sambuc ::close(fds[0]); 28411be35a1SLionel Sambuc safe_dup(fds[1], STDOUT_FILENO); 28511be35a1SLionel Sambuc safe_dup(fds[1], STDERR_FILENO); 28611be35a1SLionel Sambuc ::close(fds[1]); 28711be35a1SLionel Sambuc } catch (const system_error& e) { 28811be35a1SLionel Sambuc std::cerr << F("Failed to set up subprocess: %s\n") % e.what(); 28911be35a1SLionel Sambuc std::abort(); 29011be35a1SLionel Sambuc } 29111be35a1SLionel Sambuc return std::auto_ptr< process::child >(NULL); 29211be35a1SLionel Sambuc } else { 29311be35a1SLionel Sambuc ::close(fds[1]); 29411be35a1SLionel Sambuc LD(F("Spawned process %s: stdout and stderr inherited") % pid); 29511be35a1SLionel Sambuc signals::add_pid_to_kill(pid); 29611be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 29711be35a1SLionel Sambuc return std::auto_ptr< process::child >( 29811be35a1SLionel Sambuc new process::child(new impl(pid, new process::ifdstream(fds[0])))); 29911be35a1SLionel Sambuc } 30011be35a1SLionel Sambuc } 30111be35a1SLionel Sambuc 30211be35a1SLionel Sambuc 30311be35a1SLionel Sambuc /// Helper function for fork(). 30411be35a1SLionel Sambuc /// 30511be35a1SLionel Sambuc /// Please note: if you update this function to change the return type or to 30611be35a1SLionel Sambuc /// raise different errors, do not forget to update fork() accordingly. 30711be35a1SLionel Sambuc /// 30811be35a1SLionel Sambuc /// \param stdout_file The name of the file in which to store the stdout. 30911be35a1SLionel Sambuc /// If this has the magic value /dev/stdout, then the parent's stdout is 31011be35a1SLionel Sambuc /// reused without applying any redirection. 31111be35a1SLionel Sambuc /// \param stderr_file The name of the file in which to store the stderr. 31211be35a1SLionel Sambuc /// If this has the magic value /dev/stderr, then the parent's stderr is 31311be35a1SLionel Sambuc /// reused without applying any redirection. 31411be35a1SLionel Sambuc /// 31511be35a1SLionel Sambuc /// \return In the case of the parent, a new child object returned as a 31611be35a1SLionel Sambuc /// dynamically-allocated object because children classes are unique and thus 31711be35a1SLionel Sambuc /// noncopyable. In the case of the child, a NULL pointer. 31811be35a1SLionel Sambuc /// 31911be35a1SLionel Sambuc /// \throw process::system_error If the call to fork(2) fails. 32011be35a1SLionel Sambuc std::auto_ptr< process::child > 32111be35a1SLionel Sambuc process::child::fork_files_aux(const fs::path& stdout_file, 32211be35a1SLionel Sambuc const fs::path& stderr_file) 32311be35a1SLionel Sambuc { 32411be35a1SLionel Sambuc std::cout.flush(); 32511be35a1SLionel Sambuc std::cerr.flush(); 32611be35a1SLionel Sambuc 32711be35a1SLionel Sambuc std::auto_ptr< signals::interrupts_inhibiter > inhibiter( 32811be35a1SLionel Sambuc new signals::interrupts_inhibiter); 32911be35a1SLionel Sambuc pid_t pid = detail::syscall_fork(); 33011be35a1SLionel Sambuc if (pid == -1) { 33111be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 33211be35a1SLionel Sambuc throw process::system_error("fork(2) failed", errno); 33311be35a1SLionel Sambuc } else if (pid == 0) { 33411be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 33511be35a1SLionel Sambuc #if !defined(__minix) 33611be35a1SLionel Sambuc ::setpgid(::getpid(), ::getpid()); 33711be35a1SLionel Sambuc #endif /* !defined(__minix) */ 33811be35a1SLionel Sambuc 33911be35a1SLionel Sambuc try { 34011be35a1SLionel Sambuc if (stdout_file != fs::path("/dev/stdout")) { 34111be35a1SLionel Sambuc const int stdout_fd = open_for_append(stdout_file); 34211be35a1SLionel Sambuc safe_dup(stdout_fd, STDOUT_FILENO); 34311be35a1SLionel Sambuc ::close(stdout_fd); 34411be35a1SLionel Sambuc } 34511be35a1SLionel Sambuc if (stderr_file != fs::path("/dev/stderr")) { 34611be35a1SLionel Sambuc const int stderr_fd = open_for_append(stderr_file); 34711be35a1SLionel Sambuc safe_dup(stderr_fd, STDERR_FILENO); 34811be35a1SLionel Sambuc ::close(stderr_fd); 34911be35a1SLionel Sambuc } 35011be35a1SLionel Sambuc } catch (const system_error& e) { 35111be35a1SLionel Sambuc std::cerr << F("Failed to set up subprocess: %s\n") % e.what(); 35211be35a1SLionel Sambuc std::abort(); 35311be35a1SLionel Sambuc } 35411be35a1SLionel Sambuc return std::auto_ptr< process::child >(NULL); 35511be35a1SLionel Sambuc } else { 35611be35a1SLionel Sambuc LD(F("Spawned process %s: stdout=%s, stderr=%s") % pid % stdout_file % 35711be35a1SLionel Sambuc stderr_file); 35811be35a1SLionel Sambuc signals::add_pid_to_kill(pid); 35911be35a1SLionel Sambuc inhibiter.reset(NULL); // Unblock signals. 36011be35a1SLionel Sambuc return std::auto_ptr< process::child >( 36111be35a1SLionel Sambuc new process::child(new impl(pid, NULL))); 36211be35a1SLionel Sambuc } 36311be35a1SLionel Sambuc } 36411be35a1SLionel Sambuc 36511be35a1SLionel Sambuc 36611be35a1SLionel Sambuc /// Spawns a new binary and multiplexes and captures its stdout and stderr. 36711be35a1SLionel Sambuc /// 36811be35a1SLionel Sambuc /// If the subprocess cannot be completely set up for any reason, it attempts to 36911be35a1SLionel Sambuc /// dump an error message to its stderr channel and it then calls std::abort(). 37011be35a1SLionel Sambuc /// 37111be35a1SLionel Sambuc /// \param program The binary to execute. 37211be35a1SLionel Sambuc /// \param args The arguments to pass to the binary, without the program name. 37311be35a1SLionel Sambuc /// 37411be35a1SLionel Sambuc /// \return A new child object, returned as a dynamically-allocated object 37511be35a1SLionel Sambuc /// because children classes are unique and thus noncopyable. 37611be35a1SLionel Sambuc /// 37711be35a1SLionel Sambuc /// \throw process::system_error If the process cannot be spawned due to a 37811be35a1SLionel Sambuc /// system call error. 37911be35a1SLionel Sambuc std::auto_ptr< process::child > 38011be35a1SLionel Sambuc process::child::spawn_capture(const fs::path& program, const args_vector& args) 38111be35a1SLionel Sambuc { 38211be35a1SLionel Sambuc std::auto_ptr< child > child = fork_capture_aux(); 38311be35a1SLionel Sambuc if (child.get() == NULL) 38411be35a1SLionel Sambuc cxx_exec(program, args); 38511be35a1SLionel Sambuc log_exec(program, args); 38611be35a1SLionel Sambuc return child; 38711be35a1SLionel Sambuc } 38811be35a1SLionel Sambuc 38911be35a1SLionel Sambuc 39011be35a1SLionel Sambuc /// Spawns a new binary and redirects its stdout and stderr to files. 39111be35a1SLionel Sambuc /// 39211be35a1SLionel Sambuc /// If the subprocess cannot be completely set up for any reason, it attempts to 39311be35a1SLionel Sambuc /// dump an error message to its stderr channel and it then calls std::abort(). 39411be35a1SLionel Sambuc /// 39511be35a1SLionel Sambuc /// \param program The binary to execute. 39611be35a1SLionel Sambuc /// \param args The arguments to pass to the binary, without the program name. 39711be35a1SLionel Sambuc /// \param stdout_file The name of the file in which to store the stdout. 39811be35a1SLionel Sambuc /// \param stderr_file The name of the file in which to store the stderr. 39911be35a1SLionel Sambuc /// 40011be35a1SLionel Sambuc /// \return A new child object, returned as a dynamically-allocated object 40111be35a1SLionel Sambuc /// because children classes are unique and thus noncopyable. 40211be35a1SLionel Sambuc /// 40311be35a1SLionel Sambuc /// \throw process::system_error If the process cannot be spawned due to a 40411be35a1SLionel Sambuc /// system call error. 40511be35a1SLionel Sambuc std::auto_ptr< process::child > 40611be35a1SLionel Sambuc process::child::spawn_files(const fs::path& program, 40711be35a1SLionel Sambuc const args_vector& args, 40811be35a1SLionel Sambuc const fs::path& stdout_file, 40911be35a1SLionel Sambuc const fs::path& stderr_file) 41011be35a1SLionel Sambuc { 41111be35a1SLionel Sambuc std::auto_ptr< child > child = fork_files_aux(stdout_file, stderr_file); 41211be35a1SLionel Sambuc if (child.get() == NULL) 41311be35a1SLionel Sambuc cxx_exec(program, args); 41411be35a1SLionel Sambuc log_exec(program, args); 41511be35a1SLionel Sambuc return child; 41611be35a1SLionel Sambuc } 41711be35a1SLionel Sambuc 41811be35a1SLionel Sambuc 41911be35a1SLionel Sambuc /// Returns the process identifier of this child. 42011be35a1SLionel Sambuc /// 42111be35a1SLionel Sambuc /// \return A process identifier. 42211be35a1SLionel Sambuc int 42311be35a1SLionel Sambuc process::child::pid(void) const 42411be35a1SLionel Sambuc { 42511be35a1SLionel Sambuc return _pimpl->_pid; 42611be35a1SLionel Sambuc } 42711be35a1SLionel Sambuc 42811be35a1SLionel Sambuc 42911be35a1SLionel Sambuc /// Gets the input stream corresponding to the stdout and stderr of the child. 43011be35a1SLionel Sambuc /// 43111be35a1SLionel Sambuc /// \pre The child must have been started by fork_capture(). 43211be35a1SLionel Sambuc /// 43311be35a1SLionel Sambuc /// \return A reference to the input stream connected to the output of the test 43411be35a1SLionel Sambuc /// case. 43511be35a1SLionel Sambuc std::istream& 43611be35a1SLionel Sambuc process::child::output(void) 43711be35a1SLionel Sambuc { 43811be35a1SLionel Sambuc PRE(_pimpl->_output.get() != NULL); 43911be35a1SLionel Sambuc return *_pimpl->_output; 44011be35a1SLionel Sambuc } 44111be35a1SLionel Sambuc 44211be35a1SLionel Sambuc 44311be35a1SLionel Sambuc /// Blocks to wait for completion. 44411be35a1SLionel Sambuc /// 44511be35a1SLionel Sambuc /// \return The termination status of the child process. 44611be35a1SLionel Sambuc /// 44711be35a1SLionel Sambuc /// \throw process::system_error If the call to waitpid(2) fails. 44811be35a1SLionel Sambuc process::status 44911be35a1SLionel Sambuc process::child::wait(void) 45011be35a1SLionel Sambuc { 45111be35a1SLionel Sambuc const process::status status = safe_wait(_pimpl->_pid); 45211be35a1SLionel Sambuc { 45311be35a1SLionel Sambuc signals::interrupts_inhibiter inhibiter; 45411be35a1SLionel Sambuc signals::remove_pid_to_kill(_pimpl->_pid); 45511be35a1SLionel Sambuc } 45611be35a1SLionel Sambuc return status; 45711be35a1SLionel Sambuc } 458