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