pidns13.c revision 044315e5614273e9d65f41b672b3b916d3e86459
1/*
2* Copyright (c) International Business Machines Corp., 2007
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: pidns13.c
17* *
18* * Description:
19* *  The pidns13.c testcase checks container init, for async I/O
20* *  triggered by peer namespace process.
21* *
22* * Test Assertion & Strategy:
23* *  Create a pipe in parent namespace.
24* *  Create two PID namespace containers(cinit1 and cinit2).
25* *  In cinit1, set pipe read end to send SIGUSR1.
26* *    for asynchronous I/O.
27* *  Let cinit2 to trigger async I/O on pipe write end.
28* *  In signal info, check si_code to be POLL_IN and si_fd to be pipe read fd.
29* *
30* * Usage: <for command-line>
31* *  pidns13
32* *
33* * History:
34* *  DATE      NAME                             DESCRIPTION
35* *  23/10/08  Gowrishankar M 			Created test scenarion.
36* *            <gowrishankar.m@in.ibm.com>
37*
38******************************************************************************/
39#define _GNU_SOURCE 1
40#include <sys/wait.h>
41#include <sys/types.h>
42#include <fcntl.h>
43#include <signal.h>
44#include <string.h>
45#include <stdlib.h>
46#include <unistd.h>
47#include <stdio.h>
48#include "test.h"
49#include <libclone.h>
50#include "pidns_helper.h"
51
52char *TCID = "pidns13";
53int TST_TOTAL = 1;
54int pipe_fd[2];
55
56#define CHILD_PID       1
57#define PARENT_PID      0
58
59/*
60 * child_signal_handler() - dummy function for sigaction()
61 */
62static void child_signal_handler(int sig, siginfo_t * si, void *unused)
63{
64	/* sigtimedwait() traps siginfo details, so this wont be called */
65	tst_resm(TWARN, "cinit(pid %d): control should have not reached here!",
66		 getpid());
67}
68
69/*
70 * child_fn() - Inside container
71 */
72int child_fn(void *arg)
73{
74	struct sigaction sa;
75	sigset_t newset;
76	siginfo_t info;
77	struct timespec timeout;
78	pid_t pid, ppid;
79	int cinit_no = *((int *)arg);
80
81	/* Set process id and parent pid */
82	pid = getpid();
83	ppid = getppid();
84	if (pid != CHILD_PID || ppid != PARENT_PID) {
85		tst_resm(TBROK, "cinit%d: pidns is not created.", cinit_no);
86	}
87
88	if (cinit_no == 1) {
89		/* in container 1 */
90		/* close pipe write descriptor */
91		if (close(pipe_fd[1]) == -1) {
92			tst_resm(TBROK, "cinit1: close(pipe_fd[1]) failed");
93		}
94
95		/* Let cinit1 to get SIGUSR1 on I/O availability */
96		if (fcntl(pipe_fd[0], F_SETOWN, pid) == -1) {
97			tst_resm(TBROK, "cinit1: fcntl(F_SETOWN) failed");
98		}
99
100		if (fcntl(pipe_fd[0], F_SETSIG, SIGUSR1) == -1) {
101			tst_resm(TBROK, "cinit1: fcntl(F_SETSIG) failed");
102		}
103
104		if (fcntl(pipe_fd[0], F_SETFL,
105			  fcntl(pipe_fd[0], F_GETFL) | O_ASYNC) == -1) {
106			tst_resm(TBROK, "cinit1: fcntl(F_SETFL) failed");
107		}
108
109		/* Set signal handler for SIGUSR1, also mask other signals */
110		sa.sa_flags = SA_SIGINFO;
111		sigfillset(&sa.sa_mask);
112		sa.sa_sigaction = child_signal_handler;
113		if (sigaction(SIGUSR1, &sa, NULL) == -1) {
114			tst_resm(TBROK, "cinit1: sigaction() failed");
115		}
116
117		tst_resm(TINFO, "cinit1: setup handler for async I/O on pipe");
118
119		/* Set timeout for sigtimedwait */
120		timeout.tv_sec = 10;
121		timeout.tv_nsec = 0;
122
123		/* Set mask to wait for SIGUSR1 signal */
124		sigemptyset(&newset);
125		sigaddset(&newset, SIGUSR1);
126
127		/* Wait for SIGUSR1 */
128		if (sigtimedwait(&newset, &info, &timeout) != SIGUSR1) {
129			tst_resm(TBROK, "cinit1: sigtimedwait() failed.");
130		}
131
132		/* Recieved SIGUSR1. Check details. */
133		if (info.si_fd == pipe_fd[0] && info.si_code == POLL_IN)
134			tst_resm(TPASS, "cinit1: si_fd is %d, si_code is %d",
135				 info.si_fd, info.si_code);
136		else
137			tst_resm(TFAIL, "cinit1: si_fd is %d, si_code is %d",
138				 info.si_fd, info.si_code);
139
140		/* all done, close the descriptors opened */
141		close(pipe_fd[0]);
142
143	} else {
144		/* in container 2 */
145		/* close pipe read descriptor */
146		if (close(pipe_fd[0]) == -1) {
147			tst_resm(TBROK, "cinit2: close(pipe_fd[0]) failed");
148		}
149
150		/* sleep for few seconds to avoid race with cinit1 */
151		sleep(2);
152
153		/* Write some data in pipe to SIGUSR1 cinit1 */
154		tst_resm(TINFO, "cinit2: writing some data in pipe");
155		if (write(pipe_fd[1], "test\n", 5) == -1) {
156			tst_resm(TBROK, "cinit2: write() failed");
157		}
158
159		/* all done, close the descriptors opened */
160		close(pipe_fd[1]);
161	}
162
163	/* cleanup and exit */
164	exit(0);
165}
166
167static void setup(void)
168{
169	tst_require_root(NULL);
170	check_newpid();
171}
172
173/***********************************************************************
174*   M A I N
175***********************************************************************/
176
177int main(int argc, char *argv[])
178{
179	int status;
180	int *cinit_no = malloc(sizeof(int));
181	pid_t cpid1, cpid2;
182
183	setup();
184
185	/* create pipe */
186	if (pipe(pipe_fd) == -1) {
187		tst_resm(TBROK, "parent: pipe creation failed");
188	}
189
190	/* container creation on PID namespace */
191	if (!cinit_no) {
192		tst_resm(TBROK, "memory allocation failed.");
193	}
194
195	/* Create container 1 */
196	*cinit_no = 1;
197	cpid1 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, cinit_no);
198
199	/* Create container 2 */
200	*cinit_no = 2;
201	cpid2 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, cinit_no);
202	if (cpid1 < 0 || cpid2 < 0) {
203		tst_resm(TBROK, "parent: clone() failed.");
204	}
205
206	/* Close unwanted descriptors */
207	close(pipe_fd[0]);
208	close(pipe_fd[1]);
209
210	/* Wait for containers to exit */
211	if (waitpid(cpid2, &status, 0) < 0)
212		tst_resm(TWARN, "parent: waitpid(cpid2) failed.");
213
214	if (WIFSIGNALED(status) && WTERMSIG(status))
215		tst_resm(TWARN, "parent: cinit2 is terminated by signal(%s)",
216			 strsignal(WTERMSIG(status)));
217
218	if (waitpid(cpid1, &status, 0) < 0)
219		tst_resm(TWARN, "parent: waitpid(cpid1) failed.");
220
221	if (WIFSIGNALED(status) && WTERMSIG(status))
222		tst_resm(TWARN, "parent: cinit1 is terminated by signal(%s)",
223			 strsignal(WTERMSIG(status)));
224
225	/* Control won't reach below */
226	exit(0);
227
228}
229