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
52ATF_TC(wait6_invalid);
53ATF_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
59ATF_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
68ATF_TC(wait6_exited);
69ATF_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
75ATF_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
103ATF_TC(wait6_terminated);
104ATF_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
110ATF_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
139ATF_TC(wait6_coredumped);
140ATF_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
146ATF_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
185ATF_TC(wait6_stop_and_go);
186ATF_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
192ATF_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
256ATF_TC(wait6_stopgo_loop);
257ATF_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
263ATF_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
321ATF_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