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