1240116Smarcel// Copyright (c) 2008 The NetBSD Foundation, Inc.
2240116Smarcel// All rights reserved.
3240116Smarcel//
4240116Smarcel// Redistribution and use in source and binary forms, with or without
5240116Smarcel// modification, are permitted provided that the following conditions
6240116Smarcel// are met:
7240116Smarcel// 1. Redistributions of source code must retain the above copyright
8240116Smarcel//    notice, this list of conditions and the following disclaimer.
9240116Smarcel// 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel//    notice, this list of conditions and the following disclaimer in the
11240116Smarcel//    documentation and/or other materials provided with the distribution.
12240116Smarcel//
13240116Smarcel// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24240116Smarcel// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25240116Smarcel
26273929Sjmmv#include "atf-c++/detail/process.hpp"
27273929Sjmmv
28240116Smarcelextern "C" {
29240116Smarcel#include <signal.h>
30240116Smarcel
31273929Sjmmv#include "atf-c/detail/process.h"
32273929Sjmmv#include "atf-c/error.h"
33240116Smarcel}
34240116Smarcel
35240116Smarcel#include <iostream>
36240116Smarcel
37273929Sjmmv#include "atf-c++/detail/exceptions.hpp"
38273929Sjmmv#include "atf-c++/detail/sanity.hpp"
39240116Smarcel
40240116Smarcelnamespace detail = atf::process::detail;
41240116Smarcelnamespace impl = atf::process;
42240116Smarcel#define IMPL_NAME "atf::process"
43240116Smarcel
44240116Smarcel// ------------------------------------------------------------------------
45240116Smarcel// Auxiliary functions.
46240116Smarcel// ------------------------------------------------------------------------
47240116Smarcel
48240116Smarceltemplate< class C >
49258289Sjmmvatf::auto_array< const char* >
50240116Smarcelcollection_to_argv(const C& c)
51240116Smarcel{
52258289Sjmmv    atf::auto_array< const char* > argv(new const char*[c.size() + 1]);
53240116Smarcel
54240116Smarcel    std::size_t pos = 0;
55240116Smarcel    for (typename C::const_iterator iter = c.begin(); iter != c.end();
56240116Smarcel         iter++) {
57240116Smarcel        argv[pos] = (*iter).c_str();
58240116Smarcel        pos++;
59240116Smarcel    }
60240116Smarcel    INV(pos == c.size());
61240116Smarcel    argv[pos] = NULL;
62240116Smarcel
63240116Smarcel    return argv;
64240116Smarcel}
65240116Smarcel
66240116Smarceltemplate< class C >
67240116SmarcelC
68240116Smarcelargv_to_collection(const char* const* argv)
69240116Smarcel{
70240116Smarcel    C c;
71240116Smarcel
72240116Smarcel    for (const char* const* iter = argv; *iter != NULL; iter++)
73240116Smarcel        c.push_back(std::string(*iter));
74240116Smarcel
75240116Smarcel    return c;
76240116Smarcel}
77240116Smarcel
78240116Smarcel// ------------------------------------------------------------------------
79240116Smarcel// The "argv_array" type.
80240116Smarcel// ------------------------------------------------------------------------
81240116Smarcel
82240116Smarcelimpl::argv_array::argv_array(void) :
83240116Smarcel    m_exec_argv(collection_to_argv(m_args))
84240116Smarcel{
85240116Smarcel}
86240116Smarcel
87240116Smarcelimpl::argv_array::argv_array(const char* arg1, ...)
88240116Smarcel{
89240116Smarcel    m_args.push_back(arg1);
90240116Smarcel
91240116Smarcel    {
92240116Smarcel        va_list ap;
93240116Smarcel        const char* nextarg;
94240116Smarcel
95240116Smarcel        va_start(ap, arg1);
96240116Smarcel        while ((nextarg = va_arg(ap, const char*)) != NULL)
97240116Smarcel            m_args.push_back(nextarg);
98240116Smarcel        va_end(ap);
99240116Smarcel    }
100240116Smarcel
101240116Smarcel    ctor_init_exec_argv();
102240116Smarcel}
103240116Smarcel
104240116Smarcelimpl::argv_array::argv_array(const char* const* ca) :
105240116Smarcel    m_args(argv_to_collection< args_vector >(ca)),
106240116Smarcel    m_exec_argv(collection_to_argv(m_args))
107240116Smarcel{
108240116Smarcel}
109240116Smarcel
110240116Smarcelimpl::argv_array::argv_array(const argv_array& a) :
111240116Smarcel    m_args(a.m_args),
112240116Smarcel    m_exec_argv(collection_to_argv(m_args))
113240116Smarcel{
114240116Smarcel}
115240116Smarcel
116240116Smarcelvoid
117240116Smarcelimpl::argv_array::ctor_init_exec_argv(void)
118240116Smarcel{
119240116Smarcel    m_exec_argv = collection_to_argv(m_args);
120240116Smarcel}
121240116Smarcel
122240116Smarcelconst char* const*
123240116Smarcelimpl::argv_array::exec_argv(void)
124240116Smarcel    const
125240116Smarcel{
126240116Smarcel    return m_exec_argv.get();
127240116Smarcel}
128240116Smarcel
129240116Smarcelimpl::argv_array::size_type
130240116Smarcelimpl::argv_array::size(void)
131240116Smarcel    const
132240116Smarcel{
133240116Smarcel    return m_args.size();
134240116Smarcel}
135240116Smarcel
136240116Smarcelconst char*
137240116Smarcelimpl::argv_array::operator[](int idx)
138240116Smarcel    const
139240116Smarcel{
140240116Smarcel    return m_args[idx].c_str();
141240116Smarcel}
142240116Smarcel
143240116Smarcelimpl::argv_array::const_iterator
144240116Smarcelimpl::argv_array::begin(void)
145240116Smarcel    const
146240116Smarcel{
147240116Smarcel    return m_args.begin();
148240116Smarcel}
149240116Smarcel
150240116Smarcelimpl::argv_array::const_iterator
151240116Smarcelimpl::argv_array::end(void)
152240116Smarcel    const
153240116Smarcel{
154240116Smarcel    return m_args.end();
155240116Smarcel}
156240116Smarcel
157240116Smarcelimpl::argv_array&
158240116Smarcelimpl::argv_array::operator=(const argv_array& a)
159240116Smarcel{
160240116Smarcel    if (this != &a) {
161240116Smarcel        m_args = a.m_args;
162240116Smarcel        m_exec_argv = collection_to_argv(m_args);
163240116Smarcel    }
164240116Smarcel    return *this;
165240116Smarcel}
166240116Smarcel
167240116Smarcel// ------------------------------------------------------------------------
168240116Smarcel// The "stream" types.
169240116Smarcel// ------------------------------------------------------------------------
170240116Smarcel
171240116Smarcelimpl::basic_stream::basic_stream(void) :
172240116Smarcel    m_inited(false)
173240116Smarcel{
174240116Smarcel}
175240116Smarcel
176240116Smarcelimpl::basic_stream::~basic_stream(void)
177240116Smarcel{
178240116Smarcel    if (m_inited)
179240116Smarcel        atf_process_stream_fini(&m_sb);
180240116Smarcel}
181240116Smarcel
182240116Smarcelconst atf_process_stream_t*
183240116Smarcelimpl::basic_stream::get_sb(void)
184240116Smarcel    const
185240116Smarcel{
186240116Smarcel    INV(m_inited);
187240116Smarcel    return &m_sb;
188240116Smarcel}
189240116Smarcel
190240116Smarcelimpl::stream_capture::stream_capture(void)
191240116Smarcel{
192240116Smarcel    atf_error_t err = atf_process_stream_init_capture(&m_sb);
193240116Smarcel    if (atf_is_error(err))
194240116Smarcel        throw_atf_error(err);
195240116Smarcel    m_inited = true;
196240116Smarcel}
197240116Smarcel
198240116Smarcelimpl::stream_connect::stream_connect(const int src_fd, const int tgt_fd)
199240116Smarcel{
200240116Smarcel    atf_error_t err = atf_process_stream_init_connect(&m_sb, src_fd, tgt_fd);
201240116Smarcel    if (atf_is_error(err))
202240116Smarcel        throw_atf_error(err);
203240116Smarcel    m_inited = true;
204240116Smarcel}
205240116Smarcel
206240116Smarcelimpl::stream_inherit::stream_inherit(void)
207240116Smarcel{
208240116Smarcel    atf_error_t err = atf_process_stream_init_inherit(&m_sb);
209240116Smarcel    if (atf_is_error(err))
210240116Smarcel        throw_atf_error(err);
211240116Smarcel    m_inited = true;
212240116Smarcel}
213240116Smarcel
214240116Smarcelimpl::stream_redirect_fd::stream_redirect_fd(const int fd)
215240116Smarcel{
216240116Smarcel    atf_error_t err = atf_process_stream_init_redirect_fd(&m_sb, fd);
217240116Smarcel    if (atf_is_error(err))
218240116Smarcel        throw_atf_error(err);
219240116Smarcel    m_inited = true;
220240116Smarcel}
221240116Smarcel
222240116Smarcelimpl::stream_redirect_path::stream_redirect_path(const fs::path& p)
223240116Smarcel{
224240116Smarcel    atf_error_t err = atf_process_stream_init_redirect_path(&m_sb, p.c_path());
225240116Smarcel    if (atf_is_error(err))
226240116Smarcel        throw_atf_error(err);
227240116Smarcel    m_inited = true;
228240116Smarcel}
229240116Smarcel
230240116Smarcel// ------------------------------------------------------------------------
231240116Smarcel// The "status" type.
232240116Smarcel// ------------------------------------------------------------------------
233240116Smarcel
234240116Smarcelimpl::status::status(atf_process_status_t& s) :
235240116Smarcel    m_status(s)
236240116Smarcel{
237240116Smarcel}
238240116Smarcel
239240116Smarcelimpl::status::~status(void)
240240116Smarcel{
241240116Smarcel    atf_process_status_fini(&m_status);
242240116Smarcel}
243240116Smarcel
244240116Smarcelbool
245240116Smarcelimpl::status::exited(void)
246240116Smarcel    const
247240116Smarcel{
248240116Smarcel    return atf_process_status_exited(&m_status);
249240116Smarcel}
250240116Smarcel
251240116Smarcelint
252240116Smarcelimpl::status::exitstatus(void)
253240116Smarcel    const
254240116Smarcel{
255240116Smarcel    return atf_process_status_exitstatus(&m_status);
256240116Smarcel}
257240116Smarcel
258240116Smarcelbool
259240116Smarcelimpl::status::signaled(void)
260240116Smarcel    const
261240116Smarcel{
262240116Smarcel    return atf_process_status_signaled(&m_status);
263240116Smarcel}
264240116Smarcel
265240116Smarcelint
266240116Smarcelimpl::status::termsig(void)
267240116Smarcel    const
268240116Smarcel{
269240116Smarcel    return atf_process_status_termsig(&m_status);
270240116Smarcel}
271240116Smarcel
272240116Smarcelbool
273240116Smarcelimpl::status::coredump(void)
274240116Smarcel    const
275240116Smarcel{
276240116Smarcel    return atf_process_status_coredump(&m_status);
277240116Smarcel}
278240116Smarcel
279240116Smarcel// ------------------------------------------------------------------------
280240116Smarcel// The "child" type.
281240116Smarcel// ------------------------------------------------------------------------
282240116Smarcel
283240116Smarcelimpl::child::child(atf_process_child_t& c) :
284240116Smarcel    m_child(c),
285240116Smarcel    m_waited(false)
286240116Smarcel{
287240116Smarcel}
288240116Smarcel
289240116Smarcelimpl::child::~child(void)
290240116Smarcel{
291240116Smarcel    if (!m_waited) {
292240116Smarcel        ::kill(atf_process_child_pid(&m_child), SIGTERM);
293240116Smarcel
294240116Smarcel        atf_process_status_t s;
295240116Smarcel        atf_error_t err = atf_process_child_wait(&m_child, &s);
296240116Smarcel        INV(!atf_is_error(err));
297240116Smarcel        atf_process_status_fini(&s);
298240116Smarcel    }
299240116Smarcel}
300240116Smarcel
301240116Smarcelimpl::status
302240116Smarcelimpl::child::wait(void)
303240116Smarcel{
304240116Smarcel    atf_process_status_t s;
305240116Smarcel
306240116Smarcel    atf_error_t err = atf_process_child_wait(&m_child, &s);
307240116Smarcel    if (atf_is_error(err))
308240116Smarcel        throw_atf_error(err);
309240116Smarcel
310240116Smarcel    m_waited = true;
311240116Smarcel    return status(s);
312240116Smarcel}
313240116Smarcel
314240116Smarcelpid_t
315240116Smarcelimpl::child::pid(void)
316240116Smarcel    const
317240116Smarcel{
318240116Smarcel    return atf_process_child_pid(&m_child);
319240116Smarcel}
320240116Smarcel
321240116Smarcelint
322240116Smarcelimpl::child::stdout_fd(void)
323240116Smarcel{
324240116Smarcel    return atf_process_child_stdout(&m_child);
325240116Smarcel}
326240116Smarcel
327240116Smarcelint
328240116Smarcelimpl::child::stderr_fd(void)
329240116Smarcel{
330240116Smarcel    return atf_process_child_stderr(&m_child);
331240116Smarcel}
332240116Smarcel
333240116Smarcel// ------------------------------------------------------------------------
334240116Smarcel// Free functions.
335240116Smarcel// ------------------------------------------------------------------------
336240116Smarcel
337240116Smarcelvoid
338240116Smarceldetail::flush_streams(void)
339240116Smarcel{
340240116Smarcel    // TODO: This should only be executed when inheriting the stdout or
341240116Smarcel    // stderr file descriptors.  However, the flushing is specific to the
342240116Smarcel    // iostreams, so we cannot do it from the C library where all the process
343240116Smarcel    // logic is performed.  Come up with a better design.
344240116Smarcel    std::cout.flush();
345240116Smarcel    std::cerr.flush();
346240116Smarcel}
347