2 * Copyright (c) 2016 Jilles Tjoelker
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/procctl.h>
38 ATF_TC_WITHOUT_HEAD(reaper_wait_child_first);
39 ATF_TC_BODY(reaper_wait_child_first, tc)
41 pid_t parent, child, grandchild, pid;
46 pid = waitpid(-1, NULL, WNOHANG);
47 ATF_REQUIRE(pid == -1 && errno == ECHILD);
50 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
57 ATF_REQUIRE(child != -1);
59 if (close(pip[1]) != 0)
64 else if (grandchild == 0) {
65 if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
67 if (getppid() != parent)
74 pid = waitpid(child, &status, 0);
75 ATF_REQUIRE_EQ(child, pid);
76 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
82 pid = waitpid(-1, &status, 0);
83 ATF_REQUIRE(pid > 0 && pid != child);
84 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
91 ATF_TC_WITHOUT_HEAD(reaper_wait_grandchild_first);
92 ATF_TC_BODY(reaper_wait_grandchild_first, tc)
94 pid_t parent, child, grandchild, pid;
98 pid = waitpid(-1, NULL, WNOHANG);
99 ATF_REQUIRE(pid == -1 && errno == ECHILD);
102 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
103 ATF_REQUIRE_EQ(0, r);
106 ATF_REQUIRE(child != -1);
109 if (grandchild == -1)
111 else if (grandchild == 0)
114 if (waitid(P_PID, grandchild, NULL,
115 WNOWAIT | WEXITED) != 0)
121 pid = waitpid(child, &status, 0);
122 ATF_REQUIRE_EQ(child, pid);
123 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
126 pid = waitpid(-1, &status, 0);
127 ATF_REQUIRE(pid > 0 && pid != child);
128 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
132 ATF_TC_WITHOUT_HEAD(reaper_status);
133 ATF_TC_BODY(reaper_status, tc)
135 struct procctl_reaper_status st;
137 pid_t parent, child, pid;
142 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
143 ATF_REQUIRE_EQ(0, r);
144 ATF_CHECK_EQ(0, st.rs_flags & REAPER_STATUS_OWNED);
145 ATF_CHECK(st.rs_children > 0);
146 ATF_CHECK(st.rs_descendants > 0);
147 ATF_CHECK(st.rs_descendants >= st.rs_children);
148 ATF_CHECK(st.rs_reaper != parent);
149 ATF_CHECK(st.rs_reaper > 0);
151 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
152 ATF_REQUIRE_EQ(0, r);
154 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
155 ATF_REQUIRE_EQ(0, r);
156 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
157 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
158 ATF_CHECK_EQ(0, st.rs_children);
159 ATF_CHECK_EQ(0, st.rs_descendants);
160 ATF_CHECK(st.rs_reaper == parent);
161 ATF_CHECK_EQ(-1, st.rs_pid);
164 ATF_REQUIRE_EQ(0, r);
166 ATF_REQUIRE(child != -1);
168 if (close(pip[0]) != 0)
170 if (procctl(P_PID, parent, PROC_REAP_STATUS, &st) != 0)
172 if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
174 if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &st) != 0)
176 if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
181 ATF_REQUIRE_EQ(0, r);
183 sr = read(pip[0], &st, sizeof(st));
184 ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
185 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
186 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
187 ATF_CHECK_EQ(1, st.rs_children);
188 ATF_CHECK_EQ(1, st.rs_descendants);
189 ATF_CHECK(st.rs_reaper == parent);
190 ATF_CHECK_EQ(child, st.rs_pid);
191 sr = read(pip[0], &st, sizeof(st));
192 ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
194 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
195 ATF_CHECK_EQ(1, st.rs_children);
196 ATF_CHECK_EQ(1, st.rs_descendants);
197 ATF_CHECK(st.rs_reaper == parent);
198 ATF_CHECK_EQ(child, st.rs_pid);
201 ATF_REQUIRE_EQ(0, r);
202 pid = waitpid(child, &status, 0);
203 ATF_REQUIRE_EQ(child, pid);
204 ATF_CHECK_EQ(0, status);
206 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
207 ATF_REQUIRE_EQ(0, r);
208 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
209 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
210 ATF_CHECK_EQ(0, st.rs_children);
211 ATF_CHECK_EQ(0, st.rs_descendants);
212 ATF_CHECK(st.rs_reaper == parent);
213 ATF_CHECK_EQ(-1, st.rs_pid);
216 ATF_TC_WITHOUT_HEAD(reaper_getpids);
217 ATF_TC_BODY(reaper_getpids, tc)
219 struct procctl_reaper_pidinfo info[10];
221 pid_t parent, child, grandchild, pid;
222 int r, status, childidx;
223 int pipa[2], pipb[2];
226 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
227 ATF_REQUIRE_EQ(0, r);
229 memset(info, '\0', sizeof(info));
230 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
231 &(struct procctl_reaper_pids){
232 .rp_count = sizeof(info) / sizeof(info[0]),
236 ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
239 ATF_REQUIRE_EQ(0, r);
241 ATF_REQUIRE_EQ(0, r);
243 ATF_REQUIRE(child != -1);
245 if (close(pipa[1]) != 0)
247 if (close(pipb[0]) != 0)
249 if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
252 if (grandchild == -1)
254 if (grandchild == 0) {
255 if (write(pipb[1], &(uint8_t){ 0 }, 1) != 1)
257 if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
265 ATF_REQUIRE_EQ(0, r);
267 ATF_REQUIRE_EQ(0, r);
269 memset(info, '\0', sizeof(info));
270 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
271 &(struct procctl_reaper_pids){
272 .rp_count = sizeof(info) / sizeof(info[0]),
276 ATF_CHECK_EQ(REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD,
277 info[0].pi_flags & (REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD));
278 ATF_CHECK_EQ(child, info[0].pi_pid);
279 ATF_CHECK_EQ(child, info[0].pi_subtree);
280 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
282 sr = write(pipa[1], &(uint8_t){ 0 }, 1);
283 ATF_REQUIRE_EQ(1, sr);
284 sr = read(pipb[0], &(uint8_t){ 0 }, 1);
285 ATF_REQUIRE_EQ(1, sr);
287 memset(info, '\0', sizeof(info));
288 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
289 &(struct procctl_reaper_pids){
290 .rp_count = sizeof(info) / sizeof(info[0]),
294 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
295 info[0].pi_flags & REAPER_PIDINFO_VALID);
296 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
297 info[1].pi_flags & REAPER_PIDINFO_VALID);
298 ATF_CHECK_EQ(0, info[2].pi_flags & REAPER_PIDINFO_VALID);
299 ATF_CHECK_EQ(child, info[0].pi_subtree);
300 ATF_CHECK_EQ(child, info[1].pi_subtree);
301 childidx = info[1].pi_pid == child ? 1 : 0;
302 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
303 info[childidx].pi_flags & REAPER_PIDINFO_CHILD);
304 ATF_CHECK_EQ(0, info[childidx ^ 1].pi_flags & REAPER_PIDINFO_CHILD);
305 ATF_CHECK(info[childidx].pi_pid == child);
306 grandchild = info[childidx ^ 1].pi_pid;
307 ATF_CHECK(grandchild > 0);
308 ATF_CHECK(grandchild != child);
309 ATF_CHECK(grandchild != parent);
311 r = kill(child, SIGTERM);
312 ATF_REQUIRE_EQ(0, r);
314 pid = waitpid(child, &status, 0);
315 ATF_REQUIRE_EQ(child, pid);
316 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
318 memset(info, '\0', sizeof(info));
319 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
320 &(struct procctl_reaper_pids){
321 .rp_count = sizeof(info) / sizeof(info[0]),
325 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
326 info[0].pi_flags & REAPER_PIDINFO_VALID);
327 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
328 ATF_CHECK_EQ(child, info[0].pi_subtree);
329 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
330 info[0].pi_flags & REAPER_PIDINFO_CHILD);
331 ATF_CHECK_EQ(grandchild, info[0].pi_pid);
333 sr = write(pipa[1], &(uint8_t){ 0 }, 1);
334 ATF_REQUIRE_EQ(1, sr);
336 memset(info, '\0', sizeof(info));
337 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
338 &(struct procctl_reaper_pids){
339 .rp_count = sizeof(info) / sizeof(info[0]),
343 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
344 info[0].pi_flags & REAPER_PIDINFO_VALID);
345 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
346 ATF_CHECK_EQ(child, info[0].pi_subtree);
347 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
348 info[0].pi_flags & REAPER_PIDINFO_CHILD);
349 ATF_CHECK_EQ(grandchild, info[0].pi_pid);
351 pid = waitpid(grandchild, &status, 0);
352 ATF_REQUIRE_EQ(grandchild, pid);
353 ATF_CHECK_EQ(0, status);
355 memset(info, '\0', sizeof(info));
356 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
357 &(struct procctl_reaper_pids){
358 .rp_count = sizeof(info) / sizeof(info[0]),
362 ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
365 ATF_REQUIRE_EQ(0, r);
367 ATF_REQUIRE_EQ(0, r);
370 ATF_TC_WITHOUT_HEAD(reaper_kill_badsig);
371 ATF_TC_BODY(reaper_kill_badsig, tc)
373 struct procctl_reaper_kill params;
378 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
379 ATF_REQUIRE_EQ(0, r);
383 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
384 ATF_CHECK(r == -1 && errno == EINVAL);
387 ATF_TC_WITHOUT_HEAD(reaper_kill_sigzero);
388 ATF_TC_BODY(reaper_kill_sigzero, tc)
390 struct procctl_reaper_kill params;
395 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
396 ATF_REQUIRE_EQ(0, r);
400 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
401 ATF_CHECK(r == -1 && errno == EINVAL);
404 ATF_TC_WITHOUT_HEAD(reaper_kill_empty);
405 ATF_TC_BODY(reaper_kill_empty, tc)
407 struct procctl_reaper_kill params;
412 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
413 ATF_REQUIRE_EQ(0, r);
415 params.rk_sig = SIGTERM;
417 params.rk_killed = 77;
418 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
419 ATF_CHECK(r == -1 && errno == ESRCH);
420 ATF_CHECK_EQ(0, params.rk_killed);
423 ATF_TC_WITHOUT_HEAD(reaper_kill_normal);
424 ATF_TC_BODY(reaper_kill_normal, tc)
426 struct procctl_reaper_kill params;
428 pid_t parent, child, grandchild, pid;
433 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
434 ATF_REQUIRE_EQ(0, r);
437 ATF_REQUIRE_EQ(0, r);
439 ATF_REQUIRE(child != -1);
441 if (close(pip[0]) != 0)
444 if (grandchild == -1)
446 if (grandchild == 0) {
447 if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
456 ATF_REQUIRE_EQ(0, r);
458 sr = read(pip[0], &(uint8_t){ 0 }, 1);
459 ATF_REQUIRE_EQ(1, sr);
461 params.rk_sig = SIGTERM;
463 params.rk_killed = 77;
464 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
466 ATF_CHECK_EQ(2, params.rk_killed);
468 pid = waitpid(child, &status, 0);
469 ATF_REQUIRE_EQ(child, pid);
470 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
472 pid = waitpid(-1, &status, 0);
473 ATF_REQUIRE(pid > 0);
474 ATF_CHECK(pid != parent);
475 ATF_CHECK(pid != child);
476 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
479 ATF_REQUIRE_EQ(0, r);
485 ATF_TP_ADD_TC(tp, reaper_wait_child_first);
486 ATF_TP_ADD_TC(tp, reaper_wait_grandchild_first);
487 ATF_TP_ADD_TC(tp, reaper_status);
488 ATF_TP_ADD_TC(tp, reaper_getpids);
489 ATF_TP_ADD_TC(tp, reaper_kill_badsig);
490 ATF_TP_ADD_TC(tp, reaper_kill_sigzero);
491 ATF_TP_ADD_TC(tp, reaper_kill_empty);
492 ATF_TP_ADD_TC(tp, reaper_kill_normal);
493 return (atf_no_error());