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