Remove building with NOCRYPTO option
[minix.git] / external / bsd / atf / dist / tools / process.cpp
blobe06b5c5d29f142b7f9c9702f13b002b2a60e6f7a
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.
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.
30 extern "C" {
31 #include <sys/types.h>
32 #include <sys/wait.h>
34 #include <fcntl.h>
35 #include <signal.h>
38 #include <cassert>
39 #include <cstdarg>
40 #include <cerrno>
41 #include <cstring>
42 #include <iostream>
44 #include "exceptions.hpp"
45 #include "text.hpp"
46 #include "process.hpp"
48 namespace detail = tools::process::detail;
49 namespace impl = tools::process;
50 #define IMPL_NAME "tools::process"
52 // ------------------------------------------------------------------------
53 // Auxiliary functions.
54 // ------------------------------------------------------------------------
56 template< class C >
57 tools::auto_array< const char* >
58 collection_to_argv(const C& c)
60 tools::auto_array< const char* > argv(new const char*[c.size() + 1]);
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++;
68 assert(pos == c.size());
69 argv[pos] = NULL;
71 return argv;
74 template< class C >
76 argv_to_collection(const char* const* argv)
78 C c;
80 for (const char* const* iter = argv; *iter != NULL; iter++)
81 c.push_back(std::string(*iter));
83 return c;
86 static
87 void
88 safe_dup(const int oldfd, const int newfd)
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);
101 static
103 const_execvp(const char *file, const char *const *argv)
105 #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
106 return ::execvp(file, (char* const*)(UNCONST(argv)));
107 #undef UNCONST
110 void
111 detail::do_exec(void *v)
113 struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
115 if (ea->m_prehook != NULL)
116 ea->m_prehook();
118 #if !defined(NDEBUG) && defined(__minix)
119 const int ret =
120 #endif /* !defined(NDEBUG) && defined(__minix) */
121 const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
122 const int errnocopy = errno;
123 assert(ret == -1);
124 std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
125 << std::strerror(errnocopy) << "\n";
126 std::exit(EXIT_FAILURE);
129 // ------------------------------------------------------------------------
130 // The "argv_array" type.
131 // ------------------------------------------------------------------------
133 impl::argv_array::argv_array(void) :
134 m_exec_argv(collection_to_argv(m_args))
138 impl::argv_array::argv_array(const char* arg1, ...)
140 m_args.push_back(arg1);
143 va_list ap;
144 const char* nextarg;
146 va_start(ap, arg1);
147 while ((nextarg = va_arg(ap, const char*)) != NULL)
148 m_args.push_back(nextarg);
149 va_end(ap);
152 ctor_init_exec_argv();
155 impl::argv_array::argv_array(const char* const* ca) :
156 m_args(argv_to_collection< args_vector >(ca)),
157 m_exec_argv(collection_to_argv(m_args))
161 impl::argv_array::argv_array(const argv_array& a) :
162 m_args(a.m_args),
163 m_exec_argv(collection_to_argv(m_args))
167 void
168 impl::argv_array::ctor_init_exec_argv(void)
170 m_exec_argv = collection_to_argv(m_args);
173 const char* const*
174 impl::argv_array::exec_argv(void)
175 const
177 return m_exec_argv.get();
180 impl::argv_array::size_type
181 impl::argv_array::size(void)
182 const
184 return m_args.size();
187 const char*
188 impl::argv_array::operator[](int idx)
189 const
191 return m_args[idx].c_str();
194 impl::argv_array::const_iterator
195 impl::argv_array::begin(void)
196 const
198 return m_args.begin();
201 impl::argv_array::const_iterator
202 impl::argv_array::end(void)
203 const
205 return m_args.end();
208 impl::argv_array&
209 impl::argv_array::operator=(const argv_array& a)
211 if (this != &a) {
212 m_args = a.m_args;
213 m_exec_argv = collection_to_argv(m_args);
215 return *this;
218 // ------------------------------------------------------------------------
219 // The "stream" types.
220 // ------------------------------------------------------------------------
222 impl::stream_capture::stream_capture(void)
224 for (int i = 0; i < 2; i++)
225 m_pipefds[i] = -1;
228 impl::stream_capture::~stream_capture(void)
230 for (int i = 0; i < 2; i++)
231 if (m_pipefds[i] != -1)
232 ::close(m_pipefds[i]);
235 void
236 impl::stream_capture::prepare(void)
238 if (pipe(m_pipefds) == -1)
239 throw system_error(IMPL_NAME "::stream_capture::prepare",
240 "Failed to create pipe", errno);
244 impl::stream_capture::connect_parent(void)
246 ::close(m_pipefds[1]); m_pipefds[1] = -1;
247 const int fd = m_pipefds[0];
248 m_pipefds[0] = -1;
249 return fd;
252 void
253 impl::stream_capture::connect_child(const int fd)
255 ::close(m_pipefds[0]); m_pipefds[0] = -1;
256 if (m_pipefds[1] != fd) {
257 safe_dup(m_pipefds[1], fd);
259 m_pipefds[1] = -1;
262 impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
263 m_src_fd(src_fd), m_tgt_fd(tgt_fd)
267 void
268 impl::stream_connect::prepare(void)
273 impl::stream_connect::connect_parent(void)
275 return -1;
278 void
279 impl::stream_connect::connect_child(const int fd __attribute__((__unused__)))
281 safe_dup(m_tgt_fd, m_src_fd);
284 impl::stream_inherit::stream_inherit(void)
288 void
289 impl::stream_inherit::prepare(void)
294 impl::stream_inherit::connect_parent(void)
296 return -1;
299 void
300 impl::stream_inherit::connect_child(const int fd __attribute__((__unused__)))
304 impl::stream_redirect_fd::stream_redirect_fd(const int fd) :
305 m_fd(fd)
309 void
310 impl::stream_redirect_fd::prepare(void)
315 impl::stream_redirect_fd::connect_parent(void)
317 return -1;
320 void
321 impl::stream_redirect_fd::connect_child(const int fd)
323 safe_dup(m_fd, fd);
326 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
327 m_path(p)
331 void
332 impl::stream_redirect_path::prepare(void)
337 impl::stream_redirect_path::connect_parent(void)
339 return -1;
342 void
343 impl::stream_redirect_path::connect_child(const int fd)
345 const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
346 if (aux == -1)
347 throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
348 "Could not create " + m_path.str(), errno);
349 else
350 safe_dup(aux, fd);
353 // ------------------------------------------------------------------------
354 // The "status" type.
355 // ------------------------------------------------------------------------
357 impl::status::status(int s) :
358 m_status(s)
362 impl::status::~status(void)
366 bool
367 impl::status::exited(void)
368 const
370 int mutable_status = m_status;
371 return WIFEXITED(mutable_status);
375 impl::status::exitstatus(void)
376 const
378 assert(exited());
379 int mutable_status = m_status;
380 return WEXITSTATUS(mutable_status);
383 bool
384 impl::status::signaled(void)
385 const
387 int mutable_status = m_status;
388 return WIFSIGNALED(mutable_status);
392 impl::status::termsig(void)
393 const
395 assert(signaled());
396 int mutable_status = m_status;
397 return WTERMSIG(mutable_status);
400 bool
401 impl::status::coredump(void)
402 const
404 assert(signaled());
405 int mutable_status = m_status;
406 return WCOREDUMP(mutable_status);
409 // ------------------------------------------------------------------------
410 // The "child" type.
411 // ------------------------------------------------------------------------
413 impl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
414 const int stderr_fd_arg) :
415 m_pid(pid_arg),
416 m_stdout(stdout_fd_arg),
417 m_stderr(stderr_fd_arg),
418 m_waited(false)
422 impl::child::~child(void)
424 if (!m_waited) {
425 ::kill(m_pid, SIGTERM);
426 (void)wait();
428 if (m_stdout != -1)
429 ::close(m_stdout);
430 if (m_stderr != -1)
431 ::close(m_stderr);
435 impl::status
436 impl::child::wait(void)
438 int s;
440 if (::waitpid(m_pid, &s, 0) == -1)
441 throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
442 "process " + text::to_string(m_pid), errno);
444 if (m_stdout != -1)
445 ::close(m_stdout); m_stdout = -1;
446 if (m_stderr != -1)
447 ::close(m_stderr); m_stderr = -1;
449 m_waited = true;
450 return status(s);
453 pid_t
454 impl::child::pid(void)
455 const
457 return m_pid;
461 impl::child::stdout_fd(void)
463 return m_stdout;
467 impl::child::stderr_fd(void)
469 return m_stderr;
472 // ------------------------------------------------------------------------
473 // Free functions.
474 // ------------------------------------------------------------------------
476 void
477 detail::flush_streams(void)
479 // This is a weird hack to ensure that the output of the parent process
480 // is flushed before executing a child which prevents, for example, the
481 // output of the atf-run hooks to appear before the output of atf-run
482 // itself.
484 // TODO: This should only be executed when inheriting the stdout or
485 // stderr file descriptors. However, the flushing is specific to the
486 // iostreams, so we cannot do it from the C library where all the process
487 // logic is performed. Come up with a better design.
488 std::cout.flush();
489 std::cerr.flush();