xref: /freebsd/contrib/atf/atf-c++/detail/process.hpp (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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 >
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
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
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
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