pidns20.c revision e8530df4da095b0ea36a9ff8118ab5ce906b3e84
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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@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 "usctest.h" 50#include "test.h" 51#include <libclone.h> 52 53char *TCID = "pidns20"; 54int TST_TOTAL = 1; 55 56int errno; 57int parent_cinit[2]; 58int cinit_parent[2]; 59int broken = 1; /* broken should be 0 when test completes properly */ 60 61#define CHILD_PID 1 62#define PARENT_PID 0 63 64void cleanup() 65{ 66 /* Clean the test testcase as LTP wants*/ 67 TEST_CLEANUP; 68} 69 70/* 71 * child_signal_handler() - to handle SIGUSR1 72 */ 73static void child_signal_handler(int sig, siginfo_t *si, void *unused) 74{ 75 if (si->si_signo != SIGUSR1) 76 tst_resm(TBROK, "cinit: recieved %s unexpectedly!",\ 77 strsignal(si->si_signo)); 78 else 79 tst_resm(TPASS, "cinit: user function is called as expected"); 80 81 /* Disable broken flag */ 82 broken = 0; 83} 84 85/* 86 * child_fn() - Inside container 87 */ 88int child_fn(void *arg) 89{ 90 pid_t pid, ppid; 91 sigset_t newset; 92 struct sigaction sa; 93 char buf[5]; 94 95 /* Setup pipe read and write ends */ 96 pid = getpid(); 97 ppid = getppid(); 98 99 if (pid != CHILD_PID || ppid != PARENT_PID) { 100 printf("cinit: pidns was not created properly\n"); 101 exit(1); 102 } 103 104 /* Setup pipes to communicate with parent */ 105 close(cinit_parent[0]); 106 close(parent_cinit[1]); 107 108 /* Block SIGUSR1 signal */ 109 sigemptyset(&newset); 110 sigaddset(&newset, SIGUSR1); 111 if (sigprocmask(SIG_BLOCK, &newset, 0) == -1) { 112 perror("cinit: sigprocmask() failed"); 113 exit(1); 114 } 115 tst_resm(TINFO, "cinit: blocked SIGUSR1"); 116 117 /* Let parent to queue SIGUSR1 in pending */ 118 if (write(cinit_parent[1], "c:go", 5) != 5) { 119 perror("cinit: pipe is broken to write"); 120 exit(1); 121 } 122 123 /* Check if parent has queued up SIGUSR1 */ 124 read(parent_cinit[0], buf, 5); 125 if (strcmp(buf, "p:go") != 0) { 126 printf("cinit: parent did not respond!\n"); 127 exit(1); 128 } 129 130 /* Now redefine handler for SIGUSR1 */ 131 sa.sa_flags = SA_SIGINFO; 132 sigfillset(&sa.sa_mask); 133 sa.sa_sigaction = child_signal_handler; 134 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 135 perror("cinit: sigaction failed"); 136 exit(1); 137 } 138 139 /* Unblock traffic on SIGUSR1 queue */ 140 tst_resm(TINFO, "cinit: unblocking SIGUSR1"); 141 sigprocmask(SIG_UNBLOCK, &newset, 0); 142 143 /* Check if new handler is called */ 144 if (broken == 1) { 145 printf("cinit: broken flag didn't change\n"); 146 exit(1); 147 } 148 149 /* Cleanup and exit */ 150 close(cinit_parent[1]); 151 close(parent_cinit[0]); 152 exit(0); 153} 154 155int main(int argc, char *argv[]) 156{ 157 int status; 158 char buf[5]; 159 pid_t cpid; 160 161 /* Create pipes for intercommunication */ 162 if (pipe(parent_cinit) == -1 || pipe(cinit_parent) == -1) { 163 tst_brkm(TBROK|TERRNO, cleanup, "pipe failed"); 164 } 165 166 cpid = ltp_clone_quick(CLONE_NEWPID|SIGCHLD, child_fn, NULL); 167 if (cpid == -1) { 168 tst_brkm(TBROK|TERRNO, cleanup, "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, cleanup, "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, cleanup, "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, cleanup, "write failed"); 189 } 190 191 /* collect exit status of child */ 192 if (wait(&status) == -1) { 193 tst_brkm(TBROK|TERRNO, cleanup, "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", WTERMSIG(status)); 203 } 204 205 /* Cleanup and exit */ 206 close(parent_cinit[1]); 207 close(cinit_parent[0]); 208 cleanup(); 209 tst_exit(); 210}