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 31 extern "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 58 namespace utils { 59 namespace process { 60 61 62 /// Private implementation fields for child objects. 63 struct 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 83 namespace fs = utils::fs; 84 namespace process = utils::process; 85 namespace signals = utils::signals; 86 87 88 namespace { 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. 98 static void 99 safe_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. 116 static int 117 open_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. 135 static void 136 log_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. 150 void 151 utils::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. 161 void 162 utils::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. 173 process::child::child(impl *implptr) : 174 _pimpl(implptr) 175 { 176 } 177 178 179 /// Destructor for child. 180 process::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. 195 std::auto_ptr< process::child > 196 process::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. 255 std::auto_ptr< process::child > 256 process::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. 312 std::auto_ptr< process::child > 313 process::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. 338 std::auto_ptr< process::child > 339 process::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. 355 int 356 process::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. 368 std::istream& 369 process::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. 381 process::status 382 process::child::wait(void) 383 { 384 return process::wait(_pimpl->_pid); 385 } 386