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
29 extern "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
43 namespace atf {
44 namespace process {
45
46 class child;
47 class status;
48
49 // ------------------------------------------------------------------------
50 // The "argv_array" type.
51 // ------------------------------------------------------------------------
52
53 class 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
64 public:
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
84 template< class C >
argv_array(const C & c)85 argv_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
97 class basic_stream {
98 protected:
99 atf_process_stream_t m_sb;
100 bool m_inited;
101
102 const atf_process_stream_t* get_sb(void) const;
103
104 public:
105 basic_stream(void);
106 ~basic_stream(void);
107 };
108
109 class 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
117 public:
118 stream_capture(void);
119 };
120
121 class 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
129 public:
130 stream_connect(const int, const int);
131 };
132
133 class 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
141 public:
142 stream_inherit(void);
143 };
144
145 class 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
153 public:
154 stream_redirect_fd(const int);
155 };
156
157 class 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
165 public:
166 stream_redirect_path(const fs::path&);
167 };
168
169 // ------------------------------------------------------------------------
170 // The "status" type.
171 // ------------------------------------------------------------------------
172
173 class 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
183 public:
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
198 class 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
207 public:
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
221 namespace detail {
222 void flush_streams(void);
223 } // namespace detail
224
225 // TODO: The void* cookie can probably be templatized, thus also allowing
226 // const data structures.
227 template< class OutStream, class ErrStream >
228 child
fork(void (* start)(void *),const OutStream & outsb,const ErrStream & errsb,void * v)229 fork(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
243 template< class OutStream, class ErrStream >
244 status
exec(const atf::fs::path & prog,const argv_array & argv,const OutStream & outsb,const ErrStream & errsb,void (* prehook)(void))245 exec(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
263 template< class OutStream, class ErrStream >
264 status
exec(const atf::fs::path & prog,const argv_array & argv,const OutStream & outsb,const ErrStream & errsb)265 exec(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