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