Path: blob/main/contrib/atf/atf-c++/detail/process.cpp
39563 views
// Copyright (c) 2008 The NetBSD Foundation, Inc.1// All rights reserved.2//3// Redistribution and use in source and binary forms, with or without4// modification, are permitted provided that the following conditions5// are met:6// 1. Redistributions of source code must retain the above copyright7// notice, this list of conditions and the following disclaimer.8// 2. Redistributions in binary form must reproduce the above copyright9// notice, this list of conditions and the following disclaimer in the10// documentation and/or other materials provided with the distribution.11//12// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND13// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,14// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF15// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.16// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY17// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE19// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS20// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER21// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR22// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN23// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.2425#include "atf-c++/detail/process.hpp"2627extern "C" {28#include <signal.h>2930#include "atf-c/detail/process.h"31#include "atf-c/error.h"32}3334#include <iostream>3536#include "atf-c++/detail/exceptions.hpp"37#include "atf-c++/detail/sanity.hpp"3839namespace detail = atf::process::detail;40namespace impl = atf::process;41#define IMPL_NAME "atf::process"4243// ------------------------------------------------------------------------44// Auxiliary functions.45// ------------------------------------------------------------------------4647template< class C >48atf::auto_array< const char* >49collection_to_argv(const C& c)50{51atf::auto_array< const char* > argv(new const char*[c.size() + 1]);5253std::size_t pos = 0;54for (typename C::const_iterator iter = c.begin(); iter != c.end();55iter++) {56argv[pos] = (*iter).c_str();57pos++;58}59INV(pos == c.size());60argv[pos] = NULL;6162return argv;63}6465template< class C >66C67argv_to_collection(const char* const* argv)68{69C c;7071for (const char* const* iter = argv; *iter != NULL; iter++)72c.push_back(std::string(*iter));7374return c;75}7677// ------------------------------------------------------------------------78// The "argv_array" type.79// ------------------------------------------------------------------------8081impl::argv_array::argv_array(void) :82m_exec_argv(collection_to_argv(m_args))83{84}8586impl::argv_array::argv_array(const char* arg1, ...)87{88m_args.push_back(arg1);8990{91va_list ap;92const char* nextarg;9394va_start(ap, arg1);95while ((nextarg = va_arg(ap, const char*)) != NULL)96m_args.push_back(nextarg);97va_end(ap);98}99100ctor_init_exec_argv();101}102103impl::argv_array::argv_array(const char* const* ca) :104m_args(argv_to_collection< args_vector >(ca)),105m_exec_argv(collection_to_argv(m_args))106{107}108109impl::argv_array::argv_array(const argv_array& a) :110m_args(a.m_args),111m_exec_argv(collection_to_argv(m_args))112{113}114115void116impl::argv_array::ctor_init_exec_argv(void)117{118m_exec_argv = collection_to_argv(m_args);119}120121const char* const*122impl::argv_array::exec_argv(void)123const124{125return m_exec_argv.get();126}127128impl::argv_array::size_type129impl::argv_array::size(void)130const131{132return m_args.size();133}134135const char*136impl::argv_array::operator[](int idx)137const138{139return m_args[idx].c_str();140}141142impl::argv_array::const_iterator143impl::argv_array::begin(void)144const145{146return m_args.begin();147}148149impl::argv_array::const_iterator150impl::argv_array::end(void)151const152{153return m_args.end();154}155156impl::argv_array&157impl::argv_array::operator=(const argv_array& a)158{159if (this != &a) {160m_args = a.m_args;161m_exec_argv = collection_to_argv(m_args);162}163return *this;164}165166// ------------------------------------------------------------------------167// The "stream" types.168// ------------------------------------------------------------------------169170impl::basic_stream::basic_stream(void) :171m_inited(false)172{173}174175impl::basic_stream::~basic_stream(void)176{177if (m_inited)178atf_process_stream_fini(&m_sb);179}180181const atf_process_stream_t*182impl::basic_stream::get_sb(void)183const184{185INV(m_inited);186return &m_sb;187}188189impl::stream_capture::stream_capture(void)190{191atf_error_t err = atf_process_stream_init_capture(&m_sb);192if (atf_is_error(err))193throw_atf_error(err);194m_inited = true;195}196197impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)198{199atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);200if (atf_is_error(err))201throw_atf_error(err);202m_inited = true;203}204205impl::stream_inherit::stream_inherit(void)206{207atf_error_t err = atf_process_stream_init_inherit(&m_sb);208if (atf_is_error(err))209throw_atf_error(err);210m_inited = true;211}212213impl::stream_redirect_fd::stream_redirect_fd(const int fd)214{215atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);216if (atf_is_error(err))217throw_atf_error(err);218m_inited = true;219}220221impl::stream_redirect_path::stream_redirect_path(const fs::path& p)222{223atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());224if (atf_is_error(err))225throw_atf_error(err);226m_inited = true;227}228229// ------------------------------------------------------------------------230// The "status" type.231// ------------------------------------------------------------------------232233impl::status::status(atf_process_status_t& s) :234m_status(s)235{236}237238impl::status::~status(void)239{240atf_process_status_fini(&m_status);241}242243bool244impl::status::exited(void)245const246{247return atf_process_status_exited(&m_status);248}249250int251impl::status::exitstatus(void)252const253{254return atf_process_status_exitstatus(&m_status);255}256257bool258impl::status::signaled(void)259const260{261return atf_process_status_signaled(&m_status);262}263264int265impl::status::termsig(void)266const267{268return atf_process_status_termsig(&m_status);269}270271bool272impl::status::coredump(void)273const274{275return atf_process_status_coredump(&m_status);276}277278// ------------------------------------------------------------------------279// The "child" type.280// ------------------------------------------------------------------------281282impl::child::child(atf_process_child_t& c) :283m_child(c),284m_waited(false)285{286}287288impl::child::~child(void)289{290if (!m_waited) {291::kill(atf_process_child_pid(&m_child), SIGTERM);292293atf_process_status_t s;294atf_error_t err = atf_process_child_wait(&m_child, &s);295INV(!atf_is_error(err));296atf_process_status_fini(&s);297}298}299300impl::status301impl::child::wait(void)302{303atf_process_status_t s;304305atf_error_t err = atf_process_child_wait(&m_child, &s);306if (atf_is_error(err))307throw_atf_error(err);308309m_waited = true;310return status(s);311}312313pid_t314impl::child::pid(void)315const316{317return atf_process_child_pid(&m_child);318}319320int321impl::child::stdout_fd(void)322{323return atf_process_child_stdout(&m_child);324}325326int327impl::child::stderr_fd(void)328{329return atf_process_child_stderr(&m_child);330}331332// ------------------------------------------------------------------------333// Free functions.334// ------------------------------------------------------------------------335336void337detail::flush_streams(void)338{339// TODO: This should only be executed when inheriting the stdout or340// stderr file descriptors. However, the flushing is specific to the341// iostreams, so we cannot do it from the C library where all the process342// logic is performed. Come up with a better design.343std::cout.flush();344std::cerr.flush();345}346347348