Home | History | Annotate | Download | only in clone
      1 /*
      2  * Copyright (c) Wipro Technologies Ltd, 2002.  All Rights Reserved.
      3  * Copyright (c) 2012 Wanlong Gao <gaowanlong (at) cn.fujitsu.com>
      4  *
      5  * This program is free software; you can redistribute it and/or modify it
      6  * under the terms of version 2 of the GNU General Public License as
      7  * published by the Free Software Foundation.
      8  *
      9  * This program is distributed in the hope that it would be useful, but
     10  * WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12  *
     13  * You should have received a copy of the GNU General Public License along
     14  * with this program; if not, write the Free Software Foundation, Inc.,
     15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     16  *
     17  */
     18 /*
     19  *	 TEST1
     20  *	 -----
     21  *		Call clone() with all resources shared.
     22  *
     23  *		CHILD:
     24  *			modify the shared resources
     25  *			return 1 on success
     26  *		PARENT:
     27  *			wait for child to finish
     28  *			verify that the shared resourses are modified
     29  *			return 1 on success
     30  *		If parent & child returns successfully
     31  *			test passed
     32  *		else
     33  *			test failed
     34  *
     35  *	 TEST2
     36  *	 -----
     37  *		Call clone() with no resources shared.
     38  *
     39  *		CHILD:
     40  *			modify the resources in child's address space
     41  *			return 1 on success
     42  *		PARENT:
     43  *			wait for child to finish
     44  *			verify that the parent's resourses are not modified
     45  *			return 1 on success
     46  *		If parent & child returns successfully
     47  *			test passed
     48  *		else
     49  *			test failed
     50  */
     51 
     52 #if defined UCLINUX && !__THROW
     53 /* workaround for libc bug */
     54 #define __THROW
     55 #endif
     56 
     57 #define _GNU_SOURCE
     58 
     59 #include <errno.h>
     60 #include <fcntl.h>
     61 #include <sys/wait.h>
     62 #include <sys/types.h>
     63 #include <sys/syscall.h>
     64 #include <sched.h>
     65 #include "test.h"
     66 #include "safe_macros.h"
     67 
     68 #define FLAG_ALL (CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD)
     69 #define FLAG_NONE SIGCHLD
     70 #define PARENT_VALUE 1
     71 #define CHILD_VALUE 2
     72 #define TRUE 1
     73 #define FALSE 0
     74 
     75 #include "clone_platform.h"
     76 
     77 static void setup(void);
     78 static int test_setup(void);
     79 static void cleanup(void);
     80 static void test_cleanup(void);
     81 static int child_fn();
     82 static int parent_test1(void);
     83 static int parent_test2(void);
     84 static int test_VM(void);
     85 static int test_FS(void);
     86 static int test_FILES(void);
     87 static int test_SIG(void);
     88 static int modified_VM(void);
     89 static int modified_FS(void);
     90 static int modified_FILES(void);
     91 static int modified_SIG(void);
     92 static void sig_child_defined_handler(int);
     93 static void sig_default_handler();
     94 
     95 static int fd_parent;
     96 static char file_name[25];
     97 static int parent_variable;
     98 static char cwd_parent[FILENAME_MAX];
     99 static int parent_got_signal, child_pid;
    100 
    101 char *TCID = "clone02";
    102 
    103 struct test_case_t {
    104 	int flags;
    105 	int (*parent_fn) ();
    106 } test_cases[] = {
    107 	{
    108 	FLAG_ALL, parent_test1}, {
    109 	FLAG_NONE, parent_test2}
    110 };
    111 
    112 int TST_TOTAL = sizeof(test_cases) / sizeof(test_cases[0]);
    113 
    114 int main(int ac, char **av)
    115 {
    116 
    117 	int lc;
    118 	void *child_stack;
    119 	int status, i;
    120 
    121 	tst_parse_opts(ac, av, NULL, NULL);
    122 
    123 	setup();
    124 
    125 	child_stack = malloc(CHILD_STACK_SIZE);
    126 	if (child_stack == NULL)
    127 		tst_brkm(TBROK, cleanup, "Cannot allocate stack for child");
    128 
    129 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    130 		tst_count = 0;
    131 
    132 		for (i = 0; i < TST_TOTAL; ++i) {
    133 			if (test_setup() != 0) {
    134 				tst_resm(TWARN, "test_setup() failed,"
    135 					 "skipping this test case");
    136 				continue;
    137 			}
    138 
    139 			/* Test the system call */
    140 			TEST(ltp_clone(test_cases[i].flags, child_fn, NULL,
    141 				       CHILD_STACK_SIZE, child_stack));
    142 
    143 			/* check return code */
    144 			if (TEST_RETURN == -1) {
    145 				tst_resm(TFAIL | TTERRNO, "clone() failed");
    146 				/* Cleanup & continue with next test case */
    147 				test_cleanup();
    148 				continue;
    149 			}
    150 
    151 			/* Wait for child to finish */
    152 			if ((wait(&status)) == -1) {
    153 				tst_resm(TWARN | TERRNO,
    154 					 "wait failed; skipping testcase");
    155 				/* Cleanup & continue with next test case */
    156 				test_cleanup();
    157 				continue;
    158 			}
    159 
    160 			if (WTERMSIG(status))
    161 				tst_resm(TWARN, "child exitied with signal %d",
    162 					 WTERMSIG(status));
    163 
    164 			/*
    165 			 * Check the return value from child function and
    166 			 * parent function. If both functions returned
    167 			 * successfully, test passed, else failed
    168 			 */
    169 			if (WIFEXITED(status) && WEXITSTATUS(status) == 0 &&
    170 			    test_cases[i].parent_fn())
    171 				tst_resm(TPASS, "Test Passed");
    172 			else
    173 				tst_resm(TFAIL, "Test Failed");
    174 
    175 			/* Do test specific cleanup */
    176 			test_cleanup();
    177 		}
    178 	}
    179 
    180 	free(child_stack);
    181 
    182 	cleanup();
    183 	tst_exit();
    184 }
    185 
    186 static void setup(void)
    187 {
    188 	tst_sig(FORK, DEF_HANDLER, cleanup);
    189 	TEST_PAUSE;
    190 	tst_tmpdir();
    191 
    192 	/* Get unique file name for each child process */
    193 	if ((sprintf(file_name, "parent_file_%ld", syscall(__NR_gettid))) <= 0)
    194 		tst_brkm(TBROK | TERRNO, cleanup, "sprintf() failed");
    195 }
    196 
    197 static void cleanup(void)
    198 {
    199 	if (unlink(file_name) == -1)
    200 		tst_resm(TWARN | TERRNO, "unlink(%s) failed", file_name);
    201 	tst_rmdir();
    202 }
    203 
    204 static int test_setup(void)
    205 {
    206 
    207 	struct sigaction def_act;
    208 
    209 	/* Save current working directory of parent */
    210 	if (getcwd(cwd_parent, sizeof(cwd_parent)) == NULL) {
    211 		tst_resm(TWARN | TERRNO, "getcwd() failed in test_setup()");
    212 		return -1;
    213 	}
    214 
    215 	/*
    216 	 * Set value for parent_variable in parent, which will be
    217 	 * changed by child in test_VM(), for testing CLONE_VM flag
    218 	 */
    219 	parent_variable = PARENT_VALUE;
    220 
    221 	/*
    222 	 * Open file from parent, which will be closed by
    223 	 * child in test_FILES(), used for testing CLONE_FILES flag
    224 	 */
    225 	fd_parent = open(file_name, O_CREAT | O_RDWR, 0777);
    226 	if (fd_parent == -1) {
    227 		tst_resm(TWARN | TERRNO, "open() failed in test_setup()");
    228 		return -1;
    229 	}
    230 
    231 	/*
    232 	 * set parent_got_signal to FALSE, used for testing
    233 	 * CLONE_SIGHAND flag
    234 	 */
    235 	parent_got_signal = FALSE;
    236 
    237 	/* Setup signal handler for SIGUSR2 */
    238 	def_act.sa_handler = sig_default_handler;
    239 	def_act.sa_flags = SA_RESTART;
    240 	sigemptyset(&def_act.sa_mask);
    241 
    242 	if (sigaction(SIGUSR2, &def_act, NULL) == -1) {
    243 		tst_resm(TWARN | TERRNO, "sigaction() failed in test_setup()");
    244 		return -1;
    245 	}
    246 
    247 	return 0;
    248 }
    249 
    250 static void test_cleanup(void)
    251 {
    252 
    253 	/* Restore parent's working directory */
    254 	SAFE_CHDIR(cleanup, cwd_parent);
    255 
    256 }
    257 
    258 static int child_fn(void)
    259 {
    260 
    261 	/* save child pid */
    262 	child_pid = syscall(__NR_gettid);
    263 
    264 	if (test_VM() == 0 && test_FILES() == 0 && test_FS() == 0 &&
    265 	    test_SIG() == 0)
    266 		_exit(0);
    267 	_exit(1);
    268 }
    269 
    270 static int parent_test1(void)
    271 {
    272 
    273 	/*
    274 	 * For first test case (with all flags set), all resources are
    275 	 * shared between parent and child. So whatever changes made by
    276 	 * child should get reflected in parent also. modified_*()
    277 	 * functions check this. All of them should return 1 for
    278 	 * parent_test1() to return 1
    279 	 */
    280 
    281 	if (modified_VM() && modified_FILES() && modified_FS() &&
    282 	    modified_SIG())
    283 		return 0;
    284 	return -1;
    285 }
    286 
    287 static int parent_test2(void)
    288 {
    289 
    290 	/*
    291 	 * For second test case (with no resouce shared), all of the
    292 	 * modified_*() functions should return 0 for parent_test2()
    293 	 * to return 1
    294 	 */
    295 	if (modified_VM() || modified_FILES() || modified_FS() ||
    296 	    modified_SIG())
    297 		return 0;
    298 
    299 	return -1;
    300 }
    301 
    302 /*
    303  * test_VM() - function to change parent_variable from child's
    304  *	       address space. If CLONE_VM flag is set, child shares
    305  *	       the memory space with parent so this will be visible
    306  *	       to parent also.
    307  */
    308 
    309 static int test_VM(void)
    310 {
    311 	parent_variable = CHILD_VALUE;
    312 	return 0;
    313 }
    314 
    315 /*
    316  * test_FILES() - This function closes a file descriptor opened by
    317  *		  parent. If CLONE_FILES flag is set, the parent and
    318  *		  the child process share the same file descriptor
    319  *		  table. so this affects the parent also
    320  */
    321 static int test_FILES(void)
    322 {
    323 	if (close(fd_parent) == -1) {
    324 		tst_resm(TWARN | TERRNO, "close failed in test_FILES");
    325 		return -1;
    326 	}
    327 	return 0;
    328 }
    329 
    330 /*
    331  * test_FS() -  This function changes the current working directory
    332  *		of the child process. If CLONE_FS flag is set, this
    333  *		will be visible to parent also.
    334  */
    335 static int test_FS(void)
    336 {
    337 	char *test_tmpdir;
    338 	int rval;
    339 
    340 	test_tmpdir = tst_get_tmpdir();
    341 	if (test_tmpdir == NULL) {
    342 		tst_resm(TWARN | TERRNO, "tst_get_tmpdir failed");
    343 		rval = -1;
    344 	} else if (chdir(test_tmpdir) == -1) {
    345 		tst_resm(TWARN | TERRNO, "chdir failed in test_FS");
    346 		rval = -1;
    347 	} else {
    348 		rval = 0;
    349 	}
    350 
    351 	free(test_tmpdir);
    352 	return rval;
    353 }
    354 
    355 /*
    356  * test_SIG() - This function changes the signal handler for SIGUSR2
    357  *		signal for child. If CLONE_SIGHAND flag is set, this
    358  *		affects parent also.
    359  */
    360 static int test_SIG(void)
    361 {
    362 
    363 	struct sigaction new_act;
    364 
    365 	new_act.sa_handler = sig_child_defined_handler;
    366 	new_act.sa_flags = SA_RESTART;
    367 	sigemptyset(&new_act.sa_mask);
    368 
    369 	/* Set signal handler to sig_child_defined_handler */
    370 	if (sigaction(SIGUSR2, &new_act, NULL) == -1) {
    371 		tst_resm(TWARN | TERRNO, "signal failed in test_SIG");
    372 		return -1;
    373 	}
    374 
    375 	/* Send SIGUSR2 signal to parent */
    376 	if (kill(getppid(), SIGUSR2) == -1) {
    377 		tst_resm(TWARN | TERRNO, "kill failed in test_SIG");
    378 		return -1;
    379 	}
    380 
    381 	return 0;
    382 }
    383 
    384 /*
    385  * modified_VM() - This function is called by parent process to check
    386  *		   whether child's modification to parent_variable
    387  *		   is visible to parent
    388  */
    389 
    390 static int modified_VM(void)
    391 {
    392 
    393 	if (parent_variable == CHILD_VALUE)
    394 		/* child has modified parent_variable */
    395 		return 1;
    396 
    397 	return 0;
    398 }
    399 
    400 /*
    401  * modified_FILES() - This function checks for file descriptor table
    402  *		      modifications done by child
    403  */
    404 static int modified_FILES(void)
    405 {
    406 	char buff[20];
    407 
    408 	if (((read(fd_parent, buff, sizeof(buff))) == -1) && (errno == EBADF))
    409 		/* Child has closed this file descriptor */
    410 		return 1;
    411 
    412 	/* close fd_parent */
    413 	if ((close(fd_parent)) == -1)
    414 		tst_resm(TWARN | TERRNO, "close() failed in modified_FILES()");
    415 
    416 	return 0;
    417 }
    418 
    419 /*
    420  * modified_FS() - This function checks parent's current working directory
    421  *		   to see whether its modified by child or not.
    422  */
    423 static int modified_FS(void)
    424 {
    425 	char cwd[FILENAME_MAX];
    426 
    427 	if ((getcwd(cwd, sizeof(cwd))) == NULL)
    428 		tst_resm(TWARN | TERRNO, "getcwd() failed");
    429 
    430 	if (!(strcmp(cwd, cwd_parent)))
    431 		/* cwd hasn't changed */
    432 		return 0;
    433 
    434 	return 1;
    435 }
    436 
    437 /*
    438  * modified_SIG() - This function checks whether child has changed
    439  *		    parent's signal handler for signal, SIGUSR2
    440  */
    441 static int modified_SIG(void)
    442 {
    443 
    444 	if (parent_got_signal)
    445 		/*
    446 		 * parent came through sig_child_defined_handler()
    447 		 * this means child has changed parent's handler
    448 		 */
    449 		return 1;
    450 
    451 	return 0;
    452 }
    453 
    454 /*
    455  * sig_child_defined_handler()  - Signal handler installed by child
    456  */
    457 static void sig_child_defined_handler(int pid)
    458 {
    459 	if ((syscall(__NR_gettid)) == child_pid)
    460 		/* Child got signal, give warning */
    461 		tst_resm(TWARN, "Child got SIGUSR2 signal");
    462 	else
    463 		parent_got_signal = TRUE;
    464 }
    465 
    466 /* sig_default_handler() - Default handler for parent */
    467 static void sig_default_handler(void)
    468 {
    469 }
    470