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 "exceptions.hpp" 45 #include "fs.hpp" 46 47 #include "../utils.hpp" 48 49 namespace atf { 50 namespace process { 51 52 class child; 53 class status; 54 55 // ------------------------------------------------------------------------ 56 // The "argv_array" type. 57 // ------------------------------------------------------------------------ 58 59 class argv_array { 60 typedef std::vector< std::string > args_vector; 61 args_vector m_args; 62 63 // TODO: This is immutable, so we should be able to use 64 // std::tr1::shared_array instead when it becomes widely available. 65 // The reason would be to remove all copy constructors and assignment 66 // operators from this class. 67 utils::auto_array< const char* > m_exec_argv; 68 void ctor_init_exec_argv(void); 69 70 public: 71 typedef args_vector::const_iterator const_iterator; 72 typedef args_vector::size_type size_type; 73 74 argv_array(void); 75 argv_array(const char*, ...); 76 explicit argv_array(const char* const*); 77 template< class C > explicit argv_array(const C&); 78 argv_array(const argv_array&); 79 80 const char* const* exec_argv(void) const; 81 size_type size(void) const; 82 const char* operator[](int) const; 83 84 const_iterator begin(void) const; 85 const_iterator end(void) const; 86 87 argv_array& operator=(const argv_array&); 88 }; 89 90 template< class C > 91 argv_array::argv_array(const C& c) 92 { 93 for (typename C::const_iterator iter = c.begin(); iter != c.end(); 94 iter++) 95 m_args.push_back(*iter); 96 ctor_init_exec_argv(); 97 } 98 99 // ------------------------------------------------------------------------ 100 // The "stream" types. 101 // ------------------------------------------------------------------------ 102 103 class basic_stream { 104 protected: 105 atf_process_stream_t m_sb; 106 bool m_inited; 107 108 const atf_process_stream_t* get_sb(void) const; 109 110 public: 111 basic_stream(void); 112 ~basic_stream(void); 113 }; 114 115 class stream_capture : basic_stream { 116 // Allow access to the getters. 117 template< class OutStream, class ErrStream > friend 118 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 119 template< class OutStream, class ErrStream > friend 120 status exec(const atf::fs::path&, const argv_array&, 121 const OutStream&, const ErrStream&, void (*)(void)); 122 123 public: 124 stream_capture(void); 125 }; 126 127 class stream_connect : basic_stream { 128 // Allow access to the getters. 129 template< class OutStream, class ErrStream > friend 130 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 131 template< class OutStream, class ErrStream > friend 132 status exec(const atf::fs::path&, const argv_array&, 133 const OutStream&, const ErrStream&, void (*)(void)); 134 135 public: 136 stream_connect(const int, const int); 137 }; 138 139 class stream_inherit : basic_stream { 140 // Allow access to the getters. 141 template< class OutStream, class ErrStream > friend 142 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 143 template< class OutStream, class ErrStream > friend 144 status exec(const atf::fs::path&, const argv_array&, 145 const OutStream&, const ErrStream&, void (*)(void)); 146 147 public: 148 stream_inherit(void); 149 }; 150 151 class stream_redirect_fd : basic_stream { 152 // Allow access to the getters. 153 template< class OutStream, class ErrStream > friend 154 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 155 template< class OutStream, class ErrStream > friend 156 status exec(const atf::fs::path&, const argv_array&, 157 const OutStream&, const ErrStream&, void (*)(void)); 158 159 public: 160 stream_redirect_fd(const int); 161 }; 162 163 class stream_redirect_path : basic_stream { 164 // Allow access to the getters. 165 template< class OutStream, class ErrStream > friend 166 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 167 template< class OutStream, class ErrStream > friend 168 status exec(const atf::fs::path&, const argv_array&, 169 const OutStream&, const ErrStream&, void (*)(void)); 170 171 public: 172 stream_redirect_path(const fs::path&); 173 }; 174 175 // ------------------------------------------------------------------------ 176 // The "status" type. 177 // ------------------------------------------------------------------------ 178 179 class status { 180 atf_process_status_t m_status; 181 182 friend class child; 183 template< class OutStream, class ErrStream > friend 184 status exec(const atf::fs::path&, const argv_array&, 185 const OutStream&, const ErrStream&, void (*)(void)); 186 187 status(atf_process_status_t&); 188 189 public: 190 ~status(void); 191 192 bool exited(void) const; 193 int exitstatus(void) const; 194 195 bool signaled(void) const; 196 int termsig(void) const; 197 bool coredump(void) const; 198 }; 199 200 // ------------------------------------------------------------------------ 201 // The "child" type. 202 // ------------------------------------------------------------------------ 203 204 class child { 205 atf_process_child_t m_child; 206 bool m_waited; 207 208 template< class OutStream, class ErrStream > friend 209 child fork(void (*)(void*), const OutStream&, const ErrStream&, void*); 210 211 child(atf_process_child_t& c); 212 213 public: 214 ~child(void); 215 216 status wait(void); 217 218 pid_t pid(void) const; 219 int stdout_fd(void); 220 int stderr_fd(void); 221 }; 222 223 // ------------------------------------------------------------------------ 224 // Free functions. 225 // ------------------------------------------------------------------------ 226 227 namespace detail { 228 void flush_streams(void); 229 } // namespace detail 230 231 // TODO: The void* cookie can probably be templatized, thus also allowing 232 // const data structures. 233 template< class OutStream, class ErrStream > 234 child 235 fork(void (*start)(void*), const OutStream& outsb, 236 const ErrStream& errsb, void* v) 237 { 238 atf_process_child_t c; 239 240 detail::flush_streams(); 241 atf_error_t err = atf_process_fork(&c, start, outsb.get_sb(), 242 errsb.get_sb(), v); 243 if (atf_is_error(err)) 244 throw_atf_error(err); 245 246 return child(c); 247 } 248 249 template< class OutStream, class ErrStream > 250 status 251 exec(const atf::fs::path& prog, const argv_array& argv, 252 const OutStream& outsb, const ErrStream& errsb, 253 void (*prehook)(void)) 254 { 255 atf_process_status_t s; 256 257 detail::flush_streams(); 258 atf_error_t err = atf_process_exec_array(&s, prog.c_path(), 259 argv.exec_argv(), 260 outsb.get_sb(), 261 errsb.get_sb(), 262 prehook); 263 if (atf_is_error(err)) 264 throw_atf_error(err); 265 266 return status(s); 267 } 268 269 template< class OutStream, class ErrStream > 270 status 271 exec(const atf::fs::path& prog, const argv_array& argv, 272 const OutStream& outsb, const ErrStream& errsb) 273 { 274 return exec(prog, argv, outsb, errsb, NULL); 275 } 276 277 } // namespace process 278 } // namespace atf 279 280 #endif // !defined(_ATF_CXX_PROCESS_HPP_) 281