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, &notif) == -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