pidns05.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* 17* Assertion: 18* a) Create a container. 19* b) Create many levels of child containers inside this container. 20* c) Now do kill -9 init , outside of the container. 21* d) This should kill all the child containers. 22* (containers created at the level below) 23* 24* Description: 25* 1. Parent process clone a process with flag CLONE_NEWPID 26* 2. The container will recursively loop and creates 4 more containers. 27* 3. All the container init's goes into sleep(), waiting to be terminated. 28* 4. The parent process will kill child[3] by passing SIGKILL 29* 5. Now parent process, verifies the child containers 4 & 5 are destroyed. 30* 6. If they are killed then 31* Test passed 32* else Test failed. 33* 34* Test Name: pidns05 35* 36* History: 37* 38* FLAG DATE NAME DESCRIPTION 39* 31/10/08 Veerendra C <vechandr@in.ibm.com> Verifies killing of NestedCont's 40* 41*******************************************************************************/ 42#define _GNU_SOURCE 1 43#include <sys/wait.h> 44#include <assert.h> 45#include <stdio.h> 46#include <stdlib.h> 47#include <unistd.h> 48#include <string.h> 49#include <errno.h> 50#include "usctest.h" 51#include "test.h" 52#include <libclone.h> 53 54#define INIT_PID 1 55#define CINIT_PID 1 56#define PARENT_PID 0 57#define MAX_DEPTH 5 58 59char *TCID = "pidns05"; 60int TST_TOTAL = 1; 61int fd[2]; 62 63void 64cleanup(void) 65{ 66 TEST_CLEANUP; 67} 68 69int max_pid(void) 70{ 71 FILE *fp; 72 int ret; 73 74 fp = fopen("/proc/sys/kernel/pid_max", "r") ; 75 if (fp != NULL) { 76 fscanf(fp, "%d", &ret); 77 fclose(fp); 78 } else { 79 tst_resm(TBROK, "Cannot open /proc/sys/kernel/pid_max \n"); 80 ret = -1; 81 } 82 return ret; 83} 84 85/* find_cinit_pids() iteratively finds the pid's having same PGID as its parent. 86 * Input parameter - Accepts pointer to pid_t : To copy the pid's matching. 87 * Returns - the number of pids matched. 88*/ 89int find_cinit_pids(pid_t *pids) 90{ 91 int next = 0, pid_max, i ; 92 pid_t parentpid, pgid, pgid2; 93 94 pid_max = max_pid(); 95 parentpid = getpid(); 96 pgid = getpgid(parentpid); 97 98 /* The loop breaks, when the loop counter reaches the parentpid value */ 99 for (i = parentpid + 1; i != parentpid; i++) { 100 if (i > pid_max) 101 i = 2; 102 103 pgid2 = getpgid(i); 104 if (pgid2 == pgid) { 105 pids[next] = i; 106 next++; 107 } 108 } 109 return next; 110} 111 112/* 113* create_nested_container() Recursively create MAX_DEPTH nested containers 114*/ 115int create_nested_container(void *vtest) 116{ 117 int exit_val; 118 int ret, count, *level; 119 pid_t cpid, ppid; 120 cpid = getpid(); 121 ppid = getppid(); 122 char mesg[] = "Nested Containers are created"; 123 124 level = (int *)vtest; 125 count = *level; 126 127 /* Child process closes up read side of pipe */ 128 close(fd[0]); 129 130 /* Comparing the values to make sure pidns is created correctly */ 131 if (cpid != CINIT_PID || ppid != PARENT_PID) { 132 printf("Got unexpected cpid and/or ppid (cpid=%d ppid=%d)\n", 133 cpid, ppid); 134 exit_val = 1; 135 } 136 if (count > 1) { 137 count--; 138 ret = do_clone_unshare_test(T_CLONE, CLONE_NEWPID, 139 create_nested_container, (void *) &count); 140 if (ret == -1) { 141 printf("clone failed; errno = %d : %s\n" , 142 ret, strerror(ret)); 143 exit_val = 1; 144 } else 145 exit_val = 0; 146 } else { 147 /* Sending mesg, 'Nested containers created' through the pipe */ 148 write(fd[1], mesg, (strlen(mesg)+1)); 149 exit_val = 0; 150 } 151 152 close(fd[1]); 153 pause(); 154 155 return exit_val; 156} 157 158void kill_nested_containers() 159{ 160 int orig_count, new_count, status = 0, i; 161 pid_t pids[MAX_DEPTH]; 162 pid_t pids_new[MAX_DEPTH]; 163 164 orig_count = find_cinit_pids(pids); 165 kill(pids[MAX_DEPTH - 3], SIGKILL) ; 166 sleep(1); 167 168 /* After killing child container, getting the New PID list */ 169 new_count = find_cinit_pids(pids_new); 170 171 /* Verifying that the child containers were destroyed when parent is killed*/ 172 if (orig_count - 2 != new_count) 173 status = -1; 174 175 for (i = 0; i < new_count; i++) { 176 if (pids[i] != pids_new[i]) 177 status = -1; 178 } 179 180 if (status == 0) 181 tst_resm(TPASS, "The number of containers killed are %d\n" , 182 orig_count - new_count); 183 else 184 tst_resm(TFAIL, "Failed to kill the sub-containers of " 185 "the container %d\n", pids[MAX_DEPTH - 3]); 186 187 /* Loops through the containers created to exit from sleep() */ 188 for (i = 0; i < MAX_DEPTH; i++) { 189 if (waitpid(pids[i], &status, 0) == -1) 190 tst_resm(TFAIL|TERRNO, "waitpid(%d, ...) failed", 191 pids[i]); 192 else { 193 kill(pids[i], SIGKILL); 194 waitpid(pids[i], &status, 0); 195 } 196 } 197} 198 199int main(int argc, char *argv[]) 200{ 201 int ret, nbytes, status; 202 char readbuffer[80]; 203 pid_t pid, pgid; 204 int count = MAX_DEPTH; 205 206 /* 207 * XXX (garrcoop): why in the hell is this fork-wait written this way? 208 * This doesn't add up with the pattern used for the rest of the tests, 209 * so I'm pretty damn sure this test is written incorrectly. 210 */ 211 pid = fork(); 212 if (pid == -1) { 213 tst_brkm(TBROK|TERRNO, NULL, "fork failed"); 214 } else if (pid != 0) { 215 /* 216 * NOTE: use waitpid so that we know we're waiting for the 217 * _top-level_ child instead of a spawned subcontainer. 218 * 219 * XXX (garrcoop): Might want to mask SIGCHLD in the top-level 220 * child too, or not *shrugs*. 221 */ 222 if (waitpid(pid, &status, 0) == -1) { 223 perror("wait failed"); 224 } 225 exit(status); 226 } 227 228 /* To make all the containers share the same PGID as its parent */ 229 setpgid(0, 0); 230 231 pid = getpid(); 232 pgid = getpgid(pid); 233 ret = pipe(fd); 234 if (ret == -1) 235 tst_brkm(TBROK|TERRNO, cleanup, "pipe failed"); 236 237 TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, 238 create_nested_container, (void *)&count)); 239 if (TEST_RETURN == -1) { 240 tst_brkm(TFAIL|TTERRNO, cleanup, "clone failed"); 241 } 242 243 close(fd[1]); 244 /* Waiting for the MAX_DEPTH number of containers to be created */ 245 nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); 246 close(fd[0]); 247 if (nbytes > 0) 248 tst_resm(TINFO, " %d %s", MAX_DEPTH, readbuffer); 249 else 250 tst_brkm(TFAIL, cleanup, "unable to create %d containers", 251 MAX_DEPTH); 252 253 /* Kill the container created */ 254 kill_nested_containers(); 255 cleanup(); 256 257 tst_exit(); 258}