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