1*b0d29bc4SBrooks Davis // Copyright 2012 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/signals/interrupts.hpp" 30*b0d29bc4SBrooks Davis 31*b0d29bc4SBrooks Davis extern "C" { 32*b0d29bc4SBrooks Davis #include <signal.h> 33*b0d29bc4SBrooks Davis #include <unistd.h> 34*b0d29bc4SBrooks Davis } 35*b0d29bc4SBrooks Davis 36*b0d29bc4SBrooks Davis #include <cstdlib> 37*b0d29bc4SBrooks Davis #include <iostream> 38*b0d29bc4SBrooks Davis 39*b0d29bc4SBrooks Davis #include <atf-c++.hpp> 40*b0d29bc4SBrooks Davis 41*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp" 42*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp" 43*b0d29bc4SBrooks Davis #include "utils/process/child.ipp" 44*b0d29bc4SBrooks Davis #include "utils/process/status.hpp" 45*b0d29bc4SBrooks Davis #include "utils/signals/exceptions.hpp" 46*b0d29bc4SBrooks Davis #include "utils/signals/programmer.hpp" 47*b0d29bc4SBrooks Davis 48*b0d29bc4SBrooks Davis namespace fs = utils::fs; 49*b0d29bc4SBrooks Davis namespace process = utils::process; 50*b0d29bc4SBrooks Davis namespace signals = utils::signals; 51*b0d29bc4SBrooks Davis 52*b0d29bc4SBrooks Davis 53*b0d29bc4SBrooks Davis namespace { 54*b0d29bc4SBrooks Davis 55*b0d29bc4SBrooks Davis 56*b0d29bc4SBrooks Davis /// Set to the signal that fired; -1 if none. 57*b0d29bc4SBrooks Davis static volatile int fired_signal = -1; 58*b0d29bc4SBrooks Davis 59*b0d29bc4SBrooks Davis 60*b0d29bc4SBrooks Davis /// Test handler for signals. 61*b0d29bc4SBrooks Davis /// 62*b0d29bc4SBrooks Davis /// \post fired_signal is set to the signal that triggered the handler. 63*b0d29bc4SBrooks Davis /// 64*b0d29bc4SBrooks Davis /// \param signo The signal that triggered the handler. 65*b0d29bc4SBrooks Davis static void 66*b0d29bc4SBrooks Davis signal_handler(const int signo) 67*b0d29bc4SBrooks Davis { 68*b0d29bc4SBrooks Davis PRE(fired_signal == -1 || fired_signal == signo); 69*b0d29bc4SBrooks Davis fired_signal = signo; 70*b0d29bc4SBrooks Davis } 71*b0d29bc4SBrooks Davis 72*b0d29bc4SBrooks Davis 73*b0d29bc4SBrooks Davis /// Child process that pauses waiting to be killed. 74*b0d29bc4SBrooks Davis static void 75*b0d29bc4SBrooks Davis pause_child(void) 76*b0d29bc4SBrooks Davis { 77*b0d29bc4SBrooks Davis sigset_t mask; 78*b0d29bc4SBrooks Davis sigemptyset(&mask); 79*b0d29bc4SBrooks Davis // We loop waiting for signals because we want the parent process to send us 80*b0d29bc4SBrooks Davis // a SIGKILL that we cannot handle, not just any non-deadly signal. 81*b0d29bc4SBrooks Davis for (;;) { 82*b0d29bc4SBrooks Davis std::cerr << F("Waiting for any signal; pid=%s\n") % ::getpid(); 83*b0d29bc4SBrooks Davis ::sigsuspend(&mask); 84*b0d29bc4SBrooks Davis std::cerr << F("Signal received; pid=%s\n") % ::getpid(); 85*b0d29bc4SBrooks Davis } 86*b0d29bc4SBrooks Davis } 87*b0d29bc4SBrooks Davis 88*b0d29bc4SBrooks Davis 89*b0d29bc4SBrooks Davis /// Checks that interrupts_handler() handles a particular signal. 90*b0d29bc4SBrooks Davis /// 91*b0d29bc4SBrooks Davis /// This indirectly checks the check_interrupt() function, which is not part of 92*b0d29bc4SBrooks Davis /// the class but is tightly related. 93*b0d29bc4SBrooks Davis /// 94*b0d29bc4SBrooks Davis /// \param signo The signal to check. 95*b0d29bc4SBrooks Davis /// \param explicit_unprogram Whether to call interrupts_handler::unprogram() 96*b0d29bc4SBrooks Davis /// explicitly before letting the object go out of scope. 97*b0d29bc4SBrooks Davis static void 98*b0d29bc4SBrooks Davis check_interrupts_handler(const int signo, const bool explicit_unprogram) 99*b0d29bc4SBrooks Davis { 100*b0d29bc4SBrooks Davis fired_signal = -1; 101*b0d29bc4SBrooks Davis 102*b0d29bc4SBrooks Davis signals::programmer test_handler(signo, signal_handler); 103*b0d29bc4SBrooks Davis 104*b0d29bc4SBrooks Davis { 105*b0d29bc4SBrooks Davis signals::interrupts_handler interrupts; 106*b0d29bc4SBrooks Davis 107*b0d29bc4SBrooks Davis // No pending interrupts at first. 108*b0d29bc4SBrooks Davis signals::check_interrupt(); 109*b0d29bc4SBrooks Davis 110*b0d29bc4SBrooks Davis // Send us an interrupt and check for it. 111*b0d29bc4SBrooks Davis ::kill(getpid(), signo); 112*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(signals::interrupted_error, 113*b0d29bc4SBrooks Davis F("Interrupted by signal %s") % signo, 114*b0d29bc4SBrooks Davis signals::check_interrupt()); 115*b0d29bc4SBrooks Davis 116*b0d29bc4SBrooks Davis // Interrupts should have been cleared now, so this should not throw. 117*b0d29bc4SBrooks Davis signals::check_interrupt(); 118*b0d29bc4SBrooks Davis 119*b0d29bc4SBrooks Davis // Check to see if a second interrupt is detected. 120*b0d29bc4SBrooks Davis ::kill(getpid(), signo); 121*b0d29bc4SBrooks Davis ATF_REQUIRE_THROW_RE(signals::interrupted_error, 122*b0d29bc4SBrooks Davis F("Interrupted by signal %s") % signo, 123*b0d29bc4SBrooks Davis signals::check_interrupt()); 124*b0d29bc4SBrooks Davis 125*b0d29bc4SBrooks Davis // And ensure the interrupt was cleared again. 126*b0d29bc4SBrooks Davis signals::check_interrupt(); 127*b0d29bc4SBrooks Davis 128*b0d29bc4SBrooks Davis if (explicit_unprogram) { 129*b0d29bc4SBrooks Davis interrupts.unprogram(); 130*b0d29bc4SBrooks Davis } 131*b0d29bc4SBrooks Davis } 132*b0d29bc4SBrooks Davis 133*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(-1, fired_signal); 134*b0d29bc4SBrooks Davis ::kill(getpid(), signo); 135*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(signo, fired_signal); 136*b0d29bc4SBrooks Davis 137*b0d29bc4SBrooks Davis test_handler.unprogram(); 138*b0d29bc4SBrooks Davis } 139*b0d29bc4SBrooks Davis 140*b0d29bc4SBrooks Davis 141*b0d29bc4SBrooks Davis /// Checks that interrupts_inhibiter() handles a particular signal. 142*b0d29bc4SBrooks Davis /// 143*b0d29bc4SBrooks Davis /// \param signo The signal to check. 144*b0d29bc4SBrooks Davis static void 145*b0d29bc4SBrooks Davis check_interrupts_inhibiter(const int signo) 146*b0d29bc4SBrooks Davis { 147*b0d29bc4SBrooks Davis signals::programmer test_handler(signo, signal_handler); 148*b0d29bc4SBrooks Davis 149*b0d29bc4SBrooks Davis { 150*b0d29bc4SBrooks Davis signals::interrupts_inhibiter inhibiter; 151*b0d29bc4SBrooks Davis { 152*b0d29bc4SBrooks Davis signals::interrupts_inhibiter nested_inhibiter; 153*b0d29bc4SBrooks Davis ::kill(::getpid(), signo); 154*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(-1, fired_signal); 155*b0d29bc4SBrooks Davis } 156*b0d29bc4SBrooks Davis ::kill(::getpid(), signo); 157*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(-1, fired_signal); 158*b0d29bc4SBrooks Davis } 159*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(signo, fired_signal); 160*b0d29bc4SBrooks Davis 161*b0d29bc4SBrooks Davis test_handler.unprogram(); 162*b0d29bc4SBrooks Davis } 163*b0d29bc4SBrooks Davis 164*b0d29bc4SBrooks Davis 165*b0d29bc4SBrooks Davis } // anonymous namespace 166*b0d29bc4SBrooks Davis 167*b0d29bc4SBrooks Davis 168*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sighup); 169*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_handler__sighup) 170*b0d29bc4SBrooks Davis { 171*b0d29bc4SBrooks Davis // We run this twice in sequence to ensure that we can actually program two 172*b0d29bc4SBrooks Davis // interrupts handlers in a row. 173*b0d29bc4SBrooks Davis check_interrupts_handler(SIGHUP, true); 174*b0d29bc4SBrooks Davis check_interrupts_handler(SIGHUP, false); 175*b0d29bc4SBrooks Davis } 176*b0d29bc4SBrooks Davis 177*b0d29bc4SBrooks Davis 178*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigint); 179*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_handler__sigint) 180*b0d29bc4SBrooks Davis { 181*b0d29bc4SBrooks Davis // We run this twice in sequence to ensure that we can actually program two 182*b0d29bc4SBrooks Davis // interrupts handlers in a row. 183*b0d29bc4SBrooks Davis check_interrupts_handler(SIGINT, true); 184*b0d29bc4SBrooks Davis check_interrupts_handler(SIGINT, false); 185*b0d29bc4SBrooks Davis } 186*b0d29bc4SBrooks Davis 187*b0d29bc4SBrooks Davis 188*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_handler__sigterm); 189*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_handler__sigterm) 190*b0d29bc4SBrooks Davis { 191*b0d29bc4SBrooks Davis // We run this twice in sequence to ensure that we can actually program two 192*b0d29bc4SBrooks Davis // interrupts handlers in a row. 193*b0d29bc4SBrooks Davis check_interrupts_handler(SIGTERM, true); 194*b0d29bc4SBrooks Davis check_interrupts_handler(SIGTERM, false); 195*b0d29bc4SBrooks Davis } 196*b0d29bc4SBrooks Davis 197*b0d29bc4SBrooks Davis 198*b0d29bc4SBrooks Davis ATF_TEST_CASE(interrupts_handler__kill_children); 199*b0d29bc4SBrooks Davis ATF_TEST_CASE_HEAD(interrupts_handler__kill_children) 200*b0d29bc4SBrooks Davis { 201*b0d29bc4SBrooks Davis set_md_var("timeout", "10"); 202*b0d29bc4SBrooks Davis } 203*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_handler__kill_children) 204*b0d29bc4SBrooks Davis { 205*b0d29bc4SBrooks Davis std::auto_ptr< process::child > child1(process::child::fork_files( 206*b0d29bc4SBrooks Davis pause_child, fs::path("/dev/stdout"), fs::path("/dev/stderr"))); 207*b0d29bc4SBrooks Davis std::auto_ptr< process::child > child2(process::child::fork_files( 208*b0d29bc4SBrooks Davis pause_child, fs::path("/dev/stdout"), fs::path("/dev/stderr"))); 209*b0d29bc4SBrooks Davis 210*b0d29bc4SBrooks Davis signals::interrupts_handler interrupts; 211*b0d29bc4SBrooks Davis 212*b0d29bc4SBrooks Davis // Our children pause until the reception of a signal. Interrupting 213*b0d29bc4SBrooks Davis // ourselves will cause the signal to be re-delivered to our children due to 214*b0d29bc4SBrooks Davis // the interrupts_handler semantics. If this does not happen, the wait 215*b0d29bc4SBrooks Davis // calls below would block indefinitely and cause our test to time out. 216*b0d29bc4SBrooks Davis ::kill(::getpid(), SIGHUP); 217*b0d29bc4SBrooks Davis 218*b0d29bc4SBrooks Davis const process::status status1 = child1->wait(); 219*b0d29bc4SBrooks Davis ATF_REQUIRE(status1.signaled()); 220*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(SIGKILL, status1.termsig()); 221*b0d29bc4SBrooks Davis const process::status status2 = child2->wait(); 222*b0d29bc4SBrooks Davis ATF_REQUIRE(status2.signaled()); 223*b0d29bc4SBrooks Davis ATF_REQUIRE_EQ(SIGKILL, status2.termsig()); 224*b0d29bc4SBrooks Davis } 225*b0d29bc4SBrooks Davis 226*b0d29bc4SBrooks Davis 227*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigalrm); 228*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_inhibiter__sigalrm) 229*b0d29bc4SBrooks Davis { 230*b0d29bc4SBrooks Davis check_interrupts_inhibiter(SIGALRM); 231*b0d29bc4SBrooks Davis } 232*b0d29bc4SBrooks Davis 233*b0d29bc4SBrooks Davis 234*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sighup); 235*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_inhibiter__sighup) 236*b0d29bc4SBrooks Davis { 237*b0d29bc4SBrooks Davis check_interrupts_inhibiter(SIGHUP); 238*b0d29bc4SBrooks Davis } 239*b0d29bc4SBrooks Davis 240*b0d29bc4SBrooks Davis 241*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigint); 242*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_inhibiter__sigint) 243*b0d29bc4SBrooks Davis { 244*b0d29bc4SBrooks Davis check_interrupts_inhibiter(SIGINT); 245*b0d29bc4SBrooks Davis } 246*b0d29bc4SBrooks Davis 247*b0d29bc4SBrooks Davis 248*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(interrupts_inhibiter__sigterm); 249*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(interrupts_inhibiter__sigterm) 250*b0d29bc4SBrooks Davis { 251*b0d29bc4SBrooks Davis check_interrupts_inhibiter(SIGTERM); 252*b0d29bc4SBrooks Davis } 253*b0d29bc4SBrooks Davis 254*b0d29bc4SBrooks Davis 255*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs) 256*b0d29bc4SBrooks Davis { 257*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_handler__sighup); 258*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigint); 259*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_handler__sigterm); 260*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_handler__kill_children); 261*b0d29bc4SBrooks Davis 262*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigalrm); 263*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sighup); 264*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigint); 265*b0d29bc4SBrooks Davis ATF_ADD_TEST_CASE(tcs, interrupts_inhibiter__sigterm); 266*b0d29bc4SBrooks Davis } 267