xref: /freebsd/contrib/kyua/utils/signals/misc_test.cpp (revision b392a90ba4e5ea07d8a88a834fd102191d1967bf)
1b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2b0d29bc4SBrooks Davis // All rights reserved.
3b0d29bc4SBrooks Davis //
4b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6b0d29bc4SBrooks Davis // met:
7b0d29bc4SBrooks Davis //
8b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15b0d29bc4SBrooks Davis //   without specific prior written permission.
16b0d29bc4SBrooks Davis //
17b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28b0d29bc4SBrooks Davis 
29b0d29bc4SBrooks Davis #include "utils/signals/misc.hpp"
30b0d29bc4SBrooks Davis 
31b0d29bc4SBrooks Davis extern "C" {
32b0d29bc4SBrooks Davis #include <signal.h>
33b0d29bc4SBrooks Davis #include <unistd.h>
34b0d29bc4SBrooks Davis }
35b0d29bc4SBrooks Davis 
36b0d29bc4SBrooks Davis #include <cstdlib>
37b0d29bc4SBrooks Davis 
38b0d29bc4SBrooks Davis #include <atf-c++.hpp>
39b0d29bc4SBrooks Davis 
40b0d29bc4SBrooks Davis #include "utils/defs.hpp"
41b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
42b0d29bc4SBrooks Davis #include "utils/process/child.ipp"
43b0d29bc4SBrooks Davis #include "utils/process/status.hpp"
44b0d29bc4SBrooks Davis #include "utils/signals/exceptions.hpp"
45b0d29bc4SBrooks Davis 
46b0d29bc4SBrooks Davis namespace fs = utils::fs;
47b0d29bc4SBrooks Davis namespace process = utils::process;
48b0d29bc4SBrooks Davis namespace signals = utils::signals;
49b0d29bc4SBrooks Davis 
50b0d29bc4SBrooks Davis 
51b0d29bc4SBrooks Davis namespace {
52b0d29bc4SBrooks Davis 
53b0d29bc4SBrooks Davis 
54b0d29bc4SBrooks Davis static void program_reset_raise(void) UTILS_NORETURN;
55b0d29bc4SBrooks Davis 
56b0d29bc4SBrooks Davis 
57b0d29bc4SBrooks Davis /// Body of a subprocess that tests the signals::reset function.
58b0d29bc4SBrooks Davis ///
59b0d29bc4SBrooks Davis /// This function programs a signal to be ignored, then uses signal::reset to
60b0d29bc4SBrooks Davis /// bring it back to its default handler and then delivers the signal to self.
61b0d29bc4SBrooks Davis /// The default behavior of the signal is for the process to die, so this
62b0d29bc4SBrooks Davis /// function should never return correctly (and thus the child process should
63b0d29bc4SBrooks Davis /// always die due to a signal if all goes well).
64b0d29bc4SBrooks Davis static void
program_reset_raise(void)65b0d29bc4SBrooks Davis program_reset_raise(void)
66b0d29bc4SBrooks Davis {
67b0d29bc4SBrooks Davis     struct ::sigaction sa;
68b0d29bc4SBrooks Davis     sa.sa_handler = SIG_IGN;
69b0d29bc4SBrooks Davis     sigemptyset(&sa.sa_mask);
70b0d29bc4SBrooks Davis     sa.sa_flags = 0;
71b0d29bc4SBrooks Davis     if (::sigaction(SIGUSR1, &sa, NULL) == -1)
72b0d29bc4SBrooks Davis         std::exit(EXIT_FAILURE);
73b0d29bc4SBrooks Davis 
74b0d29bc4SBrooks Davis     signals::reset(SIGUSR1);
75b0d29bc4SBrooks Davis     ::kill(::getpid(), SIGUSR1);
76b0d29bc4SBrooks Davis 
77b0d29bc4SBrooks Davis     // Should not be reached, but we do not assert this condition because we
78b0d29bc4SBrooks Davis     // want to exit cleanly if the signal does not abort our execution to let
79b0d29bc4SBrooks Davis     // the parent easily know what happened.
80b0d29bc4SBrooks Davis     std::exit(EXIT_SUCCESS);
81b0d29bc4SBrooks Davis }
82b0d29bc4SBrooks Davis 
83b0d29bc4SBrooks Davis 
84b0d29bc4SBrooks Davis /// Body of a subprocess that executes the signals::reset_all function.
85b0d29bc4SBrooks Davis ///
86b0d29bc4SBrooks Davis /// The process exits with success if the function worked, or with a failure if
87b0d29bc4SBrooks Davis /// an error is reported.  No signals are tested.
88b0d29bc4SBrooks Davis static void
run_reset_all(void)89b0d29bc4SBrooks Davis run_reset_all(void)
90b0d29bc4SBrooks Davis {
91b0d29bc4SBrooks Davis     const bool ok = signals::reset_all();
92b0d29bc4SBrooks Davis     std::exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
93b0d29bc4SBrooks Davis }
94b0d29bc4SBrooks Davis 
95b0d29bc4SBrooks Davis 
96b0d29bc4SBrooks Davis }  // anonymous namespace
97b0d29bc4SBrooks Davis 
98b0d29bc4SBrooks Davis 
99b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(reset__ok);
ATF_TEST_CASE_BODY(reset__ok)100b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(reset__ok)
101b0d29bc4SBrooks Davis {
102*b392a90bSJohn Baldwin     std::unique_ptr< process::child > child = process::child::fork_files(
103b0d29bc4SBrooks Davis         program_reset_raise, fs::path("/dev/stdout"), fs::path("/dev/stderr"));
104b0d29bc4SBrooks Davis     process::status status = child->wait();
105b0d29bc4SBrooks Davis     ATF_REQUIRE(status.signaled());
106b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(SIGUSR1, status.termsig());
107b0d29bc4SBrooks Davis }
108b0d29bc4SBrooks Davis 
109b0d29bc4SBrooks Davis 
110b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(reset__invalid);
ATF_TEST_CASE_BODY(reset__invalid)111b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(reset__invalid)
112b0d29bc4SBrooks Davis {
113b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW(signals::system_error, signals::reset(-1));
114b0d29bc4SBrooks Davis }
115b0d29bc4SBrooks Davis 
116b0d29bc4SBrooks Davis 
117b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(reset_all);
ATF_TEST_CASE_BODY(reset_all)118b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(reset_all)
119b0d29bc4SBrooks Davis {
120*b392a90bSJohn Baldwin     std::unique_ptr< process::child > child = process::child::fork_files(
121b0d29bc4SBrooks Davis         run_reset_all, fs::path("/dev/stdout"), fs::path("/dev/stderr"));
122b0d29bc4SBrooks Davis     process::status status = child->wait();
123b0d29bc4SBrooks Davis     ATF_REQUIRE(status.exited());
124b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
125b0d29bc4SBrooks Davis }
126b0d29bc4SBrooks Davis 
127b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)128b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
129b0d29bc4SBrooks Davis {
130b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, reset__ok);
131b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, reset__invalid);
132b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, reset_all);
133b0d29bc4SBrooks Davis }
134