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