xref: /netbsd-src/external/bsd/atf/dist/tools/process.cpp (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2008 The NetBSD Foundation, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 // 1. Redistributions of source code must retain the above copyright
11 //    notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 //    notice, this list of conditions and the following disclaimer in the
14 //    documentation and/or other materials provided with the distribution.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 extern "C" {
31 #include <sys/types.h>
32 #include <sys/wait.h>
33 
34 #include <fcntl.h>
35 #include <signal.h>
36 }
37 
38 #include <cassert>
39 #include <cstdarg>
40 #include <cerrno>
41 #include <cstring>
42 #include <iostream>
43 
44 #include "exceptions.hpp"
45 #include "text.hpp"
46 #include "process.hpp"
47 
48 namespace detail = tools::process::detail;
49 namespace impl = tools::process;
50 #define IMPL_NAME "tools::process"
51 
52 // ------------------------------------------------------------------------
53 // Auxiliary functions.
54 // ------------------------------------------------------------------------
55 
56 template< class C >
57 tools::auto_array< const char* >
58 collection_to_argv(const C& c)
59 {
60     tools::auto_array< const char* > argv(new const char*[c.size() + 1]);
61 
62     std::size_t pos = 0;
63     for (typename C::const_iterator iter = c.begin(); iter != c.end();
64          iter++) {
65         argv[pos] = (*iter).c_str();
66         pos++;
67     }
68     assert(pos == c.size());
69     argv[pos] = NULL;
70 
71     return argv;
72 }
73 
74 template< class C >
75 C
76 argv_to_collection(const char* const* argv)
77 {
78     C c;
79 
80     for (const char* const* iter = argv; *iter != NULL; iter++)
81         c.push_back(std::string(*iter));
82 
83     return c;
84 }
85 
86 static
87 void
88 safe_dup(const int oldfd, const int newfd)
89 {
90     if (oldfd != newfd) {
91         if (dup2(oldfd, newfd) == -1) {
92             throw tools::system_error(IMPL_NAME "::safe_dup",
93                                       "Could not allocate file descriptor",
94                                       errno);
95         } else {
96             ::close(oldfd);
97         }
98     }
99 }
100 
101 static
102 int
103 const_execvp(const char *file, const char *const *argv)
104 {
105 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
106     return ::execvp(file, (char* const*)(UNCONST(argv)));
107 #undef UNCONST
108 }
109 
110 void
111 detail::do_exec(void *v)
112 {
113     struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
114 
115     if (ea->m_prehook != NULL)
116         ea->m_prehook();
117 
118     const int ret = const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
119     const int errnocopy = errno;
120     assert(ret == -1);
121     std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
122               << std::strerror(errnocopy) << "\n";
123     std::exit(EXIT_FAILURE);
124 }
125 
126 // ------------------------------------------------------------------------
127 // The "argv_array" type.
128 // ------------------------------------------------------------------------
129 
130 impl::argv_array::argv_array(void) :
131     m_exec_argv(collection_to_argv(m_args))
132 {
133 }
134 
135 impl::argv_array::argv_array(const char* arg1, ...)
136 {
137     m_args.push_back(arg1);
138 
139     {
140         va_list ap;
141         const char* nextarg;
142 
143         va_start(ap, arg1);
144         while ((nextarg = va_arg(ap, const char*)) != NULL)
145             m_args.push_back(nextarg);
146         va_end(ap);
147     }
148 
149     ctor_init_exec_argv();
150 }
151 
152 impl::argv_array::argv_array(const char* const* ca) :
153     m_args(argv_to_collection< args_vector >(ca)),
154     m_exec_argv(collection_to_argv(m_args))
155 {
156 }
157 
158 impl::argv_array::argv_array(const argv_array& a) :
159     m_args(a.m_args),
160     m_exec_argv(collection_to_argv(m_args))
161 {
162 }
163 
164 void
165 impl::argv_array::ctor_init_exec_argv(void)
166 {
167     m_exec_argv = collection_to_argv(m_args);
168 }
169 
170 const char* const*
171 impl::argv_array::exec_argv(void)
172     const
173 {
174     return m_exec_argv.get();
175 }
176 
177 impl::argv_array::size_type
178 impl::argv_array::size(void)
179     const
180 {
181     return m_args.size();
182 }
183 
184 const char*
185 impl::argv_array::operator[](int idx)
186     const
187 {
188     return m_args[idx].c_str();
189 }
190 
191 impl::argv_array::const_iterator
192 impl::argv_array::begin(void)
193     const
194 {
195     return m_args.begin();
196 }
197 
198 impl::argv_array::const_iterator
199 impl::argv_array::end(void)
200     const
201 {
202     return m_args.end();
203 }
204 
205 impl::argv_array&
206 impl::argv_array::operator=(const argv_array& a)
207 {
208     if (this != &a) {
209         m_args = a.m_args;
210         m_exec_argv = collection_to_argv(m_args);
211     }
212     return *this;
213 }
214 
215 // ------------------------------------------------------------------------
216 // The "stream" types.
217 // ------------------------------------------------------------------------
218 
219 impl::stream_capture::stream_capture(void)
220 {
221     for (int i = 0; i < 2; i++)
222         m_pipefds[i] = -1;
223 }
224 
225 impl::stream_capture::~stream_capture(void)
226 {
227     for (int i = 0; i < 2; i++)
228         if (m_pipefds[i] != -1)
229             ::close(m_pipefds[i]);
230 }
231 
232 void
233 impl::stream_capture::prepare(void)
234 {
235     if (pipe(m_pipefds) == -1)
236         throw system_error(IMPL_NAME "::stream_capture::prepare",
237                            "Failed to create pipe", errno);
238 }
239 
240 int
241 impl::stream_capture::connect_parent(void)
242 {
243     ::close(m_pipefds[1]); m_pipefds[1] = -1;
244     const int fd = m_pipefds[0];
245     m_pipefds[0] = -1;
246     return fd;
247 }
248 
249 void
250 impl::stream_capture::connect_child(const int fd)
251 {
252     ::close(m_pipefds[0]); m_pipefds[0] = -1;
253     if (m_pipefds[1] != fd) {
254         safe_dup(m_pipefds[1], fd);
255     }
256     m_pipefds[1] = -1;
257 }
258 
259 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
260     m_src_fd(src_fd), m_tgt_fd(tgt_fd)
261 {
262 }
263 
264 void
265 impl::stream_connect::prepare(void)
266 {
267 }
268 
269 int
270 impl::stream_connect::connect_parent(void)
271 {
272     return -1;
273 }
274 
275 void
276 impl::stream_connect::connect_child(const int fd __attribute__((__unused__)))
277 {
278     safe_dup(m_tgt_fd, m_src_fd);
279 }
280 
281 impl::stream_inherit::stream_inherit(void)
282 {
283 }
284 
285 void
286 impl::stream_inherit::prepare(void)
287 {
288 }
289 
290 int
291 impl::stream_inherit::connect_parent(void)
292 {
293     return -1;
294 }
295 
296 void
297 impl::stream_inherit::connect_child(const int fd __attribute__((__unused__)))
298 {
299 }
300 
301 impl::stream_redirect_fd::stream_redirect_fd(const int fd) :
302     m_fd(fd)
303 {
304 }
305 
306 void
307 impl::stream_redirect_fd::prepare(void)
308 {
309 }
310 
311 int
312 impl::stream_redirect_fd::connect_parent(void)
313 {
314     return -1;
315 }
316 
317 void
318 impl::stream_redirect_fd::connect_child(const int fd)
319 {
320     safe_dup(m_fd, fd);
321 }
322 
323 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
324     m_path(p)
325 {
326 }
327 
328 void
329 impl::stream_redirect_path::prepare(void)
330 {
331 }
332 
333 int
334 impl::stream_redirect_path::connect_parent(void)
335 {
336     return -1;
337 }
338 
339 void
340 impl::stream_redirect_path::connect_child(const int fd)
341 {
342     const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
343     if (aux == -1)
344         throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
345                            "Could not create " + m_path.str(), errno);
346     else
347         safe_dup(aux, fd);
348 }
349 
350 // ------------------------------------------------------------------------
351 // The "status" type.
352 // ------------------------------------------------------------------------
353 
354 impl::status::status(int s) :
355     m_status(s)
356 {
357 }
358 
359 impl::status::~status(void)
360 {
361 }
362 
363 std::string
364 impl::status::str(void)
365      const
366 {
367     int mutable_status = m_status;
368     std::stringstream rv;
369     if (WIFEXITED(mutable_status))
370 	rv << "exit("  << WEXITSTATUS(mutable_status);
371     else if (WIFSTOPPED(mutable_status))
372 	rv << "stopped("  << WSTOPSIG(mutable_status);
373     else if (WIFSIGNALED(mutable_status))
374 	rv << "terminated("  << WTERMSIG(mutable_status);
375     if (WCOREDUMP(mutable_status))
376 	rv << "/core)";
377     else
378 	rv << ")";
379     return rv.str();
380 }
381 
382 bool
383 impl::status::exited(void)
384     const
385 {
386     int mutable_status = m_status;
387     return WIFEXITED(mutable_status);
388 }
389 
390 int
391 impl::status::exitstatus(void)
392     const
393 {
394     assert(exited());
395     int mutable_status = m_status;
396     return WEXITSTATUS(mutable_status);
397 }
398 
399 bool
400 impl::status::signaled(void)
401     const
402 {
403     int mutable_status = m_status;
404     return WIFSIGNALED(mutable_status);
405 }
406 
407 int
408 impl::status::termsig(void)
409     const
410 {
411     assert(signaled());
412     int mutable_status = m_status;
413     return WTERMSIG(mutable_status);
414 }
415 
416 bool
417 impl::status::coredump(void)
418     const
419 {
420     assert(signaled());
421     int mutable_status = m_status;
422     return WCOREDUMP(mutable_status);
423 }
424 
425 // ------------------------------------------------------------------------
426 // The "child" type.
427 // ------------------------------------------------------------------------
428 
429 impl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
430                    const int stderr_fd_arg) :
431     m_pid(pid_arg),
432     m_stdout(stdout_fd_arg),
433     m_stderr(stderr_fd_arg),
434     m_waited(false)
435 {
436 }
437 
438 impl::child::~child(void)
439 {
440     if (!m_waited) {
441         ::kill(m_pid, SIGTERM);
442         (void)wait();
443 
444         if (m_stdout != -1)
445             ::close(m_stdout);
446         if (m_stderr != -1)
447             ::close(m_stderr);
448     }
449 }
450 
451 impl::status
452 impl::child::wait(void)
453 {
454     int s;
455 
456     if (::waitpid(m_pid, &s, 0) == -1)
457         throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
458                            "process " + text::to_string(m_pid), errno);
459 
460     if (m_stdout != -1)
461         ::close(m_stdout); m_stdout = -1;
462     if (m_stderr != -1)
463         ::close(m_stderr); m_stderr = -1;
464 
465     m_waited = true;
466     return status(s);
467 }
468 
469 pid_t
470 impl::child::pid(void)
471     const
472 {
473     return m_pid;
474 }
475 
476 int
477 impl::child::stdout_fd(void)
478 {
479     return m_stdout;
480 }
481 
482 int
483 impl::child::stderr_fd(void)
484 {
485     return m_stderr;
486 }
487 
488 // ------------------------------------------------------------------------
489 // Free functions.
490 // ------------------------------------------------------------------------
491 
492 void
493 detail::flush_streams(void)
494 {
495     // This is a weird hack to ensure that the output of the parent process
496     // is flushed before executing a child which prevents, for example, the
497     // output of the atf-run hooks to appear before the output of atf-run
498     // itself.
499     //
500     // TODO: This should only be executed when inheriting the stdout or
501     // stderr file descriptors.  However, the flushing is specific to the
502     // iostreams, so we cannot do it from the C library where all the process
503     // logic is performed.  Come up with a better design.
504     std::cout.flush();
505     std::cerr.flush();
506 }
507