2 // Automated Testing Framework (atf)
4 // Copyright (c) 2008 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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.
31 #include <sys/types.h>
44 #include "exceptions.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 // ------------------------------------------------------------------------
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]);
63 for (typename
C::const_iterator iter
= c
.begin(); iter
!= c
.end();
65 argv
[pos
] = (*iter
).c_str();
68 assert(pos
== c
.size());
76 argv_to_collection(const char* const* argv
)
80 for (const char* const* iter
= argv
; *iter
!= NULL
; iter
++)
81 c
.push_back(std::string(*iter
));
88 safe_dup(const int oldfd
, const int newfd
)
91 if (dup2(oldfd
, newfd
) == -1) {
92 throw tools::system_error(IMPL_NAME
"::safe_dup",
93 "Could not allocate file descriptor",
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
)));
111 detail::do_exec(void *v
)
113 struct exec_args
*ea
= reinterpret_cast<struct exec_args
*>(v
);
115 if (ea
->m_prehook
!= NULL
)
118 #if !defined(NDEBUG) && defined(__minix)
120 #endif /* !defined(NDEBUG) && defined(__minix) */
121 const_execvp(ea
->m_prog
.c_str(), ea
->m_argv
.exec_argv());
122 const int errnocopy
= errno
;
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
);
147 while ((nextarg
= va_arg(ap
, const char*)) != NULL
)
148 m_args
.push_back(nextarg
);
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
) :
163 m_exec_argv(collection_to_argv(m_args
))
168 impl::argv_array::ctor_init_exec_argv(void)
170 m_exec_argv
= collection_to_argv(m_args
);
174 impl::argv_array::exec_argv(void)
177 return m_exec_argv
.get();
180 impl::argv_array::size_type
181 impl::argv_array::size(void)
184 return m_args
.size();
188 impl::argv_array::operator[](int idx
)
191 return m_args
[idx
].c_str();
194 impl::argv_array::const_iterator
195 impl::argv_array::begin(void)
198 return m_args
.begin();
201 impl::argv_array::const_iterator
202 impl::argv_array::end(void)
209 impl::argv_array::operator=(const argv_array
& a
)
213 m_exec_argv
= collection_to_argv(m_args
);
218 // ------------------------------------------------------------------------
219 // The "stream" types.
220 // ------------------------------------------------------------------------
222 impl::stream_capture::stream_capture(void)
224 for (int i
= 0; i
< 2; i
++)
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
]);
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];
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
);
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
)
268 impl::stream_connect::prepare(void)
273 impl::stream_connect::connect_parent(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)
289 impl::stream_inherit::prepare(void)
294 impl::stream_inherit::connect_parent(void)
300 impl::stream_inherit::connect_child(const int fd
__attribute__((__unused__
)))
304 impl::stream_redirect_fd::stream_redirect_fd(const int fd
) :
310 impl::stream_redirect_fd::prepare(void)
315 impl::stream_redirect_fd::connect_parent(void)
321 impl::stream_redirect_fd::connect_child(const int fd
)
326 impl::stream_redirect_path::stream_redirect_path(const tools::fs::path
& p
) :
332 impl::stream_redirect_path::prepare(void)
337 impl::stream_redirect_path::connect_parent(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);
347 throw system_error(IMPL_NAME
"::stream_redirect_path::connect_child",
348 "Could not create " + m_path
.str(), errno
);
353 // ------------------------------------------------------------------------
354 // The "status" type.
355 // ------------------------------------------------------------------------
357 impl::status::status(int s
) :
362 impl::status::~status(void)
367 impl::status::exited(void)
370 int mutable_status
= m_status
;
371 return WIFEXITED(mutable_status
);
375 impl::status::exitstatus(void)
379 int mutable_status
= m_status
;
380 return WEXITSTATUS(mutable_status
);
384 impl::status::signaled(void)
387 int mutable_status
= m_status
;
388 return WIFSIGNALED(mutable_status
);
392 impl::status::termsig(void)
396 int mutable_status
= m_status
;
397 return WTERMSIG(mutable_status
);
401 impl::status::coredump(void)
405 int mutable_status
= m_status
;
406 return WCOREDUMP(mutable_status
);
409 // ------------------------------------------------------------------------
411 // ------------------------------------------------------------------------
413 impl::child::child(const pid_t pid_arg
, const int stdout_fd_arg
,
414 const int stderr_fd_arg
) :
416 m_stdout(stdout_fd_arg
),
417 m_stderr(stderr_fd_arg
),
422 impl::child::~child(void)
425 ::kill(m_pid
, SIGTERM
);
436 impl::child::wait(void)
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
);
445 ::close(m_stdout
); m_stdout
= -1;
447 ::close(m_stderr
); m_stderr
= -1;
454 impl::child::pid(void)
461 impl::child::stdout_fd(void)
467 impl::child::stderr_fd(void)
472 // ------------------------------------------------------------------------
474 // ------------------------------------------------------------------------
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
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.