1 // Copyright 2012 Google Inc.
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/signals/interrupts.hpp"
30
31 extern "C" {
32 #include <signal.h>
33 #include <unistd.h>
34 }
35
36 #include <cstdlib>
37
38 #include <atf-c++.hpp>
39
40 #include "utils/format/macros.hpp"
41 #include "utils/process/child.ipp"
42 #include "utils/process/status.hpp"
43 #include "utils/signals/exceptions.hpp"
44 #include "utils/signals/programmer.hpp"
45
46 namespace process = utils::process;
47 namespace signals = utils::signals;
48
49
50 namespace {
51
52
53 /// Set to the signal that fired; -1 if none.
54 static volatile int fired_signal = -1;
55
56
57 /// Test handler for signals.
58 ///
59 /// \post fired_signal is set to the signal that triggered the handler.
60 ///
61 /// \param signo The signal that triggered the handler.
62 static void
signal_handler(const int signo)63 signal_handler(const int signo)
64 {
65 fired_signal = signo;
66 }
67
68
69 /// Child process that pauses waiting to be killed.
70 static void
pause_child(void)71 pause_child(void)
72 {
73 sigset_t mask;
74 sigemptyset(&mask);
75 if (sigsuspend(&mask) == -1)
76 ::exit(EXIT_FAILURE);
77 else {
78 // If this happens, it is because we received a non-deadly signal and
79 // the execution resumed. This is not what we expect, so exit with an
80 // arbitrary code.
81 ::exit(45);
82 }
83 }
84
85
86 /// Checks that interrupts_handler() handles a particular signal.
87 ///
88 /// This indirectly checks the check_interrupt() function, which is not part of
89 /// the class but is tightly related.
90 ///
91 /// \param signo The signal to check.
92 static void
check_interrupts_handler(const int signo)93 check_interrupts_handler(const int signo)
94 {
95 signals::programmer test_handler(signo, signal_handler);
96
97 {
98 signals::interrupts_handler interrupts;
99
100 signals::check_interrupt();
101 ::kill(getpid(), signo);
102 ATF_REQUIRE_THROW_RE(signals::interrupted_error,
103 F("Interrupted by signal %s") % signo,
104 signals::check_interrupt());
105 }
106
107 ATF_REQUIRE_EQ(-1, fired_signal);
108 ::kill(getpid(), signo);
109 ATF_REQUIRE_EQ(signo, fired_signal);
110
111 test_handler.unprogram();
112 }
113
114
115 /// Checks that interrupts_inhibiter() handles a particular signal.
116 ///
117 /// \param signo The signal to check.
118 static void
check_interrupts_inhibiter(const int signo)119 check_interrupts_inhibiter(const int signo)
120 {
121 signals::programmer test_handler(signo, signal_handler);
122
123 {
124 signals::interrupts_inhibiter inhibiter;
125 ::kill(::getpid(), signo);
126 ATF_REQUIRE_EQ(-1, fired_signal);
127 }
128 ATF_REQUIRE_EQ(signo, fired_signal);
129
130 test_handler.unprogram();
131 }
132
133
134 } // anonymous namespace
135
136
137 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup);
ATF_TEST_CASE_BODY(interrupts_handler__sighup)138 ATF_TEST_CASE_BODY(interrupts_handler__sighup)
139 {
140 check_interrupts_handler(SIGHUP);
141 }
142
143
144 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint);
ATF_TEST_CASE_BODY(interrupts_handler__sigint)145 ATF_TEST_CASE_BODY(interrupts_handler__sigint)
146 {
147 check_interrupts_handler(SIGINT);
148 }
149
150
151 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm);
ATF_TEST_CASE_BODY(interrupts_handler__sigterm)152 ATF_TEST_CASE_BODY(interrupts_handler__sigterm)
153 {
154 check_interrupts_handler(SIGTERM);
155 }
156
157
158 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__kill_children);
ATF_TEST_CASE_BODY(interrupts_handler__kill_children)159 ATF_TEST_CASE_BODY(interrupts_handler__kill_children)
160 {
161 std::unique_ptr< process::child > child1(process::child::fork_capture(
162 pause_child));
163 std::unique_ptr< process::child > child2(process::child::fork_capture(
164 pause_child));
165
166 signals::interrupts_handler interrupts;
167
168 // Our children pause until the reception of a signal. Interrupting
169 // ourselves will cause the signal to be re-delivered to our children due to
170 // the interrupts_handler semantics. If this does not happen, the wait
171 // calls below would block indefinitely and cause our test to time out.
172 ::kill(::getpid(), SIGHUP);
173
174 const process::status status1 = child1->wait();
175 ATF_REQUIRE(status1.signaled());
176 ATF_REQUIRE_EQ(SIGHUP, status1.termsig());
177 const process::status status2 = child2->wait();
178 ATF_REQUIRE(status2.signaled());
179 ATF_REQUIRE_EQ(SIGHUP, status2.termsig());
180 }
181
182
183 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup);
ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup)184 ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup)
185 {
186 check_interrupts_inhibiter(SIGHUP);
187 }
188
189
190 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint);
ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint)191 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint)
192 {
193 check_interrupts_inhibiter(SIGINT);
194 }
195
196
197 ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm);
ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm)198 ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm)
199 {
200 check_interrupts_inhibiter(SIGTERM);
201 }
202
203
ATF_INIT_TEST_CASES(tcs)204 ATF_INIT_TEST_CASES(tcs)
205 {
206 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sighup);
207 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigint);
208 ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigterm);
209 ATF_ADD_TEST_CASE(tcs, interrupts_handler__kill_children);
210
211 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sighup);
212 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigint);
213 ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigterm);
214 }
215