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