process.cpp revision 275988
1// Copyright (c) 2008 The NetBSD Foundation, Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions 6// are met: 7// 1. Redistributions of source code must retain the above copyright 8// notice, this list of conditions and the following disclaimer. 9// 2. Redistributions in binary form must reproduce the above copyright 10// notice, this list of conditions and the following disclaimer in the 11// documentation and/or other materials provided with the distribution. 12// 13// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26#include "atf-c++/detail/process.hpp" 27 28extern "C" { 29#include <signal.h> 30 31#include "atf-c/detail/process.h" 32#include "atf-c/error.h" 33} 34 35#include <iostream> 36 37#include "atf-c++/detail/exceptions.hpp" 38#include "atf-c++/detail/sanity.hpp" 39 40namespace detail = atf::process::detail; 41namespace impl = atf::process; 42#define IMPL_NAME "atf::process" 43 44// ------------------------------------------------------------------------ 45// Auxiliary functions. 46// ------------------------------------------------------------------------ 47 48template< class C > 49atf::auto_array< const char* > 50collection_to_argv(const C& c) 51{ 52 atf::auto_array< const char* > argv(new const char*[c.size() + 1]); 53 54 std::size_t pos = 0; 55 for (typename C::const_iterator iter = c.begin(); iter != c.end(); 56 iter++) { 57 argv[pos] = (*iter).c_str(); 58 pos++; 59 } 60 INV(pos == c.size()); 61 argv[pos] = NULL; 62 63 return argv; 64} 65 66template< class C > 67C 68argv_to_collection(const char* const* argv) 69{ 70 C c; 71 72 for (const char* const* iter = argv; *iter != NULL; iter++) 73 c.push_back(std::string(*iter)); 74 75 return c; 76} 77 78// ------------------------------------------------------------------------ 79// The "argv_array" type. 80// ------------------------------------------------------------------------ 81 82impl::argv_array::argv_array(void) : 83 m_exec_argv(collection_to_argv(m_args)) 84{ 85} 86 87impl::argv_array::argv_array(const char* arg1, ...) 88{ 89 m_args.push_back(arg1); 90 91 { 92 va_list ap; 93 const char* nextarg; 94 95 va_start(ap, arg1); 96 while ((nextarg = va_arg(ap, const char*)) != NULL) 97 m_args.push_back(nextarg); 98 va_end(ap); 99 } 100 101 ctor_init_exec_argv(); 102} 103 104impl::argv_array::argv_array(const char* const* ca) : 105 m_args(argv_to_collection< args_vector >(ca)), 106 m_exec_argv(collection_to_argv(m_args)) 107{ 108} 109 110impl::argv_array::argv_array(const argv_array& a) : 111 m_args(a.m_args), 112 m_exec_argv(collection_to_argv(m_args)) 113{ 114} 115 116void 117impl::argv_array::ctor_init_exec_argv(void) 118{ 119 m_exec_argv = collection_to_argv(m_args); 120} 121 122const char* const* 123impl::argv_array::exec_argv(void) 124 const 125{ 126 return m_exec_argv.get(); 127} 128 129impl::argv_array::size_type 130impl::argv_array::size(void) 131 const 132{ 133 return m_args.size(); 134} 135 136const char* 137impl::argv_array::operator[](int idx) 138 const 139{ 140 return m_args[idx].c_str(); 141} 142 143impl::argv_array::const_iterator 144impl::argv_array::begin(void) 145 const 146{ 147 return m_args.begin(); 148} 149 150impl::argv_array::const_iterator 151impl::argv_array::end(void) 152 const 153{ 154 return m_args.end(); 155} 156 157impl::argv_array& 158impl::argv_array::operator=(const argv_array& a) 159{ 160 if (this != &a) { 161 m_args = a.m_args; 162 m_exec_argv = collection_to_argv(m_args); 163 } 164 return *this; 165} 166 167// ------------------------------------------------------------------------ 168// The "stream" types. 169// ------------------------------------------------------------------------ 170 171impl::basic_stream::basic_stream(void) : 172 m_inited(false) 173{ 174} 175 176impl::basic_stream::~basic_stream(void) 177{ 178 if (m_inited) 179 atf_process_stream_fini(&m_sb); 180} 181 182const atf_process_stream_t* 183impl::basic_stream::get_sb(void) 184 const 185{ 186 INV(m_inited); 187 return &m_sb; 188} 189 190impl::stream_capture::stream_capture(void) 191{ 192 atf_error_t err = atf_process_stream_init_capture(&m_sb); 193 if (atf_is_error(err)) 194 throw_atf_error(err); 195 m_inited = true; 196} 197 198impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) 199{ 200 atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd); 201 if (atf_is_error(err)) 202 throw_atf_error(err); 203 m_inited = true; 204} 205 206impl::stream_inherit::stream_inherit(void) 207{ 208 atf_error_t err = atf_process_stream_init_inherit(&m_sb); 209 if (atf_is_error(err)) 210 throw_atf_error(err); 211 m_inited = true; 212} 213 214impl::stream_redirect_fd::stream_redirect_fd(const int fd) 215{ 216 atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd); 217 if (atf_is_error(err)) 218 throw_atf_error(err); 219 m_inited = true; 220} 221 222impl::stream_redirect_path::stream_redirect_path(const fs::path& p) 223{ 224 atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path()); 225 if (atf_is_error(err)) 226 throw_atf_error(err); 227 m_inited = true; 228} 229 230// ------------------------------------------------------------------------ 231// The "status" type. 232// ------------------------------------------------------------------------ 233 234impl::status::status(atf_process_status_t& s) : 235 m_status(s) 236{ 237} 238 239impl::status::~status(void) 240{ 241 atf_process_status_fini(&m_status); 242} 243 244bool 245impl::status::exited(void) 246 const 247{ 248 return atf_process_status_exited(&m_status); 249} 250 251int 252impl::status::exitstatus(void) 253 const 254{ 255 return atf_process_status_exitstatus(&m_status); 256} 257 258bool 259impl::status::signaled(void) 260 const 261{ 262 return atf_process_status_signaled(&m_status); 263} 264 265int 266impl::status::termsig(void) 267 const 268{ 269 return atf_process_status_termsig(&m_status); 270} 271 272bool 273impl::status::coredump(void) 274 const 275{ 276 return atf_process_status_coredump(&m_status); 277} 278 279// ------------------------------------------------------------------------ 280// The "child" type. 281// ------------------------------------------------------------------------ 282 283impl::child::child(atf_process_child_t& c) : 284 m_child(c), 285 m_waited(false) 286{ 287} 288 289impl::child::~child(void) 290{ 291 if (!m_waited) { 292 ::kill(atf_process_child_pid(&m_child), SIGTERM); 293 294 atf_process_status_t s; 295 atf_error_t err = atf_process_child_wait(&m_child, &s); 296 INV(!atf_is_error(err)); 297 atf_process_status_fini(&s); 298 } 299} 300 301impl::status 302impl::child::wait(void) 303{ 304 atf_process_status_t s; 305 306 atf_error_t err = atf_process_child_wait(&m_child, &s); 307 if (atf_is_error(err)) 308 throw_atf_error(err); 309 310 m_waited = true; 311 return status(s); 312} 313 314pid_t 315impl::child::pid(void) 316 const 317{ 318 return atf_process_child_pid(&m_child); 319} 320 321int 322impl::child::stdout_fd(void) 323{ 324 return atf_process_child_stdout(&m_child); 325} 326 327int 328impl::child::stderr_fd(void) 329{ 330 return atf_process_child_stderr(&m_child); 331} 332 333// ------------------------------------------------------------------------ 334// Free functions. 335// ------------------------------------------------------------------------ 336 337void 338detail::flush_streams(void) 339{ 340 // TODO: This should only be executed when inheriting the stdout or 341 // stderr file descriptors. However, the flushing is specific to the 342 // iostreams, so we cannot do it from the C library where all the process 343 // logic is performed. Come up with a better design. 344 std::cout.flush(); 345 std::cerr.flush(); 346} 347