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 31extern "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 46namespace process = utils::process; 47namespace signals = utils::signals; 48 49 50namespace { 51 52 53/// Set to the signal that fired; -1 if none. 54static 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. 62static void 63signal_handler(const int signo) 64{ 65 fired_signal = signo; 66} 67 68 69/// Child process that pauses waiting to be killed. 70static void 71pause_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. 92static void 93check_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. 118static void 119check_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 137ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup); 138ATF_TEST_CASE_BODY(interrupts_handler__sighup) 139{ 140 check_interrupts_handler(SIGHUP); 141} 142 143 144ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint); 145ATF_TEST_CASE_BODY(interrupts_handler__sigint) 146{ 147 check_interrupts_handler(SIGINT); 148} 149 150 151ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm); 152ATF_TEST_CASE_BODY(interrupts_handler__sigterm) 153{ 154 check_interrupts_handler(SIGTERM); 155} 156 157 158ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__kill_children); 159ATF_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 183ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup); 184ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup) 185{ 186 check_interrupts_inhibiter(SIGHUP); 187} 188 189 190ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint); 191ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint) 192{ 193 check_interrupts_inhibiter(SIGINT); 194} 195 196 197ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm); 198ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm) 199{ 200 check_interrupts_inhibiter(SIGTERM); 201} 202 203 204ATF_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