1240116Smarcel// Copyright (c) 2008 The NetBSD Foundation, Inc. 2240116Smarcel// All rights reserved. 3240116Smarcel// 4240116Smarcel// Redistribution and use in source and binary forms, with or without 5240116Smarcel// modification, are permitted provided that the following conditions 6240116Smarcel// are met: 7240116Smarcel// 1. Redistributions of source code must retain the above copyright 8240116Smarcel// notice, this list of conditions and the following disclaimer. 9240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel// notice, this list of conditions and the following disclaimer in the 11240116Smarcel// documentation and/or other materials provided with the distribution. 12240116Smarcel// 13240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25240116Smarcel 26273929Sjmmv#include "atf-c++/detail/process.hpp" 27273929Sjmmv 28240116Smarcelextern "C" { 29240116Smarcel#include <signal.h> 30240116Smarcel 31273929Sjmmv#include "atf-c/detail/process.h" 32273929Sjmmv#include "atf-c/error.h" 33240116Smarcel} 34240116Smarcel 35240116Smarcel#include <iostream> 36240116Smarcel 37273929Sjmmv#include "atf-c++/detail/exceptions.hpp" 38273929Sjmmv#include "atf-c++/detail/sanity.hpp" 39240116Smarcel 40240116Smarcelnamespace detail = atf::process::detail; 41240116Smarcelnamespace impl = atf::process; 42240116Smarcel#define IMPL_NAME "atf::process" 43240116Smarcel 44240116Smarcel// ------------------------------------------------------------------------ 45240116Smarcel// Auxiliary functions. 46240116Smarcel// ------------------------------------------------------------------------ 47240116Smarcel 48240116Smarceltemplate< class C > 49258289Sjmmvatf::auto_array< const char* > 50240116Smarcelcollection_to_argv(const C& c) 51240116Smarcel{ 52258289Sjmmv atf::auto_array< const char* > argv(new const char*[c.size() + 1]); 53240116Smarcel 54240116Smarcel std::size_t pos = 0; 55240116Smarcel for (typename C::const_iterator iter = c.begin(); iter != c.end(); 56240116Smarcel iter++) { 57240116Smarcel argv[pos] = (*iter).c_str(); 58240116Smarcel pos++; 59240116Smarcel } 60240116Smarcel INV(pos == c.size()); 61240116Smarcel argv[pos] = NULL; 62240116Smarcel 63240116Smarcel return argv; 64240116Smarcel} 65240116Smarcel 66240116Smarceltemplate< class C > 67240116SmarcelC 68240116Smarcelargv_to_collection(const char* const* argv) 69240116Smarcel{ 70240116Smarcel C c; 71240116Smarcel 72240116Smarcel for (const char* const* iter = argv; *iter != NULL; iter++) 73240116Smarcel c.push_back(std::string(*iter)); 74240116Smarcel 75240116Smarcel return c; 76240116Smarcel} 77240116Smarcel 78240116Smarcel// ------------------------------------------------------------------------ 79240116Smarcel// The "argv_array" type. 80240116Smarcel// ------------------------------------------------------------------------ 81240116Smarcel 82240116Smarcelimpl::argv_array::argv_array(void) : 83240116Smarcel m_exec_argv(collection_to_argv(m_args)) 84240116Smarcel{ 85240116Smarcel} 86240116Smarcel 87240116Smarcelimpl::argv_array::argv_array(const char* arg1, ...) 88240116Smarcel{ 89240116Smarcel m_args.push_back(arg1); 90240116Smarcel 91240116Smarcel { 92240116Smarcel va_list ap; 93240116Smarcel const char* nextarg; 94240116Smarcel 95240116Smarcel va_start(ap, arg1); 96240116Smarcel while ((nextarg = va_arg(ap, const char*)) != NULL) 97240116Smarcel m_args.push_back(nextarg); 98240116Smarcel va_end(ap); 99240116Smarcel } 100240116Smarcel 101240116Smarcel ctor_init_exec_argv(); 102240116Smarcel} 103240116Smarcel 104240116Smarcelimpl::argv_array::argv_array(const char* const* ca) : 105240116Smarcel m_args(argv_to_collection< args_vector >(ca)), 106240116Smarcel m_exec_argv(collection_to_argv(m_args)) 107240116Smarcel{ 108240116Smarcel} 109240116Smarcel 110240116Smarcelimpl::argv_array::argv_array(const argv_array& a) : 111240116Smarcel m_args(a.m_args), 112240116Smarcel m_exec_argv(collection_to_argv(m_args)) 113240116Smarcel{ 114240116Smarcel} 115240116Smarcel 116240116Smarcelvoid 117240116Smarcelimpl::argv_array::ctor_init_exec_argv(void) 118240116Smarcel{ 119240116Smarcel m_exec_argv = collection_to_argv(m_args); 120240116Smarcel} 121240116Smarcel 122240116Smarcelconst char* const* 123240116Smarcelimpl::argv_array::exec_argv(void) 124240116Smarcel const 125240116Smarcel{ 126240116Smarcel return m_exec_argv.get(); 127240116Smarcel} 128240116Smarcel 129240116Smarcelimpl::argv_array::size_type 130240116Smarcelimpl::argv_array::size(void) 131240116Smarcel const 132240116Smarcel{ 133240116Smarcel return m_args.size(); 134240116Smarcel} 135240116Smarcel 136240116Smarcelconst char* 137240116Smarcelimpl::argv_array::operator[](int idx) 138240116Smarcel const 139240116Smarcel{ 140240116Smarcel return m_args[idx].c_str(); 141240116Smarcel} 142240116Smarcel 143240116Smarcelimpl::argv_array::const_iterator 144240116Smarcelimpl::argv_array::begin(void) 145240116Smarcel const 146240116Smarcel{ 147240116Smarcel return m_args.begin(); 148240116Smarcel} 149240116Smarcel 150240116Smarcelimpl::argv_array::const_iterator 151240116Smarcelimpl::argv_array::end(void) 152240116Smarcel const 153240116Smarcel{ 154240116Smarcel return m_args.end(); 155240116Smarcel} 156240116Smarcel 157240116Smarcelimpl::argv_array& 158240116Smarcelimpl::argv_array::operator=(const argv_array& a) 159240116Smarcel{ 160240116Smarcel if (this != &a) { 161240116Smarcel m_args = a.m_args; 162240116Smarcel m_exec_argv = collection_to_argv(m_args); 163240116Smarcel } 164240116Smarcel return *this; 165240116Smarcel} 166240116Smarcel 167240116Smarcel// ------------------------------------------------------------------------ 168240116Smarcel// The "stream" types. 169240116Smarcel// ------------------------------------------------------------------------ 170240116Smarcel 171240116Smarcelimpl::basic_stream::basic_stream(void) : 172240116Smarcel m_inited(false) 173240116Smarcel{ 174240116Smarcel} 175240116Smarcel 176240116Smarcelimpl::basic_stream::~basic_stream(void) 177240116Smarcel{ 178240116Smarcel if (m_inited) 179240116Smarcel atf_process_stream_fini(&m_sb); 180240116Smarcel} 181240116Smarcel 182240116Smarcelconst atf_process_stream_t* 183240116Smarcelimpl::basic_stream::get_sb(void) 184240116Smarcel const 185240116Smarcel{ 186240116Smarcel INV(m_inited); 187240116Smarcel return &m_sb; 188240116Smarcel} 189240116Smarcel 190240116Smarcelimpl::stream_capture::stream_capture(void) 191240116Smarcel{ 192240116Smarcel atf_error_t err = atf_process_stream_init_capture(&m_sb); 193240116Smarcel if (atf_is_error(err)) 194240116Smarcel throw_atf_error(err); 195240116Smarcel m_inited = true; 196240116Smarcel} 197240116Smarcel 198240116Smarcelimpl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) 199240116Smarcel{ 200240116Smarcel atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd); 201240116Smarcel if (atf_is_error(err)) 202240116Smarcel throw_atf_error(err); 203240116Smarcel m_inited = true; 204240116Smarcel} 205240116Smarcel 206240116Smarcelimpl::stream_inherit::stream_inherit(void) 207240116Smarcel{ 208240116Smarcel atf_error_t err = atf_process_stream_init_inherit(&m_sb); 209240116Smarcel if (atf_is_error(err)) 210240116Smarcel throw_atf_error(err); 211240116Smarcel m_inited = true; 212240116Smarcel} 213240116Smarcel 214240116Smarcelimpl::stream_redirect_fd::stream_redirect_fd(const int fd) 215240116Smarcel{ 216240116Smarcel atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd); 217240116Smarcel if (atf_is_error(err)) 218240116Smarcel throw_atf_error(err); 219240116Smarcel m_inited = true; 220240116Smarcel} 221240116Smarcel 222240116Smarcelimpl::stream_redirect_path::stream_redirect_path(const fs::path& p) 223240116Smarcel{ 224240116Smarcel atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path()); 225240116Smarcel if (atf_is_error(err)) 226240116Smarcel throw_atf_error(err); 227240116Smarcel m_inited = true; 228240116Smarcel} 229240116Smarcel 230240116Smarcel// ------------------------------------------------------------------------ 231240116Smarcel// The "status" type. 232240116Smarcel// ------------------------------------------------------------------------ 233240116Smarcel 234240116Smarcelimpl::status::status(atf_process_status_t& s) : 235240116Smarcel m_status(s) 236240116Smarcel{ 237240116Smarcel} 238240116Smarcel 239240116Smarcelimpl::status::~status(void) 240240116Smarcel{ 241240116Smarcel atf_process_status_fini(&m_status); 242240116Smarcel} 243240116Smarcel 244240116Smarcelbool 245240116Smarcelimpl::status::exited(void) 246240116Smarcel const 247240116Smarcel{ 248240116Smarcel return atf_process_status_exited(&m_status); 249240116Smarcel} 250240116Smarcel 251240116Smarcelint 252240116Smarcelimpl::status::exitstatus(void) 253240116Smarcel const 254240116Smarcel{ 255240116Smarcel return atf_process_status_exitstatus(&m_status); 256240116Smarcel} 257240116Smarcel 258240116Smarcelbool 259240116Smarcelimpl::status::signaled(void) 260240116Smarcel const 261240116Smarcel{ 262240116Smarcel return atf_process_status_signaled(&m_status); 263240116Smarcel} 264240116Smarcel 265240116Smarcelint 266240116Smarcelimpl::status::termsig(void) 267240116Smarcel const 268240116Smarcel{ 269240116Smarcel return atf_process_status_termsig(&m_status); 270240116Smarcel} 271240116Smarcel 272240116Smarcelbool 273240116Smarcelimpl::status::coredump(void) 274240116Smarcel const 275240116Smarcel{ 276240116Smarcel return atf_process_status_coredump(&m_status); 277240116Smarcel} 278240116Smarcel 279240116Smarcel// ------------------------------------------------------------------------ 280240116Smarcel// The "child" type. 281240116Smarcel// ------------------------------------------------------------------------ 282240116Smarcel 283240116Smarcelimpl::child::child(atf_process_child_t& c) : 284240116Smarcel m_child(c), 285240116Smarcel m_waited(false) 286240116Smarcel{ 287240116Smarcel} 288240116Smarcel 289240116Smarcelimpl::child::~child(void) 290240116Smarcel{ 291240116Smarcel if (!m_waited) { 292240116Smarcel ::kill(atf_process_child_pid(&m_child), SIGTERM); 293240116Smarcel 294240116Smarcel atf_process_status_t s; 295240116Smarcel atf_error_t err = atf_process_child_wait(&m_child, &s); 296240116Smarcel INV(!atf_is_error(err)); 297240116Smarcel atf_process_status_fini(&s); 298240116Smarcel } 299240116Smarcel} 300240116Smarcel 301240116Smarcelimpl::status 302240116Smarcelimpl::child::wait(void) 303240116Smarcel{ 304240116Smarcel atf_process_status_t s; 305240116Smarcel 306240116Smarcel atf_error_t err = atf_process_child_wait(&m_child, &s); 307240116Smarcel if (atf_is_error(err)) 308240116Smarcel throw_atf_error(err); 309240116Smarcel 310240116Smarcel m_waited = true; 311240116Smarcel return status(s); 312240116Smarcel} 313240116Smarcel 314240116Smarcelpid_t 315240116Smarcelimpl::child::pid(void) 316240116Smarcel const 317240116Smarcel{ 318240116Smarcel return atf_process_child_pid(&m_child); 319240116Smarcel} 320240116Smarcel 321240116Smarcelint 322240116Smarcelimpl::child::stdout_fd(void) 323240116Smarcel{ 324240116Smarcel return atf_process_child_stdout(&m_child); 325240116Smarcel} 326240116Smarcel 327240116Smarcelint 328240116Smarcelimpl::child::stderr_fd(void) 329240116Smarcel{ 330240116Smarcel return atf_process_child_stderr(&m_child); 331240116Smarcel} 332240116Smarcel 333240116Smarcel// ------------------------------------------------------------------------ 334240116Smarcel// Free functions. 335240116Smarcel// ------------------------------------------------------------------------ 336240116Smarcel 337240116Smarcelvoid 338240116Smarceldetail::flush_streams(void) 339240116Smarcel{ 340240116Smarcel // TODO: This should only be executed when inheriting the stdout or 341240116Smarcel // stderr file descriptors. However, the flushing is specific to the 342240116Smarcel // iostreams, so we cannot do it from the C library where all the process 343240116Smarcel // logic is performed. Come up with a better design. 344240116Smarcel std::cout.flush(); 345240116Smarcel std::cerr.flush(); 346240116Smarcel} 347