1 // Copyright (c) 2008 The NetBSD Foundation, Inc.
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
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.
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.
26 #include "atf-c++/detail/process.hpp"
31 #include "atf-c/detail/process.h"
32 #include "atf-c/error.h"
37 #include "atf-c++/detail/exceptions.hpp"
38 #include "atf-c++/detail/sanity.hpp"
40 namespace detail = atf::process::detail;
41 namespace impl = atf::process;
42 #define IMPL_NAME "atf::process"
44 // ------------------------------------------------------------------------
45 // Auxiliary functions.
46 // ------------------------------------------------------------------------
49 atf::auto_array< const char* >
50 collection_to_argv(const C& c)
52 atf::auto_array< const char* > argv(new const char*[c.size() + 1]);
55 for (typename C::const_iterator iter = c.begin(); iter != c.end();
57 argv[pos] = (*iter).c_str();
68 argv_to_collection(const char* const* argv)
72 for (const char* const* iter = argv; *iter != NULL; iter++)
73 c.push_back(std::string(*iter));
78 // ------------------------------------------------------------------------
79 // The "argv_array" type.
80 // ------------------------------------------------------------------------
82 impl::argv_array::argv_array(void) :
83 m_exec_argv(collection_to_argv(m_args))
87 impl::argv_array::argv_array(const char* arg1, ...)
89 m_args.push_back(arg1);
96 while ((nextarg = va_arg(ap, const char*)) != NULL)
97 m_args.push_back(nextarg);
101 ctor_init_exec_argv();
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))
110 impl::argv_array::argv_array(const argv_array& a) :
112 m_exec_argv(collection_to_argv(m_args))
117 impl::argv_array::ctor_init_exec_argv(void)
119 m_exec_argv = collection_to_argv(m_args);
123 impl::argv_array::exec_argv(void)
126 return m_exec_argv.get();
129 impl::argv_array::size_type
130 impl::argv_array::size(void)
133 return m_args.size();
137 impl::argv_array::operator[](int idx)
140 return m_args[idx].c_str();
143 impl::argv_array::const_iterator
144 impl::argv_array::begin(void)
147 return m_args.begin();
150 impl::argv_array::const_iterator
151 impl::argv_array::end(void)
158 impl::argv_array::operator=(const argv_array& a)
162 m_exec_argv = collection_to_argv(m_args);
167 // ------------------------------------------------------------------------
168 // The "stream" types.
169 // ------------------------------------------------------------------------
171 impl::basic_stream::basic_stream(void) :
176 impl::basic_stream::~basic_stream(void)
179 atf_process_stream_fini(&m_sb);
182 const atf_process_stream_t*
183 impl::basic_stream::get_sb(void)
190 impl::stream_capture::stream_capture(void)
192 atf_error_t err = atf_process_stream_init_capture(&m_sb);
193 if (atf_is_error(err))
194 throw_atf_error(err);
198 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
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);
206 impl::stream_inherit::stream_inherit(void)
208 atf_error_t err = atf_process_stream_init_inherit(&m_sb);
209 if (atf_is_error(err))
210 throw_atf_error(err);
214 impl::stream_redirect_fd::stream_redirect_fd(const int fd)
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);
222 impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
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);
230 // ------------------------------------------------------------------------
231 // The "status" type.
232 // ------------------------------------------------------------------------
234 impl::status::status(atf_process_status_t& s) :
239 impl::status::~status(void)
241 atf_process_status_fini(&m_status);
245 impl::status::exited(void)
248 return atf_process_status_exited(&m_status);
252 impl::status::exitstatus(void)
255 return atf_process_status_exitstatus(&m_status);
259 impl::status::signaled(void)
262 return atf_process_status_signaled(&m_status);
266 impl::status::termsig(void)
269 return atf_process_status_termsig(&m_status);
273 impl::status::coredump(void)
276 return atf_process_status_coredump(&m_status);
279 // ------------------------------------------------------------------------
281 // ------------------------------------------------------------------------
283 impl::child::child(atf_process_child_t& c) :
289 impl::child::~child(void)
292 ::kill(atf_process_child_pid(&m_child), SIGTERM);
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);
302 impl::child::wait(void)
304 atf_process_status_t s;
306 atf_error_t err = atf_process_child_wait(&m_child, &s);
307 if (atf_is_error(err))
308 throw_atf_error(err);
315 impl::child::pid(void)
318 return atf_process_child_pid(&m_child);
322 impl::child::stdout_fd(void)
324 return atf_process_child_stdout(&m_child);
328 impl::child::stderr_fd(void)
330 return atf_process_child_stderr(&m_child);
333 // ------------------------------------------------------------------------
335 // ------------------------------------------------------------------------
338 detail::flush_streams(void)
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.