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