2 // Automated Testing Framework (atf)
4 // Copyright (c) 2008 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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.
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.
33 #include "../../atf-c/error.h"
35 #include "../../atf-c/detail/process.h"
40 #include "exceptions.hpp"
41 #include "process.hpp"
44 namespace detail
= atf::process::detail
;
45 namespace impl
= atf::process
;
46 #define IMPL_NAME "atf::process"
48 // ------------------------------------------------------------------------
49 // Auxiliary functions.
50 // ------------------------------------------------------------------------
53 atf::auto_array
< const char* >
54 collection_to_argv(const C
& c
)
56 atf::auto_array
< const char* > argv(new const char*[c
.size() + 1]);
59 for (typename
C::const_iterator iter
= c
.begin(); iter
!= c
.end();
61 argv
[pos
] = (*iter
).c_str();
72 argv_to_collection(const char* const* argv
)
76 for (const char* const* iter
= argv
; *iter
!= NULL
; iter
++)
77 c
.push_back(std::string(*iter
));
82 // ------------------------------------------------------------------------
83 // The "argv_array" type.
84 // ------------------------------------------------------------------------
86 impl::argv_array::argv_array(void) :
87 m_exec_argv(collection_to_argv(m_args
))
91 impl::argv_array::argv_array(const char* arg1
, ...)
93 m_args
.push_back(arg1
);
100 while ((nextarg
= va_arg(ap
, const char*)) != NULL
)
101 m_args
.push_back(nextarg
);
105 ctor_init_exec_argv();
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
))
114 impl::argv_array::argv_array(const argv_array
& a
) :
116 m_exec_argv(collection_to_argv(m_args
))
121 impl::argv_array::ctor_init_exec_argv(void)
123 m_exec_argv
= collection_to_argv(m_args
);
127 impl::argv_array::exec_argv(void)
130 return m_exec_argv
.get();
133 impl::argv_array::size_type
134 impl::argv_array::size(void)
137 return m_args
.size();
141 impl::argv_array::operator[](int idx
)
144 return m_args
[idx
].c_str();
147 impl::argv_array::const_iterator
148 impl::argv_array::begin(void)
151 return m_args
.begin();
154 impl::argv_array::const_iterator
155 impl::argv_array::end(void)
162 impl::argv_array::operator=(const argv_array
& a
)
166 m_exec_argv
= collection_to_argv(m_args
);
171 // ------------------------------------------------------------------------
172 // The "stream" types.
173 // ------------------------------------------------------------------------
175 impl::basic_stream::basic_stream(void) :
180 impl::basic_stream::~basic_stream(void)
183 atf_process_stream_fini(&m_sb
);
186 const atf_process_stream_t
*
187 impl::basic_stream::get_sb(void)
194 impl::stream_capture::stream_capture(void)
196 atf_error_t err
= atf_process_stream_init_capture(&m_sb
);
197 if (atf_is_error(err
))
198 throw_atf_error(err
);
202 impl::stream_connect::stream_connect(const int src_fd
, const int tgt_fd
)
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
);
210 impl::stream_inherit::stream_inherit(void)
212 atf_error_t err
= atf_process_stream_init_inherit(&m_sb
);
213 if (atf_is_error(err
))
214 throw_atf_error(err
);
218 impl::stream_redirect_fd::stream_redirect_fd(const int fd
)
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
);
226 impl::stream_redirect_path::stream_redirect_path(const fs::path
& p
)
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
);
234 // ------------------------------------------------------------------------
235 // The "status" type.
236 // ------------------------------------------------------------------------
238 impl::status::status(atf_process_status_t
& s
) :
243 impl::status::~status(void)
245 atf_process_status_fini(&m_status
);
249 impl::status::exited(void)
252 return atf_process_status_exited(&m_status
);
256 impl::status::exitstatus(void)
259 return atf_process_status_exitstatus(&m_status
);
263 impl::status::signaled(void)
266 return atf_process_status_signaled(&m_status
);
270 impl::status::termsig(void)
273 return atf_process_status_termsig(&m_status
);
277 impl::status::coredump(void)
280 return atf_process_status_coredump(&m_status
);
283 // ------------------------------------------------------------------------
285 // ------------------------------------------------------------------------
287 impl::child::child(atf_process_child_t
& c
) :
293 impl::child::~child(void)
296 ::kill(atf_process_child_pid(&m_child
), SIGTERM
);
298 atf_process_status_t s
;
299 #if defined(__minix) && !defined(NDEBUG)
301 #endif /* defined(__minix) && !defined(NDEBUG) */
302 atf_process_child_wait(&m_child
, &s
);
303 INV(!atf_is_error(err
));
304 atf_process_status_fini(&s
);
309 impl::child::wait(void)
311 atf_process_status_t s
;
313 atf_error_t err
= atf_process_child_wait(&m_child
, &s
);
314 if (atf_is_error(err
))
315 throw_atf_error(err
);
322 impl::child::pid(void)
325 return atf_process_child_pid(&m_child
);
329 impl::child::stdout_fd(void)
331 return atf_process_child_stdout(&m_child
);
335 impl::child::stderr_fd(void)
337 return atf_process_child_stderr(&m_child
);
340 // ------------------------------------------------------------------------
342 // ------------------------------------------------------------------------
345 detail::flush_streams(void)
347 // This is a weird hack to ensure that the output of the parent process
348 // is flushed before executing a child which prevents, for example, the
349 // output of the atf-run hooks to appear before the output of atf-run
352 // TODO: This should only be executed when inheriting the stdout or
353 // stderr file descriptors. However, the flushing is specific to the
354 // iostreams, so we cannot do it from the C library where all the process
355 // logic is performed. Come up with a better design.