4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews//
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// Automated Testing Framework (atf)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews//
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// Copyright (c) 2008 The NetBSD Foundation, Inc.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// All rights reserved.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews//
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// Redistribution and use in source and binary forms, with or without
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// modification, are permitted provided that the following conditions
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// are met:
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// 1. Redistributions of source code must retain the above copyright
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// notice, this list of conditions and the following disclaimer.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// 2. Redistributions in binary form must reproduce the above copyright
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// notice, this list of conditions and the following disclaimer in the
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// documentation and/or other materials provided with the distribution.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews//
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews//
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsextern "C" {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <sys/types.h>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <sys/wait.h>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <fcntl.h>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <signal.h>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <cassert>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <cstdarg>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <cerrno>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <cstring>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include <iostream>
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include "defs.hpp"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include "exceptions.hpp"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include "text.hpp"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#include "process.hpp"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsnamespace detail = tools::process::detail;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsnamespace impl = tools::process;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#define IMPL_NAME "tools::process"
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// Auxiliary functions.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewstemplate< class C >
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewstools::auto_array< const char* >
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewscollection_to_argv(const C& c)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews tools::auto_array< const char* > argv(new const char*[c.size() + 1]);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews std::size_t pos = 0;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews for (typename C::const_iterator iter = c.begin(); iter != c.end();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews iter++) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews argv[pos] = (*iter).c_str();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews pos++;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews assert(pos == c.size());
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews argv[pos] = NULL;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return argv;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewstemplate< class C >
4a53e3c2b83c476a93148eaee0272649beb221caMark AndrewsC
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsargv_to_collection(const char* const* argv)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews C c;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews for (const char* const* iter = argv; *iter != NULL; iter++)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews c.push_back(std::string(*iter));
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return c;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsstatic
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewssafe_dup(const int oldfd, const int newfd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (oldfd != newfd) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (dup2(oldfd, newfd) == -1) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews throw tools::system_error(IMPL_NAME "::safe_dup",
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews "Could not allocate file descriptor",
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews errno);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews } else {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(oldfd);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsstatic
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsconst_execvp(const char *file, const char *const *argv)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return ::execvp(file, (char* const*)(UNCONST(argv)));
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#undef UNCONST
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsdetail::do_exec(void *v)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (ea->m_prehook != NULL)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ea->m_prehook();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const int errnocopy = errno;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews assert(ret == -1);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews << std::strerror(errnocopy) << "\n";
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews std::exit(EXIT_FAILURE);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// The "argv_array" type.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::argv_array(void) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_exec_argv(collection_to_argv(m_args))
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::argv_array(const char* arg1, ...)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_args.push_back(arg1);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews va_list ap;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const char* nextarg;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews va_start(ap, arg1);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews while ((nextarg = va_arg(ap, const char*)) != NULL)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_args.push_back(nextarg);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews va_end(ap);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ctor_init_exec_argv();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::argv_array(const char* const* ca) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_args(argv_to_collection< args_vector >(ca)),
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_exec_argv(collection_to_argv(m_args))
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::argv_array(const argv_array& a) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_args(a.m_args),
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_exec_argv(collection_to_argv(m_args))
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::ctor_init_exec_argv(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_exec_argv = collection_to_argv(m_args);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsconst char* const*
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::exec_argv(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_exec_argv.get();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::size_type
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::size(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_args.size();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsconst char*
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::operator[](int idx)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_args[idx].c_str();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::const_iterator
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::begin(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_args.begin();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::const_iterator
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::end(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_args.end();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array&
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::argv_array::operator=(const argv_array& a)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (this != &a) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_args = a.m_args;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_exec_argv = collection_to_argv(m_args);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return *this;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// The "stream" types.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_capture::stream_capture(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews for (int i = 0; i < 2; i++)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_pipefds[i] = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_capture::~stream_capture(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews for (int i = 0; i < 2; i++)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_pipefds[i] != -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_pipefds[i]);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_capture::prepare(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (pipe(m_pipefds) == -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews throw system_error(IMPL_NAME "::stream_capture::prepare",
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews "Failed to create pipe", errno);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_capture::connect_parent(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_pipefds[1]); m_pipefds[1] = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const int fd = m_pipefds[0];
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_pipefds[0] = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return fd;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_capture::connect_child(const int fd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_pipefds[0]); m_pipefds[0] = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_pipefds[1] != fd) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews safe_dup(m_pipefds[1], fd);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_pipefds[1] = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_src_fd(src_fd), m_tgt_fd(tgt_fd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_connect::prepare(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_connect::connect_parent(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_connect::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews safe_dup(m_tgt_fd, m_src_fd);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_inherit::stream_inherit(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_inherit::prepare(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_inherit::connect_parent(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_inherit::connect_child(const int fd ATF_DEFS_ATTRIBUTE_UNUSED)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_fd::stream_redirect_fd(const int fd) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_fd(fd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_fd::prepare(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_fd::connect_parent(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_fd::connect_child(const int fd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews safe_dup(m_fd, fd);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_path(p)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_path::prepare(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_path::connect_parent(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::stream_redirect_path::connect_child(const int fd)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (aux == -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews "Could not create " + m_path.str(), errno);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews else
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews safe_dup(aux, fd);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// The "status" type.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::status(int s) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_status(s)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::~status(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsbool
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::exited(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int mutable_status = m_status;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return WIFEXITED(mutable_status);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::exitstatus(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews assert(exited());
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int mutable_status = m_status;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return WEXITSTATUS(mutable_status);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsbool
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::signaled(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int mutable_status = m_status;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return WIFSIGNALED(mutable_status);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::termsig(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews assert(signaled());
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int mutable_status = m_status;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return WTERMSIG(mutable_status);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsbool
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status::coredump(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews assert(signaled());
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#if defined(WCOREDUMP)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int mutable_status = m_status;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return WCOREDUMP(mutable_status);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#else
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return false;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews#endif
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// The "child" type.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const int stderr_fd_arg) :
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_pid(pid_arg),
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_stdout(stdout_fd_arg),
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_stderr(stderr_fd_arg),
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_waited(false)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::~child(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (!m_waited) {
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::kill(m_pid, SIGTERM);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews (void)wait();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_stdout != -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_stdout);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_stderr != -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_stderr);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews }
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::status
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::wait(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews int s;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (::waitpid(m_pid, &s, 0) == -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews "process " + text::to_string(m_pid), errno);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_stdout != -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_stdout); m_stdout = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews if (m_stderr != -1)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews ::close(m_stderr); m_stderr = -1;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews m_waited = true;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return status(s);
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewspid_t
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::pid(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews const
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_pid;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::stdout_fd(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_stdout;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsint
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsimpl::child::stderr_fd(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews return m_stderr;
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// Free functions.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews// ------------------------------------------------------------------------
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsvoid
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrewsdetail::flush_streams(void)
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews{
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // This is a weird hack to ensure that the output of the parent process
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // is flushed before executing a child which prevents, for example, the
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // output of the atf-run hooks to appear before the output of atf-run
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // itself.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews //
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // TODO: This should only be executed when inheriting the stdout or
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // stderr file descriptors. However, the flushing is specific to the
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // iostreams, so we cannot do it from the C library where all the process
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews // logic is performed. Come up with a better design.
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews std::cout.flush();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews std::cerr.flush();
4a53e3c2b83c476a93148eaee0272649beb221caMark Andrews}