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