xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/waitpid/waitpid01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines Corp., 2001
4  *    07/2001 John George
5  * Copyright (c) 2018 Cyril Hrubis <[email protected]>
6  */
7 
8 /*\
9  * [Description]
10  *
11  * Check that when a child kills itself with one of the standard signals,
12  * the waiting parent is correctly notified.
13  *
14  * Fork a child that sends given signal to itself using raise() or kill(),
15  * the parent checks that the signal was returned.
16  */
17 #include <stdlib.h>
18 #include <sys/wait.h>
19 #include "tst_test.h"
20 
21 static int test_coredump;
22 static struct testcase {
23 	int sig;
24 	int coredump;
25 } testcase_list[] = {
26 	{SIGABRT, 1},
27 	{SIGALRM, 0},
28 	{SIGBUS, 1},
29 	{SIGFPE, 1},
30 	{SIGHUP, 0},
31 	{SIGILL, 1},
32 	{SIGINT, 0},
33 	{SIGKILL, 0},
34 	{SIGPIPE, 0},
35 	{SIGPOLL, 0},
36 	{SIGPROF, 0},
37 	{SIGQUIT, 1},
38 	{SIGSEGV, 1},
39 	{SIGSYS, 1},
40 	{SIGTERM, 0},
41 	{SIGTRAP, 1},
42 	{SIGUSR1, 0},
43 	{SIGUSR2, 0},
44 	{SIGVTALRM, 0},
45 	{SIGXCPU, 1},
46 	{SIGXFSZ, 1}
47 };
48 
child_raise(int sig)49 static void child_raise(int sig)
50 {
51 	raise(sig);
52 	exit(0);
53 }
54 
child_kill(int sig)55 static void child_kill(int sig)
56 {
57 	kill(getpid(), sig);
58 	exit(0);
59 }
60 
61 static struct testvariant {
62 	void (*func)(int sig);
63 	const char *desc;
64 } variant_list[] = {
65 	{child_raise, "raise(sig)"},
66 	{child_kill, "kill(getpid(), sig)"}
67 };
68 
setup(void)69 static void setup(void)
70 {
71 	struct rlimit lim = { 0 };
72 
73 	/* Disable core dumps */
74 	SAFE_GETRLIMIT(RLIMIT_CORE, &lim);
75 
76 	if (lim.rlim_max) {
77 		lim.rlim_cur = getpagesize();
78 
79 		if (lim.rlim_max > 0 && lim.rlim_max < lim.rlim_cur)
80 			lim.rlim_cur = lim.rlim_max;
81 
82 		SAFE_SETRLIMIT(RLIMIT_CORE, &lim);
83 		test_coredump = 1;
84 	} else {
85 		tst_res(TCONF, "Skipping coredump tests due to low rlimit");
86 	}
87 
88 	tst_res(TINFO, "Testing child: %s", variant_list[tst_variant].desc);
89 }
90 
run(unsigned int n)91 static void run(unsigned int n)
92 {
93 	pid_t pid;
94 	int status;
95 	const struct testcase *tc = testcase_list + n;
96 
97 	if (tc->sig != SIGKILL)
98 		SAFE_SIGNAL(tc->sig, SIG_DFL);
99 
100 	pid = SAFE_FORK();
101 	if (!pid)
102 		variant_list[tst_variant].func(tc->sig);
103 
104 	TST_EXP_PID_SILENT(waitpid(pid, &status, 0));
105 	if (!TST_PASS)
106 		return;
107 
108 	if (TST_RET != pid) {
109 		tst_res(TFAIL, "waitpid() returned wrong pid %li, expected %i",
110 			TST_RET, pid);
111 	} else {
112 		tst_res(TPASS, "waitpid() returned correct pid %i", pid);
113 	}
114 
115 	if (!WIFSIGNALED(status)) {
116 		tst_res(TFAIL, "WIFSIGNALED() not set in status (%s)",
117 			tst_strstatus(status));
118 		return;
119 	}
120 
121 	tst_res(TPASS, "WIFSIGNALED() set in status");
122 
123 	if (WTERMSIG(status) != tc->sig) {
124 		tst_res(TFAIL, "WTERMSIG() != %s but %s", tst_strsig(tc->sig),
125 			tst_strsig(WTERMSIG(status)));
126 		return;
127 	}
128 
129 	tst_res(TPASS, "WTERMSIG() == %s", tst_strsig(tc->sig));
130 
131 	if (!test_coredump)
132 		return;
133 
134 	if (!tc->coredump) {
135 		if (WCOREDUMP(status))
136 			tst_res(TFAIL, "Child unexpectedly dumped core");
137 
138 		return;
139 	}
140 
141 	if (!WCOREDUMP(status)) {
142 		tst_res(TFAIL, "Child did not dump core when expected");
143 		return;
144 	}
145 
146 	tst_res(TPASS, "Child dumped core as expected");
147 }
148 
149 static struct tst_test test = {
150 	.forks_child = 1,
151 	.setup = setup,
152 	.test = run,
153 	.tcnt = ARRAY_SIZE(testcase_list),
154 	.test_variants = ARRAY_SIZE(variant_list),
155 	.needs_tmpdir = 1	/* for coredumps */
156 };
157