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