Home | History | Annotate | Line # | Download | only in detail
      1 //
      2 // Automated Testing Framework (atf)
      3 //
      4 // Copyright (c) 2008 The NetBSD Foundation, Inc.
      5 // All rights reserved.
      6 //
      7 // Redistribution and use in source and binary forms, with or without
      8 // modification, are permitted provided that the following conditions
      9 // are met:
     10 // 1. Redistributions of source code must retain the above copyright
     11 //    notice, this list of conditions and the following disclaimer.
     12 // 2. Redistributions in binary form must reproduce the above copyright
     13 //    notice, this list of conditions and the following disclaimer in the
     14 //    documentation and/or other materials provided with the distribution.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
     17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
     21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 //
     29 
     30 #if !defined(_ATF_CXX_PROCESS_HPP_)
     31 #define _ATF_CXX_PROCESS_HPP_
     32 
     33 extern "C" {
     34 #include <sys/types.h>
     35 
     36 #include "../../atf-c/error.h"
     37 
     38 #include "../../atf-c/detail/process.h"
     39 }
     40 
     41 #include <string>
     42 #include <vector>
     43 
     44 #include "auto_array.hpp"
     45 #include "exceptions.hpp"
     46 #include "fs.hpp"
     47 
     48 namespace atf {
     49 namespace process {
     50 
     51 class child;
     52 class status;
     53 
     54 // ------------------------------------------------------------------------
     55 // The "argv_array" type.
     56 // ------------------------------------------------------------------------
     57 
     58 class argv_array {
     59     typedef std::vector< std::string > args_vector;
     60     args_vector m_args;
     61 
     62     // TODO: This is immutable, so we should be able to use
     63     // std::tr1::shared_array instead when it becomes widely available.
     64     // The reason would be to remove all copy constructors and assignment
     65     // operators from this class.
     66     auto_array< const char* > m_exec_argv;
     67     void ctor_init_exec_argv(void);
     68 
     69 public:
     70     typedef args_vector::const_iterator const_iterator;
     71     typedef args_vector::size_type size_type;
     72 
     73     argv_array(void);
     74     argv_array(const char*, ...);
     75     explicit argv_array(const char* const*);
     76     template< class C > explicit argv_array(const C&);
     77     argv_array(const argv_array&);
     78 
     79     const char* const* exec_argv(void) const;
     80     size_type size(void) const;
     81     const char* operator[](int) const;
     82 
     83     const_iterator begin(void) const;
     84     const_iterator end(void) const;
     85 
     86     argv_array& operator=(const argv_array&);
     87 };
     88 
     89 template< class C >
     90 argv_array::argv_array(const C& c)
     91 {
     92     for (typename C::const_iterator iter = c.begin(); iter != c.end();
     93          iter++)
     94         m_args.push_back(*iter);
     95     ctor_init_exec_argv();
     96 }
     97 
     98 // ------------------------------------------------------------------------
     99 // The "stream" types.
    100 // ------------------------------------------------------------------------
    101 
    102 class basic_stream {
    103 protected:
    104     atf_process_stream_t m_sb;
    105     bool m_inited;
    106 
    107     const atf_process_stream_t* get_sb(void) const;
    108 
    109 public:
    110     basic_stream(void);
    111     ~basic_stream(void);
    112 };
    113 
    114 class stream_capture : basic_stream {
    115     // Allow access to the getters.
    116     template< class OutStream, class ErrStream > friend
    117     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    118     template< class OutStream, class ErrStream > friend
    119     status exec(const atf::fs::path&, const argv_array&,
    120                 const OutStream&, const ErrStream&, void (*)(void));
    121 
    122 public:
    123     stream_capture(void);
    124 };
    125 
    126 class stream_connect : basic_stream {
    127     // Allow access to the getters.
    128     template< class OutStream, class ErrStream > friend
    129     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    130     template< class OutStream, class ErrStream > friend
    131     status exec(const atf::fs::path&, const argv_array&,
    132                 const OutStream&, const ErrStream&, void (*)(void));
    133 
    134 public:
    135     stream_connect(const int, const int);
    136 };
    137 
    138 class stream_inherit : basic_stream {
    139     // Allow access to the getters.
    140     template< class OutStream, class ErrStream > friend
    141     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    142     template< class OutStream, class ErrStream > friend
    143     status exec(const atf::fs::path&, const argv_array&,
    144                 const OutStream&, const ErrStream&, void (*)(void));
    145 
    146 public:
    147     stream_inherit(void);
    148 };
    149 
    150 class stream_redirect_fd : basic_stream {
    151     // Allow access to the getters.
    152     template< class OutStream, class ErrStream > friend
    153     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    154     template< class OutStream, class ErrStream > friend
    155     status exec(const atf::fs::path&, const argv_array&,
    156                 const OutStream&, const ErrStream&, void (*)(void));
    157 
    158 public:
    159     stream_redirect_fd(const int);
    160 };
    161 
    162 class stream_redirect_path : basic_stream {
    163     // Allow access to the getters.
    164     template< class OutStream, class ErrStream > friend
    165     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    166     template< class OutStream, class ErrStream > friend
    167     status exec(const atf::fs::path&, const argv_array&,
    168                 const OutStream&, const ErrStream&, void (*)(void));
    169 
    170 public:
    171     stream_redirect_path(const fs::path&);
    172 };
    173 
    174 // ------------------------------------------------------------------------
    175 // The "status" type.
    176 // ------------------------------------------------------------------------
    177 
    178 class status {
    179     atf_process_status_t m_status;
    180 
    181     friend class child;
    182     template< class OutStream, class ErrStream > friend
    183     status exec(const atf::fs::path&, const argv_array&,
    184                 const OutStream&, const ErrStream&, void (*)(void));
    185 
    186     status(atf_process_status_t&);
    187 
    188 public:
    189     ~status(void);
    190 
    191     bool exited(void) const;
    192     int exitstatus(void) const;
    193 
    194     bool signaled(void) const;
    195     int termsig(void) const;
    196     bool coredump(void) const;
    197 };
    198 
    199 // ------------------------------------------------------------------------
    200 // The "child" type.
    201 // ------------------------------------------------------------------------
    202 
    203 class child {
    204     atf_process_child_t m_child;
    205     bool m_waited;
    206 
    207     template< class OutStream, class ErrStream > friend
    208     child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
    209 
    210     child(atf_process_child_t& c);
    211 
    212 public:
    213     ~child(void);
    214 
    215     status wait(void);
    216 
    217     pid_t pid(void) const;
    218     int stdout_fd(void);
    219     int stderr_fd(void);
    220 };
    221 
    222 // ------------------------------------------------------------------------
    223 // Free functions.
    224 // ------------------------------------------------------------------------
    225 
    226 namespace detail {
    227 void flush_streams(void);
    228 } // namespace detail
    229 
    230 // TODO: The void* cookie can probably be templatized, thus also allowing
    231 // const data structures.
    232 template< class OutStream, class ErrStream >
    233 child
    234 fork(void (*start)(void*), const OutStream& outsb,
    235      const ErrStream& errsb, void* v)
    236 {
    237     atf_process_child_t c;
    238 
    239     detail::flush_streams();
    240     atf_error_t err = atf_process_fork(&c, start, outsb.get_sb(),
    241                                        errsb.get_sb(), v);
    242     if (atf_is_error(err))
    243         throw_atf_error(err);
    244 
    245     return child(c);
    246 }
    247 
    248 template< class OutStream, class ErrStream >
    249 status
    250 exec(const atf::fs::path& prog, const argv_array& argv,
    251      const OutStream& outsb, const ErrStream& errsb,
    252      void (*prehook)(void))
    253 {
    254     atf_process_status_t s;
    255 
    256     detail::flush_streams();
    257     atf_error_t err = atf_process_exec_array(&s, prog.c_path(),
    258                                              argv.exec_argv(),
    259                                              outsb.get_sb(),
    260                                              errsb.get_sb(),
    261                                              prehook);
    262     if (atf_is_error(err))
    263         throw_atf_error(err);
    264 
    265     return status(s);
    266 }
    267 
    268 template< class OutStream, class ErrStream >
    269 status
    270 exec(const atf::fs::path& prog, const argv_array& argv,
    271      const OutStream& outsb, const ErrStream& errsb)
    272 {
    273     return exec(prog, argv, outsb, errsb, NULL);
    274 }
    275 
    276 } // namespace process
    277 } // namespace atf
    278 
    279 #endif // !defined(_ATF_CXX_PROCESS_HPP_)
    280