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