1 /* 2 * Copyright (c) International Business Machines Corp., 2007 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation; either version 2 of the License, or 6 * (at your option) any later version. 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 10 * the GNU General Public License for more details. 11 * You should have received a copy of the GNU General Public License 12 * along with this program; if not, write to the Free Software 13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 14 * 15 *************************************************************************** 16 * File: pidns20.c 17 * * 18 * * Description: 19 * * The pidns20.c testcase verifies that signal handler of SIGUSR1 is called 20 * * (and cinit is NOT terminated) when: 21 * * - container-init blocks SIGUSR1, 22 * * - parent queues SIGUSR1 and 23 * * - a handler is specified for SIGUSR1 before it is unblocked. 24 * * 25 * * Test Assertion & Strategy: 26 * * Create a PID namespace container. 27 * * Block SIGUSR1 signal inside it. 28 * * Let parent to deliver SIGUSR1 signal to container. 29 * * Redefine SIGUSR1 handler of cinit to user function. 30 * * Unblock SIGUSR1 from blocked queue. 31 * * Check if user function is called. 32 * * 33 * * Usage: <for command-line> 34 * * pidns20 35 * * 36 * * History: 37 * * DATE NAME DESCRIPTION 38 * * 13/11/08 Gowrishankar M Creation of this test. 39 * * <gowrishankar.m (at) in.ibm.com> 40 * 41 ******************************************************************************/ 42 #define _GNU_SOURCE 1 43 #include <sys/wait.h> 44 #include <sys/types.h> 45 #include <signal.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 #include <stdio.h> 49 #include "pidns_helper.h" 50 #include "test.h" 51 52 char *TCID = "pidns20"; 53 int TST_TOTAL = 1; 54 55 int parent_cinit[2]; 56 int cinit_parent[2]; 57 int broken = 1; /* broken should be 0 when test completes properly */ 58 59 #define CHILD_PID 1 60 #define PARENT_PID 0 61 62 /* 63 * child_signal_handler() - to handle SIGUSR1 64 */ 65 static void child_signal_handler(int sig, siginfo_t * si, void *unused) 66 { 67 if (si->si_signo != SIGUSR1) 68 tst_resm(TBROK, "cinit: recieved %s unexpectedly!", 69 strsignal(si->si_signo)); 70 else 71 tst_resm(TPASS, "cinit: user function is called as expected"); 72 73 /* Disable broken flag */ 74 broken = 0; 75 } 76 77 /* 78 * child_fn() - Inside container 79 */ 80 int child_fn(void *arg) 81 { 82 pid_t pid, ppid; 83 sigset_t newset; 84 struct sigaction sa; 85 char buf[5]; 86 87 /* Setup pipe read and write ends */ 88 pid = getpid(); 89 ppid = getppid(); 90 91 if (pid != CHILD_PID || ppid != PARENT_PID) { 92 printf("cinit: pidns was not created properly\n"); 93 exit(1); 94 } 95 96 /* Setup pipes to communicate with parent */ 97 close(cinit_parent[0]); 98 close(parent_cinit[1]); 99 100 /* Block SIGUSR1 signal */ 101 sigemptyset(&newset); 102 sigaddset(&newset, SIGUSR1); 103 if (sigprocmask(SIG_BLOCK, &newset, 0) == -1) { 104 perror("cinit: sigprocmask() failed"); 105 exit(1); 106 } 107 tst_resm(TINFO, "cinit: blocked SIGUSR1"); 108 109 /* Let parent to queue SIGUSR1 in pending */ 110 if (write(cinit_parent[1], "c:go", 5) != 5) { 111 perror("cinit: pipe is broken to write"); 112 exit(1); 113 } 114 115 /* Check if parent has queued up SIGUSR1 */ 116 read(parent_cinit[0], buf, 5); 117 if (strcmp(buf, "p:go") != 0) { 118 printf("cinit: parent did not respond!\n"); 119 exit(1); 120 } 121 122 /* Now redefine handler for SIGUSR1 */ 123 sa.sa_flags = SA_SIGINFO; 124 sigfillset(&sa.sa_mask); 125 sa.sa_sigaction = child_signal_handler; 126 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 127 perror("cinit: sigaction failed"); 128 exit(1); 129 } 130 131 /* Unblock traffic on SIGUSR1 queue */ 132 tst_resm(TINFO, "cinit: unblocking SIGUSR1"); 133 sigprocmask(SIG_UNBLOCK, &newset, 0); 134 135 /* Check if new handler is called */ 136 if (broken == 1) { 137 printf("cinit: broken flag didn't change\n"); 138 exit(1); 139 } 140 141 /* Cleanup and exit */ 142 close(cinit_parent[1]); 143 close(parent_cinit[0]); 144 exit(0); 145 } 146 147 static void setup(void) 148 { 149 tst_require_root(); 150 check_newpid(); 151 } 152 153 int main(int argc, char *argv[]) 154 { 155 int status; 156 char buf[5]; 157 pid_t cpid; 158 159 setup(); 160 161 /* Create pipes for intercommunication */ 162 if (pipe(parent_cinit) == -1 || pipe(cinit_parent) == -1) { 163 tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); 164 } 165 166 cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); 167 if (cpid == -1) { 168 tst_brkm(TBROK | TERRNO, NULL, "clone failed"); 169 } 170 171 /* Setup pipe read and write ends */ 172 close(cinit_parent[1]); 173 close(parent_cinit[0]); 174 175 /* Is container ready */ 176 read(cinit_parent[0], buf, 5); 177 if (strcmp(buf, "c:go") != 0) { 178 tst_brkm(TBROK, NULL, "parent: container did not respond!"); 179 } 180 181 /* Enqueue SIGUSR1 in pending signal queue of container */ 182 if (kill(cpid, SIGUSR1) == -1) { 183 tst_brkm(TBROK | TERRNO, NULL, "kill() failed"); 184 } 185 186 tst_resm(TINFO, "parent: signalled SIGUSR1 to container"); 187 if (write(parent_cinit[1], "p:go", 5) != 5) { 188 tst_brkm(TBROK | TERRNO, NULL, "write failed"); 189 } 190 191 /* collect exit status of child */ 192 if (wait(&status) == -1) { 193 tst_brkm(TBROK | TERRNO, NULL, "wait failed"); 194 } 195 196 if (WIFSIGNALED(status)) { 197 if (WTERMSIG(status) == SIGUSR1) 198 tst_resm(TFAIL, 199 "user function was not called inside cinit"); 200 else 201 tst_resm(TBROK, 202 "cinit was terminated by %d", 203 WTERMSIG(status)); 204 } 205 206 /* Cleanup and exit */ 207 close(parent_cinit[1]); 208 close(cinit_parent[0]); 209 tst_exit(); 210 } 211