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 #include "atf-c++/detail/process.hpp" 27 28 extern "C" { 29 #include <signal.h> 30 31 #include "atf-c/detail/process.h" 32 #include "atf-c/error.h" 33 } 34 35 #include <iostream> 36 37 #include "atf-c++/detail/exceptions.hpp" 38 #include "atf-c++/detail/sanity.hpp" 39 40 namespace detail = atf::process::detail; 41 namespace impl = atf::process; 42 #define IMPL_NAME "atf::process" 43 44 // ------------------------------------------------------------------------ 45 // Auxiliary functions. 46 // ------------------------------------------------------------------------ 47 48 template< class C > 49 atf::auto_array< const char* > 50 collection_to_argv(const C& c) 51 { 52 atf::auto_array< const char* > argv(new const char*[c.size() + 1]); 53 54 std::size_t pos = 0; 55 for (typename C::const_iterator iter = c.begin(); iter != c.end(); 56 iter++) { 57 argv[pos] = (*iter).c_str(); 58 pos++; 59 } 60 INV(pos == c.size()); 61 argv[pos] = NULL; 62 63 return argv; 64 } 65 66 template< class C > 67 C 68 argv_to_collection(const char* const* argv) 69 { 70 C c; 71 72 for (const char* const* iter = argv; *iter != NULL; iter++) 73 c.push_back(std::string(*iter)); 74 75 return c; 76 } 77 78 // ------------------------------------------------------------------------ 79 // The "argv_array" type. 80 // ------------------------------------------------------------------------ 81 82 impl::argv_array::argv_array(void) : 83 m_exec_argv(collection_to_argv(m_args)) 84 { 85 } 86 87 impl::argv_array::argv_array(const char* arg1, ...) 88 { 89 m_args.push_back(arg1); 90 91 { 92 va_list ap; 93 const char* nextarg; 94 95 va_start(ap, arg1); 96 while ((nextarg = va_arg(ap, const char*)) != NULL) 97 m_args.push_back(nextarg); 98 va_end(ap); 99 } 100 101 ctor_init_exec_argv(); 102 } 103 104 impl::argv_array::argv_array(const char* const* ca) : 105 m_args(argv_to_collection< args_vector >(ca)), 106 m_exec_argv(collection_to_argv(m_args)) 107 { 108 } 109 110 impl::argv_array::argv_array(const argv_array& a) : 111 m_args(a.m_args), 112 m_exec_argv(collection_to_argv(m_args)) 113 { 114 } 115 116 void 117 impl::argv_array::ctor_init_exec_argv(void) 118 { 119 m_exec_argv = collection_to_argv(m_args); 120 } 121 122 const char* const* 123 impl::argv_array::exec_argv(void) 124 const 125 { 126 return m_exec_argv.get(); 127 } 128 129 impl::argv_array::size_type 130 impl::argv_array::size(void) 131 const 132 { 133 return m_args.size(); 134 } 135 136 const char* 137 impl::argv_array::operator[](int idx) 138 const 139 { 140 return m_args[idx].c_str(); 141 } 142 143 impl::argv_array::const_iterator 144 impl::argv_array::begin(void) 145 const 146 { 147 return m_args.begin(); 148 } 149 150 impl::argv_array::const_iterator 151 impl::argv_array::end(void) 152 const 153 { 154 return m_args.end(); 155 } 156 157 impl::argv_array& 158 impl::argv_array::operator=(const argv_array& a) 159 { 160 if (this != &a) { 161 m_args = a.m_args; 162 m_exec_argv = collection_to_argv(m_args); 163 } 164 return *this; 165 } 166 167 // ------------------------------------------------------------------------ 168 // The "stream" types. 169 // ------------------------------------------------------------------------ 170 171 impl::basic_stream::basic_stream(void) : 172 m_inited(false) 173 { 174 } 175 176 impl::basic_stream::~basic_stream(void) 177 { 178 if (m_inited) 179 atf_process_stream_fini(&m_sb); 180 } 181 182 const atf_process_stream_t* 183 impl::basic_stream::get_sb(void) 184 const 185 { 186 INV(m_inited); 187 return &m_sb; 188 } 189 190 impl::stream_capture::stream_capture(void) 191 { 192 atf_error_t err = atf_process_stream_init_capture(&m_sb); 193 if (atf_is_error(err)) 194 throw_atf_error(err); 195 m_inited = true; 196 } 197 198 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) 199 { 200 atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd); 201 if (atf_is_error(err)) 202 throw_atf_error(err); 203 m_inited = true; 204 } 205 206 impl::stream_inherit::stream_inherit(void) 207 { 208 atf_error_t err = atf_process_stream_init_inherit(&m_sb); 209 if (atf_is_error(err)) 210 throw_atf_error(err); 211 m_inited = true; 212 } 213 214 impl::stream_redirect_fd::stream_redirect_fd(const int fd) 215 { 216 atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd); 217 if (atf_is_error(err)) 218 throw_atf_error(err); 219 m_inited = true; 220 } 221 222 impl::stream_redirect_path::stream_redirect_path(const fs::path& p) 223 { 224 atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path()); 225 if (atf_is_error(err)) 226 throw_atf_error(err); 227 m_inited = true; 228 } 229 230 // ------------------------------------------------------------------------ 231 // The "status" type. 232 // ------------------------------------------------------------------------ 233 234 impl::status::status(atf_process_status_t& s) : 235 m_status(s) 236 { 237 } 238 239 impl::status::~status(void) 240 { 241 atf_process_status_fini(&m_status); 242 } 243 244 bool 245 impl::status::exited(void) 246 const 247 { 248 return atf_process_status_exited(&m_status); 249 } 250 251 int 252 impl::status::exitstatus(void) 253 const 254 { 255 return atf_process_status_exitstatus(&m_status); 256 } 257 258 bool 259 impl::status::signaled(void) 260 const 261 { 262 return atf_process_status_signaled(&m_status); 263 } 264 265 int 266 impl::status::termsig(void) 267 const 268 { 269 return atf_process_status_termsig(&m_status); 270 } 271 272 bool 273 impl::status::coredump(void) 274 const 275 { 276 return atf_process_status_coredump(&m_status); 277 } 278 279 // ------------------------------------------------------------------------ 280 // The "child" type. 281 // ------------------------------------------------------------------------ 282 283 impl::child::child(atf_process_child_t& c) : 284 m_child(c), 285 m_waited(false) 286 { 287 } 288 289 impl::child::~child(void) 290 { 291 if (!m_waited) { 292 ::kill(atf_process_child_pid(&m_child), SIGTERM); 293 294 atf_process_status_t s; 295 atf_error_t err = atf_process_child_wait(&m_child, &s); 296 INV(!atf_is_error(err)); 297 atf_process_status_fini(&s); 298 } 299 } 300 301 impl::status 302 impl::child::wait(void) 303 { 304 atf_process_status_t s; 305 306 atf_error_t err = atf_process_child_wait(&m_child, &s); 307 if (atf_is_error(err)) 308 throw_atf_error(err); 309 310 m_waited = true; 311 return status(s); 312 } 313 314 pid_t 315 impl::child::pid(void) 316 const 317 { 318 return atf_process_child_pid(&m_child); 319 } 320 321 int 322 impl::child::stdout_fd(void) 323 { 324 return atf_process_child_stdout(&m_child); 325 } 326 327 int 328 impl::child::stderr_fd(void) 329 { 330 return atf_process_child_stderr(&m_child); 331 } 332 333 // ------------------------------------------------------------------------ 334 // Free functions. 335 // ------------------------------------------------------------------------ 336 337 void 338 detail::flush_streams(void) 339 { 340 // TODO: This should only be executed when inheriting the stdout or 341 // stderr file descriptors. However, the flushing is specific to the 342 // iostreams, so we cannot do it from the C library where all the process 343 // logic is performed. Come up with a better design. 344 std::cout.flush(); 345 std::cerr.flush(); 346 } 347