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