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