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