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::unique_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::unique_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::unique_ptr< signals::interrupts_inhibiter > inhibiter( 206 new signals::interrupts_inhibiter); 207 pid_t pid = detail::syscall_fork(); 208 if (pid == -1) { 209 inhibiter.reset(); // 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(); // 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 {}; 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::unique_ptr< process::child >( 233 new process::child(new impl(pid, new process::ifdstream(fds[0])))); 234 } 235 } 236 237 238 std::unique_ptr< process::child > 239 process::child::fork_interactive(void) 240 { 241 std::cout.flush(); 242 std::cerr.flush(); 243 244 std::unique_ptr< signals::interrupts_inhibiter > inhibiter( 245 new signals::interrupts_inhibiter); 246 pid_t pid = detail::syscall_fork(); 247 if (pid == -1) { 248 inhibiter.reset(); // Unblock signals. 249 throw process::system_error("fork(2) failed", errno); 250 } else if (pid == 0) { 251 inhibiter.reset(); // Unblock signals. 252 return {}; 253 } else { 254 signals::add_pid_to_kill(pid); 255 inhibiter.reset(NULL); // Unblock signals. 256 return std::unique_ptr< process::child >( 257 new process::child(new impl(pid, NULL))); 258 } 259 } 260 261 262 /// Helper function for fork(). 263 /// 264 /// Please note: if you update this function to change the return type or to 265 /// raise different errors, do not forget to update fork() accordingly. 266 /// 267 /// \param stdout_file The name of the file in which to store the stdout. 268 /// If this has the magic value /dev/stdout, then the parent's stdout is 269 /// reused without applying any redirection. 270 /// \param stderr_file The name of the file in which to store the stderr. 271 /// If this has the magic value /dev/stderr, then the parent's stderr is 272 /// reused without applying any redirection. 273 /// 274 /// \return In the case of the parent, a new child object returned as a 275 /// dynamically-allocated object because children classes are unique and thus 276 /// noncopyable. In the case of the child, a NULL pointer. 277 /// 278 /// \throw process::system_error If the call to fork(2) fails. 279 std::unique_ptr< process::child > 280 process::child::fork_files_aux(const fs::path& stdout_file, 281 const fs::path& stderr_file) 282 { 283 std::cout.flush(); 284 std::cerr.flush(); 285 286 std::unique_ptr< signals::interrupts_inhibiter > inhibiter( 287 new signals::interrupts_inhibiter); 288 pid_t pid = detail::syscall_fork(); 289 if (pid == -1) { 290 inhibiter.reset(); // Unblock signals. 291 throw process::system_error("fork(2) failed", errno); 292 } else if (pid == 0) { 293 inhibiter.reset(); // Unblock signals. 294 ::setsid(); 295 296 try { 297 if (stdout_file != fs::path("/dev/stdout")) { 298 const int stdout_fd = open_for_append(stdout_file); 299 safe_dup(stdout_fd, STDOUT_FILENO); 300 ::close(stdout_fd); 301 } 302 if (stderr_file != fs::path("/dev/stderr")) { 303 const int stderr_fd = open_for_append(stderr_file); 304 safe_dup(stderr_fd, STDERR_FILENO); 305 ::close(stderr_fd); 306 } 307 } catch (const system_error& e) { 308 std::cerr << F("Failed to set up subprocess: %s\n") % e.what(); 309 std::abort(); 310 } 311 return {}; 312 } else { 313 LD(F("Spawned process %s: stdout=%s, stderr=%s") % pid % stdout_file % 314 stderr_file); 315 signals::add_pid_to_kill(pid); 316 inhibiter.reset(); // Unblock signals. 317 return std::unique_ptr< process::child >( 318 new process::child(new impl(pid, NULL))); 319 } 320 } 321 322 323 /// Spawns a new binary and multiplexes and captures its stdout and stderr. 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 /// 331 /// \return A new child object, returned as a dynamically-allocated object 332 /// because children classes are unique and thus noncopyable. 333 /// 334 /// \throw process::system_error If the process cannot be spawned due to a 335 /// system call error. 336 std::unique_ptr< process::child > 337 process::child::spawn_capture(const fs::path& program, const args_vector& args) 338 { 339 std::unique_ptr< child > child = fork_capture_aux(); 340 if (child.get() == NULL) 341 exec(program, args); 342 log_exec(program, args); 343 return child; 344 } 345 346 347 /// Spawns a new binary and redirects its stdout and stderr to files. 348 /// 349 /// If the subprocess cannot be completely set up for any reason, it attempts to 350 /// dump an error message to its stderr channel and it then calls std::abort(). 351 /// 352 /// \param program The binary to execute. 353 /// \param args The arguments to pass to the binary, without the program name. 354 /// \param stdout_file The name of the file in which to store the stdout. 355 /// \param stderr_file The name of the file in which to store the stderr. 356 /// 357 /// \return A new child object, returned as a dynamically-allocated object 358 /// because children classes are unique and thus noncopyable. 359 /// 360 /// \throw process::system_error If the process cannot be spawned due to a 361 /// system call error. 362 std::unique_ptr< process::child > 363 process::child::spawn_files(const fs::path& program, 364 const args_vector& args, 365 const fs::path& stdout_file, 366 const fs::path& stderr_file) 367 { 368 std::unique_ptr< child > child = fork_files_aux(stdout_file, stderr_file); 369 if (child.get() == NULL) 370 exec(program, args); 371 log_exec(program, args); 372 return child; 373 } 374 375 376 /// Returns the process identifier of this child. 377 /// 378 /// \return A process identifier. 379 int 380 process::child::pid(void) const 381 { 382 return _pimpl->_pid; 383 } 384 385 386 /// Gets the input stream corresponding to the stdout and stderr of the child. 387 /// 388 /// \pre The child must have been started by fork_capture(). 389 /// 390 /// \return A reference to the input stream connected to the output of the test 391 /// case. 392 std::istream& 393 process::child::output(void) 394 { 395 PRE(_pimpl->_output.get() != NULL); 396 return *_pimpl->_output; 397 } 398 399 400 /// Blocks to wait for completion. 401 /// 402 /// \return The termination status of the child process. 403 /// 404 /// \throw process::system_error If the call to waitpid(2) fails. 405 process::status 406 process::child::wait(void) 407 { 408 return process::wait(_pimpl->_pid); 409 } 410