pidns30.c revision ce23f15806425582250d38d41a02b1a547a32d7b
1/* 2* Copyright (c) Bull S.A.S. 2008 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: pidns30.c 17* 18* Description: 19* This testcase checks if the si_pid is correctly set when a process 20* that has registered for notification on a posix mqueue is in a 21* descendant namespace wrt the process that sends a message to that posix 22* mqueue. 23* 24* Test Assertion & Strategy: 25* Parent Child 26* -------------------------------------------------------------------------- 27* Create a POSIX mqueue. 28* Create a PID namespace container. 29* Open that mqueue for reading 30* Register for notification when a 31* message arrives in that mqueue 32* Install a handler for SIGUSR1. 33* Write something to the mqueue. 34* Inside the handler, check that 35* si_pid is set to 0 36* 37* Usage: <for command-line> 38* pidns30 39* 40* History: 41* DATE NAME DESCRIPTION 42* 01/12/08 Nadia Derbey Creation of this test. 43* <Nadia.Derbey@bull.net> 44* 45******************************************************************************/ 46#define _GNU_SOURCE 1 47#include <sys/wait.h> 48#include <sys/types.h> 49#include <signal.h> 50#include <stdlib.h> 51#include <unistd.h> 52#include <stdio.h> 53#include <mqueue.h> 54#include <usctest.h> 55#include <test.h> 56#include <libclone.h> 57 58char *TCID = "pidns30"; 59int TST_TOTAL = 1; 60 61char *mqname = "/mq1"; 62int result = TFAIL; 63 64int errno; 65int father_to_child[2]; 66int child_to_father[2]; 67 68#define CHILD_PID 1 69#define PARENT_PID 0 70 71#define MSG "HOW ARE YOU" 72#define MSG_PRIO 1 73 74#define NO_STEP -1 75#define F_STEP_0 0x00 76#define F_STEP_1 0x01 77#define F_STEP_2 0x02 78#define F_STEP_3 0x03 79#define C_STEP_0 0x10 80#define C_STEP_1 0x11 81#define C_STEP_2 0x12 82 83static void remove_pipe(int *fd) 84{ 85 close(fd[0]); 86 close(fd[1]); 87} 88 89static void remove_mqueue(mqd_t mqd) 90{ 91 mq_close(mqd); 92 mq_unlink(mqname); 93} 94 95/* 96 * steps F_STEP_XX : called from main 97 * steps C_STEP_XX : called from child_fn 98 */ 99static void cleanup_resources(int step, mqd_t mqd) 100{ 101 switch (step) { 102 case C_STEP_2: 103 close(child_to_father[1]); 104 close(father_to_child[0]); 105 mq_close(mqd); 106 break; 107 108 case C_STEP_1: 109 mq_notify(mqd, NULL); 110 /* fall through */ 111 case C_STEP_0: 112 mq_close(mqd); 113 break; 114 115 case F_STEP_3: 116 remove_mqueue(mqd); 117 close(child_to_father[0]); 118 close(father_to_child[1]); 119 break; 120 121 case F_STEP_2: 122 remove_mqueue(mqd); 123 /* fall through */ 124 case F_STEP_1: 125 remove_pipe(father_to_child); 126 /* fall through */ 127 case F_STEP_0: 128 remove_pipe(child_to_father); 129 break; 130 default: 131 tst_resm(TWARN, "Unknown code - no resource removed."); 132 break; 133 } 134} 135 136/* 137 * cleanup() - performs all ONE TIME cleanup for this test at 138 * completion or premature exit. 139 */ 140static void cleanup(int result, int step, mqd_t mqd) 141{ 142 if (step != NO_STEP) 143 cleanup_resources(step, mqd); 144 145 /* Clean the test testcase as LTP wants*/ 146 TEST_CLEANUP; 147 148 /* exit with return code appropriate for results */ 149 tst_exit(result); 150} 151 152/* 153 * child_signal_handler() - to handle SIGUSR1 154 */ 155static void child_signal_handler(int sig, siginfo_t *si, void *unused) 156{ 157 char buf[256]; 158 mqd_t rc; 159 struct mq_attr attr; 160 161 if (si->si_signo != SIGUSR1) { 162 tst_resm(TBROK, "cinit: received %s unexpectedly", 163 strsignal(si->si_signo)); 164 return; 165 } 166 167 if (si->si_code != SI_MESGQ) { 168 tst_resm(TBROK, "cinit: expected signal code SI_MESGQ - Got %d", 169 si->si_code); 170 return; 171 } 172 173 if (si->si_pid) { 174 tst_resm(TFAIL, 175 "cinit: expected signal originator PID = 0 - Got %d", 176 si->si_pid); 177 return; 178 } 179 180 tst_resm(TPASS, "cinit: signal originator PID = 0"); 181 result = TPASS; 182 183 /* 184 * Now read the message - Be silent on errors since this is not the 185 * test purpose. 186 */ 187 rc = mq_getattr((mqd_t)si->si_int, &attr); 188 if (rc == (mqd_t)-1) 189 return; 190 191 mq_receive((mqd_t)si->si_int, buf, attr.mq_msgsize, NULL); 192} 193 194 195/* 196 * child_fn() - Inside container 197 */ 198int child_fn(void *arg) 199{ 200 pid_t pid, ppid; 201 struct sigaction sa; 202 mqd_t mqd; 203 struct sigevent notif; 204 char buf[5]; 205 206 /* Set process id and parent pid */ 207 pid = getpid(); 208 ppid = getppid(); 209 210 if (pid != CHILD_PID || ppid != PARENT_PID) { 211 tst_resm(TBROK, "cinit: pidns is not created"); 212 cleanup(TBROK, NO_STEP, 0); 213 } 214 215 /* Close the appropriate end of each pipe */ 216 close(child_to_father[0]); 217 close(father_to_child[1]); 218 219 mqd = mq_open(mqname, O_RDONLY); 220 if (mqd == (mqd_t)-1) { 221 tst_resm(TBROK, "cinit: mq_open() failed (%s)", 222 strerror(errno)); 223 cleanup(TBROK, NO_STEP, 0); 224 } 225 tst_resm(TINFO, "cinit: mq_open succeeded"); 226 227 /* Register for notification on message arrival */ 228 notif.sigev_notify = SIGEV_SIGNAL; 229 notif.sigev_signo = SIGUSR1; 230 notif.sigev_value.sival_int = mqd; 231 if (mq_notify(mqd, ¬if) == (mqd_t)-1) { 232 tst_resm(TBROK, "cinit: mq_notify() failed (%s)", 233 strerror(errno)); 234 cleanup(TBROK, C_STEP_0, mqd); 235 } 236 tst_resm(TINFO, "cinit: successfully registered for notification"); 237 238 /* Define handler for SIGUSR1 */ 239 sa.sa_flags = SA_SIGINFO; 240 sigemptyset(&sa.sa_mask); 241 sa.sa_sigaction = child_signal_handler; 242 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 243 tst_resm(TBROK, "cinit: sigaction() failed(%s)", 244 strerror(errno)); 245 cleanup(TBROK, C_STEP_1, mqd); 246 } 247 tst_resm(TINFO, "cinit: successfully registered handler for SIGUSR1"); 248 249 /* Ask parent to send a message to the mqueue */ 250 if (write(child_to_father[1], "c:ok", 5) != 5) { 251 tst_resm(TBROK, "cinit: pipe is broken (%s)", strerror(errno)); 252 cleanup(TBROK, C_STEP_1, mqd); 253 } 254 255 sleep(3); 256 257 /* Has parent sent a message? */ 258 read(father_to_child[0], buf, 5); 259 if (strcmp(buf, "f:ok")) { 260 tst_resm(TBROK, "cinit: parent did not send the message!"); 261 cleanup(TBROK, C_STEP_1, mqd); 262 } 263 tst_resm(TINFO, "cinit: my father is done - cleaning"); 264 265 /* Be silent on errors from now on */ 266 cleanup_resources(C_STEP_2, mqd); 267 268 exit(0); 269} 270 271/*********************************************************************** 272* M A I N 273***********************************************************************/ 274 275int main(int argc, char *argv[]) 276{ 277 int status; 278 char buf[5]; 279 pid_t cpid; 280 mqd_t mqd; 281 mqd_t rc; 282 283 if (pipe(child_to_father) == -1) { 284 tst_resm(TBROK, "parent: pipe() failed. aborting!"); 285 cleanup(TBROK, NO_STEP, 0); 286 } 287 288 if (pipe(father_to_child) == -1) { 289 tst_resm(TBROK, "parent: pipe() failed. aborting!"); 290 cleanup(TBROK, F_STEP_0, 0); 291 } 292 293 mq_unlink(mqname); 294 mqd = mq_open(mqname, O_RDWR|O_CREAT|O_EXCL, 0777, NULL); 295 if (mqd == (mqd_t)-1) { 296 tst_resm(TBROK, "parent: mq_open() failed (%s)", 297 strerror(errno)); 298 cleanup(TBROK, F_STEP_1, 0); 299 } 300 tst_resm(TINFO, "parent: successfully created posix mqueue"); 301 302 /* container creation on PID namespace */ 303 cpid = do_clone(CLONE_NEWPID|SIGCHLD, child_fn, NULL); 304 if (cpid < 0) { 305 tst_resm(TBROK, "parent: clone() failed(%s)", strerror(errno)); 306 cleanup(TBROK, F_STEP_2, mqd); 307 } 308 309 /* Close the appropriate end of each pipe */ 310 close(child_to_father[1]); 311 close(father_to_child[0]); 312 313 /* Is container ready */ 314 read(child_to_father[0], buf, 5); 315 if (strcmp(buf, "c:ok")) { 316 tst_resm(TBROK, "parent: container did not respond!"); 317 cleanup(TBROK, F_STEP_2, mqd); 318 } 319 320 rc = mq_send(mqd, MSG, strlen(MSG), MSG_PRIO); 321 if (rc == (mqd_t)-1) { 322 tst_resm(TBROK, "parent: mq_send() failed (%s)", 323 strerror(errno)); 324 cleanup(TBROK, F_STEP_2, mqd); 325 } 326 tst_resm(TINFO, "parent: mq_send() succeeded"); 327 328 /* Tell the child the message has been sent */ 329 if (write(father_to_child[1], "f:ok", 5) != 5) { 330 tst_resm(TBROK, "father: pipe is broken(%s)", strerror(errno)); 331 cleanup(TBROK, F_STEP_2, mqd); 332 } 333 334 /* Wait for child to finish */ 335 if (wait(&status) == -1) { 336 tst_resm(TBROK, "parent: wait() failed(%s)", strerror(errno)); 337 cleanup(TBROK, F_STEP_2, mqd); 338 } 339 340 cleanup(result, F_STEP_3, mqd); 341 342 /* NOT REACHED */ 343 return 0; 344} /* End main */ 345