2 // Automated Testing Framework (atf)
4 // Copyright (c) 2008, 2009 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>
43 #include "atf-c++/application.hpp"
44 #include "atf-c++/exceptions.hpp"
45 #include "atf-c++/process.hpp"
46 #include "atf-c++/sanity.hpp"
47 #include "atf-c++/signals.hpp"
48 #include "atf-c++/text.hpp"
51 static bool happened
= false;
60 class atf_exec
: public atf::application::app
{
61 static const char* m_description
;
63 std::string
specific_args(void) const;
64 options_set
specific_options(void) const;
65 void process_option(int, const char*);
67 void process_option_t(const std::string
&);
68 unsigned int m_timeout_secs
;
69 std::string m_timeout_file
;
71 static void route_do_exec(void *);
72 void do_exec(void) const;
74 static int handle_status(const atf::process::status
&);
82 const char* atf_exec::m_description
=
83 "atf-exec executes the given command in a controlled manner.";
85 atf_exec::atf_exec(void) :
86 app(m_description
, "atf-exec(1)", "atf(7)"),
92 atf_exec::specific_args(void)
99 atf_exec::specific_options(void)
102 using atf::application::option
;
104 opts
.insert(option('t', "secs:file", "Kills the command after the "
105 "specified amount of time and "
106 "creates the given file"));
111 atf_exec::process_option_t(const std::string
& arg
)
113 using atf::application::usage_error
;
115 std::string::size_type pos
= arg
.find(':');
116 if (pos
== std::string::npos
)
117 throw usage_error("Invalid value for -t option; must be of the "
120 throw usage_error("Invalid value for -t option; secs cannot be "
122 if (pos
== arg
.length() - 1)
123 throw usage_error("Invalid value for -t option; file cannot be "
126 m_timeout_secs
= atf::text::to_type
< unsigned int >(arg
.substr(0, pos
));
127 m_timeout_file
= arg
.substr(pos
+ 1);
131 atf_exec::process_option(int ch
, const char* arg
)
135 process_option_t(arg
);
144 atf_exec::route_do_exec(void *v
)
146 atf_exec
* ae
= static_cast< atf_exec
* >(v
);
151 atf_exec::do_exec(void)
154 if (::setpgid(::getpid(), 0) == -1)
155 throw atf::system_error("main", "setpgid failed", errno
);
157 char** argv
= new char*[m_argc
+ 1];
158 for (int i
= 0; i
< m_argc
; i
++)
159 argv
[i
] = ::strdup(m_argv
[i
]);
162 ::execvp(m_argv
[0], argv
);
163 // TODO: Handle error code from execvp.
168 atf_exec::handle_status(const atf::process::status
& s
)
170 int exitcode
= EXIT_FAILURE
;
173 exitcode
= s
.exitstatus();
174 else if (s
.signaled())
175 ::kill(0, s
.termsig());
186 throw atf::application::usage_error("No command specified");
188 atf::process::child c
=
189 atf::process::fork(route_do_exec
,
190 atf::process::stream_inherit(),
191 atf::process::stream_inherit(),
194 atf::signals::signal_programmer
sp(SIGALRM
, sigalarm::handler
);
196 if (m_timeout_secs
> 0) {
197 struct itimerval itv
;
199 timerclear(&itv
.it_interval
);
200 timerclear(&itv
.it_value
);
201 itv
.it_value
.tv_sec
= m_timeout_secs
;
202 if (setitimer(ITIMER_REAL
, &itv
, NULL
) == -1)
203 throw atf::system_error("main", "setitimer failed", errno
);
208 const atf::process::status s
= c
.wait();
209 exitcode
= handle_status(s
);
210 } catch (const atf::system_error
& e
) {
211 if (e
.code() == EINTR
) {
212 if (sigalarm::happened
) {
213 INV(m_timeout_secs
> 0);
215 ::killpg(c
.pid(), SIGTERM
);
217 std::ofstream
os(m_timeout_file
.c_str());
220 exitcode
= EXIT_FAILURE
;
233 main(int argc
, char* const* argv
)
235 return atf_exec().run(argc
, argv
);