pidns30.c revision 2c28215423293e443469a07ae7011135d058b671
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 "linux_syscall_numbers.h" 57#include "libclone.h" 58 59char *TCID = "pidns30"; 60int TST_TOTAL = 1; 61 62char *mqname = "mq1"; 63int result = TFAIL; 64 65int errno; 66int father_to_child[2]; 67int child_to_father[2]; 68 69#define CHILD_PID 1 70#define PARENT_PID 0 71 72#define MSG "HOW ARE YOU" 73#define MSG_PRIO 1 74 75#define NO_STEP -1 76#define F_STEP_0 0x00 77#define F_STEP_1 0x01 78#define F_STEP_2 0x02 79#define F_STEP_3 0x03 80#define C_STEP_0 0x10 81#define C_STEP_1 0x11 82#define C_STEP_2 0x12 83 84static void remove_pipe(int *fd) 85{ 86 close(fd[0]); 87 close(fd[1]); 88} 89 90static void remove_mqueue(mqd_t mqd) 91{ 92 mq_close(mqd); 93 syscall(__NR_mq_unlink, mqname); 94} 95 96/* 97 * steps F_STEP_XX : called from main 98 * steps C_STEP_XX : called from child_fn 99 */ 100static void cleanup_resources(int step, mqd_t mqd) 101{ 102 switch (step) { 103 case C_STEP_2: 104 close(child_to_father[1]); 105 close(father_to_child[0]); 106 mq_close(mqd); 107 break; 108 109 case C_STEP_1: 110 syscall(__NR_mq_notify, mqd, NULL); 111 /* fall through */ 112 case C_STEP_0: 113 mq_close(mqd); 114 break; 115 116 case F_STEP_3: 117 remove_mqueue(mqd); 118 close(child_to_father[0]); 119 close(father_to_child[1]); 120 break; 121 122 case F_STEP_2: 123 remove_mqueue(mqd); 124 /* fall through */ 125 case F_STEP_1: 126 remove_pipe(father_to_child); 127 /* fall through */ 128 case F_STEP_0: 129 remove_pipe(child_to_father); 130 break; 131 default: 132 tst_resm(TWARN, "Unknown code - no resource removed."); 133 break; 134 } 135} 136 137/* 138 * cleanup_mqueue() - performs all ONE TIME cleanup for this test at 139 * completion or premature exit. 140 */ 141static void cleanup_mqueue(int result, int step, mqd_t mqd) 142{ 143 if (step != NO_STEP) 144 cleanup_resources(step, mqd); 145 146 /* Clean the test testcase as LTP wants*/ 147 TEST_CLEANUP; 148 149 tst_exit(); 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 * child_fn() - Inside container 196 */ 197int child_fn(void *arg) 198{ 199 pid_t pid, ppid; 200 struct sigaction sa; 201 mqd_t mqd; 202 struct sigevent notif; 203 char buf[5]; 204 205 /* Set process id and parent pid */ 206 pid = getpid(); 207 ppid = getppid(); 208 209 if (pid != CHILD_PID || ppid != PARENT_PID) { 210 tst_resm(TBROK, "cinit: pidns is not created"); 211 cleanup_mqueue(TBROK, NO_STEP, 0); 212 } 213 214 /* Close the appropriate end of each pipe */ 215 close(child_to_father[0]); 216 close(father_to_child[1]); 217 218 mqd = syscall(__NR_mq_open, mqname, O_RDONLY); 219 if (mqd == (mqd_t)-1) { 220 tst_resm(TBROK, "cinit: mq_open() failed (%s)", 221 strerror(errno)); 222 cleanup_mqueue(TBROK, NO_STEP, 0); 223 } 224 tst_resm(TINFO, "cinit: mq_open succeeded"); 225 226 /* Register for notification on message arrival */ 227 notif.sigev_notify = SIGEV_SIGNAL; 228 notif.sigev_signo = SIGUSR1; 229 notif.sigev_value.sival_int = mqd; 230 if (syscall(__NR_mq_notify, mqd, ¬if) == (mqd_t)-1) { 231 tst_resm(TBROK, "cinit: mq_notify() failed (%s)", 232 strerror(errno)); 233 cleanup_mqueue(TBROK, C_STEP_0, mqd); 234 } 235 tst_resm(TINFO, "cinit: successfully registered for notification"); 236 237 /* Define handler for SIGUSR1 */ 238 sa.sa_flags = SA_SIGINFO; 239 sigemptyset(&sa.sa_mask); 240 sa.sa_sigaction = child_signal_handler; 241 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 242 tst_resm(TBROK, "cinit: sigaction() failed(%s)", 243 strerror(errno)); 244 cleanup_mqueue(TBROK, C_STEP_1, mqd); 245 } 246 tst_resm(TINFO, "cinit: successfully registered handler for SIGUSR1"); 247 248 /* Ask parent to send a message to the mqueue */ 249 if (write(child_to_father[1], "c:ok", 5) != 5) { 250 tst_resm(TBROK, "cinit: pipe is broken (%s)", strerror(errno)); 251 cleanup_mqueue(TBROK, C_STEP_1, mqd); 252 } 253 254 sleep(3); 255 256 /* Has parent sent a message? */ 257 read(father_to_child[0], buf, 5); 258 if (strcmp(buf, "f:ok")) { 259 tst_resm(TBROK, "cinit: parent did not send the message!"); 260 cleanup_mqueue(TBROK, C_STEP_1, mqd); 261 } 262 tst_resm(TINFO, "cinit: my father is done - cleaning"); 263 264 /* Be silent on errors from now on */ 265 cleanup_resources(C_STEP_2, mqd); 266 267 exit(0); 268} 269 270/*********************************************************************** 271* M A I N 272***********************************************************************/ 273 274int main(int argc, char *argv[]) 275{ 276 int status; 277 char buf[5]; 278 pid_t cpid; 279 mqd_t mqd; 280 mqd_t rc; 281 282 if (pipe(child_to_father) == -1) { 283 tst_resm(TBROK, "parent: pipe() failed. aborting!"); 284 cleanup_mqueue(TBROK, NO_STEP, 0); 285 } 286 287 if (pipe(father_to_child) == -1) { 288 tst_resm(TBROK, "parent: pipe() failed. aborting!"); 289 cleanup_mqueue(TBROK, F_STEP_0, 0); 290 } 291 292 syscall(__NR_mq_unlink, mqname); 293 mqd = syscall(__NR_mq_open, mqname, O_RDWR|O_CREAT|O_EXCL, 0777, NULL); 294 if (mqd == (mqd_t)-1) { 295 tst_resm(TBROK, "parent: mq_open() failed (%s)", 296 strerror(errno)); 297 cleanup_mqueue(TBROK, F_STEP_1, 0); 298 } 299 tst_resm(TINFO, "parent: successfully created posix mqueue"); 300 301 /* container creation on PID namespace */ 302 cpid = ltp_clone_quick(CLONE_NEWPID|SIGCHLD, child_fn, NULL); 303 if (cpid < 0) { 304 tst_resm(TBROK, "parent: clone() failed(%s)", strerror(errno)); 305 cleanup_mqueue(TBROK, F_STEP_2, mqd); 306 } 307 308 /* Close the appropriate end of each pipe */ 309 close(child_to_father[1]); 310 close(father_to_child[0]); 311 312 /* Is container ready */ 313 read(child_to_father[0], buf, 5); 314 if (strcmp(buf, "c:ok")) { 315 tst_resm(TBROK, "parent: container did not respond!"); 316 cleanup_mqueue(TBROK, F_STEP_2, mqd); 317 } 318 319 rc = mq_send(mqd, MSG, strlen(MSG), MSG_PRIO); 320 if (rc == (mqd_t)-1) { 321 tst_resm(TBROK, "parent: mq_send() failed (%s)", 322 strerror(errno)); 323 cleanup_mqueue(TBROK, F_STEP_2, mqd); 324 } 325 tst_resm(TINFO, "parent: mq_send() succeeded"); 326 327 /* Tell the child the message has been sent */ 328 if (write(father_to_child[1], "f:ok", 5) != 5) { 329 tst_resm(TBROK, "father: pipe is broken(%s)", strerror(errno)); 330 cleanup_mqueue(TBROK, F_STEP_2, mqd); 331 } 332 333 /* Wait for child to finish */ 334 if (wait(&status) == -1) { 335 tst_resm(TBROK, "parent: wait() failed(%s)", strerror(errno)); 336 cleanup_mqueue(TBROK, F_STEP_2, mqd); 337 } 338 339 cleanup_mqueue(result, F_STEP_3, mqd); 340 341 tst_exit(); 342}