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