void tst_record_childstatus(void (*cleanup)(void), pid_t child) { int status, ttype_result; if (waitpid(child, &status, 0) < 0) tst_brkm(TBROK | TERRNO, cleanup, "waitpid(%d) failed", child); if (WIFEXITED(status)) { ttype_result = WEXITSTATUS(status); ttype_result = TTYPE_RESULT(ttype_result); T_exitval |= ttype_result; if (ttype_result == TPASS) tst_resm(TINFO, "Child process returned TPASS"); if (ttype_result & TFAIL) tst_resm(TINFO, "Child process returned TFAIL"); if (ttype_result & TBROK) tst_resm(TINFO, "Child process returned TBROK"); if (ttype_result & TCONF) tst_resm(TINFO, "Child process returned TCONF"); } else { tst_brkm(TBROK, cleanup, "child process(%d) killed by " "unexpected signal %s(%d)", child, tst_strsig(WTERMSIG(status)), WTERMSIG(status)); } }
void tst_record_childstatus(void (*cleanup)(void), pid_t child) { int status, ttype_result; NO_NEWLIB_ASSERT("Unknown", 0); SAFE_WAITPID(cleanup, child, &status, 0); if (WIFEXITED(status)) { ttype_result = WEXITSTATUS(status); ttype_result = TTYPE_RESULT(ttype_result); T_exitval |= ttype_result; if (ttype_result == TPASS) tst_resm(TINFO, "Child process returned TPASS"); if (ttype_result & TFAIL) tst_resm(TINFO, "Child process returned TFAIL"); if (ttype_result & TBROK) tst_resm(TINFO, "Child process returned TBROK"); if (ttype_result & TCONF) tst_resm(TINFO, "Child process returned TCONF"); } else { tst_brkm(TBROK, cleanup, "child process(%d) killed by " "unexpected signal %s(%d)", child, tst_strsig(WTERMSIG(status)), WTERMSIG(status)); } }
static void test(void) { int status, ret = 0; ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_msg, NULL); if (ret == -1) tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_msg, NULL); if (ret == -1) tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); while (wait(&status) > 0) { if (WIFEXITED(status) && WEXITSTATUS(status) == 1) ret = 1; if (WIFEXITED(status) && WEXITSTATUS(status) == 2) tst_brkm(TBROK | TERRNO, cleanup, "error in child"); if (WIFSIGNALED(status)) { tst_resm(TFAIL, "child was killed with signal %s", tst_strsig(WTERMSIG(status))); return; } } if (ret) tst_resm(TFAIL, "SysV msg: communication with identical keys" " between namespaces"); else tst_resm(TPASS, "SysV msg: communication with identical keys" " between namespaces"); }
void do_child(void) { int cnt; int sig; /* set up signal handler routine */ for (sig = 1; sig < NUMSIGS; sig++) { if (skip_sig(sig)) continue; if (signal(sig, handle_sigs) == SIG_ERR) { tst_resm(TBROK | TERRNO, "signal() %i(%s) failed", sig, tst_strsig(sig)); } } /* all set up to catch signals, now hold them */ for (cnt = 0, sig = 1; sig < NUMSIGS; sig++) { if (skip_sig(sig)) continue; cnt++; TEST(sighold(sig)); if (TEST_RETURN != 0) { tst_resm(TBROK | TTERRNO, "sighold() %i(%s) failed", sig, tst_strsig(sig)); } } TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); if (!sigs_catched) { tst_resm(TPASS, "All signals were hold"); tst_exit(); } tst_resm(TFAIL, "Signal handler was executed"); for (sig = 1; sig < NUMSIGS; sig++) { if (sigs_map[sig]) { tst_resm(TINFO, "Signal %i(%s) catched", sig, tst_strsig(sig)); } } tst_exit(); }
/* * oom - allocates memory according to specified testcase and checks * desired outcome (e.g. child killed, operation failed with ENOMEM) * @testcase: selects how child allocates memory * valid choices are: NORMAL, MLOCK and KSM * @lite: if non-zero, child makes only single TESTMEM+MB allocation * if zero, child keeps allocating memory until it gets killed * or some operation fails * @retcode: expected return code of child process * if matches child ret code, this function reports PASS, * otherwise it reports FAIL * @allow_sigkill: if zero and child is killed, this function reports FAIL * if non-zero, then if child is killed by SIGKILL * it is considered as PASS */ void oom(int testcase, int lite, int retcode, int allow_sigkill) { pid_t pid; int status, threads; switch (pid = fork()) { case -1: if (errno == retcode) { tst_resm(TPASS | TERRNO, "fork"); return; } tst_brkm(TBROK | TERRNO, cleanup, "fork"); case 0: threads = MAX(1, tst_ncpus() - 1); child_alloc(testcase, lite, threads); default: break; } tst_resm(TINFO, "expected victim is %d.", pid); if (waitpid(-1, &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (WIFSIGNALED(status)) { if (allow_sigkill && WTERMSIG(status) == SIGKILL) { tst_resm(TPASS, "victim signalled: (%d) %s", SIGKILL, tst_strsig(SIGKILL)); } else { tst_resm(TFAIL, "victim signalled: (%d) %s", WTERMSIG(status), tst_strsig(WTERMSIG(status))); } } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == retcode) { tst_resm(TPASS, "victim retcode: (%d) %s", retcode, strerror(retcode)); } else { tst_resm(TFAIL, "victim unexpectedly ended with " "retcode: %d, expected: %d", WEXITSTATUS(status), retcode); } } else { tst_resm(TFAIL, "victim unexpectedly ended"); } }
static void test(void) { int status; /* unshares the mount ns */ if (unshare(CLONE_NEWNS) == -1) tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); /* makes sure parent mounts/umounts have no effect on a real system */ SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); /* bind mounts DIRA to itself */ SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); /* makes mount DIRA shared */ SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); /* waits for child to make a slave mount */ TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1); /* bind mounts DIRB to DIRA making contents of DIRB visible * in DIRA */ SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2); TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1); SAFE_UMOUNT(cleanup, DIRA); TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2); TST_CHECKPOINT_PARENT_WAIT(cleanup, &checkpoint1); /* checks that slave mount doesn't propagate to shared mount */ if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1)) tst_resm(TPASS, "propagation from slave mount passed"); else tst_resm(TFAIL, "propagation form slave mount failed"); TST_CHECKPOINT_SIGNAL_CHILD(cleanup, &checkpoint2); SAFE_WAIT(cleanup, &status); if (WIFEXITED(status)) { if (WEXITSTATUS(status) == 0) tst_resm(TPASS, "propagation to slave mount passed"); else tst_resm(TFAIL, "propagation to slave mount failed"); } if (WIFSIGNALED(status)) { tst_resm(TBROK, "child was killed with signal %s", tst_strsig(WTERMSIG(status))); return; } SAFE_UMOUNT(cleanup, DIRA); }
static void test(void) { int status; /* unshares the mount ns */ if (unshare(CLONE_NEWNS) == -1) tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); /* makes sure parent mounts/umounts have no effect on a real system */ SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); /* bind mounts DIRA to itself */ SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); /* makes mount DIRA shared */ SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); /* bind mounts DIRB to DIRA making contents of DIRB visible * in DIRA */ SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); SAFE_UMOUNT(cleanup, DIRA); TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); if (access(DIRA"/B", F_OK) == 0) tst_resm(TPASS, "shared mount in child passed"); else tst_resm(TFAIL, "shared mount in child failed"); TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); SAFE_WAIT(cleanup, &status); if (WIFEXITED(status)) { if ((WEXITSTATUS(status) == 0)) tst_resm(TPASS, "shared mount in parent passed"); else tst_resm(TFAIL, "shared mount in parent failed"); } if (WIFSIGNALED(status)) { tst_resm(TBROK, "child was killed with signal %s", tst_strsig(WTERMSIG(status))); return; } SAFE_UMOUNT(cleanup, DIRA); }
/* * oom - allocates memory according to specified testcase and checks * desired outcome (e.g. child killed, operation failed with ENOMEM) * @testcase: selects how child allocates memory * valid choices are: NORMAL, MLOCK and KSM * @lite: if non-zero, child makes only single TESTMEM+MB allocation * if zero, child keeps allocating memory until it gets killed * or some operation fails * @retcode: expected return code of child process * if matches child ret code, this function reports PASS, * otherwise it reports FAIL * @allow_sigkill: if zero and child is killed, this function reports FAIL * if non-zero, then if child is killed by SIGKILL * it is considered as PASS */ void oom(int testcase, int lite, int retcode, int allow_sigkill) { pid_t pid; int status, threads; switch (pid = SAFE_FORK()) { case 0: threads = MAX(1, tst_ncpus() - 1); child_alloc(testcase, lite, threads); default: break; } tst_res(TINFO, "expected victim is %d.", pid); SAFE_WAITPID(-1, &status, 0); if (WIFSIGNALED(status)) { if (allow_sigkill && WTERMSIG(status) == SIGKILL) { tst_res(TPASS, "victim signalled: (%d) %s", SIGKILL, tst_strsig(SIGKILL)); } else { tst_res(TFAIL, "victim signalled: (%d) %s", WTERMSIG(status), tst_strsig(WTERMSIG(status))); } } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == retcode) { tst_res(TPASS, "victim retcode: (%d) %s", retcode, strerror(retcode)); } else { tst_res(TFAIL, "victim unexpectedly ended with " "retcode: %d, expected: %d", WEXITSTATUS(status), retcode); } } else { tst_res(TFAIL, "victim unexpectedly ended"); } }
int main(int ac, char **av) { int lc; int status; tst_parse_opts(ac, av, NULL, NULL); #ifdef UCLINUX maybe_run_child(&do_child, ""); #endif setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; if ((cpid = FORK_OR_VFORK()) == -1) tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); if (cpid == 0) { #ifdef UCLINUX if (self_exec(av[0], "") < 0) tst_brkm(TBROK, cleanup, "self_exec failed"); #else do_child(); #endif } TST_PROCESS_STATE_WAIT(cleanup, cpid, 'S'); kill(cpid, SIGKILL); SAFE_WAIT(NULL, &status); if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { tst_resm(TPASS, "pause() did not return after SIGKILL"); continue; } if (WIFSIGNALED(status)) { tst_resm(TFAIL, "child killed by %s unexpectedly", tst_strsig(WTERMSIG(status))); continue; } tst_resm(TFAIL, "child exited with %i", WEXITSTATUS(status)); } cleanup(); tst_exit(); }
int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void), pid_t pid, int sig) { int rval; rval = kill(pid, sig); if (rval == -1) { tst_brkm(TBROK | TERRNO, cleanup_fn, "%s:%d: kill(%d,%s) failed", file, lineno, pid, tst_strsig(sig)); } return rval; }
int safe_sigaction(const char *file, const int lineno, int signum, const struct sigaction *act, struct sigaction *oldact) { int rval; rval = sigaction(signum, act, oldact); if (rval == -1) { tst_brk_(file, lineno, TBROK | TERRNO, "sigaction(%s (%d), %p, %p) failed", tst_strsig(signum), signum, act, oldact); } return rval; }
static void test(void) { pid_t pid; int status; /* unshares the network namespace */ if (unshare(CLONE_NEWNET) == -1) tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); pid = tst_fork(); if (pid < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); } if (pid == 0) { _exit(child_func()); } /* creates TAP network interface dummy0 */ if (WEXITSTATUS(system("ip tuntap add dev dummy0 mode tap")) == -1) tst_brkm(TBROK | TERRNO, cleanup, "system failed"); /* removes previously created dummy0 device */ if (WEXITSTATUS(system("ip tuntap del mode tap dummy0")) == -1) tst_brkm(TBROK | TERRNO, cleanup, "system failed"); /* allow child to continue */ TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); SAFE_WAITPID(cleanup, pid, &status, 0); if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { tst_resm(TFAIL, "netlink interface fail"); return; } if (WIFSIGNALED(status)) { tst_resm(TFAIL, "child was killed with signal %s", tst_strsig(WTERMSIG(status))); return; } tst_resm(TPASS, "netlink interface pass"); }
static int fork_testrun(void) { int status; if (tst_test->timeout) tst_set_timeout(tst_test->timeout); else tst_set_timeout(300); SAFE_SIGNAL(SIGINT, sigint_handler); test_pid = fork(); if (test_pid < 0) tst_brk(TBROK | TERRNO, "fork()"); if (!test_pid) { SAFE_SIGNAL(SIGALRM, SIG_DFL); SAFE_SIGNAL(SIGUSR1, SIG_DFL); SAFE_SIGNAL(SIGINT, SIG_DFL); SAFE_SETPGID(0, 0); testrun(); } SAFE_WAITPID(test_pid, &status, 0); alarm(0); SAFE_SIGNAL(SIGINT, SIG_DFL); if (WIFEXITED(status) && WEXITSTATUS(status)) return WEXITSTATUS(status); if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { tst_res(TINFO, "If you are running on slow machine, " "try exporting LTP_TIMEOUT_MUL > 1"); tst_brk(TBROK, "Test killed! (timeout?)"); } if (WIFSIGNALED(status)) tst_brk(TBROK, "Test killed by %s!", tst_strsig(WTERMSIG(status))); return 0; }
static void check_child_status(pid_t pid, int status) { int ret; if (WIFSIGNALED(status)) { tst_brk(TBROK, "Child (%i) killed by signal %s", pid, tst_strsig(WTERMSIG(status))); } if (!(WIFEXITED(status))) tst_brk(TBROK, "Child (%i) exitted abnormaly", pid); ret = WEXITSTATUS(status); switch (ret) { case TPASS: break; case TBROK: case TCONF: tst_brk(ret, "Reported by child (%i)", pid); default: tst_brk(TBROK, "Invalid child (%i) exit value %i", pid, ret); } }
const char *signaled(int status) { snprintf(buf, sizeof(buf), "killed by %s", tst_strsig(status)); return buf; }
int main(void) { fprintf(stderr, "SIGKILL = %s\n", tst_strsig(SIGKILL)); fprintf(stderr, "SIGALRM = %s\n", tst_strsig(SIGALRM)); return 0; }
static void verify_kill(struct tcase *t) { int core; int pid, npid; int nsig, nexno, status; if (t->sig != SIGKILL) { #ifndef BCS if (t->sig != SIGSTOP) #endif if (sigset(t->sig, SIG_DFL) == SIG_ERR) { tst_brkm(TBROK | TERRNO, tst_rmdir, "sigset(%d) failed", sig); } } pid = FORK_OR_VFORK(); if (pid < 0) tst_brkm(TBROK | TERRNO, tst_rmdir, "fork() failed"); if (pid == 0) { #ifdef UCLINUX if (self_exec(argv[0], "dd", t->sig) < 0) exit(1); #else do_child(); #endif } kill(pid, t->sig); npid = wait(&status); if (npid != pid) { tst_resm(TFAIL, "wait() returned %d, expected %d", npid, pid); return; } nsig = WTERMSIG(status); #ifdef WCOREDUMP core = WCOREDUMP(status); #endif nexno = WIFEXITED(status); if (t->dumps_core) { if (!core) { tst_resm(TFAIL, "core dump bit not set for %s", tst_strsig(t->sig)); return; } } else { if (core) { tst_resm(TFAIL, "core dump bit set for %s", tst_strsig(t->sig)); return; } } if (nsig != t->sig) { tst_resm(TFAIL, "wait: unexpected signal %d returned, expected %d", nsig, t->sig); return; } if (nexno != 0) { tst_resm(TFAIL, "signal: unexpected exit number %d returned, expected 0\n", nexno); return; } tst_resm(TPASS, "signal %-16s%s", tst_strsig(t->sig), t->dumps_core ? " dumped core" : ""); }