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