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