1 // 2 // Automated Testing Framework (atf) 3 // 4 // Copyright (c) 2008 The NetBSD Foundation, Inc. 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions 9 // are met: 10 // 1. Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // 2. Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 // 29 30 extern "C" { 31 #include <sys/types.h> 32 #include <sys/wait.h> 33 34 #include <fcntl.h> 35 #include <signal.h> 36 } 37 38 #include <cassert> 39 #include <cstdarg> 40 #include <cerrno> 41 #include <cstring> 42 #include <iostream> 43 44 #include "exceptions.hpp" 45 #include "text.hpp" 46 #include "process.hpp" 47 48 namespace detail = tools::process::detail; 49 namespace impl = tools::process; 50 #define IMPL_NAME "tools::process" 51 52 // ------------------------------------------------------------------------ 53 // Auxiliary functions. 54 // ------------------------------------------------------------------------ 55 56 template< class C > 57 tools::auto_array< const char* > 58 collection_to_argv(const C& c) 59 { 60 tools::auto_array< const char* > argv(new const char*[c.size() + 1]); 61 62 std::size_t pos = 0; 63 for (typename C::const_iterator iter = c.begin(); iter != c.end(); 64 iter++) { 65 argv[pos] = (*iter).c_str(); 66 pos++; 67 } 68 assert(pos == c.size()); 69 argv[pos] = NULL; 70 71 return argv; 72 } 73 74 template< class C > 75 C 76 argv_to_collection(const char* const* argv) 77 { 78 C c; 79 80 for (const char* const* iter = argv; *iter != NULL; iter++) 81 c.push_back(std::string(*iter)); 82 83 return c; 84 } 85 86 static 87 void 88 safe_dup(const int oldfd, const int newfd) 89 { 90 if (oldfd != newfd) { 91 if (dup2(oldfd, newfd) == -1) { 92 throw tools::system_error(IMPL_NAME "::safe_dup", 93 "Could not allocate file descriptor", 94 errno); 95 } else { 96 ::close(oldfd); 97 } 98 } 99 } 100 101 static 102 int 103 const_execvp(const char *file, const char *const *argv) 104 { 105 return ::execvp(file, const_cast<char* const*>(argv)); 106 #undef UNCONST 107 } 108 109 void 110 detail::do_exec(void *v) 111 { 112 struct exec_args *ea = reinterpret_cast<struct exec_args *>(v); 113 114 if (ea->m_prehook != NULL) 115 ea->m_prehook(); 116 117 const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv()); 118 const int errnocopy = errno; 119 assert(ret == -1); 120 std::cerr << "exec(" << ea->m_prog.str() << ") failed: " 121 << std::strerror(errnocopy) << "\n"; 122 std::exit(EXIT_FAILURE); 123 } 124 125 // ------------------------------------------------------------------------ 126 // The "argv_array" type. 127 // ------------------------------------------------------------------------ 128 129 impl::argv_array::argv_array(void) : 130 m_exec_argv(collection_to_argv(m_args)) 131 { 132 } 133 134 impl::argv_array::argv_array(const char* arg1, ...) 135 { 136 m_args.push_back(arg1); 137 138 { 139 va_list ap; 140 const char* nextarg; 141 142 va_start(ap, arg1); 143 while ((nextarg = va_arg(ap, const char*)) != NULL) 144 m_args.push_back(nextarg); 145 va_end(ap); 146 } 147 148 ctor_init_exec_argv(); 149 } 150 151 impl::argv_array::argv_array(const char* const* ca) : 152 m_args(argv_to_collection< args_vector >(ca)), 153 m_exec_argv(collection_to_argv(m_args)) 154 { 155 } 156 157 impl::argv_array::argv_array(const argv_array& a) : 158 m_args(a.m_args), 159 m_exec_argv(collection_to_argv(m_args)) 160 { 161 } 162 163 void 164 impl::argv_array::ctor_init_exec_argv(void) 165 { 166 m_exec_argv = collection_to_argv(m_args); 167 } 168 169 const char* const* 170 impl::argv_array::exec_argv(void) 171 const 172 { 173 return m_exec_argv.get(); 174 } 175 176 impl::argv_array::size_type 177 impl::argv_array::size(void) 178 const 179 { 180 return m_args.size(); 181 } 182 183 const char* 184 impl::argv_array::operator[](int idx) 185 const 186 { 187 return m_args[idx].c_str(); 188 } 189 190 impl::argv_array::const_iterator 191 impl::argv_array::begin(void) 192 const 193 { 194 return m_args.begin(); 195 } 196 197 impl::argv_array::const_iterator 198 impl::argv_array::end(void) 199 const 200 { 201 return m_args.end(); 202 } 203 204 impl::argv_array& 205 impl::argv_array::operator=(const argv_array& a) 206 { 207 if (this != &a) { 208 m_args = a.m_args; 209 m_exec_argv = collection_to_argv(m_args); 210 } 211 return *this; 212 } 213 214 // ------------------------------------------------------------------------ 215 // The "stream" types. 216 // ------------------------------------------------------------------------ 217 218 impl::stream_capture::stream_capture(void) 219 { 220 for (int i = 0; i < 2; i++) 221 m_pipefds[i] = -1; 222 } 223 224 impl::stream_capture::~stream_capture(void) 225 { 226 for (int i = 0; i < 2; i++) 227 if (m_pipefds[i] != -1) 228 ::close(m_pipefds[i]); 229 } 230 231 void 232 impl::stream_capture::prepare(void) 233 { 234 if (pipe(m_pipefds) == -1) 235 throw system_error(IMPL_NAME "::stream_capture::prepare", 236 "Failed to create pipe", errno); 237 } 238 239 int 240 impl::stream_capture::connect_parent(void) 241 { 242 ::close(m_pipefds[1]); m_pipefds[1] = -1; 243 const int fd = m_pipefds[0]; 244 m_pipefds[0] = -1; 245 return fd; 246 } 247 248 void 249 impl::stream_capture::connect_child(const int fd) 250 { 251 ::close(m_pipefds[0]); m_pipefds[0] = -1; 252 if (m_pipefds[1] != fd) { 253 safe_dup(m_pipefds[1], fd); 254 } 255 m_pipefds[1] = -1; 256 } 257 258 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) : 259 m_src_fd(src_fd), m_tgt_fd(tgt_fd) 260 { 261 } 262 263 void 264 impl::stream_connect::prepare(void) 265 { 266 } 267 268 int 269 impl::stream_connect::connect_parent(void) 270 { 271 return -1; 272 } 273 274 void 275 impl::stream_connect::connect_child(const int fd __attribute__((__unused__))) 276 { 277 safe_dup(m_tgt_fd, m_src_fd); 278 } 279 280 impl::stream_inherit::stream_inherit(void) 281 { 282 } 283 284 void 285 impl::stream_inherit::prepare(void) 286 { 287 } 288 289 int 290 impl::stream_inherit::connect_parent(void) 291 { 292 return -1; 293 } 294 295 void 296 impl::stream_inherit::connect_child(const int fd __attribute__((__unused__))) 297 { 298 } 299 300 impl::stream_redirect_fd::stream_redirect_fd(const int fd) : 301 m_fd(fd) 302 { 303 } 304 305 void 306 impl::stream_redirect_fd::prepare(void) 307 { 308 } 309 310 int 311 impl::stream_redirect_fd::connect_parent(void) 312 { 313 return -1; 314 } 315 316 void 317 impl::stream_redirect_fd::connect_child(const int fd) 318 { 319 safe_dup(m_fd, fd); 320 } 321 322 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) : 323 m_path(p) 324 { 325 } 326 327 void 328 impl::stream_redirect_path::prepare(void) 329 { 330 } 331 332 int 333 impl::stream_redirect_path::connect_parent(void) 334 { 335 return -1; 336 } 337 338 void 339 impl::stream_redirect_path::connect_child(const int fd) 340 { 341 const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644); 342 if (aux == -1) 343 throw system_error(IMPL_NAME "::stream_redirect_path::connect_child", 344 "Could not create " + m_path.str(), errno); 345 else 346 safe_dup(aux, fd); 347 } 348 349 // ------------------------------------------------------------------------ 350 // The "status" type. 351 // ------------------------------------------------------------------------ 352 353 impl::status::status(int s) : 354 m_status(s) 355 { 356 } 357 358 impl::status::~status(void) 359 { 360 } 361 362 std::string 363 impl::status::str(void) 364 const 365 { 366 int mutable_status = m_status; 367 std::stringstream rv; 368 if (WIFEXITED(mutable_status)) 369 rv << "exit(" << WEXITSTATUS(mutable_status); 370 else if (WIFSTOPPED(mutable_status)) 371 rv << "stopped(" << WSTOPSIG(mutable_status); 372 else if (WIFSIGNALED(mutable_status)) 373 rv << "terminated(" << WTERMSIG(mutable_status); 374 if (WCOREDUMP(mutable_status)) 375 rv << "/core)"; 376 else 377 rv << ")"; 378 return rv.str(); 379 } 380 381 bool 382 impl::status::exited(void) 383 const 384 { 385 int mutable_status = m_status; 386 return WIFEXITED(mutable_status); 387 } 388 389 int 390 impl::status::exitstatus(void) 391 const 392 { 393 assert(exited()); 394 int mutable_status = m_status; 395 return WEXITSTATUS(mutable_status); 396 } 397 398 bool 399 impl::status::signaled(void) 400 const 401 { 402 int mutable_status = m_status; 403 return WIFSIGNALED(mutable_status); 404 } 405 406 int 407 impl::status::termsig(void) 408 const 409 { 410 assert(signaled()); 411 int mutable_status = m_status; 412 return WTERMSIG(mutable_status); 413 } 414 415 bool 416 impl::status::coredump(void) 417 const 418 { 419 assert(signaled()); 420 int mutable_status = m_status; 421 return WCOREDUMP(mutable_status); 422 } 423 424 // ------------------------------------------------------------------------ 425 // The "child" type. 426 // ------------------------------------------------------------------------ 427 428 impl::child::child(const pid_t pid_arg, const int stdout_fd_arg, 429 const int stderr_fd_arg) : 430 m_pid(pid_arg), 431 m_stdout(stdout_fd_arg), 432 m_stderr(stderr_fd_arg), 433 m_waited(false) 434 { 435 } 436 437 impl::child::~child(void) 438 { 439 if (!m_waited) { 440 ::kill(m_pid, SIGTERM); 441 (void)wait(); 442 443 if (m_stdout != -1) { 444 ::close(m_stdout); m_stdout = -1; 445 } 446 if (m_stderr != -1) { 447 ::close(m_stderr); m_stderr = -1; 448 } 449 } 450 } 451 452 impl::status 453 impl::child::wait(void) 454 { 455 int s; 456 457 if (::waitpid(m_pid, &s, 0) == -1) 458 throw system_error(IMPL_NAME "::child::wait", "Failed waiting for " 459 "process " + text::to_string(m_pid), errno); 460 461 if (m_stdout != -1) { 462 ::close(m_stdout); m_stdout = -1; 463 } 464 if (m_stderr != -1) { 465 ::close(m_stderr); m_stderr = -1; 466 } 467 468 m_waited = true; 469 return status(s); 470 } 471 472 pid_t 473 impl::child::pid(void) 474 const 475 { 476 return m_pid; 477 } 478 479 int 480 impl::child::stdout_fd(void) 481 { 482 return m_stdout; 483 } 484 485 int 486 impl::child::stderr_fd(void) 487 { 488 return m_stderr; 489 } 490 491 // ------------------------------------------------------------------------ 492 // Free functions. 493 // ------------------------------------------------------------------------ 494 495 void 496 detail::flush_streams(void) 497 { 498 // This is a weird hack to ensure that the output of the parent process 499 // is flushed before executing a child which prevents, for example, the 500 // output of the atf-run hooks to appear before the output of atf-run 501 // itself. 502 // 503 // TODO: This should only be executed when inheriting the stdout or 504 // stderr file descriptors. However, the flushing is specific to the 505 // iostreams, so we cannot do it from the C library where all the process 506 // logic is performed. Come up with a better design. 507 std::cout.flush(); 508 std::cerr.flush(); 509 } 510