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: pidns20.c
     17 * *
     18 * * Description:
     19 * *  The pidns20.c testcase verifies that signal handler of SIGUSR1 is called
     20 * *  (and cinit is NOT terminated) when:
     21 * *    - container-init blocks SIGUSR1,
     22 * *    - parent queues SIGUSR1 and
     23 * *    - a handler is specified for SIGUSR1 before it is unblocked.
     24 * *
     25 * * Test Assertion & Strategy:
     26 * *  Create a PID namespace container.
     27 * *  Block SIGUSR1 signal inside it.
     28 * *  Let parent to deliver SIGUSR1 signal to container.
     29 * *  Redefine SIGUSR1 handler of cinit to user function.
     30 * *  Unblock SIGUSR1 from blocked queue.
     31 * *  Check if user function is called.
     32 * *
     33 * * Usage: <for command-line>
     34 * *  pidns20
     35 * *
     36 * * History:
     37 * *  DATE      NAME                             DESCRIPTION
     38 * *  13/11/08  Gowrishankar M 			Creation of this test.
     39 * *            <gowrishankar.m (at) in.ibm.com>
     40 *
     41 ******************************************************************************/
     42 #define _GNU_SOURCE 1
     43 #include <sys/wait.h>
     44 #include <sys/types.h>
     45 #include <signal.h>
     46 #include <stdlib.h>
     47 #include <unistd.h>
     48 #include <stdio.h>
     49 #include "pidns_helper.h"
     50 #include "test.h"
     51 #include "safe_macros.h"
     52 
     53 char *TCID = "pidns20";
     54 int TST_TOTAL = 1;
     55 
     56 int parent_cinit[2];
     57 int cinit_parent[2];
     58 int broken = 1;			/* broken should be 0 when test completes properly */
     59 
     60 #define CHILD_PID       1
     61 #define PARENT_PID      0
     62 
     63 /*
     64  * child_signal_handler() - to handle SIGUSR1
     65  */
     66 static void child_signal_handler(int sig, siginfo_t * si, void *unused)
     67 {
     68 	if (si->si_signo != SIGUSR1)
     69 		tst_resm(TBROK, "cinit: recieved %s unexpectedly!",
     70 			 strsignal(si->si_signo));
     71 	else
     72 		tst_resm(TPASS, "cinit: user function is called as expected");
     73 
     74 	/* Disable broken flag */
     75 	broken = 0;
     76 }
     77 
     78 /*
     79  * child_fn() - Inside container
     80  */
     81 int child_fn(void *arg)
     82 {
     83 	pid_t pid, ppid;
     84 	sigset_t newset;
     85 	struct sigaction sa;
     86 	char buf[5];
     87 
     88 	/* Setup pipe read and write ends */
     89 	pid = getpid();
     90 	ppid = getppid();
     91 
     92 	if (pid != CHILD_PID || ppid != PARENT_PID) {
     93 		printf("cinit: pidns was not created properly\n");
     94 		exit(1);
     95 	}
     96 
     97 	/* Setup pipes to communicate with parent */
     98 	close(cinit_parent[0]);
     99 	close(parent_cinit[1]);
    100 
    101 	/* Block SIGUSR1 signal */
    102 	sigemptyset(&newset);
    103 	sigaddset(&newset, SIGUSR1);
    104 	if (sigprocmask(SIG_BLOCK, &newset, 0) == -1) {
    105 		perror("cinit: sigprocmask() failed");
    106 		exit(1);
    107 	}
    108 	tst_resm(TINFO, "cinit: blocked SIGUSR1");
    109 
    110 	/* Let parent to queue SIGUSR1 in pending */
    111 	if (write(cinit_parent[1], "c:go", 5) != 5) {
    112 		perror("cinit: pipe is broken to write");
    113 		exit(1);
    114 	}
    115 
    116 	/* Check if parent has queued up SIGUSR1 */
    117 	read(parent_cinit[0], buf, 5);
    118 	if (strcmp(buf, "p:go") != 0) {
    119 		printf("cinit: parent did not respond!\n");
    120 		exit(1);
    121 	}
    122 
    123 	/* Now redefine handler for SIGUSR1 */
    124 	sa.sa_flags = SA_SIGINFO;
    125 	sigfillset(&sa.sa_mask);
    126 	sa.sa_sigaction = child_signal_handler;
    127 	if (sigaction(SIGUSR1, &sa, NULL) == -1) {
    128 		perror("cinit: sigaction failed");
    129 		exit(1);
    130 	}
    131 
    132 	/* Unblock traffic on SIGUSR1 queue */
    133 	tst_resm(TINFO, "cinit: unblocking SIGUSR1");
    134 	sigprocmask(SIG_UNBLOCK, &newset, 0);
    135 
    136 	/* Check if new handler is called */
    137 	if (broken == 1) {
    138 		printf("cinit: broken flag didn't change\n");
    139 		exit(1);
    140 	}
    141 
    142 	/* Cleanup and exit */
    143 	close(cinit_parent[1]);
    144 	close(parent_cinit[0]);
    145 	exit(0);
    146 }
    147 
    148 static void setup(void)
    149 {
    150 	tst_require_root();
    151 	check_newpid();
    152 }
    153 
    154 int main(int argc, char *argv[])
    155 {
    156 	int status;
    157 	char buf[5];
    158 	pid_t cpid;
    159 
    160 	setup();
    161 
    162 	/* Create pipes for intercommunication */
    163 	if (pipe(parent_cinit) == -1 || pipe(cinit_parent) == -1) {
    164 		tst_brkm(TBROK | TERRNO, NULL, "pipe failed");
    165 	}
    166 
    167 	cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL);
    168 	if (cpid == -1) {
    169 		tst_brkm(TBROK | TERRNO, NULL, "clone failed");
    170 	}
    171 
    172 	/* Setup pipe read and write ends */
    173 	close(cinit_parent[1]);
    174 	close(parent_cinit[0]);
    175 
    176 	/* Is container ready */
    177 	read(cinit_parent[0], buf, 5);
    178 	if (strcmp(buf, "c:go") != 0) {
    179 		tst_brkm(TBROK, NULL, "parent: container did not respond!");
    180 	}
    181 
    182 	/* Enqueue SIGUSR1 in pending signal queue of container */
    183 	SAFE_KILL(NULL, cpid, SIGUSR1);
    184 
    185 	tst_resm(TINFO, "parent: signalled SIGUSR1 to container");
    186 	if (write(parent_cinit[1], "p:go", 5) != 5) {
    187 		tst_brkm(TBROK | TERRNO, NULL, "write failed");
    188 	}
    189 
    190 	/* collect exit status of child */
    191 	SAFE_WAIT(NULL, &status);
    192 
    193 	if (WIFSIGNALED(status)) {
    194 		if (WTERMSIG(status) == SIGUSR1)
    195 			tst_resm(TFAIL,
    196 				 "user function was not called inside cinit");
    197 		else
    198 			tst_resm(TBROK,
    199 				 "cinit was terminated by %d",
    200 				 WTERMSIG(status));
    201 	}
    202 
    203 	/* Cleanup and exit */
    204 	close(parent_cinit[1]);
    205 	close(cinit_parent[0]);
    206 	tst_exit();
    207 }
    208