1*b0d29bc4SBrooks Davis // Copyright 2014 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/process/operations.hpp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis extern "C" {
32*b0d29bc4SBrooks Davis #include <sys/types.h>
33*b0d29bc4SBrooks Davis #include <sys/wait.h>
34*b0d29bc4SBrooks Davis 
35*b0d29bc4SBrooks Davis #include <signal.h>
36*b0d29bc4SBrooks Davis #include <unistd.h>
37*b0d29bc4SBrooks Davis }
38*b0d29bc4SBrooks Davis 
39*b0d29bc4SBrooks Davis #include <cerrno>
40*b0d29bc4SBrooks Davis #include <iostream>
41*b0d29bc4SBrooks Davis 
42*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
43*b0d29bc4SBrooks Davis 
44*b0d29bc4SBrooks Davis #include "utils/defs.hpp"
45*b0d29bc4SBrooks Davis #include "utils/format/containers.ipp"
46*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
47*b0d29bc4SBrooks Davis #include "utils/process/child.ipp"
48*b0d29bc4SBrooks Davis #include "utils/process/exceptions.hpp"
49*b0d29bc4SBrooks Davis #include "utils/process/status.hpp"
50*b0d29bc4SBrooks Davis #include "utils/stacktrace.hpp"
51*b0d29bc4SBrooks Davis #include "utils/test_utils.ipp"
52*b0d29bc4SBrooks Davis 
53*b0d29bc4SBrooks Davis namespace fs = utils::fs;
54*b0d29bc4SBrooks Davis namespace process = utils::process;
55*b0d29bc4SBrooks Davis 
56*b0d29bc4SBrooks Davis 
57*b0d29bc4SBrooks Davis namespace {
58*b0d29bc4SBrooks Davis 
59*b0d29bc4SBrooks Davis 
60*b0d29bc4SBrooks Davis /// Type of the process::exec() and process::exec_unsafe() functions.
61*b0d29bc4SBrooks Davis typedef void (*exec_function)(const fs::path&, const process::args_vector&);
62*b0d29bc4SBrooks Davis 
63*b0d29bc4SBrooks Davis 
64*b0d29bc4SBrooks Davis /// Calculates the path to the test helpers binary.
65*b0d29bc4SBrooks Davis ///
66*b0d29bc4SBrooks Davis /// \param tc A pointer to the caller test case, needed to extract the value of
67*b0d29bc4SBrooks Davis ///     the "srcdir" property.
68*b0d29bc4SBrooks Davis ///
69*b0d29bc4SBrooks Davis /// \return The path to the helpers binary.
70*b0d29bc4SBrooks Davis static fs::path
get_helpers(const atf::tests::tc * tc)71*b0d29bc4SBrooks Davis get_helpers(const atf::tests::tc* tc)
72*b0d29bc4SBrooks Davis {
73*b0d29bc4SBrooks Davis     return fs::path(tc->get_config_var("srcdir")) / "helpers";
74*b0d29bc4SBrooks Davis }
75*b0d29bc4SBrooks Davis 
76*b0d29bc4SBrooks Davis 
77*b0d29bc4SBrooks Davis /// Body for a subprocess that runs exec().
78*b0d29bc4SBrooks Davis class child_exec {
79*b0d29bc4SBrooks Davis     /// Function to do the exec.
80*b0d29bc4SBrooks Davis     const exec_function _do_exec;
81*b0d29bc4SBrooks Davis 
82*b0d29bc4SBrooks Davis     /// Path to the binary to exec.
83*b0d29bc4SBrooks Davis     const fs::path& _program;
84*b0d29bc4SBrooks Davis 
85*b0d29bc4SBrooks Davis     /// Arguments to the binary, not including argv[0].
86*b0d29bc4SBrooks Davis     const process::args_vector& _args;
87*b0d29bc4SBrooks Davis 
88*b0d29bc4SBrooks Davis public:
89*b0d29bc4SBrooks Davis     /// Constructor.
90*b0d29bc4SBrooks Davis     ///
91*b0d29bc4SBrooks Davis     /// \param do_exec Function to do the exec.
92*b0d29bc4SBrooks Davis     /// \param program Path to the binary to exec.
93*b0d29bc4SBrooks Davis     /// \param args Arguments to the binary, not including argv[0].
child_exec(const exec_function do_exec,const fs::path & program,const process::args_vector & args)94*b0d29bc4SBrooks Davis     child_exec(const exec_function do_exec, const fs::path& program,
95*b0d29bc4SBrooks Davis                const process::args_vector& args) :
96*b0d29bc4SBrooks Davis         _do_exec(do_exec), _program(program), _args(args)
97*b0d29bc4SBrooks Davis     {
98*b0d29bc4SBrooks Davis     }
99*b0d29bc4SBrooks Davis 
100*b0d29bc4SBrooks Davis     /// Body for the subprocess.
101*b0d29bc4SBrooks Davis     void
operator ()(void)102*b0d29bc4SBrooks Davis     operator()(void)
103*b0d29bc4SBrooks Davis     {
104*b0d29bc4SBrooks Davis         _do_exec(_program, _args);
105*b0d29bc4SBrooks Davis     }
106*b0d29bc4SBrooks Davis };
107*b0d29bc4SBrooks Davis 
108*b0d29bc4SBrooks Davis 
109*b0d29bc4SBrooks Davis /// Body for a process that returns a specific exit code.
110*b0d29bc4SBrooks Davis ///
111*b0d29bc4SBrooks Davis /// \tparam ExitStatus The exit status for the subprocess.
112*b0d29bc4SBrooks Davis template< int ExitStatus >
113*b0d29bc4SBrooks Davis static void
child_exit(void)114*b0d29bc4SBrooks Davis child_exit(void)
115*b0d29bc4SBrooks Davis {
116*b0d29bc4SBrooks Davis     std::exit(ExitStatus);
117*b0d29bc4SBrooks Davis }
118*b0d29bc4SBrooks Davis 
119*b0d29bc4SBrooks Davis 
120*b0d29bc4SBrooks Davis static void suspend(void) UTILS_NORETURN;
121*b0d29bc4SBrooks Davis 
122*b0d29bc4SBrooks Davis 
123*b0d29bc4SBrooks Davis /// Blocks a subprocess from running indefinitely.
124*b0d29bc4SBrooks Davis static void
suspend(void)125*b0d29bc4SBrooks Davis suspend(void)
126*b0d29bc4SBrooks Davis {
127*b0d29bc4SBrooks Davis     sigset_t mask;
128*b0d29bc4SBrooks Davis     sigemptyset(&mask);
129*b0d29bc4SBrooks Davis     for (;;) {
130*b0d29bc4SBrooks Davis         ::sigsuspend(&mask);
131*b0d29bc4SBrooks Davis     }
132*b0d29bc4SBrooks Davis }
133*b0d29bc4SBrooks Davis 
134*b0d29bc4SBrooks Davis 
135*b0d29bc4SBrooks Davis static void write_loop(const int) UTILS_NORETURN;
136*b0d29bc4SBrooks Davis 
137*b0d29bc4SBrooks Davis 
138*b0d29bc4SBrooks Davis /// Provides an infinite stream of data in a subprocess.
139*b0d29bc4SBrooks Davis ///
140*b0d29bc4SBrooks Davis /// \param fd Descriptor into which to write.
141*b0d29bc4SBrooks Davis static void
write_loop(const int fd)142*b0d29bc4SBrooks Davis write_loop(const int fd)
143*b0d29bc4SBrooks Davis {
144*b0d29bc4SBrooks Davis     const int cookie = 0x12345678;
145*b0d29bc4SBrooks Davis     for (;;) {
146*b0d29bc4SBrooks Davis         std::cerr << "Still alive in PID " << ::getpid() << '\n';
147*b0d29bc4SBrooks Davis         if (::write(fd, &cookie, sizeof(cookie)) != sizeof(cookie))
148*b0d29bc4SBrooks Davis             std::exit(EXIT_FAILURE);
149*b0d29bc4SBrooks Davis         ::sleep(1);
150*b0d29bc4SBrooks Davis     }
151*b0d29bc4SBrooks Davis }
152*b0d29bc4SBrooks Davis 
153*b0d29bc4SBrooks Davis 
154*b0d29bc4SBrooks Davis }  // anonymous namespace
155*b0d29bc4SBrooks Davis 
156*b0d29bc4SBrooks Davis 
157*b0d29bc4SBrooks Davis /// Tests an exec function with no arguments.
158*b0d29bc4SBrooks Davis ///
159*b0d29bc4SBrooks Davis /// \param tc The calling test case.
160*b0d29bc4SBrooks Davis /// \param do_exec The exec function to test.
161*b0d29bc4SBrooks Davis static void
check_exec_no_args(const atf::tests::tc * tc,const exec_function do_exec)162*b0d29bc4SBrooks Davis check_exec_no_args(const atf::tests::tc* tc, const exec_function do_exec)
163*b0d29bc4SBrooks Davis {
164*b0d29bc4SBrooks Davis     std::auto_ptr< process::child > child = process::child::fork_files(
165*b0d29bc4SBrooks Davis         child_exec(do_exec, get_helpers(tc), process::args_vector()),
166*b0d29bc4SBrooks Davis         fs::path("stdout"), fs::path("stderr"));
167*b0d29bc4SBrooks Davis     const process::status status = child->wait();
168*b0d29bc4SBrooks Davis     ATF_REQUIRE(status.exited());
169*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(EXIT_FAILURE, status.exitstatus());
170*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::grep_file("Must provide a helper name", "stderr"));
171*b0d29bc4SBrooks Davis }
172*b0d29bc4SBrooks Davis 
173*b0d29bc4SBrooks Davis 
174*b0d29bc4SBrooks Davis /// Tests an exec function with some arguments.
175*b0d29bc4SBrooks Davis ///
176*b0d29bc4SBrooks Davis /// \param tc The calling test case.
177*b0d29bc4SBrooks Davis /// \param do_exec The exec function to test.
178*b0d29bc4SBrooks Davis static void
check_exec_some_args(const atf::tests::tc * tc,const exec_function do_exec)179*b0d29bc4SBrooks Davis check_exec_some_args(const atf::tests::tc* tc, const exec_function do_exec)
180*b0d29bc4SBrooks Davis {
181*b0d29bc4SBrooks Davis     process::args_vector args;
182*b0d29bc4SBrooks Davis     args.push_back("print-args");
183*b0d29bc4SBrooks Davis     args.push_back("foo");
184*b0d29bc4SBrooks Davis     args.push_back("bar");
185*b0d29bc4SBrooks Davis 
186*b0d29bc4SBrooks Davis     std::auto_ptr< process::child > child = process::child::fork_files(
187*b0d29bc4SBrooks Davis         child_exec(do_exec, get_helpers(tc), args),
188*b0d29bc4SBrooks Davis         fs::path("stdout"), fs::path("stderr"));
189*b0d29bc4SBrooks Davis     const process::status status = child->wait();
190*b0d29bc4SBrooks Davis     ATF_REQUIRE(status.exited());
191*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
192*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::grep_file("argv\\[1\\] = print-args", "stdout"));
193*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::grep_file("argv\\[2\\] = foo", "stdout"));
194*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::grep_file("argv\\[3\\] = bar", "stdout"));
195*b0d29bc4SBrooks Davis }
196*b0d29bc4SBrooks Davis 
197*b0d29bc4SBrooks Davis 
198*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec__no_args);
ATF_TEST_CASE_BODY(exec__no_args)199*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec__no_args)
200*b0d29bc4SBrooks Davis {
201*b0d29bc4SBrooks Davis     check_exec_no_args(this, process::exec);
202*b0d29bc4SBrooks Davis }
203*b0d29bc4SBrooks Davis 
204*b0d29bc4SBrooks Davis 
205*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec__some_args);
ATF_TEST_CASE_BODY(exec__some_args)206*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec__some_args)
207*b0d29bc4SBrooks Davis {
208*b0d29bc4SBrooks Davis     check_exec_some_args(this, process::exec);
209*b0d29bc4SBrooks Davis }
210*b0d29bc4SBrooks Davis 
211*b0d29bc4SBrooks Davis 
212*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec__fail);
ATF_TEST_CASE_BODY(exec__fail)213*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec__fail)
214*b0d29bc4SBrooks Davis {
215*b0d29bc4SBrooks Davis     utils::avoid_coredump_on_crash();
216*b0d29bc4SBrooks Davis 
217*b0d29bc4SBrooks Davis     std::auto_ptr< process::child > child = process::child::fork_files(
218*b0d29bc4SBrooks Davis         child_exec(process::exec, fs::path("non-existent"),
219*b0d29bc4SBrooks Davis                    process::args_vector()),
220*b0d29bc4SBrooks Davis         fs::path("stdout"), fs::path("stderr"));
221*b0d29bc4SBrooks Davis     const process::status status = child->wait();
222*b0d29bc4SBrooks Davis     ATF_REQUIRE(status.signaled());
223*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(SIGABRT, status.termsig());
224*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::grep_file("Failed to execute non-existent",
225*b0d29bc4SBrooks Davis                                       "stderr"));
226*b0d29bc4SBrooks Davis }
227*b0d29bc4SBrooks Davis 
228*b0d29bc4SBrooks Davis 
229*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__no_args);
ATF_TEST_CASE_BODY(exec_unsafe__no_args)230*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec_unsafe__no_args)
231*b0d29bc4SBrooks Davis {
232*b0d29bc4SBrooks Davis     check_exec_no_args(this, process::exec_unsafe);
233*b0d29bc4SBrooks Davis }
234*b0d29bc4SBrooks Davis 
235*b0d29bc4SBrooks Davis 
236*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__some_args);
ATF_TEST_CASE_BODY(exec_unsafe__some_args)237*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec_unsafe__some_args)
238*b0d29bc4SBrooks Davis {
239*b0d29bc4SBrooks Davis     check_exec_some_args(this, process::exec_unsafe);
240*b0d29bc4SBrooks Davis }
241*b0d29bc4SBrooks Davis 
242*b0d29bc4SBrooks Davis 
243*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(exec_unsafe__fail);
ATF_TEST_CASE_BODY(exec_unsafe__fail)244*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(exec_unsafe__fail)
245*b0d29bc4SBrooks Davis {
246*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(
247*b0d29bc4SBrooks Davis         process::system_error, "Failed to execute missing-program",
248*b0d29bc4SBrooks Davis         process::exec_unsafe(fs::path("missing-program"),
249*b0d29bc4SBrooks Davis                              process::args_vector()));
250*b0d29bc4SBrooks Davis }
251*b0d29bc4SBrooks Davis 
252*b0d29bc4SBrooks Davis 
253*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(terminate_group__setpgrp_executed);
ATF_TEST_CASE_BODY(terminate_group__setpgrp_executed)254*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(terminate_group__setpgrp_executed)
255*b0d29bc4SBrooks Davis {
256*b0d29bc4SBrooks Davis     int first_fds[2], second_fds[2];
257*b0d29bc4SBrooks Davis     ATF_REQUIRE(::pipe(first_fds) != -1);
258*b0d29bc4SBrooks Davis     ATF_REQUIRE(::pipe(second_fds) != -1);
259*b0d29bc4SBrooks Davis 
260*b0d29bc4SBrooks Davis     const pid_t pid = ::fork();
261*b0d29bc4SBrooks Davis     ATF_REQUIRE(pid != -1);
262*b0d29bc4SBrooks Davis     if (pid == 0) {
263*b0d29bc4SBrooks Davis         ::setpgid(::getpid(), ::getpid());
264*b0d29bc4SBrooks Davis         const pid_t pid2 = ::fork();
265*b0d29bc4SBrooks Davis         if (pid2 == -1) {
266*b0d29bc4SBrooks Davis             std::exit(EXIT_FAILURE);
267*b0d29bc4SBrooks Davis         } else if (pid2 == 0) {
268*b0d29bc4SBrooks Davis             ::close(first_fds[0]);
269*b0d29bc4SBrooks Davis             ::close(first_fds[1]);
270*b0d29bc4SBrooks Davis             ::close(second_fds[0]);
271*b0d29bc4SBrooks Davis             write_loop(second_fds[1]);
272*b0d29bc4SBrooks Davis         }
273*b0d29bc4SBrooks Davis         ::close(first_fds[0]);
274*b0d29bc4SBrooks Davis         ::close(second_fds[0]);
275*b0d29bc4SBrooks Davis         ::close(second_fds[1]);
276*b0d29bc4SBrooks Davis         write_loop(first_fds[1]);
277*b0d29bc4SBrooks Davis     }
278*b0d29bc4SBrooks Davis     ::close(first_fds[1]);
279*b0d29bc4SBrooks Davis     ::close(second_fds[1]);
280*b0d29bc4SBrooks Davis 
281*b0d29bc4SBrooks Davis     int dummy;
282*b0d29bc4SBrooks Davis     std::cerr << "Waiting for children to start\n";
283*b0d29bc4SBrooks Davis     while (::read(first_fds[0], &dummy, sizeof(dummy)) <= 0 ||
284*b0d29bc4SBrooks Davis            ::read(second_fds[0], &dummy, sizeof(dummy)) <= 0) {
285*b0d29bc4SBrooks Davis         // Wait for children to come up.
286*b0d29bc4SBrooks Davis     }
287*b0d29bc4SBrooks Davis 
288*b0d29bc4SBrooks Davis     process::terminate_group(pid);
289*b0d29bc4SBrooks Davis     std::cerr << "Waiting for children to die\n";
290*b0d29bc4SBrooks Davis     while (::read(first_fds[0], &dummy, sizeof(dummy)) > 0 ||
291*b0d29bc4SBrooks Davis            ::read(second_fds[0], &dummy, sizeof(dummy)) > 0) {
292*b0d29bc4SBrooks Davis         // Wait for children to terminate.  If they don't, then the test case
293*b0d29bc4SBrooks Davis         // will time out.
294*b0d29bc4SBrooks Davis     }
295*b0d29bc4SBrooks Davis 
296*b0d29bc4SBrooks Davis     int status;
297*b0d29bc4SBrooks Davis     ATF_REQUIRE(::wait(&status) != -1);
298*b0d29bc4SBrooks Davis     ATF_REQUIRE(WIFSIGNALED(status));
299*b0d29bc4SBrooks Davis     ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
300*b0d29bc4SBrooks Davis }
301*b0d29bc4SBrooks Davis 
302*b0d29bc4SBrooks Davis 
303*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(terminate_group__setpgrp_not_executed);
ATF_TEST_CASE_BODY(terminate_group__setpgrp_not_executed)304*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(terminate_group__setpgrp_not_executed)
305*b0d29bc4SBrooks Davis {
306*b0d29bc4SBrooks Davis     const pid_t pid = ::fork();
307*b0d29bc4SBrooks Davis     ATF_REQUIRE(pid != -1);
308*b0d29bc4SBrooks Davis     if (pid == 0) {
309*b0d29bc4SBrooks Davis         // We do not call setgprp() here to simulate the race that happens when
310*b0d29bc4SBrooks Davis         // we invoke terminate_group on a process that has not yet had a chance
311*b0d29bc4SBrooks Davis         // to run the setpgrp() call.
312*b0d29bc4SBrooks Davis         suspend();
313*b0d29bc4SBrooks Davis     }
314*b0d29bc4SBrooks Davis 
315*b0d29bc4SBrooks Davis     process::terminate_group(pid);
316*b0d29bc4SBrooks Davis 
317*b0d29bc4SBrooks Davis     int status;
318*b0d29bc4SBrooks Davis     ATF_REQUIRE(::wait(&status) != -1);
319*b0d29bc4SBrooks Davis     ATF_REQUIRE(WIFSIGNALED(status));
320*b0d29bc4SBrooks Davis     ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
321*b0d29bc4SBrooks Davis }
322*b0d29bc4SBrooks Davis 
323*b0d29bc4SBrooks Davis 
324*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__exitstatus);
ATF_TEST_CASE_BODY(terminate_self_with__exitstatus)325*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(terminate_self_with__exitstatus)
326*b0d29bc4SBrooks Davis {
327*b0d29bc4SBrooks Davis     const pid_t pid = ::fork();
328*b0d29bc4SBrooks Davis     ATF_REQUIRE(pid != -1);
329*b0d29bc4SBrooks Davis     if (pid == 0) {
330*b0d29bc4SBrooks Davis         const process::status status = process::status::fake_exited(123);
331*b0d29bc4SBrooks Davis         process::terminate_self_with(status);
332*b0d29bc4SBrooks Davis     }
333*b0d29bc4SBrooks Davis 
334*b0d29bc4SBrooks Davis     int status;
335*b0d29bc4SBrooks Davis     ATF_REQUIRE(::wait(&status) != -1);
336*b0d29bc4SBrooks Davis     ATF_REQUIRE(WIFEXITED(status));
337*b0d29bc4SBrooks Davis     ATF_REQUIRE(WEXITSTATUS(status) == 123);
338*b0d29bc4SBrooks Davis }
339*b0d29bc4SBrooks Davis 
340*b0d29bc4SBrooks Davis 
341*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__termsig);
ATF_TEST_CASE_BODY(terminate_self_with__termsig)342*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(terminate_self_with__termsig)
343*b0d29bc4SBrooks Davis {
344*b0d29bc4SBrooks Davis     const pid_t pid = ::fork();
345*b0d29bc4SBrooks Davis     ATF_REQUIRE(pid != -1);
346*b0d29bc4SBrooks Davis     if (pid == 0) {
347*b0d29bc4SBrooks Davis         const process::status status = process::status::fake_signaled(
348*b0d29bc4SBrooks Davis             SIGKILL, false);
349*b0d29bc4SBrooks Davis         process::terminate_self_with(status);
350*b0d29bc4SBrooks Davis     }
351*b0d29bc4SBrooks Davis 
352*b0d29bc4SBrooks Davis     int status;
353*b0d29bc4SBrooks Davis     ATF_REQUIRE(::wait(&status) != -1);
354*b0d29bc4SBrooks Davis     ATF_REQUIRE(WIFSIGNALED(status));
355*b0d29bc4SBrooks Davis     ATF_REQUIRE(WTERMSIG(status) == SIGKILL);
356*b0d29bc4SBrooks Davis     ATF_REQUIRE(!WCOREDUMP(status));
357*b0d29bc4SBrooks Davis }
358*b0d29bc4SBrooks Davis 
359*b0d29bc4SBrooks Davis 
360*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(terminate_self_with__termsig_and_core);
ATF_TEST_CASE_BODY(terminate_self_with__termsig_and_core)361*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(terminate_self_with__termsig_and_core)
362*b0d29bc4SBrooks Davis {
363*b0d29bc4SBrooks Davis     utils::prepare_coredump_test(this);
364*b0d29bc4SBrooks Davis 
365*b0d29bc4SBrooks Davis     const pid_t pid = ::fork();
366*b0d29bc4SBrooks Davis     ATF_REQUIRE(pid != -1);
367*b0d29bc4SBrooks Davis     if (pid == 0) {
368*b0d29bc4SBrooks Davis         const process::status status = process::status::fake_signaled(
369*b0d29bc4SBrooks Davis             SIGABRT, true);
370*b0d29bc4SBrooks Davis         process::terminate_self_with(status);
371*b0d29bc4SBrooks Davis     }
372*b0d29bc4SBrooks Davis 
373*b0d29bc4SBrooks Davis     int status;
374*b0d29bc4SBrooks Davis     ATF_REQUIRE(::wait(&status) != -1);
375*b0d29bc4SBrooks Davis     ATF_REQUIRE(WIFSIGNALED(status));
376*b0d29bc4SBrooks Davis     ATF_REQUIRE(WTERMSIG(status) == SIGABRT);
377*b0d29bc4SBrooks Davis     ATF_REQUIRE(WCOREDUMP(status));
378*b0d29bc4SBrooks Davis }
379*b0d29bc4SBrooks Davis 
380*b0d29bc4SBrooks Davis 
381*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(wait__ok);
ATF_TEST_CASE_BODY(wait__ok)382*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(wait__ok)
383*b0d29bc4SBrooks Davis {
384*b0d29bc4SBrooks Davis     std::auto_ptr< process::child > child = process::child::fork_capture(
385*b0d29bc4SBrooks Davis         child_exit< 15 >);
386*b0d29bc4SBrooks Davis     const pid_t pid = child->pid();
387*b0d29bc4SBrooks Davis     child.reset();  // Ensure there is no conflict between destructor and wait.
388*b0d29bc4SBrooks Davis 
389*b0d29bc4SBrooks Davis     const process::status status = process::wait(pid);
390*b0d29bc4SBrooks Davis     ATF_REQUIRE(status.exited());
391*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(15, status.exitstatus());
392*b0d29bc4SBrooks Davis }
393*b0d29bc4SBrooks Davis 
394*b0d29bc4SBrooks Davis 
395*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(wait__fail);
ATF_TEST_CASE_BODY(wait__fail)396*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(wait__fail)
397*b0d29bc4SBrooks Davis {
398*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW(process::system_error, process::wait(1));
399*b0d29bc4SBrooks Davis }
400*b0d29bc4SBrooks Davis 
401*b0d29bc4SBrooks Davis 
402*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(wait_any__one);
ATF_TEST_CASE_BODY(wait_any__one)403*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(wait_any__one)
404*b0d29bc4SBrooks Davis {
405*b0d29bc4SBrooks Davis     process::child::fork_capture(child_exit< 15 >);
406*b0d29bc4SBrooks Davis 
407*b0d29bc4SBrooks Davis     const process::status status = process::wait_any();
408*b0d29bc4SBrooks Davis     ATF_REQUIRE(status.exited());
409*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(15, status.exitstatus());
410*b0d29bc4SBrooks Davis }
411*b0d29bc4SBrooks Davis 
412*b0d29bc4SBrooks Davis 
413*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(wait_any__many);
ATF_TEST_CASE_BODY(wait_any__many)414*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(wait_any__many)
415*b0d29bc4SBrooks Davis {
416*b0d29bc4SBrooks Davis     process::child::fork_capture(child_exit< 15 >);
417*b0d29bc4SBrooks Davis     process::child::fork_capture(child_exit< 30 >);
418*b0d29bc4SBrooks Davis     process::child::fork_capture(child_exit< 45 >);
419*b0d29bc4SBrooks Davis 
420*b0d29bc4SBrooks Davis     std::set< int > exit_codes;
421*b0d29bc4SBrooks Davis     for (int i = 0; i < 3; i++) {
422*b0d29bc4SBrooks Davis         const process::status status = process::wait_any();
423*b0d29bc4SBrooks Davis         ATF_REQUIRE(status.exited());
424*b0d29bc4SBrooks Davis         exit_codes.insert(status.exitstatus());
425*b0d29bc4SBrooks Davis     }
426*b0d29bc4SBrooks Davis 
427*b0d29bc4SBrooks Davis     std::set< int > exp_exit_codes;
428*b0d29bc4SBrooks Davis     exp_exit_codes.insert(15);
429*b0d29bc4SBrooks Davis     exp_exit_codes.insert(30);
430*b0d29bc4SBrooks Davis     exp_exit_codes.insert(45);
431*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_exit_codes, exit_codes);
432*b0d29bc4SBrooks Davis }
433*b0d29bc4SBrooks Davis 
434*b0d29bc4SBrooks Davis 
435*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(wait_any__none_is_failure);
ATF_TEST_CASE_BODY(wait_any__none_is_failure)436*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(wait_any__none_is_failure)
437*b0d29bc4SBrooks Davis {
438*b0d29bc4SBrooks Davis     try {
439*b0d29bc4SBrooks Davis         const process::status status = process::wait_any();
440*b0d29bc4SBrooks Davis         fail("Expected exception but none raised");
441*b0d29bc4SBrooks Davis     } catch (const process::system_error& e) {
442*b0d29bc4SBrooks Davis         ATF_REQUIRE(atf::utils::grep_string("Failed to wait", e.what()));
443*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(ECHILD, e.original_errno());
444*b0d29bc4SBrooks Davis     }
445*b0d29bc4SBrooks Davis }
446*b0d29bc4SBrooks Davis 
447*b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)448*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
449*b0d29bc4SBrooks Davis {
450*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec__no_args);
451*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec__some_args);
452*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec__fail);
453*b0d29bc4SBrooks Davis 
454*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec_unsafe__no_args);
455*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec_unsafe__some_args);
456*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, exec_unsafe__fail);
457*b0d29bc4SBrooks Davis 
458*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, terminate_group__setpgrp_executed);
459*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, terminate_group__setpgrp_not_executed);
460*b0d29bc4SBrooks Davis 
461*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, terminate_self_with__exitstatus);
462*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, terminate_self_with__termsig);
463*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, terminate_self_with__termsig_and_core);
464*b0d29bc4SBrooks Davis 
465*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, wait__ok);
466*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, wait__fail);
467*b0d29bc4SBrooks Davis 
468*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, wait_any__one);
469*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, wait_any__many);
470*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, wait_any__none_is_failure);
471*b0d29bc4SBrooks Davis }
472