xref: /freebsd/contrib/atf/atf-c++/detail/process.cpp (revision 8f0ea33f2bbf3a6aa80235f0a02fa5f2780c2b17)
1c243e490SMarcel Moolenaar // Copyright (c) 2008 The NetBSD Foundation, Inc.
2c243e490SMarcel Moolenaar // All rights reserved.
3c243e490SMarcel Moolenaar //
4c243e490SMarcel Moolenaar // Redistribution and use in source and binary forms, with or without
5c243e490SMarcel Moolenaar // modification, are permitted provided that the following conditions
6c243e490SMarcel Moolenaar // are met:
7c243e490SMarcel Moolenaar // 1. Redistributions of source code must retain the above copyright
8c243e490SMarcel Moolenaar //    notice, this list of conditions and the following disclaimer.
9c243e490SMarcel Moolenaar // 2. Redistributions in binary form must reproduce the above copyright
10c243e490SMarcel Moolenaar //    notice, this list of conditions and the following disclaimer in the
11c243e490SMarcel Moolenaar //    documentation and/or other materials provided with the distribution.
12c243e490SMarcel Moolenaar //
13c243e490SMarcel Moolenaar // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14c243e490SMarcel Moolenaar // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15c243e490SMarcel Moolenaar // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16c243e490SMarcel Moolenaar // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c243e490SMarcel Moolenaar // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18c243e490SMarcel Moolenaar // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c243e490SMarcel Moolenaar // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20c243e490SMarcel Moolenaar // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21c243e490SMarcel Moolenaar // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22c243e490SMarcel Moolenaar // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23c243e490SMarcel Moolenaar // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24c243e490SMarcel Moolenaar // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*0677dfd1SJulio Merino 
26*0677dfd1SJulio Merino #include "atf-c++/detail/process.hpp"
27c243e490SMarcel Moolenaar 
28c243e490SMarcel Moolenaar extern "C" {
29c243e490SMarcel Moolenaar #include <signal.h>
30c243e490SMarcel Moolenaar 
31*0677dfd1SJulio Merino #include "atf-c/detail/process.h"
32*0677dfd1SJulio Merino #include "atf-c/error.h"
33c243e490SMarcel Moolenaar }
34c243e490SMarcel Moolenaar 
35c243e490SMarcel Moolenaar #include <iostream>
36c243e490SMarcel Moolenaar 
37*0677dfd1SJulio Merino #include "atf-c++/detail/exceptions.hpp"
38*0677dfd1SJulio Merino #include "atf-c++/detail/sanity.hpp"
39c243e490SMarcel Moolenaar 
40c243e490SMarcel Moolenaar namespace detail = atf::process::detail;
41c243e490SMarcel Moolenaar namespace impl = atf::process;
42c243e490SMarcel Moolenaar #define IMPL_NAME "atf::process"
43c243e490SMarcel Moolenaar 
44c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
45c243e490SMarcel Moolenaar // Auxiliary functions.
46c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
47c243e490SMarcel Moolenaar 
48c243e490SMarcel Moolenaar template< class C >
49a18eacbeSJulio Merino atf::auto_array< const char* >
collection_to_argv(const C & c)50c243e490SMarcel Moolenaar collection_to_argv(const C& c)
51c243e490SMarcel Moolenaar {
52a18eacbeSJulio Merino     atf::auto_array< const char* > argv(new const char*[c.size() + 1]);
53c243e490SMarcel Moolenaar 
54c243e490SMarcel Moolenaar     std::size_t pos = 0;
55c243e490SMarcel Moolenaar     for (typename C::const_iterator iter = c.begin(); iter != c.end();
56c243e490SMarcel Moolenaar          iter++) {
57c243e490SMarcel Moolenaar         argv[pos] = (*iter).c_str();
58c243e490SMarcel Moolenaar         pos++;
59c243e490SMarcel Moolenaar     }
60c243e490SMarcel Moolenaar     INV(pos == c.size());
61c243e490SMarcel Moolenaar     argv[pos] = NULL;
62c243e490SMarcel Moolenaar 
63c243e490SMarcel Moolenaar     return argv;
64c243e490SMarcel Moolenaar }
65c243e490SMarcel Moolenaar 
66c243e490SMarcel Moolenaar template< class C >
67c243e490SMarcel Moolenaar C
argv_to_collection(const char * const * argv)68c243e490SMarcel Moolenaar argv_to_collection(const char* const* argv)
69c243e490SMarcel Moolenaar {
70c243e490SMarcel Moolenaar     C c;
71c243e490SMarcel Moolenaar 
72c243e490SMarcel Moolenaar     for (const char* const* iter = argv; *iter != NULL; iter++)
73c243e490SMarcel Moolenaar         c.push_back(std::string(*iter));
74c243e490SMarcel Moolenaar 
75c243e490SMarcel Moolenaar     return c;
76c243e490SMarcel Moolenaar }
77c243e490SMarcel Moolenaar 
78c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
79c243e490SMarcel Moolenaar // The "argv_array" type.
80c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
81c243e490SMarcel Moolenaar 
argv_array(void)82c243e490SMarcel Moolenaar impl::argv_array::argv_array(void) :
83c243e490SMarcel Moolenaar     m_exec_argv(collection_to_argv(m_args))
84c243e490SMarcel Moolenaar {
85c243e490SMarcel Moolenaar }
86c243e490SMarcel Moolenaar 
argv_array(const char * arg1,...)87c243e490SMarcel Moolenaar impl::argv_array::argv_array(const char* arg1, ...)
88c243e490SMarcel Moolenaar {
89c243e490SMarcel Moolenaar     m_args.push_back(arg1);
90c243e490SMarcel Moolenaar 
91c243e490SMarcel Moolenaar     {
92c243e490SMarcel Moolenaar         va_list ap;
93c243e490SMarcel Moolenaar         const char* nextarg;
94c243e490SMarcel Moolenaar 
95c243e490SMarcel Moolenaar         va_start(ap, arg1);
96c243e490SMarcel Moolenaar         while ((nextarg = va_arg(ap, const char*)) != NULL)
97c243e490SMarcel Moolenaar             m_args.push_back(nextarg);
98c243e490SMarcel Moolenaar         va_end(ap);
99c243e490SMarcel Moolenaar     }
100c243e490SMarcel Moolenaar 
101c243e490SMarcel Moolenaar     ctor_init_exec_argv();
102c243e490SMarcel Moolenaar }
103c243e490SMarcel Moolenaar 
argv_array(const char * const * ca)104c243e490SMarcel Moolenaar impl::argv_array::argv_array(const char* const* ca) :
105c243e490SMarcel Moolenaar     m_args(argv_to_collection< args_vector >(ca)),
106c243e490SMarcel Moolenaar     m_exec_argv(collection_to_argv(m_args))
107c243e490SMarcel Moolenaar {
108c243e490SMarcel Moolenaar }
109c243e490SMarcel Moolenaar 
argv_array(const argv_array & a)110c243e490SMarcel Moolenaar impl::argv_array::argv_array(const argv_array& a) :
111c243e490SMarcel Moolenaar     m_args(a.m_args),
112c243e490SMarcel Moolenaar     m_exec_argv(collection_to_argv(m_args))
113c243e490SMarcel Moolenaar {
114c243e490SMarcel Moolenaar }
115c243e490SMarcel Moolenaar 
116c243e490SMarcel Moolenaar void
ctor_init_exec_argv(void)117c243e490SMarcel Moolenaar impl::argv_array::ctor_init_exec_argv(void)
118c243e490SMarcel Moolenaar {
119c243e490SMarcel Moolenaar     m_exec_argv = collection_to_argv(m_args);
120c243e490SMarcel Moolenaar }
121c243e490SMarcel Moolenaar 
122c243e490SMarcel Moolenaar const char* const*
exec_argv(void) const123c243e490SMarcel Moolenaar impl::argv_array::exec_argv(void)
124c243e490SMarcel Moolenaar     const
125c243e490SMarcel Moolenaar {
126c243e490SMarcel Moolenaar     return m_exec_argv.get();
127c243e490SMarcel Moolenaar }
128c243e490SMarcel Moolenaar 
129c243e490SMarcel Moolenaar impl::argv_array::size_type
size(void) const130c243e490SMarcel Moolenaar impl::argv_array::size(void)
131c243e490SMarcel Moolenaar     const
132c243e490SMarcel Moolenaar {
133c243e490SMarcel Moolenaar     return m_args.size();
134c243e490SMarcel Moolenaar }
135c243e490SMarcel Moolenaar 
136c243e490SMarcel Moolenaar const char*
operator [](int idx) const137c243e490SMarcel Moolenaar impl::argv_array::operator[](int idx)
138c243e490SMarcel Moolenaar     const
139c243e490SMarcel Moolenaar {
140c243e490SMarcel Moolenaar     return m_args[idx].c_str();
141c243e490SMarcel Moolenaar }
142c243e490SMarcel Moolenaar 
143c243e490SMarcel Moolenaar impl::argv_array::const_iterator
begin(void) const144c243e490SMarcel Moolenaar impl::argv_array::begin(void)
145c243e490SMarcel Moolenaar     const
146c243e490SMarcel Moolenaar {
147c243e490SMarcel Moolenaar     return m_args.begin();
148c243e490SMarcel Moolenaar }
149c243e490SMarcel Moolenaar 
150c243e490SMarcel Moolenaar impl::argv_array::const_iterator
end(void) const151c243e490SMarcel Moolenaar impl::argv_array::end(void)
152c243e490SMarcel Moolenaar     const
153c243e490SMarcel Moolenaar {
154c243e490SMarcel Moolenaar     return m_args.end();
155c243e490SMarcel Moolenaar }
156c243e490SMarcel Moolenaar 
157c243e490SMarcel Moolenaar impl::argv_array&
operator =(const argv_array & a)158c243e490SMarcel Moolenaar impl::argv_array::operator=(const argv_array& a)
159c243e490SMarcel Moolenaar {
160c243e490SMarcel Moolenaar     if (this != &a) {
161c243e490SMarcel Moolenaar         m_args = a.m_args;
162c243e490SMarcel Moolenaar         m_exec_argv = collection_to_argv(m_args);
163c243e490SMarcel Moolenaar     }
164c243e490SMarcel Moolenaar     return *this;
165c243e490SMarcel Moolenaar }
166c243e490SMarcel Moolenaar 
167c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
168c243e490SMarcel Moolenaar // The "stream" types.
169c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
170c243e490SMarcel Moolenaar 
basic_stream(void)171c243e490SMarcel Moolenaar impl::basic_stream::basic_stream(void) :
172c243e490SMarcel Moolenaar     m_inited(false)
173c243e490SMarcel Moolenaar {
174c243e490SMarcel Moolenaar }
175c243e490SMarcel Moolenaar 
~basic_stream(void)176c243e490SMarcel Moolenaar impl::basic_stream::~basic_stream(void)
177c243e490SMarcel Moolenaar {
178c243e490SMarcel Moolenaar     if (m_inited)
179c243e490SMarcel Moolenaar         atf_process_stream_fini(&m_sb);
180c243e490SMarcel Moolenaar }
181c243e490SMarcel Moolenaar 
182c243e490SMarcel Moolenaar const atf_process_stream_t*
get_sb(void) const183c243e490SMarcel Moolenaar impl::basic_stream::get_sb(void)
184c243e490SMarcel Moolenaar     const
185c243e490SMarcel Moolenaar {
186c243e490SMarcel Moolenaar     INV(m_inited);
187c243e490SMarcel Moolenaar     return &m_sb;
188c243e490SMarcel Moolenaar }
189c243e490SMarcel Moolenaar 
stream_capture(void)190c243e490SMarcel Moolenaar impl::stream_capture::stream_capture(void)
191c243e490SMarcel Moolenaar {
192c243e490SMarcel Moolenaar     atf_error_t err = atf_process_stream_init_capture(&m_sb);
193c243e490SMarcel Moolenaar     if (atf_is_error(err))
194c243e490SMarcel Moolenaar         throw_atf_error(err);
195c243e490SMarcel Moolenaar     m_inited = true;
196c243e490SMarcel Moolenaar }
197c243e490SMarcel Moolenaar 
stream_connect(const int src_fd,const int tgt_fd)198c243e490SMarcel Moolenaar impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
199c243e490SMarcel Moolenaar {
200c243e490SMarcel Moolenaar     atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
201c243e490SMarcel Moolenaar     if (atf_is_error(err))
202c243e490SMarcel Moolenaar         throw_atf_error(err);
203c243e490SMarcel Moolenaar     m_inited = true;
204c243e490SMarcel Moolenaar }
205c243e490SMarcel Moolenaar 
stream_inherit(void)206c243e490SMarcel Moolenaar impl::stream_inherit::stream_inherit(void)
207c243e490SMarcel Moolenaar {
208c243e490SMarcel Moolenaar     atf_error_t err = atf_process_stream_init_inherit(&m_sb);
209c243e490SMarcel Moolenaar     if (atf_is_error(err))
210c243e490SMarcel Moolenaar         throw_atf_error(err);
211c243e490SMarcel Moolenaar     m_inited = true;
212c243e490SMarcel Moolenaar }
213c243e490SMarcel Moolenaar 
stream_redirect_fd(const int fd)214c243e490SMarcel Moolenaar impl::stream_redirect_fd::stream_redirect_fd(const int fd)
215c243e490SMarcel Moolenaar {
216c243e490SMarcel Moolenaar     atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
217c243e490SMarcel Moolenaar     if (atf_is_error(err))
218c243e490SMarcel Moolenaar         throw_atf_error(err);
219c243e490SMarcel Moolenaar     m_inited = true;
220c243e490SMarcel Moolenaar }
221c243e490SMarcel Moolenaar 
stream_redirect_path(const fs::path & p)222c243e490SMarcel Moolenaar impl::stream_redirect_path::stream_redirect_path(const fs::path& p)
223c243e490SMarcel Moolenaar {
224c243e490SMarcel Moolenaar     atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
225c243e490SMarcel Moolenaar     if (atf_is_error(err))
226c243e490SMarcel Moolenaar         throw_atf_error(err);
227c243e490SMarcel Moolenaar     m_inited = true;
228c243e490SMarcel Moolenaar }
229c243e490SMarcel Moolenaar 
230c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
231c243e490SMarcel Moolenaar // The "status" type.
232c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
233c243e490SMarcel Moolenaar 
status(atf_process_status_t & s)234c243e490SMarcel Moolenaar impl::status::status(atf_process_status_t& s) :
235c243e490SMarcel Moolenaar     m_status(s)
236c243e490SMarcel Moolenaar {
237c243e490SMarcel Moolenaar }
238c243e490SMarcel Moolenaar 
~status(void)239c243e490SMarcel Moolenaar impl::status::~status(void)
240c243e490SMarcel Moolenaar {
241c243e490SMarcel Moolenaar     atf_process_status_fini(&m_status);
242c243e490SMarcel Moolenaar }
243c243e490SMarcel Moolenaar 
244c243e490SMarcel Moolenaar bool
exited(void) const245c243e490SMarcel Moolenaar impl::status::exited(void)
246c243e490SMarcel Moolenaar     const
247c243e490SMarcel Moolenaar {
248c243e490SMarcel Moolenaar     return atf_process_status_exited(&m_status);
249c243e490SMarcel Moolenaar }
250c243e490SMarcel Moolenaar 
251c243e490SMarcel Moolenaar int
exitstatus(void) const252c243e490SMarcel Moolenaar impl::status::exitstatus(void)
253c243e490SMarcel Moolenaar     const
254c243e490SMarcel Moolenaar {
255c243e490SMarcel Moolenaar     return atf_process_status_exitstatus(&m_status);
256c243e490SMarcel Moolenaar }
257c243e490SMarcel Moolenaar 
258c243e490SMarcel Moolenaar bool
signaled(void) const259c243e490SMarcel Moolenaar impl::status::signaled(void)
260c243e490SMarcel Moolenaar     const
261c243e490SMarcel Moolenaar {
262c243e490SMarcel Moolenaar     return atf_process_status_signaled(&m_status);
263c243e490SMarcel Moolenaar }
264c243e490SMarcel Moolenaar 
265c243e490SMarcel Moolenaar int
termsig(void) const266c243e490SMarcel Moolenaar impl::status::termsig(void)
267c243e490SMarcel Moolenaar     const
268c243e490SMarcel Moolenaar {
269c243e490SMarcel Moolenaar     return atf_process_status_termsig(&m_status);
270c243e490SMarcel Moolenaar }
271c243e490SMarcel Moolenaar 
272c243e490SMarcel Moolenaar bool
coredump(void) const273c243e490SMarcel Moolenaar impl::status::coredump(void)
274c243e490SMarcel Moolenaar     const
275c243e490SMarcel Moolenaar {
276c243e490SMarcel Moolenaar     return atf_process_status_coredump(&m_status);
277c243e490SMarcel Moolenaar }
278c243e490SMarcel Moolenaar 
279c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
280c243e490SMarcel Moolenaar // The "child" type.
281c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
282c243e490SMarcel Moolenaar 
child(atf_process_child_t & c)283c243e490SMarcel Moolenaar impl::child::child(atf_process_child_t& c) :
284c243e490SMarcel Moolenaar     m_child(c),
285c243e490SMarcel Moolenaar     m_waited(false)
286c243e490SMarcel Moolenaar {
287c243e490SMarcel Moolenaar }
288c243e490SMarcel Moolenaar 
~child(void)289c243e490SMarcel Moolenaar impl::child::~child(void)
290c243e490SMarcel Moolenaar {
291c243e490SMarcel Moolenaar     if (!m_waited) {
292c243e490SMarcel Moolenaar         ::kill(atf_process_child_pid(&m_child), SIGTERM);
293c243e490SMarcel Moolenaar 
294c243e490SMarcel Moolenaar         atf_process_status_t s;
295c243e490SMarcel Moolenaar         atf_error_t err = atf_process_child_wait(&m_child, &s);
296c243e490SMarcel Moolenaar         INV(!atf_is_error(err));
297c243e490SMarcel Moolenaar         atf_process_status_fini(&s);
298c243e490SMarcel Moolenaar     }
299c243e490SMarcel Moolenaar }
300c243e490SMarcel Moolenaar 
301c243e490SMarcel Moolenaar impl::status
wait(void)302c243e490SMarcel Moolenaar impl::child::wait(void)
303c243e490SMarcel Moolenaar {
304c243e490SMarcel Moolenaar     atf_process_status_t s;
305c243e490SMarcel Moolenaar 
306c243e490SMarcel Moolenaar     atf_error_t err = atf_process_child_wait(&m_child, &s);
307c243e490SMarcel Moolenaar     if (atf_is_error(err))
308c243e490SMarcel Moolenaar         throw_atf_error(err);
309c243e490SMarcel Moolenaar 
310c243e490SMarcel Moolenaar     m_waited = true;
311c243e490SMarcel Moolenaar     return status(s);
312c243e490SMarcel Moolenaar }
313c243e490SMarcel Moolenaar 
314c243e490SMarcel Moolenaar pid_t
pid(void) const315c243e490SMarcel Moolenaar impl::child::pid(void)
316c243e490SMarcel Moolenaar     const
317c243e490SMarcel Moolenaar {
318c243e490SMarcel Moolenaar     return atf_process_child_pid(&m_child);
319c243e490SMarcel Moolenaar }
320c243e490SMarcel Moolenaar 
321c243e490SMarcel Moolenaar int
stdout_fd(void)322c243e490SMarcel Moolenaar impl::child::stdout_fd(void)
323c243e490SMarcel Moolenaar {
324c243e490SMarcel Moolenaar     return atf_process_child_stdout(&m_child);
325c243e490SMarcel Moolenaar }
326c243e490SMarcel Moolenaar 
327c243e490SMarcel Moolenaar int
stderr_fd(void)328c243e490SMarcel Moolenaar impl::child::stderr_fd(void)
329c243e490SMarcel Moolenaar {
330c243e490SMarcel Moolenaar     return atf_process_child_stderr(&m_child);
331c243e490SMarcel Moolenaar }
332c243e490SMarcel Moolenaar 
333c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
334c243e490SMarcel Moolenaar // Free functions.
335c243e490SMarcel Moolenaar // ------------------------------------------------------------------------
336c243e490SMarcel Moolenaar 
337c243e490SMarcel Moolenaar void
flush_streams(void)338c243e490SMarcel Moolenaar detail::flush_streams(void)
339c243e490SMarcel Moolenaar {
340c243e490SMarcel Moolenaar     // TODO: This should only be executed when inheriting the stdout or
341c243e490SMarcel Moolenaar     // stderr file descriptors.  However, the flushing is specific to the
342c243e490SMarcel Moolenaar     // iostreams, so we cannot do it from the C library where all the process
343c243e490SMarcel Moolenaar     // logic is performed.  Come up with a better design.
344c243e490SMarcel Moolenaar     std::cout.flush();
345c243e490SMarcel Moolenaar     std::cerr.flush();
346c243e490SMarcel Moolenaar }
347