| /* IBM Corporation |
| * 01/02/2003 Port to LTP avenkat@us.ibm.com |
| * 06/30/2001 Port to Linux nsharoff@us.ibm.com |
| * |
| * Copyright (c) International Business Machines Corp., 2002 |
| * Copyright (c) Cyril Hrubis <chrubis@suse.cz> 2014 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| /* |
| |
| Test check that when a child is killed by its parent, it returns the correct |
| values to the waiting parent--default behaviour assumed by child. |
| |
| */ |
| |
| #define _GNU_SOURCE 1 |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <signal.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <sys/wait.h> |
| #include <sys/resource.h> |
| |
| #include "test.h" |
| #include "safe_macros.h" |
| |
| #define FAILED 0 |
| #define PASSED 1 |
| |
| char *TCID = "kill11"; |
| |
| int local_flag = PASSED; |
| int block_number; |
| FILE *temp; |
| int TST_TOTAL = 1; |
| static int sig; |
| |
| void setup(void); |
| void do_child(void); |
| |
| /* |
| * These signals terminate process by default, some create core file. |
| */ |
| struct tcase { |
| int sig; |
| int dumps_core; |
| } tcases[] = { |
| {SIGHUP, 0}, |
| {SIGINT, 0}, |
| {SIGQUIT, 1}, |
| {SIGILL, 1}, |
| {SIGTRAP, 1}, |
| {SIGABRT, 1}, |
| {SIGIOT, 1}, |
| {SIGBUS, 1}, |
| {SIGFPE, 1}, |
| {SIGKILL, 0}, |
| {SIGUSR1, 0}, |
| {SIGSEGV, 1}, |
| {SIGUSR2, 0}, |
| {SIGPIPE, 0}, |
| {SIGALRM, 0}, |
| {SIGTERM, 0}, |
| {SIGXCPU, 1}, |
| {SIGXFSZ, 1}, |
| {SIGVTALRM, 0}, |
| {SIGPROF, 0}, |
| {SIGIO, 0}, |
| {SIGPWR, 0}, |
| {SIGSYS, 1}, |
| }; |
| |
| 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" : ""); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| int lc; |
| unsigned int i; |
| const char *msg; |
| |
| if ((msg = parse_opts(argc, argv, NULL, NULL)) != NULL) |
| tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
| |
| #ifdef UCLINUX |
| maybe_run_child(&do_child, "dd", &sig); |
| #endif |
| |
| setup(); |
| |
| for (lc = 0; TEST_LOOPING(lc); lc++) { |
| for (i = 0; i < ARRAY_SIZE(tcases); i++) |
| verify_kill(tcases + i); |
| } |
| |
| tst_rmdir(); |
| tst_exit(); |
| } |
| |
| void do_child(void) |
| { |
| int i; |
| |
| for (i = 0; i < 180; i++) |
| sleep(1); |
| |
| fprintf(stderr, "Child missed siggnal"); |
| fflush(stderr); |
| exit(1); |
| } |
| |
| /* 1024 GNU blocks */ |
| #define MIN_RLIMIT_CORE (1024 * 1024) |
| |
| void setup(void) |
| { |
| struct rlimit rlim; |
| |
| SAFE_GETRLIMIT(NULL, RLIMIT_CORE, &rlim); |
| |
| if (rlim.rlim_cur < MIN_RLIMIT_CORE) { |
| tst_resm(TINFO, "Adjusting RLIMIT_CORE to %i", MIN_RLIMIT_CORE); |
| rlim.rlim_cur = MIN_RLIMIT_CORE; |
| SAFE_SETRLIMIT(NULL, RLIMIT_CORE, &rlim); |
| } |
| |
| temp = stderr; |
| tst_tmpdir(); |
| } |