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