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