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 30extern "C" { 31#include <signal.h> 32 33#include "../../atf-c/error.h" 34 35#include "../../atf-c/detail/process.h" 36} 37 38#include <iostream> 39 40#include "exceptions.hpp" 41#include "process.hpp" 42#include "sanity.hpp" 43 44namespace detail = atf::process::detail; 45namespace impl = atf::process; 46#define IMPL_NAME "atf::process" 47 48// ------------------------------------------------------------------------ 49// Auxiliary functions. 50// ------------------------------------------------------------------------ 51 52template< class C > 53atf::auto_array< const char* > 54collection_to_argv(const C& c) 55{ 56 atf::auto_array< const char* > argv(new const char*[c.size() + 1]); 57 58 std::size_t pos = 0; 59 for (typename C::const_iterator iter = c.begin(); iter != c.end(); 60 iter++) { 61 argv[pos] = (*iter).c_str(); 62 pos++; 63 } 64 INV(pos == c.size()); 65 argv[pos] = NULL; 66 67 return argv; 68} 69 70template< class C > 71C 72argv_to_collection(const char* const* argv) 73{ 74 C c; 75 76 for (const char* const* iter = argv; *iter != NULL; iter++) 77 c.push_back(std::string(*iter)); 78 79 return c; 80} 81 82// ------------------------------------------------------------------------ 83// The "argv_array" type. 84// ------------------------------------------------------------------------ 85 86impl::argv_array::argv_array(void) : 87 m_exec_argv(collection_to_argv(m_args)) 88{ 89} 90 91impl::argv_array::argv_array(const char* arg1, ...) 92{ 93 m_args.push_back(arg1); 94 95 { 96 va_list ap; 97 const char* nextarg; 98 99 va_start(ap, arg1); 100 while ((nextarg = va_arg(ap, const char*)) != NULL) 101 m_args.push_back(nextarg); 102 va_end(ap); 103 } 104 105 ctor_init_exec_argv(); 106} 107 108impl::argv_array::argv_array(const char* const* ca) : 109 m_args(argv_to_collection< args_vector >(ca)), 110 m_exec_argv(collection_to_argv(m_args)) 111{ 112} 113 114impl::argv_array::argv_array(const argv_array& a) : 115 m_args(a.m_args), 116 m_exec_argv(collection_to_argv(m_args)) 117{ 118} 119 120void 121impl::argv_array::ctor_init_exec_argv(void) 122{ 123 m_exec_argv = collection_to_argv(m_args); 124} 125 126const char* const* 127impl::argv_array::exec_argv(void) 128 const 129{ 130 return m_exec_argv.get(); 131} 132 133impl::argv_array::size_type 134impl::argv_array::size(void) 135 const 136{ 137 return m_args.size(); 138} 139 140const char* 141impl::argv_array::operator[](int idx) 142 const 143{ 144 return m_args[idx].c_str(); 145} 146 147impl::argv_array::const_iterator 148impl::argv_array::begin(void) 149 const 150{ 151 return m_args.begin(); 152} 153 154impl::argv_array::const_iterator 155impl::argv_array::end(void) 156 const 157{ 158 return m_args.end(); 159} 160 161impl::argv_array& 162impl::argv_array::operator=(const argv_array& a) 163{ 164 if (this != &a) { 165 m_args = a.m_args; 166 m_exec_argv = collection_to_argv(m_args); 167 } 168 return *this; 169} 170 171// ------------------------------------------------------------------------ 172// The "stream" types. 173// ------------------------------------------------------------------------ 174 175impl::basic_stream::basic_stream(void) : 176 m_inited(false) 177{ 178} 179 180impl::basic_stream::~basic_stream(void) 181{ 182 if (m_inited) 183 atf_process_stream_fini(&m_sb); 184} 185 186const atf_process_stream_t* 187impl::basic_stream::get_sb(void) 188 const 189{ 190 INV(m_inited); 191 return &m_sb; 192} 193 194impl::stream_capture::stream_capture(void) 195{ 196 atf_error_t err = atf_process_stream_init_capture(&m_sb); 197 if (atf_is_error(err)) 198 throw_atf_error(err); 199 m_inited = true; 200} 201 202impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) 203{ 204 atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd); 205 if (atf_is_error(err)) 206 throw_atf_error(err); 207 m_inited = true; 208} 209 210impl::stream_inherit::stream_inherit(void) 211{ 212 atf_error_t err = atf_process_stream_init_inherit(&m_sb); 213 if (atf_is_error(err)) 214 throw_atf_error(err); 215 m_inited = true; 216} 217 218impl::stream_redirect_fd::stream_redirect_fd(const int fd) 219{ 220 atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd); 221 if (atf_is_error(err)) 222 throw_atf_error(err); 223 m_inited = true; 224} 225 226impl::stream_redirect_path::stream_redirect_path(const fs::path& p) 227{ 228 atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path()); 229 if (atf_is_error(err)) 230 throw_atf_error(err); 231 m_inited = true; 232} 233 234// ------------------------------------------------------------------------ 235// The "status" type. 236// ------------------------------------------------------------------------ 237 238impl::status::status(atf_process_status_t& s) : 239 m_status(s) 240{ 241} 242 243impl::status::~status(void) 244{ 245 atf_process_status_fini(&m_status); 246} 247 248bool 249impl::status::exited(void) 250 const 251{ 252 return atf_process_status_exited(&m_status); 253} 254 255int 256impl::status::exitstatus(void) 257 const 258{ 259 return atf_process_status_exitstatus(&m_status); 260} 261 262bool 263impl::status::signaled(void) 264 const 265{ 266 return atf_process_status_signaled(&m_status); 267} 268 269int 270impl::status::termsig(void) 271 const 272{ 273 return atf_process_status_termsig(&m_status); 274} 275 276bool 277impl::status::coredump(void) 278 const 279{ 280 return atf_process_status_coredump(&m_status); 281} 282 283// ------------------------------------------------------------------------ 284// The "child" type. 285// ------------------------------------------------------------------------ 286 287impl::child::child(atf_process_child_t& c) : 288 m_child(c), 289 m_waited(false) 290{ 291} 292 293impl::child::~child(void) 294{ 295 if (!m_waited) { 296 ::kill(atf_process_child_pid(&m_child), SIGTERM); 297 298 atf_process_status_t s; 299 atf_error_t err = atf_process_child_wait(&m_child, &s); 300 INV(!atf_is_error(err)); 301 atf_process_status_fini(&s); 302 } 303} 304 305impl::status 306impl::child::wait(void) 307{ 308 atf_process_status_t s; 309 310 atf_error_t err = atf_process_child_wait(&m_child, &s); 311 if (atf_is_error(err)) 312 throw_atf_error(err); 313 314 m_waited = true; 315 return status(s); 316} 317 318pid_t 319impl::child::pid(void) 320 const 321{ 322 return atf_process_child_pid(&m_child); 323} 324 325int 326impl::child::stdout_fd(void) 327{ 328 return atf_process_child_stdout(&m_child); 329} 330 331int 332impl::child::stderr_fd(void) 333{ 334 return atf_process_child_stderr(&m_child); 335} 336 337// ------------------------------------------------------------------------ 338// Free functions. 339// ------------------------------------------------------------------------ 340 341void 342detail::flush_streams(void) 343{ 344 // This is a weird hack to ensure that the output of the parent process 345 // is flushed before executing a child which prevents, for example, the 346 // output of the atf-run hooks to appear before the output of atf-run 347 // itself. 348 // 349 // TODO: This should only be executed when inheriting the stdout or 350 // stderr file descriptors. However, the flushing is specific to the 351 // iostreams, so we cannot do it from the C library where all the process 352 // logic is performed. Come up with a better design. 353 std::cout.flush(); 354 std::cerr.flush(); 355} 356