10a6a1f1dSLionel Sambuc //
20a6a1f1dSLionel Sambuc // Automated Testing Framework (atf)
30a6a1f1dSLionel Sambuc //
40a6a1f1dSLionel Sambuc // Copyright (c) 2008 The NetBSD Foundation, Inc.
50a6a1f1dSLionel Sambuc // All rights reserved.
60a6a1f1dSLionel Sambuc //
70a6a1f1dSLionel Sambuc // Redistribution and use in source and binary forms, with or without
80a6a1f1dSLionel Sambuc // modification, are permitted provided that the following conditions
90a6a1f1dSLionel Sambuc // are met:
100a6a1f1dSLionel Sambuc // 1. Redistributions of source code must retain the above copyright
110a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer.
120a6a1f1dSLionel Sambuc // 2. Redistributions in binary form must reproduce the above copyright
130a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer in the
140a6a1f1dSLionel Sambuc // documentation and/or other materials provided with the distribution.
150a6a1f1dSLionel Sambuc //
160a6a1f1dSLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
170a6a1f1dSLionel Sambuc // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
180a6a1f1dSLionel Sambuc // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
190a6a1f1dSLionel Sambuc // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
200a6a1f1dSLionel Sambuc // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
210a6a1f1dSLionel Sambuc // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220a6a1f1dSLionel Sambuc // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
230a6a1f1dSLionel Sambuc // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240a6a1f1dSLionel Sambuc // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
250a6a1f1dSLionel Sambuc // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
260a6a1f1dSLionel Sambuc // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
270a6a1f1dSLionel Sambuc // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
280a6a1f1dSLionel Sambuc //
290a6a1f1dSLionel Sambuc
300a6a1f1dSLionel Sambuc extern "C" {
310a6a1f1dSLionel Sambuc #include <sys/types.h>
320a6a1f1dSLionel Sambuc #include <sys/wait.h>
330a6a1f1dSLionel Sambuc
340a6a1f1dSLionel Sambuc #include <fcntl.h>
350a6a1f1dSLionel Sambuc #include <signal.h>
360a6a1f1dSLionel Sambuc }
370a6a1f1dSLionel Sambuc
380a6a1f1dSLionel Sambuc #include <cassert>
390a6a1f1dSLionel Sambuc #include <cstdarg>
400a6a1f1dSLionel Sambuc #include <cerrno>
410a6a1f1dSLionel Sambuc #include <cstring>
420a6a1f1dSLionel Sambuc #include <iostream>
430a6a1f1dSLionel Sambuc
440a6a1f1dSLionel Sambuc #include "exceptions.hpp"
450a6a1f1dSLionel Sambuc #include "text.hpp"
460a6a1f1dSLionel Sambuc #include "process.hpp"
470a6a1f1dSLionel Sambuc
480a6a1f1dSLionel Sambuc namespace detail = tools::process::detail;
490a6a1f1dSLionel Sambuc namespace impl = tools::process;
500a6a1f1dSLionel Sambuc #define IMPL_NAME "tools::process"
510a6a1f1dSLionel Sambuc
520a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
530a6a1f1dSLionel Sambuc // Auxiliary functions.
540a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
550a6a1f1dSLionel Sambuc
560a6a1f1dSLionel Sambuc template< class C >
570a6a1f1dSLionel Sambuc tools::auto_array< const char* >
collection_to_argv(const C & c)580a6a1f1dSLionel Sambuc collection_to_argv(const C& c)
590a6a1f1dSLionel Sambuc {
600a6a1f1dSLionel Sambuc tools::auto_array< const char* > argv(new const char*[c.size() + 1]);
610a6a1f1dSLionel Sambuc
620a6a1f1dSLionel Sambuc std::size_t pos = 0;
630a6a1f1dSLionel Sambuc for (typename C::const_iterator iter = c.begin(); iter != c.end();
640a6a1f1dSLionel Sambuc iter++) {
650a6a1f1dSLionel Sambuc argv[pos] = (*iter).c_str();
660a6a1f1dSLionel Sambuc pos++;
670a6a1f1dSLionel Sambuc }
680a6a1f1dSLionel Sambuc assert(pos == c.size());
690a6a1f1dSLionel Sambuc argv[pos] = NULL;
700a6a1f1dSLionel Sambuc
710a6a1f1dSLionel Sambuc return argv;
720a6a1f1dSLionel Sambuc }
730a6a1f1dSLionel Sambuc
740a6a1f1dSLionel Sambuc template< class C >
750a6a1f1dSLionel Sambuc C
argv_to_collection(const char * const * argv)760a6a1f1dSLionel Sambuc argv_to_collection(const char* const* argv)
770a6a1f1dSLionel Sambuc {
780a6a1f1dSLionel Sambuc C c;
790a6a1f1dSLionel Sambuc
800a6a1f1dSLionel Sambuc for (const char* const* iter = argv; *iter != NULL; iter++)
810a6a1f1dSLionel Sambuc c.push_back(std::string(*iter));
820a6a1f1dSLionel Sambuc
830a6a1f1dSLionel Sambuc return c;
840a6a1f1dSLionel Sambuc }
850a6a1f1dSLionel Sambuc
860a6a1f1dSLionel Sambuc static
870a6a1f1dSLionel Sambuc void
safe_dup(const int oldfd,const int newfd)880a6a1f1dSLionel Sambuc safe_dup(const int oldfd, const int newfd)
890a6a1f1dSLionel Sambuc {
900a6a1f1dSLionel Sambuc if (oldfd != newfd) {
910a6a1f1dSLionel Sambuc if (dup2(oldfd, newfd) == -1) {
920a6a1f1dSLionel Sambuc throw tools::system_error(IMPL_NAME "::safe_dup",
930a6a1f1dSLionel Sambuc "Could not allocate file descriptor",
940a6a1f1dSLionel Sambuc errno);
950a6a1f1dSLionel Sambuc } else {
960a6a1f1dSLionel Sambuc ::close(oldfd);
970a6a1f1dSLionel Sambuc }
980a6a1f1dSLionel Sambuc }
990a6a1f1dSLionel Sambuc }
1000a6a1f1dSLionel Sambuc
1010a6a1f1dSLionel Sambuc static
1020a6a1f1dSLionel Sambuc int
const_execvp(const char * file,const char * const * argv)1030a6a1f1dSLionel Sambuc const_execvp(const char *file, const char *const *argv)
1040a6a1f1dSLionel Sambuc {
1050a6a1f1dSLionel Sambuc #define UNCONST(a) ((void *)(unsigned long)(const void *)(a))
1060a6a1f1dSLionel Sambuc return ::execvp(file, (char* const*)(UNCONST(argv)));
1070a6a1f1dSLionel Sambuc #undef UNCONST
1080a6a1f1dSLionel Sambuc }
1090a6a1f1dSLionel Sambuc
1100a6a1f1dSLionel Sambuc void
do_exec(void * v)1110a6a1f1dSLionel Sambuc detail::do_exec(void *v)
1120a6a1f1dSLionel Sambuc {
1130a6a1f1dSLionel Sambuc struct exec_args *ea = reinterpret_cast<struct exec_args *>(v);
1140a6a1f1dSLionel Sambuc
1150a6a1f1dSLionel Sambuc if (ea->m_prehook != NULL)
1160a6a1f1dSLionel Sambuc ea->m_prehook();
1170a6a1f1dSLionel Sambuc
118*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
119*e1cdaee1SLionel Sambuc const int ret =
120*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
121*e1cdaee1SLionel Sambuc const_execvp(ea->m_prog.c_str(), ea->m_argv.exec_argv());
1220a6a1f1dSLionel Sambuc const int errnocopy = errno;
1230a6a1f1dSLionel Sambuc assert(ret == -1);
1240a6a1f1dSLionel Sambuc std::cerr << "exec(" << ea->m_prog.str() << ") failed: "
1250a6a1f1dSLionel Sambuc << std::strerror(errnocopy) << "\n";
1260a6a1f1dSLionel Sambuc std::exit(EXIT_FAILURE);
1270a6a1f1dSLionel Sambuc }
1280a6a1f1dSLionel Sambuc
1290a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
1300a6a1f1dSLionel Sambuc // The "argv_array" type.
1310a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
1320a6a1f1dSLionel Sambuc
argv_array(void)1330a6a1f1dSLionel Sambuc impl::argv_array::argv_array(void) :
1340a6a1f1dSLionel Sambuc m_exec_argv(collection_to_argv(m_args))
1350a6a1f1dSLionel Sambuc {
1360a6a1f1dSLionel Sambuc }
1370a6a1f1dSLionel Sambuc
argv_array(const char * arg1,...)1380a6a1f1dSLionel Sambuc impl::argv_array::argv_array(const char* arg1, ...)
1390a6a1f1dSLionel Sambuc {
1400a6a1f1dSLionel Sambuc m_args.push_back(arg1);
1410a6a1f1dSLionel Sambuc
1420a6a1f1dSLionel Sambuc {
1430a6a1f1dSLionel Sambuc va_list ap;
1440a6a1f1dSLionel Sambuc const char* nextarg;
1450a6a1f1dSLionel Sambuc
1460a6a1f1dSLionel Sambuc va_start(ap, arg1);
1470a6a1f1dSLionel Sambuc while ((nextarg = va_arg(ap, const char*)) != NULL)
1480a6a1f1dSLionel Sambuc m_args.push_back(nextarg);
1490a6a1f1dSLionel Sambuc va_end(ap);
1500a6a1f1dSLionel Sambuc }
1510a6a1f1dSLionel Sambuc
1520a6a1f1dSLionel Sambuc ctor_init_exec_argv();
1530a6a1f1dSLionel Sambuc }
1540a6a1f1dSLionel Sambuc
argv_array(const char * const * ca)1550a6a1f1dSLionel Sambuc impl::argv_array::argv_array(const char* const* ca) :
1560a6a1f1dSLionel Sambuc m_args(argv_to_collection< args_vector >(ca)),
1570a6a1f1dSLionel Sambuc m_exec_argv(collection_to_argv(m_args))
1580a6a1f1dSLionel Sambuc {
1590a6a1f1dSLionel Sambuc }
1600a6a1f1dSLionel Sambuc
argv_array(const argv_array & a)1610a6a1f1dSLionel Sambuc impl::argv_array::argv_array(const argv_array& a) :
1620a6a1f1dSLionel Sambuc m_args(a.m_args),
1630a6a1f1dSLionel Sambuc m_exec_argv(collection_to_argv(m_args))
1640a6a1f1dSLionel Sambuc {
1650a6a1f1dSLionel Sambuc }
1660a6a1f1dSLionel Sambuc
1670a6a1f1dSLionel Sambuc void
ctor_init_exec_argv(void)1680a6a1f1dSLionel Sambuc impl::argv_array::ctor_init_exec_argv(void)
1690a6a1f1dSLionel Sambuc {
1700a6a1f1dSLionel Sambuc m_exec_argv = collection_to_argv(m_args);
1710a6a1f1dSLionel Sambuc }
1720a6a1f1dSLionel Sambuc
1730a6a1f1dSLionel Sambuc const char* const*
exec_argv(void) const1740a6a1f1dSLionel Sambuc impl::argv_array::exec_argv(void)
1750a6a1f1dSLionel Sambuc const
1760a6a1f1dSLionel Sambuc {
1770a6a1f1dSLionel Sambuc return m_exec_argv.get();
1780a6a1f1dSLionel Sambuc }
1790a6a1f1dSLionel Sambuc
1800a6a1f1dSLionel Sambuc impl::argv_array::size_type
size(void) const1810a6a1f1dSLionel Sambuc impl::argv_array::size(void)
1820a6a1f1dSLionel Sambuc const
1830a6a1f1dSLionel Sambuc {
1840a6a1f1dSLionel Sambuc return m_args.size();
1850a6a1f1dSLionel Sambuc }
1860a6a1f1dSLionel Sambuc
1870a6a1f1dSLionel Sambuc const char*
operator [](int idx) const1880a6a1f1dSLionel Sambuc impl::argv_array::operator[](int idx)
1890a6a1f1dSLionel Sambuc const
1900a6a1f1dSLionel Sambuc {
1910a6a1f1dSLionel Sambuc return m_args[idx].c_str();
1920a6a1f1dSLionel Sambuc }
1930a6a1f1dSLionel Sambuc
1940a6a1f1dSLionel Sambuc impl::argv_array::const_iterator
begin(void) const1950a6a1f1dSLionel Sambuc impl::argv_array::begin(void)
1960a6a1f1dSLionel Sambuc const
1970a6a1f1dSLionel Sambuc {
1980a6a1f1dSLionel Sambuc return m_args.begin();
1990a6a1f1dSLionel Sambuc }
2000a6a1f1dSLionel Sambuc
2010a6a1f1dSLionel Sambuc impl::argv_array::const_iterator
end(void) const2020a6a1f1dSLionel Sambuc impl::argv_array::end(void)
2030a6a1f1dSLionel Sambuc const
2040a6a1f1dSLionel Sambuc {
2050a6a1f1dSLionel Sambuc return m_args.end();
2060a6a1f1dSLionel Sambuc }
2070a6a1f1dSLionel Sambuc
2080a6a1f1dSLionel Sambuc impl::argv_array&
operator =(const argv_array & a)2090a6a1f1dSLionel Sambuc impl::argv_array::operator=(const argv_array& a)
2100a6a1f1dSLionel Sambuc {
2110a6a1f1dSLionel Sambuc if (this != &a) {
2120a6a1f1dSLionel Sambuc m_args = a.m_args;
2130a6a1f1dSLionel Sambuc m_exec_argv = collection_to_argv(m_args);
2140a6a1f1dSLionel Sambuc }
2150a6a1f1dSLionel Sambuc return *this;
2160a6a1f1dSLionel Sambuc }
2170a6a1f1dSLionel Sambuc
2180a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
2190a6a1f1dSLionel Sambuc // The "stream" types.
2200a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
2210a6a1f1dSLionel Sambuc
stream_capture(void)2220a6a1f1dSLionel Sambuc impl::stream_capture::stream_capture(void)
2230a6a1f1dSLionel Sambuc {
2240a6a1f1dSLionel Sambuc for (int i = 0; i < 2; i++)
2250a6a1f1dSLionel Sambuc m_pipefds[i] = -1;
2260a6a1f1dSLionel Sambuc }
2270a6a1f1dSLionel Sambuc
~stream_capture(void)2280a6a1f1dSLionel Sambuc impl::stream_capture::~stream_capture(void)
2290a6a1f1dSLionel Sambuc {
2300a6a1f1dSLionel Sambuc for (int i = 0; i < 2; i++)
2310a6a1f1dSLionel Sambuc if (m_pipefds[i] != -1)
2320a6a1f1dSLionel Sambuc ::close(m_pipefds[i]);
2330a6a1f1dSLionel Sambuc }
2340a6a1f1dSLionel Sambuc
2350a6a1f1dSLionel Sambuc void
prepare(void)2360a6a1f1dSLionel Sambuc impl::stream_capture::prepare(void)
2370a6a1f1dSLionel Sambuc {
2380a6a1f1dSLionel Sambuc if (pipe(m_pipefds) == -1)
2390a6a1f1dSLionel Sambuc throw system_error(IMPL_NAME "::stream_capture::prepare",
2400a6a1f1dSLionel Sambuc "Failed to create pipe", errno);
2410a6a1f1dSLionel Sambuc }
2420a6a1f1dSLionel Sambuc
2430a6a1f1dSLionel Sambuc int
connect_parent(void)2440a6a1f1dSLionel Sambuc impl::stream_capture::connect_parent(void)
2450a6a1f1dSLionel Sambuc {
2460a6a1f1dSLionel Sambuc ::close(m_pipefds[1]); m_pipefds[1] = -1;
2470a6a1f1dSLionel Sambuc const int fd = m_pipefds[0];
2480a6a1f1dSLionel Sambuc m_pipefds[0] = -1;
2490a6a1f1dSLionel Sambuc return fd;
2500a6a1f1dSLionel Sambuc }
2510a6a1f1dSLionel Sambuc
2520a6a1f1dSLionel Sambuc void
connect_child(const int fd)2530a6a1f1dSLionel Sambuc impl::stream_capture::connect_child(const int fd)
2540a6a1f1dSLionel Sambuc {
2550a6a1f1dSLionel Sambuc ::close(m_pipefds[0]); m_pipefds[0] = -1;
2560a6a1f1dSLionel Sambuc if (m_pipefds[1] != fd) {
2570a6a1f1dSLionel Sambuc safe_dup(m_pipefds[1], fd);
2580a6a1f1dSLionel Sambuc }
2590a6a1f1dSLionel Sambuc m_pipefds[1] = -1;
2600a6a1f1dSLionel Sambuc }
2610a6a1f1dSLionel Sambuc
stream_connect(const int src_fd,const int tgt_fd)2620a6a1f1dSLionel Sambuc impl::stream_connect::stream_connect(const int src_fd, const int tgt_fd) :
2630a6a1f1dSLionel Sambuc m_src_fd(src_fd), m_tgt_fd(tgt_fd)
2640a6a1f1dSLionel Sambuc {
2650a6a1f1dSLionel Sambuc }
2660a6a1f1dSLionel Sambuc
2670a6a1f1dSLionel Sambuc void
prepare(void)2680a6a1f1dSLionel Sambuc impl::stream_connect::prepare(void)
2690a6a1f1dSLionel Sambuc {
2700a6a1f1dSLionel Sambuc }
2710a6a1f1dSLionel Sambuc
2720a6a1f1dSLionel Sambuc int
connect_parent(void)2730a6a1f1dSLionel Sambuc impl::stream_connect::connect_parent(void)
2740a6a1f1dSLionel Sambuc {
2750a6a1f1dSLionel Sambuc return -1;
2760a6a1f1dSLionel Sambuc }
2770a6a1f1dSLionel Sambuc
2780a6a1f1dSLionel Sambuc void
connect_child(const int fd)2790a6a1f1dSLionel Sambuc impl::stream_connect::connect_child(const int fd __attribute__((__unused__)))
2800a6a1f1dSLionel Sambuc {
2810a6a1f1dSLionel Sambuc safe_dup(m_tgt_fd, m_src_fd);
2820a6a1f1dSLionel Sambuc }
2830a6a1f1dSLionel Sambuc
stream_inherit(void)2840a6a1f1dSLionel Sambuc impl::stream_inherit::stream_inherit(void)
2850a6a1f1dSLionel Sambuc {
2860a6a1f1dSLionel Sambuc }
2870a6a1f1dSLionel Sambuc
2880a6a1f1dSLionel Sambuc void
prepare(void)2890a6a1f1dSLionel Sambuc impl::stream_inherit::prepare(void)
2900a6a1f1dSLionel Sambuc {
2910a6a1f1dSLionel Sambuc }
2920a6a1f1dSLionel Sambuc
2930a6a1f1dSLionel Sambuc int
connect_parent(void)2940a6a1f1dSLionel Sambuc impl::stream_inherit::connect_parent(void)
2950a6a1f1dSLionel Sambuc {
2960a6a1f1dSLionel Sambuc return -1;
2970a6a1f1dSLionel Sambuc }
2980a6a1f1dSLionel Sambuc
2990a6a1f1dSLionel Sambuc void
connect_child(const int fd)3000a6a1f1dSLionel Sambuc impl::stream_inherit::connect_child(const int fd __attribute__((__unused__)))
3010a6a1f1dSLionel Sambuc {
3020a6a1f1dSLionel Sambuc }
3030a6a1f1dSLionel Sambuc
stream_redirect_fd(const int fd)3040a6a1f1dSLionel Sambuc impl::stream_redirect_fd::stream_redirect_fd(const int fd) :
3050a6a1f1dSLionel Sambuc m_fd(fd)
3060a6a1f1dSLionel Sambuc {
3070a6a1f1dSLionel Sambuc }
3080a6a1f1dSLionel Sambuc
3090a6a1f1dSLionel Sambuc void
prepare(void)3100a6a1f1dSLionel Sambuc impl::stream_redirect_fd::prepare(void)
3110a6a1f1dSLionel Sambuc {
3120a6a1f1dSLionel Sambuc }
3130a6a1f1dSLionel Sambuc
3140a6a1f1dSLionel Sambuc int
connect_parent(void)3150a6a1f1dSLionel Sambuc impl::stream_redirect_fd::connect_parent(void)
3160a6a1f1dSLionel Sambuc {
3170a6a1f1dSLionel Sambuc return -1;
3180a6a1f1dSLionel Sambuc }
3190a6a1f1dSLionel Sambuc
3200a6a1f1dSLionel Sambuc void
connect_child(const int fd)3210a6a1f1dSLionel Sambuc impl::stream_redirect_fd::connect_child(const int fd)
3220a6a1f1dSLionel Sambuc {
3230a6a1f1dSLionel Sambuc safe_dup(m_fd, fd);
3240a6a1f1dSLionel Sambuc }
3250a6a1f1dSLionel Sambuc
stream_redirect_path(const tools::fs::path & p)3260a6a1f1dSLionel Sambuc impl::stream_redirect_path::stream_redirect_path(const tools::fs::path& p) :
3270a6a1f1dSLionel Sambuc m_path(p)
3280a6a1f1dSLionel Sambuc {
3290a6a1f1dSLionel Sambuc }
3300a6a1f1dSLionel Sambuc
3310a6a1f1dSLionel Sambuc void
prepare(void)3320a6a1f1dSLionel Sambuc impl::stream_redirect_path::prepare(void)
3330a6a1f1dSLionel Sambuc {
3340a6a1f1dSLionel Sambuc }
3350a6a1f1dSLionel Sambuc
3360a6a1f1dSLionel Sambuc int
connect_parent(void)3370a6a1f1dSLionel Sambuc impl::stream_redirect_path::connect_parent(void)
3380a6a1f1dSLionel Sambuc {
3390a6a1f1dSLionel Sambuc return -1;
3400a6a1f1dSLionel Sambuc }
3410a6a1f1dSLionel Sambuc
3420a6a1f1dSLionel Sambuc void
connect_child(const int fd)3430a6a1f1dSLionel Sambuc impl::stream_redirect_path::connect_child(const int fd)
3440a6a1f1dSLionel Sambuc {
3450a6a1f1dSLionel Sambuc const int aux = ::open(m_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
3460a6a1f1dSLionel Sambuc if (aux == -1)
3470a6a1f1dSLionel Sambuc throw system_error(IMPL_NAME "::stream_redirect_path::connect_child",
3480a6a1f1dSLionel Sambuc "Could not create " + m_path.str(), errno);
3490a6a1f1dSLionel Sambuc else
3500a6a1f1dSLionel Sambuc safe_dup(aux, fd);
3510a6a1f1dSLionel Sambuc }
3520a6a1f1dSLionel Sambuc
3530a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
3540a6a1f1dSLionel Sambuc // The "status" type.
3550a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
3560a6a1f1dSLionel Sambuc
status(int s)3570a6a1f1dSLionel Sambuc impl::status::status(int s) :
3580a6a1f1dSLionel Sambuc m_status(s)
3590a6a1f1dSLionel Sambuc {
3600a6a1f1dSLionel Sambuc }
3610a6a1f1dSLionel Sambuc
~status(void)3620a6a1f1dSLionel Sambuc impl::status::~status(void)
3630a6a1f1dSLionel Sambuc {
3640a6a1f1dSLionel Sambuc }
3650a6a1f1dSLionel Sambuc
3660a6a1f1dSLionel Sambuc bool
exited(void) const3670a6a1f1dSLionel Sambuc impl::status::exited(void)
3680a6a1f1dSLionel Sambuc const
3690a6a1f1dSLionel Sambuc {
3700a6a1f1dSLionel Sambuc int mutable_status = m_status;
3710a6a1f1dSLionel Sambuc return WIFEXITED(mutable_status);
3720a6a1f1dSLionel Sambuc }
3730a6a1f1dSLionel Sambuc
3740a6a1f1dSLionel Sambuc int
exitstatus(void) const3750a6a1f1dSLionel Sambuc impl::status::exitstatus(void)
3760a6a1f1dSLionel Sambuc const
3770a6a1f1dSLionel Sambuc {
3780a6a1f1dSLionel Sambuc assert(exited());
3790a6a1f1dSLionel Sambuc int mutable_status = m_status;
3800a6a1f1dSLionel Sambuc return WEXITSTATUS(mutable_status);
3810a6a1f1dSLionel Sambuc }
3820a6a1f1dSLionel Sambuc
3830a6a1f1dSLionel Sambuc bool
signaled(void) const3840a6a1f1dSLionel Sambuc impl::status::signaled(void)
3850a6a1f1dSLionel Sambuc const
3860a6a1f1dSLionel Sambuc {
3870a6a1f1dSLionel Sambuc int mutable_status = m_status;
3880a6a1f1dSLionel Sambuc return WIFSIGNALED(mutable_status);
3890a6a1f1dSLionel Sambuc }
3900a6a1f1dSLionel Sambuc
3910a6a1f1dSLionel Sambuc int
termsig(void) const3920a6a1f1dSLionel Sambuc impl::status::termsig(void)
3930a6a1f1dSLionel Sambuc const
3940a6a1f1dSLionel Sambuc {
3950a6a1f1dSLionel Sambuc assert(signaled());
3960a6a1f1dSLionel Sambuc int mutable_status = m_status;
3970a6a1f1dSLionel Sambuc return WTERMSIG(mutable_status);
3980a6a1f1dSLionel Sambuc }
3990a6a1f1dSLionel Sambuc
4000a6a1f1dSLionel Sambuc bool
coredump(void) const4010a6a1f1dSLionel Sambuc impl::status::coredump(void)
4020a6a1f1dSLionel Sambuc const
4030a6a1f1dSLionel Sambuc {
4040a6a1f1dSLionel Sambuc assert(signaled());
4050a6a1f1dSLionel Sambuc int mutable_status = m_status;
4060a6a1f1dSLionel Sambuc return WCOREDUMP(mutable_status);
4070a6a1f1dSLionel Sambuc }
4080a6a1f1dSLionel Sambuc
4090a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
4100a6a1f1dSLionel Sambuc // The "child" type.
4110a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
4120a6a1f1dSLionel Sambuc
child(const pid_t pid_arg,const int stdout_fd_arg,const int stderr_fd_arg)4130a6a1f1dSLionel Sambuc impl::child::child(const pid_t pid_arg, const int stdout_fd_arg,
4140a6a1f1dSLionel Sambuc const int stderr_fd_arg) :
4150a6a1f1dSLionel Sambuc m_pid(pid_arg),
4160a6a1f1dSLionel Sambuc m_stdout(stdout_fd_arg),
4170a6a1f1dSLionel Sambuc m_stderr(stderr_fd_arg),
4180a6a1f1dSLionel Sambuc m_waited(false)
4190a6a1f1dSLionel Sambuc {
4200a6a1f1dSLionel Sambuc }
4210a6a1f1dSLionel Sambuc
~child(void)4220a6a1f1dSLionel Sambuc impl::child::~child(void)
4230a6a1f1dSLionel Sambuc {
4240a6a1f1dSLionel Sambuc if (!m_waited) {
4250a6a1f1dSLionel Sambuc ::kill(m_pid, SIGTERM);
4260a6a1f1dSLionel Sambuc (void)wait();
4270a6a1f1dSLionel Sambuc
4280a6a1f1dSLionel Sambuc if (m_stdout != -1)
4290a6a1f1dSLionel Sambuc ::close(m_stdout);
4300a6a1f1dSLionel Sambuc if (m_stderr != -1)
4310a6a1f1dSLionel Sambuc ::close(m_stderr);
4320a6a1f1dSLionel Sambuc }
4330a6a1f1dSLionel Sambuc }
4340a6a1f1dSLionel Sambuc
4350a6a1f1dSLionel Sambuc impl::status
wait(void)4360a6a1f1dSLionel Sambuc impl::child::wait(void)
4370a6a1f1dSLionel Sambuc {
4380a6a1f1dSLionel Sambuc int s;
4390a6a1f1dSLionel Sambuc
4400a6a1f1dSLionel Sambuc if (::waitpid(m_pid, &s, 0) == -1)
4410a6a1f1dSLionel Sambuc throw system_error(IMPL_NAME "::child::wait", "Failed waiting for "
4420a6a1f1dSLionel Sambuc "process " + text::to_string(m_pid), errno);
4430a6a1f1dSLionel Sambuc
4440a6a1f1dSLionel Sambuc if (m_stdout != -1)
4450a6a1f1dSLionel Sambuc ::close(m_stdout); m_stdout = -1;
4460a6a1f1dSLionel Sambuc if (m_stderr != -1)
4470a6a1f1dSLionel Sambuc ::close(m_stderr); m_stderr = -1;
4480a6a1f1dSLionel Sambuc
4490a6a1f1dSLionel Sambuc m_waited = true;
4500a6a1f1dSLionel Sambuc return status(s);
4510a6a1f1dSLionel Sambuc }
4520a6a1f1dSLionel Sambuc
4530a6a1f1dSLionel Sambuc pid_t
pid(void) const4540a6a1f1dSLionel Sambuc impl::child::pid(void)
4550a6a1f1dSLionel Sambuc const
4560a6a1f1dSLionel Sambuc {
4570a6a1f1dSLionel Sambuc return m_pid;
4580a6a1f1dSLionel Sambuc }
4590a6a1f1dSLionel Sambuc
4600a6a1f1dSLionel Sambuc int
stdout_fd(void)4610a6a1f1dSLionel Sambuc impl::child::stdout_fd(void)
4620a6a1f1dSLionel Sambuc {
4630a6a1f1dSLionel Sambuc return m_stdout;
4640a6a1f1dSLionel Sambuc }
4650a6a1f1dSLionel Sambuc
4660a6a1f1dSLionel Sambuc int
stderr_fd(void)4670a6a1f1dSLionel Sambuc impl::child::stderr_fd(void)
4680a6a1f1dSLionel Sambuc {
4690a6a1f1dSLionel Sambuc return m_stderr;
4700a6a1f1dSLionel Sambuc }
4710a6a1f1dSLionel Sambuc
4720a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
4730a6a1f1dSLionel Sambuc // Free functions.
4740a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
4750a6a1f1dSLionel Sambuc
4760a6a1f1dSLionel Sambuc void
flush_streams(void)4770a6a1f1dSLionel Sambuc detail::flush_streams(void)
4780a6a1f1dSLionel Sambuc {
4790a6a1f1dSLionel Sambuc // This is a weird hack to ensure that the output of the parent process
4800a6a1f1dSLionel Sambuc // is flushed before executing a child which prevents, for example, the
4810a6a1f1dSLionel Sambuc // output of the atf-run hooks to appear before the output of atf-run
4820a6a1f1dSLionel Sambuc // itself.
4830a6a1f1dSLionel Sambuc //
4840a6a1f1dSLionel Sambuc // TODO: This should only be executed when inheriting the stdout or
4850a6a1f1dSLionel Sambuc // stderr file descriptors. However, the flushing is specific to the
4860a6a1f1dSLionel Sambuc // iostreams, so we cannot do it from the C library where all the process
4870a6a1f1dSLionel Sambuc // logic is performed. Come up with a better design.
4880a6a1f1dSLionel Sambuc std::cout.flush();
4890a6a1f1dSLionel Sambuc std::cerr.flush();
4900a6a1f1dSLionel Sambuc }
491