xref: /netbsd-src/external/bsd/atf/dist/atf-c++/detail/process.cpp (revision 0659fc670c1f32aa49ff1d817af283a035107f2d)
1895f502bSjmmv //
2895f502bSjmmv // Automated Testing Framework (atf)
3895f502bSjmmv //
4a551a20fSjmmv // Copyright (c) 2008 The NetBSD Foundation, Inc.
5895f502bSjmmv // All rights reserved.
6895f502bSjmmv //
7895f502bSjmmv // Redistribution and use in source and binary forms, with or without
8895f502bSjmmv // modification, are permitted provided that the following conditions
9895f502bSjmmv // are met:
10895f502bSjmmv // 1. Redistributions of source code must retain the above copyright
11895f502bSjmmv //    notice, this list of conditions and the following disclaimer.
12895f502bSjmmv // 2. Redistributions in binary form must reproduce the above copyright
13895f502bSjmmv //    notice, this list of conditions and the following disclaimer in the
14895f502bSjmmv //    documentation and/or other materials provided with the distribution.
15895f502bSjmmv //
16895f502bSjmmv // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17895f502bSjmmv // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18895f502bSjmmv // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19895f502bSjmmv // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20895f502bSjmmv // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21895f502bSjmmv // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22895f502bSjmmv // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23895f502bSjmmv // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24895f502bSjmmv // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25895f502bSjmmv // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26895f502bSjmmv // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27895f502bSjmmv // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28895f502bSjmmv //
29895f502bSjmmv 
30895f502bSjmmv extern "C" {
31895f502bSjmmv #include <signal.h>
32895f502bSjmmv 
33895f502bSjmmv #include "../../atf-c/error.h"
34895f502bSjmmv 
35895f502bSjmmv #include "../../atf-c/detail/process.h"
36895f502bSjmmv }
37895f502bSjmmv 
38895f502bSjmmv #include <iostream>
39895f502bSjmmv 
40895f502bSjmmv #include "exceptions.hpp"
41895f502bSjmmv #include "process.hpp"
42895f502bSjmmv #include "sanity.hpp"
43895f502bSjmmv 
44895f502bSjmmv namespace detail = atf::process::detail;
45895f502bSjmmv namespace impl = atf::process;
46895f502bSjmmv #define IMPL_NAME "atf::process"
47895f502bSjmmv 
48895f502bSjmmv // ------------------------------------------------------------------------
49895f502bSjmmv // Auxiliary functions.
50895f502bSjmmv // ------------------------------------------------------------------------
51895f502bSjmmv 
52895f502bSjmmv template< class C >
53*0659fc67Sjmmv atf::auto_array< const char* >
collection_to_argv(const C & c)54895f502bSjmmv collection_to_argv(const C& c)
55895f502bSjmmv {
56*0659fc67Sjmmv     atf::auto_array< const char* > argv(new const char*[c.size() + 1]);
57895f502bSjmmv 
58895f502bSjmmv     std::size_t pos = 0;
59895f502bSjmmv     for (typename C::const_iterator iter = c.begin(); iter != c.end();
60895f502bSjmmv          iter++) {
61895f502bSjmmv         argv[pos] = (*iter).c_str();
62895f502bSjmmv         pos++;
63895f502bSjmmv     }
64895f502bSjmmv     INV(pos == c.size());
65895f502bSjmmv     argv[pos] = NULL;
66895f502bSjmmv 
67895f502bSjmmv     return argv;
68895f502bSjmmv }
69895f502bSjmmv 
70895f502bSjmmv template< class C >
71895f502bSjmmv C
argv_to_collection(const char * const * argv)72895f502bSjmmv argv_to_collection(const char* const* argv)
73895f502bSjmmv {
74895f502bSjmmv     C c;
75895f502bSjmmv 
76895f502bSjmmv     for (const char* const* iter = argv; *iter != NULL; iter++)
77895f502bSjmmv         c.push_back(std::string(*iter));
78895f502bSjmmv 
79895f502bSjmmv     return c;
80895f502bSjmmv }
81895f502bSjmmv 
82895f502bSjmmv // ------------------------------------------------------------------------
83895f502bSjmmv // The "argv_array" type.
84895f502bSjmmv // ------------------------------------------------------------------------
85895f502bSjmmv 
argv_array(void)86895f502bSjmmv impl::argv_array::argv_array(void) :
87895f502bSjmmv     m_exec_argv(collection_to_argv(m_args))
88895f502bSjmmv {
89895f502bSjmmv }
90895f502bSjmmv 
argv_array(const char * arg1,...)91895f502bSjmmv impl::argv_array::argv_array(const char* arg1, ...)
92895f502bSjmmv {
93895f502bSjmmv     m_args.push_back(arg1);
94895f502bSjmmv 
95895f502bSjmmv     {
96895f502bSjmmv         va_list ap;
97895f502bSjmmv         const char* nextarg;
98895f502bSjmmv 
99895f502bSjmmv         va_start(ap, arg1);
100895f502bSjmmv         while ((nextarg = va_arg(ap, const char*)) != NULL)
101895f502bSjmmv             m_args.push_back(nextarg);
102895f502bSjmmv         va_end(ap);
103895f502bSjmmv     }
104895f502bSjmmv 
105895f502bSjmmv     ctor_init_exec_argv();
106895f502bSjmmv }
107895f502bSjmmv 
argv_array(const char * const * ca)108895f502bSjmmv impl::argv_array::argv_array(const char* const* ca) :
109895f502bSjmmv     m_args(argv_to_collection< args_vector >(ca)),
110895f502bSjmmv     m_exec_argv(collection_to_argv(m_args))
111895f502bSjmmv {
112895f502bSjmmv }
113895f502bSjmmv 
argv_array(const argv_array & a)114895f502bSjmmv impl::argv_array::argv_array(const argv_array& a) :
115895f502bSjmmv     m_args(a.m_args),
116895f502bSjmmv     m_exec_argv(collection_to_argv(m_args))
117895f502bSjmmv {
118895f502bSjmmv }
119895f502bSjmmv 
120895f502bSjmmv void
ctor_init_exec_argv(void)121895f502bSjmmv impl::argv_array::ctor_init_exec_argv(void)
122895f502bSjmmv {
123895f502bSjmmv     m_exec_argv = collection_to_argv(m_args);
124895f502bSjmmv }
125895f502bSjmmv 
126895f502bSjmmv const char* const*
exec_argv(void) const127895f502bSjmmv impl::argv_array::exec_argv(void)
128895f502bSjmmv     const
129895f502bSjmmv {
130895f502bSjmmv     return m_exec_argv.get();
131895f502bSjmmv }
132895f502bSjmmv 
133895f502bSjmmv impl::argv_array::size_type
size(void) const134895f502bSjmmv impl::argv_array::size(void)
135895f502bSjmmv     const
136895f502bSjmmv {
137895f502bSjmmv     return m_args.size();
138895f502bSjmmv }
139895f502bSjmmv 
140895f502bSjmmv const char*
operator [](int idx) const141895f502bSjmmv impl::argv_array::operator[](int idx)
142895f502bSjmmv     const
143895f502bSjmmv {
144895f502bSjmmv     return m_args[idx].c_str();
145895f502bSjmmv }
146895f502bSjmmv 
147895f502bSjmmv impl::argv_array::const_iterator
begin(void) const148895f502bSjmmv impl::argv_array::begin(void)
149895f502bSjmmv     const
150895f502bSjmmv {
151895f502bSjmmv     return m_args.begin();
152895f502bSjmmv }
153895f502bSjmmv 
154895f502bSjmmv impl::argv_array::const_iterator
end(void) const155895f502bSjmmv impl::argv_array::end(void)
156895f502bSjmmv     const
157895f502bSjmmv {
158895f502bSjmmv     return m_args.end();
159895f502bSjmmv }
160895f502bSjmmv 
161895f502bSjmmv impl::argv_array&
operator =(const argv_array & a)162895f502bSjmmv impl::argv_array::operator=(const argv_array& a)
163895f502bSjmmv {
164895f502bSjmmv     if (this != &a) {
165895f502bSjmmv         m_args = a.m_args;
166895f502bSjmmv         m_exec_argv = collection_to_argv(m_args);
167895f502bSjmmv     }
168895f502bSjmmv     return *this;
169895f502bSjmmv }
170895f502bSjmmv 
171895f502bSjmmv // ------------------------------------------------------------------------
172895f502bSjmmv // The "stream" types.
173895f502bSjmmv // ------------------------------------------------------------------------
174895f502bSjmmv 
basic_stream(void)175895f502bSjmmv impl::basic_stream::basic_stream(void) :
176895f502bSjmmv     m_inited(false)
177895f502bSjmmv {
178895f502bSjmmv }
179895f502bSjmmv 
~basic_stream(void)180895f502bSjmmv impl::basic_stream::~basic_stream(void)
181895f502bSjmmv {
182895f502bSjmmv     if (m_inited)
183895f502bSjmmv         atf_process_stream_fini(&m_sb);
184895f502bSjmmv }
185895f502bSjmmv 
186895f502bSjmmv const atf_process_stream_t*
get_sb(void) const187895f502bSjmmv impl::basic_stream::get_sb(void)
188895f502bSjmmv     const
189895f502bSjmmv {
190895f502bSjmmv     INV(m_inited);
191895f502bSjmmv     return &m_sb;
192895f502bSjmmv }
193895f502bSjmmv 
stream_capture(void)194895f502bSjmmv impl::stream_capture::stream_capture(void)
195895f502bSjmmv {
196895f502bSjmmv     atf_error_t err = atf_process_stream_init_capture(&m_sb);
197895f502bSjmmv     if (atf_is_error(err))
198895f502bSjmmv         throw_atf_error(err);
199895f502bSjmmv     m_inited = true;
200895f502bSjmmv }
201895f502bSjmmv 
stream_connect(const int src_fd,const int tgt_fd)202895f502bSjmmv impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
203895f502bSjmmv {
204895f502bSjmmv     atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
205895f502bSjmmv     if (atf_is_error(err))
206895f502bSjmmv         throw_atf_error(err);
207895f502bSjmmv     m_inited = true;
208895f502bSjmmv }
209895f502bSjmmv 
stream_inherit(void)210895f502bSjmmv impl::stream_inherit::stream_inherit(void)
211895f502bSjmmv {
212895f502bSjmmv     atf_error_t err = atf_process_stream_init_inherit(&m_sb);
213895f502bSjmmv     if (atf_is_error(err))
214895f502bSjmmv         throw_atf_error(err);
215895f502bSjmmv     m_inited = true;
216895f502bSjmmv }
217895f502bSjmmv 
stream_redirect_fd(const int fd)218895f502bSjmmv impl::stream_redirect_fd::stream_redirect_fd(const int fd)
219895f502bSjmmv {
220895f502bSjmmv     atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
221895f502bSjmmv     if (atf_is_error(err))
222895f502bSjmmv         throw_atf_error(err);
223895f502bSjmmv     m_inited = true;
224895f502bSjmmv }
225895f502bSjmmv 
stream_redirect_path(const fs::path & p)226895f502bSjmmv impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
227895f502bSjmmv {
228895f502bSjmmv     atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
229895f502bSjmmv     if (atf_is_error(err))
230895f502bSjmmv         throw_atf_error(err);
231895f502bSjmmv     m_inited = true;
232895f502bSjmmv }
233895f502bSjmmv 
234895f502bSjmmv // ------------------------------------------------------------------------
235895f502bSjmmv // The "status" type.
236895f502bSjmmv // ------------------------------------------------------------------------
237895f502bSjmmv 
status(atf_process_status_t & s)238895f502bSjmmv impl::status::status(atf_process_status_t& s) :
239895f502bSjmmv     m_status(s)
240895f502bSjmmv {
241895f502bSjmmv }
242895f502bSjmmv 
~status(void)243895f502bSjmmv impl::status::~status(void)
244895f502bSjmmv {
245895f502bSjmmv     atf_process_status_fini(&m_status);
246895f502bSjmmv }
247895f502bSjmmv 
248895f502bSjmmv bool
exited(void) const249895f502bSjmmv impl::status::exited(void)
250895f502bSjmmv     const
251895f502bSjmmv {
252895f502bSjmmv     return atf_process_status_exited(&m_status);
253895f502bSjmmv }
254895f502bSjmmv 
255895f502bSjmmv int
exitstatus(void) const256895f502bSjmmv impl::status::exitstatus(void)
257895f502bSjmmv     const
258895f502bSjmmv {
259895f502bSjmmv     return atf_process_status_exitstatus(&m_status);
260895f502bSjmmv }
261895f502bSjmmv 
262895f502bSjmmv bool
signaled(void) const263895f502bSjmmv impl::status::signaled(void)
264895f502bSjmmv     const
265895f502bSjmmv {
266895f502bSjmmv     return atf_process_status_signaled(&m_status);
267895f502bSjmmv }
268895f502bSjmmv 
269895f502bSjmmv int
termsig(void) const270895f502bSjmmv impl::status::termsig(void)
271895f502bSjmmv     const
272895f502bSjmmv {
273895f502bSjmmv     return atf_process_status_termsig(&m_status);
274895f502bSjmmv }
275895f502bSjmmv 
276895f502bSjmmv bool
coredump(void) const277895f502bSjmmv impl::status::coredump(void)
278895f502bSjmmv     const
279895f502bSjmmv {
280895f502bSjmmv     return atf_process_status_coredump(&m_status);
281895f502bSjmmv }
282895f502bSjmmv 
283895f502bSjmmv // ------------------------------------------------------------------------
284895f502bSjmmv // The "child" type.
285895f502bSjmmv // ------------------------------------------------------------------------
286895f502bSjmmv 
child(atf_process_child_t & c)287895f502bSjmmv impl::child::child(atf_process_child_t& c) :
288895f502bSjmmv     m_child(c),
289895f502bSjmmv     m_waited(false)
290895f502bSjmmv {
291895f502bSjmmv }
292895f502bSjmmv 
~child(void)293895f502bSjmmv impl::child::~child(void)
294895f502bSjmmv {
295895f502bSjmmv     if (!m_waited) {
296895f502bSjmmv         ::kill(atf_process_child_pid(&m_child), SIGTERM);
297895f502bSjmmv 
298895f502bSjmmv         atf_process_status_t s;
299895f502bSjmmv         atf_error_t err = atf_process_child_wait(&m_child, &s);
300895f502bSjmmv         INV(!atf_is_error(err));
301895f502bSjmmv         atf_process_status_fini(&s);
302895f502bSjmmv     }
303895f502bSjmmv }
304895f502bSjmmv 
305895f502bSjmmv impl::status
wait(void)306895f502bSjmmv impl::child::wait(void)
307895f502bSjmmv {
308895f502bSjmmv     atf_process_status_t s;
309895f502bSjmmv 
310895f502bSjmmv     atf_error_t err = atf_process_child_wait(&m_child, &s);
311895f502bSjmmv     if (atf_is_error(err))
312895f502bSjmmv         throw_atf_error(err);
313895f502bSjmmv 
314895f502bSjmmv     m_waited = true;
315895f502bSjmmv     return status(s);
316895f502bSjmmv }
317895f502bSjmmv 
318895f502bSjmmv pid_t
pid(void) const319895f502bSjmmv impl::child::pid(void)
320895f502bSjmmv     const
321895f502bSjmmv {
322895f502bSjmmv     return atf_process_child_pid(&m_child);
323895f502bSjmmv }
324895f502bSjmmv 
325895f502bSjmmv int
stdout_fd(void)326895f502bSjmmv impl::child::stdout_fd(void)
327895f502bSjmmv {
328895f502bSjmmv     return atf_process_child_stdout(&m_child);
329895f502bSjmmv }
330895f502bSjmmv 
331895f502bSjmmv int
stderr_fd(void)332895f502bSjmmv impl::child::stderr_fd(void)
333895f502bSjmmv {
334895f502bSjmmv     return atf_process_child_stderr(&m_child);
335895f502bSjmmv }
336895f502bSjmmv 
337895f502bSjmmv // ------------------------------------------------------------------------
338895f502bSjmmv // Free functions.
339895f502bSjmmv // ------------------------------------------------------------------------
340895f502bSjmmv 
341895f502bSjmmv void
flush_streams(void)342895f502bSjmmv detail::flush_streams(void)
343895f502bSjmmv {
344895f502bSjmmv     // This is a weird hack to ensure that the output of the parent process
345895f502bSjmmv     // is flushed before executing a child which prevents, for example, the
346895f502bSjmmv     // output of the atf-run hooks to appear before the output of atf-run
347895f502bSjmmv     // itself.
348895f502bSjmmv     //
349895f502bSjmmv     // TODO: This should only be executed when inheriting the stdout or
350895f502bSjmmv     // stderr file descriptors.  However, the flushing is specific to the
351895f502bSjmmv     // iostreams, so we cannot do it from the C library where all the process
352895f502bSjmmv     // logic is performed.  Come up with a better design.
353895f502bSjmmv     std::cout.flush();
354895f502bSjmmv     std::cerr.flush();
355895f502bSjmmv }
356