process.hpp revision 275988
1// Copyright (c) 2008 The NetBSD Foundation, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
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.
12//
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.
25
26#if !defined(ATF_CXX_DETAIL_PROCESS_HPP)
27#define ATF_CXX_DETAIL_PROCESS_HPP
28
29extern "C" {
30#include <sys/types.h>
31
32#include <atf-c/detail/process.h>
33#include <atf-c/error.h>
34}
35
36#include <string>
37#include <vector>
38
39#include <atf-c++/detail/auto_array.hpp>
40#include <atf-c++/detail/exceptions.hpp>
41#include <atf-c++/detail/fs.hpp>
42
43namespace atf {
44namespace process {
45
46class child;
47class status;
48
49// ------------------------------------------------------------------------
50// The "argv_array" type.
51// ------------------------------------------------------------------------
52
53class argv_array {
54    typedef std::vector< std::string > args_vector;
55    args_vector m_args;
56
57    // TODO: This is immutable, so we should be able to use
58    // std::tr1::shared_array instead when it becomes widely available.
59    // The reason would be to remove all copy constructors and assignment
60    // operators from this class.
61    auto_array< const char* > m_exec_argv;
62    void ctor_init_exec_argv(void);
63
64public:
65    typedef args_vector::const_iterator const_iterator;
66    typedef args_vector::size_type size_type;
67
68    argv_array(void);
69    argv_array(const char*, ...);
70    explicit argv_array(const char* const*);
71    template< class C > explicit argv_array(const C&);
72    argv_array(const argv_array&);
73
74    const char* const* exec_argv(void) const;
75    size_type size(void) const;
76    const char* operator[](int) const;
77
78    const_iterator begin(void) const;
79    const_iterator end(void) const;
80
81    argv_array& operator=(const argv_array&);
82};
83
84template< class C >
85argv_array::argv_array(const C& c)
86{
87    for (typename C::const_iterator iter = c.begin(); iter != c.end();
88         iter++)
89        m_args.push_back(*iter);
90    ctor_init_exec_argv();
91}
92
93// ------------------------------------------------------------------------
94// The "stream" types.
95// ------------------------------------------------------------------------
96
97class basic_stream {
98protected:
99    atf_process_stream_t m_sb;
100    bool m_inited;
101
102    const atf_process_stream_t* get_sb(void) const;
103
104public:
105    basic_stream(void);
106    ~basic_stream(void);
107};
108
109class stream_capture : basic_stream {
110    // Allow access to the getters.
111    template< class OutStream, class ErrStream > friend
112    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
113    template< class OutStream, class ErrStream > friend
114    status exec(const atf::fs::path&, const argv_array&,
115                const OutStream&, const ErrStream&, void (*)(void));
116
117public:
118    stream_capture(void);
119};
120
121class stream_connect : basic_stream {
122    // Allow access to the getters.
123    template< class OutStream, class ErrStream > friend
124    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
125    template< class OutStream, class ErrStream > friend
126    status exec(const atf::fs::path&, const argv_array&,
127                const OutStream&, const ErrStream&, void (*)(void));
128
129public:
130    stream_connect(const int, const int);
131};
132
133class stream_inherit : basic_stream {
134    // Allow access to the getters.
135    template< class OutStream, class ErrStream > friend
136    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
137    template< class OutStream, class ErrStream > friend
138    status exec(const atf::fs::path&, const argv_array&,
139                const OutStream&, const ErrStream&, void (*)(void));
140
141public:
142    stream_inherit(void);
143};
144
145class stream_redirect_fd : basic_stream {
146    // Allow access to the getters.
147    template< class OutStream, class ErrStream > friend
148    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
149    template< class OutStream, class ErrStream > friend
150    status exec(const atf::fs::path&, const argv_array&,
151                const OutStream&, const ErrStream&, void (*)(void));
152
153public:
154    stream_redirect_fd(const int);
155};
156
157class stream_redirect_path : basic_stream {
158    // Allow access to the getters.
159    template< class OutStream, class ErrStream > friend
160    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
161    template< class OutStream, class ErrStream > friend
162    status exec(const atf::fs::path&, const argv_array&,
163                const OutStream&, const ErrStream&, void (*)(void));
164
165public:
166    stream_redirect_path(const fs::path&);
167};
168
169// ------------------------------------------------------------------------
170// The "status" type.
171// ------------------------------------------------------------------------
172
173class status {
174    atf_process_status_t m_status;
175
176    friend class child;
177    template< class OutStream, class ErrStream > friend
178    status exec(const atf::fs::path&, const argv_array&,
179                const OutStream&, const ErrStream&, void (*)(void));
180
181    status(atf_process_status_t&);
182
183public:
184    ~status(void);
185
186    bool exited(void) const;
187    int exitstatus(void) const;
188
189    bool signaled(void) const;
190    int termsig(void) const;
191    bool coredump(void) const;
192};
193
194// ------------------------------------------------------------------------
195// The "child" type.
196// ------------------------------------------------------------------------
197
198class child {
199    atf_process_child_t m_child;
200    bool m_waited;
201
202    template< class OutStream, class ErrStream > friend
203    child fork(void (*)(void*), const OutStream&, const ErrStream&, void*);
204
205    child(atf_process_child_t& c);
206
207public:
208    ~child(void);
209
210    status wait(void);
211
212    pid_t pid(void) const;
213    int stdout_fd(void);
214    int stderr_fd(void);
215};
216
217// ------------------------------------------------------------------------
218// Free functions.
219// ------------------------------------------------------------------------
220
221namespace detail {
222void flush_streams(void);
223} // namespace detail
224
225// TODO: The void* cookie can probably be templatized, thus also allowing
226// const data structures.
227template< class OutStream, class ErrStream >
228child
229fork(void (*start)(void*), const OutStream& outsb,
230     const ErrStream& errsb, void* v)
231{
232    atf_process_child_t c;
233
234    detail::flush_streams();
235    atf_error_t err = atf_process_fork(&c, start, outsb.get_sb(),
236                                       errsb.get_sb(), v);
237    if (atf_is_error(err))
238        throw_atf_error(err);
239
240    return child(c);
241}
242
243template< class OutStream, class ErrStream >
244status
245exec(const atf::fs::path& prog, const argv_array& argv,
246     const OutStream& outsb, const ErrStream& errsb,
247     void (*prehook)(void))
248{
249    atf_process_status_t s;
250
251    detail::flush_streams();
252    atf_error_t err = atf_process_exec_array(&s, prog.c_path(),
253                                             argv.exec_argv(),
254                                             outsb.get_sb(),
255                                             errsb.get_sb(),
256                                             prehook);
257    if (atf_is_error(err))
258        throw_atf_error(err);
259
260    return status(s);
261}
262
263template< class OutStream, class ErrStream >
264status
265exec(const atf::fs::path& prog, const argv_array& argv,
266     const OutStream& outsb, const ErrStream& errsb)
267{
268    return exec(prog, argv, outsb, errsb, NULL);
269}
270
271} // namespace process
272} // namespace atf
273
274#endif // !defined(ATF_CXX_DETAIL_PROCESS_HPP)
275