1 /* $NetBSD: t_wait.c,v 1.8 2017/01/13 19:28:55 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2016 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: t_wait.c,v 1.8 2017/01/13 19:28:55 christos Exp $");
33
34 #ifdef __FreeBSD__
35 #include <sys/types.h>
36 #include <sys/sysctl.h>
37 #endif
38 #include <sys/wait.h>
39 #include <sys/resource.h>
40
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <limits.h>
44 #include <pwd.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49
50 #include <atf-c.h>
51
52 ATF_TC(wait6_invalid);
ATF_TC_HEAD(wait6_invalid,tc)53 ATF_TC_HEAD(wait6_invalid, tc)
54 {
55 atf_tc_set_md_var(tc, "descr",
56 "Test that wait6(2) returns EINVAL with 0 options");
57 }
58
ATF_TC_BODY(wait6_invalid,tc)59 ATF_TC_BODY(wait6_invalid, tc)
60 {
61 siginfo_t si;
62 struct wrusage wru;
63 int st;
64 ATF_REQUIRE(wait6(P_ALL, 0, &st, 0, &wru, &si) == -1
65 && errno == EINVAL);
66 }
67
68 ATF_TC(wait6_exited);
ATF_TC_HEAD(wait6_exited,tc)69 ATF_TC_HEAD(wait6_exited, tc)
70 {
71 atf_tc_set_md_var(tc, "descr",
72 "Test that wait6(2) handled exiting process and code");
73 }
74
ATF_TC_BODY(wait6_exited,tc)75 ATF_TC_BODY(wait6_exited, tc)
76 {
77 siginfo_t si;
78 struct wrusage wru;
79 int st;
80 pid_t pid;
81
82 switch (pid = fork()) {
83 case -1:
84 ATF_REQUIRE(pid > 0);
85 case 0:
86 exit(0x5a5a5a5a);
87 /*NOTREACHED*/
88 default:
89 ATF_REQUIRE(wait6(P_PID, pid, &st, WEXITED, &wru, &si) == pid);
90 ATF_REQUIRE(WIFEXITED(st) && WEXITSTATUS(st) == 0x5a);
91 ATF_REQUIRE(si.si_status == 0x5a5a5a5a);
92 ATF_REQUIRE(si.si_pid == pid);
93 ATF_REQUIRE(si.si_uid == getuid());
94 ATF_REQUIRE(si.si_code == CLD_EXITED);
95 #ifdef __NetBSD__
96 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
97 (uintmax_t)si.si_utime);
98 #endif
99 break;
100 }
101 }
102
103 ATF_TC(wait6_terminated);
ATF_TC_HEAD(wait6_terminated,tc)104 ATF_TC_HEAD(wait6_terminated, tc)
105 {
106 atf_tc_set_md_var(tc, "descr",
107 "Test that wait6(2) handled terminated process and code");
108 }
109
ATF_TC_BODY(wait6_terminated,tc)110 ATF_TC_BODY(wait6_terminated, tc)
111 {
112 siginfo_t si;
113 struct wrusage wru;
114 int st;
115 pid_t pid;
116
117 switch (pid = fork()) {
118 case 0:
119 sleep(100);
120 /*FALLTHROUGH*/
121 case -1:
122 ATF_REQUIRE(pid > 0);
123 default:
124 ATF_REQUIRE(kill(pid, SIGTERM) == 0);
125 ATF_REQUIRE(wait6(P_PID, pid, &st, WEXITED, &wru, &si) == pid);
126 ATF_REQUIRE(WIFSIGNALED(st) && WTERMSIG(st) == SIGTERM);
127 ATF_REQUIRE(si.si_status == SIGTERM);
128 ATF_REQUIRE(si.si_pid == pid);
129 ATF_REQUIRE(si.si_uid == getuid());
130 ATF_REQUIRE(si.si_code == CLD_KILLED);
131 #ifdef __NetBSD__
132 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
133 (uintmax_t)si.si_utime);
134 #endif
135 break;
136 }
137 }
138
139 ATF_TC(wait6_coredumped);
ATF_TC_HEAD(wait6_coredumped,tc)140 ATF_TC_HEAD(wait6_coredumped, tc)
141 {
142 atf_tc_set_md_var(tc, "descr",
143 "Test that wait6(2) handled coredumped process and code");
144 }
145
ATF_TC_BODY(wait6_coredumped,tc)146 ATF_TC_BODY(wait6_coredumped, tc)
147 {
148 siginfo_t si;
149 struct wrusage wru;
150 int st;
151 pid_t pid;
152 static const struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
153
154 #ifdef __FreeBSD__
155 int coredump_enabled;
156 size_t ce_len = sizeof(coredump_enabled);
157 if (sysctlbyname("kern.coredump", &coredump_enabled, &ce_len, NULL,
158 0) == 0 && !coredump_enabled)
159 atf_tc_skip("Coredumps disabled");
160 #endif
161
162 switch (pid = fork()) {
163 case 0:
164 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0);
165 *(char *)8 = 0;
166 /*FALLTHROUGH*/
167 case -1:
168 ATF_REQUIRE(pid > 0);
169 default:
170 ATF_REQUIRE(wait6(P_PID, pid, &st, WEXITED, &wru, &si) == pid);
171 ATF_REQUIRE(WIFSIGNALED(st) && WTERMSIG(st) == SIGSEGV
172 && WCOREDUMP(st));
173 ATF_REQUIRE(si.si_status == SIGSEGV);
174 ATF_REQUIRE(si.si_pid == pid);
175 ATF_REQUIRE(si.si_uid == getuid());
176 ATF_REQUIRE(si.si_code == CLD_DUMPED);
177 #ifdef __NetBSD__
178 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
179 (uintmax_t)si.si_utime);
180 #endif
181 break;
182 }
183 }
184
185 ATF_TC(wait6_stop_and_go);
ATF_TC_HEAD(wait6_stop_and_go,tc)186 ATF_TC_HEAD(wait6_stop_and_go, tc)
187 {
188 atf_tc_set_md_var(tc, "descr",
189 "Test that wait6(2) handled stopped/continued process and code");
190 }
191
ATF_TC_BODY(wait6_stop_and_go,tc)192 ATF_TC_BODY(wait6_stop_and_go, tc)
193 {
194 siginfo_t si;
195 struct wrusage wru;
196 int st;
197 pid_t pid;
198 static const struct rlimit rl = { 0, 0 };
199
200 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0);
201 switch (pid = fork()) {
202 case 0:
203 sleep(100);
204 /*FALLTHROUGH*/
205 case -1:
206 ATF_REQUIRE(pid > 0);
207 default:
208 ATF_REQUIRE(kill(pid, SIGSTOP) == 0);
209 ATF_REQUIRE(wait6(P_PID, pid, &st, WSTOPPED, &wru, &si) == pid);
210 ATF_REQUIRE(!WIFEXITED(st));
211 ATF_REQUIRE(!WIFSIGNALED(st));
212 ATF_REQUIRE(WIFSTOPPED(st) && WSTOPSIG(st) == SIGSTOP);
213 ATF_REQUIRE(!WIFCONTINUED(st));
214 ATF_REQUIRE(si.si_status == SIGSTOP);
215 ATF_REQUIRE(si.si_pid == pid);
216 ATF_REQUIRE(si.si_uid == getuid());
217 ATF_REQUIRE(si.si_code == CLD_STOPPED);
218 #ifdef __NetBSD__
219 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
220 (uintmax_t)si.si_utime);
221 #endif
222
223 ATF_REQUIRE(kill(pid, SIGCONT) == 0);
224 ATF_REQUIRE(wait6(P_PID, pid, &st, WCONTINUED, &wru, &si) == pid);
225 ATF_REQUIRE(!WIFEXITED(st));
226 ATF_REQUIRE(!WIFSIGNALED(st));
227 ATF_REQUIRE(WIFCONTINUED(st));
228 ATF_REQUIRE(!WIFSTOPPED(st));
229 ATF_REQUIRE(si.si_status == SIGCONT);
230 ATF_REQUIRE(si.si_pid == pid);
231 ATF_REQUIRE(si.si_uid == getuid());
232 ATF_REQUIRE(si.si_code == CLD_CONTINUED);
233 #ifdef __NetBSD__
234 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
235 (uintmax_t)si.si_utime);
236 #endif
237
238 ATF_REQUIRE(kill(pid, SIGQUIT) == 0);
239 ATF_REQUIRE(wait6(P_PID, pid, &st, WEXITED, &wru, &si) == pid);
240 ATF_REQUIRE(!WIFEXITED(st));
241 ATF_REQUIRE(WIFSIGNALED(st) && WTERMSIG(st) == SIGQUIT);
242 ATF_REQUIRE(!WIFSTOPPED(st));
243 ATF_REQUIRE(!WIFCONTINUED(st));
244 ATF_REQUIRE(si.si_status == SIGQUIT);
245 ATF_REQUIRE(si.si_pid == pid);
246 ATF_REQUIRE(si.si_uid == getuid());
247 ATF_REQUIRE(si.si_code == CLD_KILLED);
248 #ifdef __NetBSD__
249 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
250 (uintmax_t)si.si_utime);
251 #endif
252 break;
253 }
254 }
255
256 ATF_TC(wait6_stopgo_loop);
ATF_TC_HEAD(wait6_stopgo_loop,tc)257 ATF_TC_HEAD(wait6_stopgo_loop, tc)
258 {
259 atf_tc_set_md_var(tc, "descr",
260 "Test that wait6(2) handled stopped/continued process loop");
261 }
262
ATF_TC_BODY(wait6_stopgo_loop,tc)263 ATF_TC_BODY(wait6_stopgo_loop, tc)
264 {
265 siginfo_t si;
266 struct wrusage wru;
267 int st;
268 pid_t pid;
269 static const struct rlimit rl = { 0, 0 };
270 size_t N = 100;
271
272 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0);
273 switch (pid = fork()) {
274 case 0:
275 sleep(100);
276 /*FALLTHROUGH*/
277 case -1:
278 ATF_REQUIRE(pid > 0);
279 }
280
281 printf("Before loop of SIGSTOP/SIGCONT sequence %zu times\n", N);
282 while (N --> 0) {
283 ATF_REQUIRE(kill(pid, SIGSTOP) == 0);
284 ATF_REQUIRE(wait6(P_PID, pid, &st, WSTOPPED, &wru, &si) == pid);
285 ATF_REQUIRE(!WIFEXITED(st));
286 ATF_REQUIRE(!WIFSIGNALED(st));
287 ATF_REQUIRE(WIFSTOPPED(st) && WSTOPSIG(st) == SIGSTOP);
288 ATF_REQUIRE(!WIFCONTINUED(st));
289 ATF_REQUIRE(si.si_status == SIGSTOP);
290 ATF_REQUIRE(si.si_pid == pid);
291 ATF_REQUIRE(si.si_uid == getuid());
292 ATF_REQUIRE(si.si_code == CLD_STOPPED);
293
294 ATF_REQUIRE(kill(pid, SIGCONT) == 0);
295 ATF_REQUIRE(wait6(P_PID, pid, &st, WCONTINUED, &wru, &si) == pid);
296 ATF_REQUIRE(!WIFEXITED(st));
297 ATF_REQUIRE(!WIFSIGNALED(st));
298 ATF_REQUIRE(WIFCONTINUED(st));
299 ATF_REQUIRE(!WIFSTOPPED(st));
300 ATF_REQUIRE(si.si_status == SIGCONT);
301 ATF_REQUIRE(si.si_pid == pid);
302 ATF_REQUIRE(si.si_uid == getuid());
303 ATF_REQUIRE(si.si_code == CLD_CONTINUED);
304 }
305 ATF_REQUIRE(kill(pid, SIGQUIT) == 0);
306 ATF_REQUIRE(wait6(P_PID, pid, &st, WEXITED, &wru, &si) == pid);
307 ATF_REQUIRE(!WIFEXITED(st));
308 ATF_REQUIRE(WIFSIGNALED(st) && WTERMSIG(st) == SIGQUIT);
309 ATF_REQUIRE(!WIFSTOPPED(st));
310 ATF_REQUIRE(!WIFCONTINUED(st));
311 ATF_REQUIRE(si.si_status == SIGQUIT);
312 ATF_REQUIRE(si.si_pid == pid);
313 ATF_REQUIRE(si.si_uid == getuid());
314 ATF_REQUIRE(si.si_code == CLD_KILLED);
315 #ifdef __NetBSD__
316 printf("user: %ju system: %ju\n", (uintmax_t)si.si_utime,
317 (uintmax_t)si.si_utime);
318 #endif
319 }
320
ATF_TP_ADD_TCS(tp)321 ATF_TP_ADD_TCS(tp)
322 {
323
324 ATF_TP_ADD_TC(tp, wait6_invalid);
325 ATF_TP_ADD_TC(tp, wait6_exited);
326 ATF_TP_ADD_TC(tp, wait6_terminated);
327 ATF_TP_ADD_TC(tp, wait6_coredumped);
328 ATF_TP_ADD_TC(tp, wait6_stop_and_go);
329 ATF_TP_ADD_TC(tp, wait6_stopgo_loop);
330
331 return atf_no_error();
332 }
333