pidns30.c revision 0ea93795469c7c1364e7f343c21df5745bf3154c
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 84mqd_t rc = -1; 85mqd_t mqd = -1; 86 87static void remove_pipe(int *fd) 88{ 89 close(fd[0]); 90 close(fd[1]); 91} 92 93static void remove_mqueue(mqd_t mqd) 94{ 95 mq_close(mqd); 96 syscall(__NR_mq_unlink, mqname); 97} 98 99static void cleanup(void) 100{ 101 if (mqd != -1) { 102 remove_mqueue(mqd); 103 } 104 if (rc != -1) { 105 remove_mqueue(rc); 106 } 107 remove_pipe(father_to_child); 108 remove_pipe(child_to_father); 109 110 TEST_CLEANUP; 111} 112 113static void cleanup_child(void) 114{ 115 if (mqd != -1) { 116 syscall(__NR_mq_notify, mqd, NULL); 117 } 118 cleanup(); 119} 120 121/* 122 * child_signal_handler() - to handle SIGUSR1 123 * 124 * XXX (garrcoop): add calls to cleanup_child() -- or should this be handled 125 * from the libltp signal handler? 126 */ 127static void child_signal_handler(int sig, siginfo_t * si, void *unused) 128{ 129 char buf[256]; 130 struct mq_attr attr; 131 132 if (si->si_signo != SIGUSR1) { 133 printf("received signal = %d unexpectedly\n", si->si_signo); 134 return; 135 } 136 137 if (si->si_code != SI_MESGQ) { 138 printf("expected signal code SI_MESGQ; got %d instead\n", 139 si->si_code); 140 return; 141 } 142 143 if (si->si_pid) { 144 printf("expected signal originator PID = 0; got %d instead\n", 145 si->si_pid); 146 return; 147 } else { 148 printf("signal originator PID = 0\n"); 149 result = TPASS; 150 } 151 152 /* 153 * Now read the message - Be silent on errors since this is not the 154 * test purpose. 155 */ 156 rc = mq_getattr(si->si_int, &attr); 157 if (rc != -1) 158 mq_receive(si->si_int, buf, attr.mq_msgsize, NULL); 159} 160 161/* 162 * child_fn() - Inside container 163 * 164 * XXX (garrcoop): add more calls to cleanup_child()? 165 */ 166int child_fn(void *arg) 167{ 168 pid_t pid, ppid; 169 struct sigaction sa; 170 struct sigevent notif; 171 char buf[5]; 172 173 /* Set process id and parent pid */ 174 pid = getpid(); 175 ppid = getppid(); 176 177 if (pid != CHILD_PID || ppid != PARENT_PID) { 178 printf("pidns was not created\n"); 179 return 1; 180 } 181 182 /* Close the appropriate end of each pipe */ 183 close(child_to_father[0]); 184 close(father_to_child[1]); 185 186 while (read(father_to_child[0], buf, 1) != 1) 187 sleep(1); 188 189 mqd = syscall(__NR_mq_open, mqname, O_RDONLY, 0, NULL); 190 if (mqd == -1) { 191 perror("mq_open failed"); 192 return 1; 193 } else 194 printf("mq_open succeeded\n"); 195 196 /* Register for notification on message arrival */ 197 notif.sigev_notify = SIGEV_SIGNAL; 198 notif.sigev_signo = SIGUSR1; 199 notif.sigev_value.sival_int = mqd; 200 if (syscall(__NR_mq_notify, mqd, ¬if) == -1) { 201 perror("mq_notify failed"); 202 return 1; 203 } else 204 printf("successfully registered for notification\n"); 205 206 /* Define handler for SIGUSR1 */ 207 sa.sa_flags = SA_SIGINFO; 208 sigemptyset(&sa.sa_mask); 209 sa.sa_sigaction = child_signal_handler; 210 if (sigaction(SIGUSR1, &sa, NULL) == -1) { 211 perror("sigaction failed"); 212 return 1; 213 } else 214 printf("successfully registered handler for SIGUSR1\n"); 215 216 /* Ask parent to send a message to the mqueue */ 217 if (write(child_to_father[1], "c:ok", 5) != 5) { 218 perror("write failed"); 219 return 1; 220 } 221 222 sleep(3); 223 224 /* Has parent sent a message? */ 225 read(father_to_child[0], buf, 5); 226 if (strcmp(buf, "f:ok") != 0) { 227 printf("parent did not send the message!\n"); 228 return 1; 229 } 230 printf("parent is done - cleaning up\n"); 231 232 cleanup_child(); 233 234 exit(0); 235} 236 237int main(int argc, char *argv[]) 238{ 239 int status; 240 char buf[5]; 241 pid_t cpid; 242 243 if (pipe(child_to_father) == -1 || pipe(father_to_child) == -1) { 244 tst_brkm(TBROK | TERRNO, cleanup, "pipe failed"); 245 } 246 247 syscall(__NR_mq_unlink, mqname); 248 249 /* container creation on PID namespace */ 250 cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); 251 if (cpid == -1) 252 tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); 253 254 mqd = 255 syscall(__NR_mq_open, mqname, O_RDWR | O_CREAT | O_EXCL, 0777, 256 NULL); 257 if (mqd == -1) 258 tst_brkm(TBROK | TERRNO, cleanup, "mq_open failed"); 259 else 260 tst_resm(TINFO, "successfully created posix mqueue"); 261 262 if (write(father_to_child[1], buf, 1) != 1) 263 tst_brkm(TBROK | TERRNO, cleanup, "write failed"); 264 265 /* Close the appropriate end of each pipe */ 266 close(child_to_father[1]); 267 close(father_to_child[0]); 268 269 /* Is container ready */ 270 read(child_to_father[0], buf, 5); 271 if (strcmp(buf, "c:ok") != 0) 272 tst_brkm(TBROK, cleanup, 273 "container did not respond as expected!"); 274 275 rc = mq_send(mqd, MSG, strlen(MSG), MSG_PRIO); 276 if (rc == -1) 277 tst_brkm(TBROK | TERRNO, cleanup, "mq_send failed"); 278 else 279 tst_resm(TINFO, "mq_send succeeded"); 280 281 /* Tell the child the message has been sent */ 282 if (write(father_to_child[1], "f:ok", 5) != 5) 283 tst_brkm(TBROK | TERRNO, cleanup, "write failed"); 284 285 /* Wait for child to finish */ 286 if (wait(&status) == -1) 287 tst_resm(TBROK | TERRNO, "wait failed"); 288 289 cleanup(); 290 291 tst_exit(); 292} 293