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 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a)) 106 return ::execvp(file, (char* const*)(UNCONST(argv))); 107 #undef UNCONST 108 } 109 110 void 111 detail::do_exec(void *v) 112 { 113 struct exec_args *ea = reinterpret_cast<struct exec_args *>(v); 114 115 if (ea->m_prehook != NULL) 116 ea->m_prehook(); 117 118 const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv()); 119 const int errnocopy = errno; 120 assert(ret == -1); 121 std::cerr << "exec(" << ea->m_prog.str() << ") failed: " 122 << std::strerror(errnocopy) << "\n"; 123 std::exit(EXIT_FAILURE); 124 } 125 126 // ------------------------------------------------------------------------ 127 // The "argv_array" type. 128 // ------------------------------------------------------------------------ 129 130 impl::argv_array::argv_array(void) : 131 m_exec_argv(collection_to_argv(m_args)) 132 { 133 } 134 135 impl::argv_array::argv_array(const char* arg1, ...) 136 { 137 m_args.push_back(arg1); 138 139 { 140 va_list ap; 141 const char* nextarg; 142 143 va_start(ap, arg1); 144 while ((nextarg = va_arg(ap, const char*)) != NULL) 145 m_args.push_back(nextarg); 146 va_end(ap); 147 } 148 149 ctor_init_exec_argv(); 150 } 151 152 impl::argv_array::argv_array(const char* const* ca) : 153 m_args(argv_to_collection< args_vector >(ca)), 154 m_exec_argv(collection_to_argv(m_args)) 155 { 156 } 157 158 impl::argv_array::argv_array(const argv_array& a) : 159 m_args(a.m_args), 160 m_exec_argv(collection_to_argv(m_args)) 161 { 162 } 163 164 void 165 impl::argv_array::ctor_init_exec_argv(void) 166 { 167 m_exec_argv = collection_to_argv(m_args); 168 } 169 170 const char* const* 171 impl::argv_array::exec_argv(void) 172 const 173 { 174 return m_exec_argv.get(); 175 } 176 177 impl::argv_array::size_type 178 impl::argv_array::size(void) 179 const 180 { 181 return m_args.size(); 182 } 183 184 const char* 185 impl::argv_array::operator[](int idx) 186 const 187 { 188 return m_args[idx].c_str(); 189 } 190 191 impl::argv_array::const_iterator 192 impl::argv_array::begin(void) 193 const 194 { 195 return m_args.begin(); 196 } 197 198 impl::argv_array::const_iterator 199 impl::argv_array::end(void) 200 const 201 { 202 return m_args.end(); 203 } 204 205 impl::argv_array& 206 impl::argv_array::operator=(const argv_array& a) 207 { 208 if (this != &a) { 209 m_args = a.m_args; 210 m_exec_argv = collection_to_argv(m_args); 211 } 212 return *this; 213 } 214 215 // ------------------------------------------------------------------------ 216 // The "stream" types. 217 // ------------------------------------------------------------------------ 218 219 impl::stream_capture::stream_capture(void) 220 { 221 for (int i = 0; i < 2; i++) 222 m_pipefds[i] = -1; 223 } 224 225 impl::stream_capture::~stream_capture(void) 226 { 227 for (int i = 0; i < 2; i++) 228 if (m_pipefds[i] != -1) 229 ::close(m_pipefds[i]); 230 } 231 232 void 233 impl::stream_capture::prepare(void) 234 { 235 if (pipe(m_pipefds) == -1) 236 throw system_error(IMPL_NAME "::stream_capture::prepare", 237 "Failed to create pipe", errno); 238 } 239 240 int 241 impl::stream_capture::connect_parent(void) 242 { 243 ::close(m_pipefds[1]); m_pipefds[1] = -1; 244 const int fd = m_pipefds[0]; 245 m_pipefds[0] = -1; 246 return fd; 247 } 248 249 void 250 impl::stream_capture::connect_child(const int fd) 251 { 252 ::close(m_pipefds[0]); m_pipefds[0] = -1; 253 if (m_pipefds[1] != fd) { 254 safe_dup(m_pipefds[1], fd); 255 } 256 m_pipefds[1] = -1; 257 } 258 259 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) : 260 m_src_fd(src_fd), m_tgt_fd(tgt_fd) 261 { 262 } 263 264 void 265 impl::stream_connect::prepare(void) 266 { 267 } 268 269 int 270 impl::stream_connect::connect_parent(void) 271 { 272 return -1; 273 } 274 275 void 276 impl::stream_connect::connect_child(const int fd __attribute__((__unused__))) 277 { 278 safe_dup(m_tgt_fd, m_src_fd); 279 } 280 281 impl::stream_inherit::stream_inherit(void) 282 { 283 } 284 285 void 286 impl::stream_inherit::prepare(void) 287 { 288 } 289 290 int 291 impl::stream_inherit::connect_parent(void) 292 { 293 return -1; 294 } 295 296 void 297 impl::stream_inherit::connect_child(const int fd __attribute__((__unused__))) 298 { 299 } 300 301 impl::stream_redirect_fd::stream_redirect_fd(const int fd) : 302 m_fd(fd) 303 { 304 } 305 306 void 307 impl::stream_redirect_fd::prepare(void) 308 { 309 } 310 311 int 312 impl::stream_redirect_fd::connect_parent(void) 313 { 314 return -1; 315 } 316 317 void 318 impl::stream_redirect_fd::connect_child(const int fd) 319 { 320 safe_dup(m_fd, fd); 321 } 322 323 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) : 324 m_path(p) 325 { 326 } 327 328 void 329 impl::stream_redirect_path::prepare(void) 330 { 331 } 332 333 int 334 impl::stream_redirect_path::connect_parent(void) 335 { 336 return -1; 337 } 338 339 void 340 impl::stream_redirect_path::connect_child(const int fd) 341 { 342 const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644); 343 if (aux == -1) 344 throw system_error(IMPL_NAME "::stream_redirect_path::connect_child", 345 "Could not create " + m_path.str(), errno); 346 else 347 safe_dup(aux, fd); 348 } 349 350 // ------------------------------------------------------------------------ 351 // The "status" type. 352 // ------------------------------------------------------------------------ 353 354 impl::status::status(int s) : 355 m_status(s) 356 { 357 } 358 359 impl::status::~status(void) 360 { 361 } 362 363 std::string 364 impl::status::str(void) 365 const 366 { 367 int mutable_status = m_status; 368 std::stringstream rv; 369 if (WIFEXITED(mutable_status)) 370 rv << "exit(" << WEXITSTATUS(mutable_status); 371 else if (WIFSTOPPED(mutable_status)) 372 rv << "stopped(" << WSTOPSIG(mutable_status); 373 else if (WIFSIGNALED(mutable_status)) 374 rv << "terminated(" << WTERMSIG(mutable_status); 375 if (WCOREDUMP(mutable_status)) 376 rv << "/core)"; 377 else 378 rv << ")"; 379 return rv.str(); 380 } 381 382 bool 383 impl::status::exited(void) 384 const 385 { 386 int mutable_status = m_status; 387 return WIFEXITED(mutable_status); 388 } 389 390 int 391 impl::status::exitstatus(void) 392 const 393 { 394 assert(exited()); 395 int mutable_status = m_status; 396 return WEXITSTATUS(mutable_status); 397 } 398 399 bool 400 impl::status::signaled(void) 401 const 402 { 403 int mutable_status = m_status; 404 return WIFSIGNALED(mutable_status); 405 } 406 407 int 408 impl::status::termsig(void) 409 const 410 { 411 assert(signaled()); 412 int mutable_status = m_status; 413 return WTERMSIG(mutable_status); 414 } 415 416 bool 417 impl::status::coredump(void) 418 const 419 { 420 assert(signaled()); 421 int mutable_status = m_status; 422 return WCOREDUMP(mutable_status); 423 } 424 425 // ------------------------------------------------------------------------ 426 // The "child" type. 427 // ------------------------------------------------------------------------ 428 429 impl::child::child(const pid_t pid_arg, const int stdout_fd_arg, 430 const int stderr_fd_arg) : 431 m_pid(pid_arg), 432 m_stdout(stdout_fd_arg), 433 m_stderr(stderr_fd_arg), 434 m_waited(false) 435 { 436 } 437 438 impl::child::~child(void) 439 { 440 if (!m_waited) { 441 ::kill(m_pid, SIGTERM); 442 (void)wait(); 443 444 if (m_stdout != -1) 445 ::close(m_stdout); 446 if (m_stderr != -1) 447 ::close(m_stderr); 448 } 449 } 450 451 impl::status 452 impl::child::wait(void) 453 { 454 int s; 455 456 if (::waitpid(m_pid, &s, 0) == -1) 457 throw system_error(IMPL_NAME "::child::wait", "Failed waiting for " 458 "process " + text::to_string(m_pid), errno); 459 460 if (m_stdout != -1) 461 ::close(m_stdout); m_stdout = -1; 462 if (m_stderr != -1) 463 ::close(m_stderr); m_stderr = -1; 464 465 m_waited = true; 466 return status(s); 467 } 468 469 pid_t 470 impl::child::pid(void) 471 const 472 { 473 return m_pid; 474 } 475 476 int 477 impl::child::stdout_fd(void) 478 { 479 return m_stdout; 480 } 481 482 int 483 impl::child::stderr_fd(void) 484 { 485 return m_stderr; 486 } 487 488 // ------------------------------------------------------------------------ 489 // Free functions. 490 // ------------------------------------------------------------------------ 491 492 void 493 detail::flush_streams(void) 494 { 495 // This is a weird hack to ensure that the output of the parent process 496 // is flushed before executing a child which prevents, for example, the 497 // output of the atf-run hooks to appear before the output of atf-run 498 // itself. 499 // 500 // TODO: This should only be executed when inheriting the stdout or 501 // stderr file descriptors. However, the flushing is specific to the 502 // iostreams, so we cannot do it from the C library where all the process 503 // logic is performed. Come up with a better design. 504 std::cout.flush(); 505 std::cerr.flush(); 506 } 507