pidns13.c revision 044315e5614273e9d65f41b672b3b916d3e86459
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: pidns13.c 17* * 18* * Description: 19* * The pidns13.c testcase checks container init, for async I/O 20* * triggered by peer namespace process. 21* * 22* * Test Assertion & Strategy: 23* * Create a pipe in parent namespace. 24* * Create two PID namespace containers(cinit1 and cinit2). 25* * In cinit1, set pipe read end to send SIGUSR1. 26* * for asynchronous I/O. 27* * Let cinit2 to trigger async I/O on pipe write end. 28* * In signal info, check si_code to be POLL_IN and si_fd to be pipe read fd. 29* * 30* * Usage: <for command-line> 31* * pidns13 32* * 33* * History: 34* * DATE NAME DESCRIPTION 35* * 23/10/08 Gowrishankar M Created test scenarion. 36* * <gowrishankar.m@in.ibm.com> 37* 38******************************************************************************/ 39#define _GNU_SOURCE 1 40#include <sys/wait.h> 41#include <sys/types.h> 42#include <fcntl.h> 43#include <signal.h> 44#include <string.h> 45#include <stdlib.h> 46#include <unistd.h> 47#include <stdio.h> 48#include "test.h" 49#include <libclone.h> 50#include "pidns_helper.h" 51 52char *TCID = "pidns13"; 53int TST_TOTAL = 1; 54int pipe_fd[2]; 55 56#define CHILD_PID 1 57#define PARENT_PID 0 58 59/* 60 * child_signal_handler() - dummy function for sigaction() 61 */ 62static void child_signal_handler(int sig, siginfo_t * si, void *unused) 63{ 64 /* sigtimedwait() traps siginfo details, so this wont be called */ 65 tst_resm(TWARN, "cinit(pid %d): control should have not reached here!", 66 getpid()); 67} 68 69/* 70 * child_fn() - Inside container 71 */ 72int child_fn(void *arg) 73{ 74 struct sigaction sa; 75 sigset_t newset; 76 siginfo_t info; 77 struct timespec timeout; 78 pid_t pid, ppid; 79 int cinit_no = *((int *)arg); 80 81 /* Set process id and parent pid */ 82 pid = getpid(); 83 ppid = getppid(); 84 if (pid != CHILD_PID || ppid != PARENT_PID) { 85 tst_resm(TBROK, "cinit%d: pidns is not created.", cinit_no); 86 } 87 88 if (cinit_no == 1) { 89 /* in container 1 */ 90 /* close pipe write descriptor */ 91 if (close(pipe_fd[1]) == -1) { 92 tst_resm(TBROK, "cinit1: close(pipe_fd[1]) failed"); 93 } 94 95 /* Let cinit1 to get SIGUSR1 on I/O availability */ 96 if (fcntl(pipe_fd[0], F_SETOWN, pid) == -1) { 97 tst_resm(TBROK, "cinit1: fcntl(F_SETOWN) failed"); 98 } 99 100 if (fcntl(pipe_fd[0], F_SETSIG, SIGUSR1) == -1) { 101 tst_resm(TBROK, "cinit1: fcntl(F_SETSIG) failed"); 102 } 103 104 if (fcntl(pipe_fd[0], F_SETFL, 105 fcntl(pipe_fd[0], F_GETFL) | O_ASYNC) == -1) { 106 tst_resm(TBROK, "cinit1: fcntl(F_SETFL) failed"); 107 } 108 109 /* Set signal handler for SIGUSR1, also mask other signals */ 110 sa.sa_flags = SA_SIGINFO; 111 sigfillset(&sa.sa_mask); 112 sa.sa_sigaction = child_signal_handler; 113 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 114 tst_resm(TBROK, "cinit1: sigaction() failed"); 115 } 116 117 tst_resm(TINFO, "cinit1: setup handler for async I/O on pipe"); 118 119 /* Set timeout for sigtimedwait */ 120 timeout.tv_sec = 10; 121 timeout.tv_nsec = 0; 122 123 /* Set mask to wait for SIGUSR1 signal */ 124 sigemptyset(&newset); 125 sigaddset(&newset, SIGUSR1); 126 127 /* Wait for SIGUSR1 */ 128 if (sigtimedwait(&newset, &info, &timeout) != SIGUSR1) { 129 tst_resm(TBROK, "cinit1: sigtimedwait() failed."); 130 } 131 132 /* Recieved SIGUSR1. Check details. */ 133 if (info.si_fd == pipe_fd[0] && info.si_code == POLL_IN) 134 tst_resm(TPASS, "cinit1: si_fd is %d, si_code is %d", 135 info.si_fd, info.si_code); 136 else 137 tst_resm(TFAIL, "cinit1: si_fd is %d, si_code is %d", 138 info.si_fd, info.si_code); 139 140 /* all done, close the descriptors opened */ 141 close(pipe_fd[0]); 142 143 } else { 144 /* in container 2 */ 145 /* close pipe read descriptor */ 146 if (close(pipe_fd[0]) == -1) { 147 tst_resm(TBROK, "cinit2: close(pipe_fd[0]) failed"); 148 } 149 150 /* sleep for few seconds to avoid race with cinit1 */ 151 sleep(2); 152 153 /* Write some data in pipe to SIGUSR1 cinit1 */ 154 tst_resm(TINFO, "cinit2: writing some data in pipe"); 155 if (write(pipe_fd[1], "test\n", 5) == -1) { 156 tst_resm(TBROK, "cinit2: write() failed"); 157 } 158 159 /* all done, close the descriptors opened */ 160 close(pipe_fd[1]); 161 } 162 163 /* cleanup and exit */ 164 exit(0); 165} 166 167static void setup(void) 168{ 169 tst_require_root(NULL); 170 check_newpid(); 171} 172 173/*********************************************************************** 174* M A I N 175***********************************************************************/ 176 177int main(int argc, char *argv[]) 178{ 179 int status; 180 int *cinit_no = malloc(sizeof(int)); 181 pid_t cpid1, cpid2; 182 183 setup(); 184 185 /* create pipe */ 186 if (pipe(pipe_fd) == -1) { 187 tst_resm(TBROK, "parent: pipe creation failed"); 188 } 189 190 /* container creation on PID namespace */ 191 if (!cinit_no) { 192 tst_resm(TBROK, "memory allocation failed."); 193 } 194 195 /* Create container 1 */ 196 *cinit_no = 1; 197 cpid1 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, cinit_no); 198 199 /* Create container 2 */ 200 *cinit_no = 2; 201 cpid2 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, cinit_no); 202 if (cpid1 < 0 || cpid2 < 0) { 203 tst_resm(TBROK, "parent: clone() failed."); 204 } 205 206 /* Close unwanted descriptors */ 207 close(pipe_fd[0]); 208 close(pipe_fd[1]); 209 210 /* Wait for containers to exit */ 211 if (waitpid(cpid2, &status, 0) < 0) 212 tst_resm(TWARN, "parent: waitpid(cpid2) failed."); 213 214 if (WIFSIGNALED(status) && WTERMSIG(status)) 215 tst_resm(TWARN, "parent: cinit2 is terminated by signal(%s)", 216 strsignal(WTERMSIG(status))); 217 218 if (waitpid(cpid1, &status, 0) < 0) 219 tst_resm(TWARN, "parent: waitpid(cpid1) failed."); 220 221 if (WIFSIGNALED(status) && WTERMSIG(status)) 222 tst_resm(TWARN, "parent: cinit1 is terminated by signal(%s)", 223 strsignal(WTERMSIG(status))); 224 225 /* Control won't reach below */ 226 exit(0); 227 228} 229