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>
39 dummy_sighandler(int sig __unused, siginfo_t *info __unused, void *ctx __unused)
43 ATF_TC_WITHOUT_HEAD(reaper_wait_child_first);
44 ATF_TC_BODY(reaper_wait_child_first, tc)
46 pid_t parent, child, grandchild, pid;
51 pid = waitpid(-1, NULL, WNOHANG);
52 ATF_REQUIRE(pid == -1 && errno == ECHILD);
55 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
62 ATF_REQUIRE(child != -1);
64 if (close(pip[1]) != 0)
69 else if (grandchild == 0) {
70 if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
72 if (getppid() != parent)
79 pid = waitpid(child, &status, 0);
80 ATF_REQUIRE_EQ(child, pid);
81 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
87 pid = waitpid(-1, &status, 0);
88 ATF_REQUIRE(pid > 0 && pid != child);
89 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
96 ATF_TC_WITHOUT_HEAD(reaper_wait_grandchild_first);
97 ATF_TC_BODY(reaper_wait_grandchild_first, tc)
99 pid_t parent, child, grandchild, pid;
103 pid = waitpid(-1, NULL, WNOHANG);
104 ATF_REQUIRE(pid == -1 && errno == ECHILD);
107 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
108 ATF_REQUIRE_EQ(0, r);
111 ATF_REQUIRE(child != -1);
114 if (grandchild == -1)
116 else if (grandchild == 0)
119 if (waitid(P_PID, grandchild, NULL,
120 WNOWAIT | WEXITED) != 0)
126 pid = waitpid(child, &status, 0);
127 ATF_REQUIRE_EQ(child, pid);
128 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
131 pid = waitpid(-1, &status, 0);
132 ATF_REQUIRE(pid > 0 && pid != child);
133 r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
137 ATF_TC(reaper_sigchld_child_first);
138 ATF_TC_HEAD(reaper_sigchld_child_first, tc)
140 atf_tc_set_md_var(tc, "timeout", "2");
142 ATF_TC_BODY(reaper_sigchld_child_first, tc)
144 struct sigaction act;
147 pid_t parent, child, grandchild, pid;
152 pid = waitpid(-1, NULL, WNOHANG);
153 ATF_REQUIRE(pid == -1 && errno == ECHILD);
155 act.sa_sigaction = dummy_sighandler;
156 act.sa_flags = SA_SIGINFO | SA_RESTART;
157 r = sigemptyset(&act.sa_mask);
158 ATF_REQUIRE_EQ(0, r);
159 r = sigaction(SIGCHLD, &act, NULL);
160 ATF_REQUIRE_EQ(0, r);
162 r = sigemptyset(&mask);
163 ATF_REQUIRE_EQ(0, r);
164 r = sigaddset(&mask, SIGCHLD);
165 ATF_REQUIRE_EQ(0, r);
166 r = sigprocmask(SIG_BLOCK, &mask, NULL);
167 ATF_REQUIRE_EQ(0, r);
170 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
171 ATF_REQUIRE_EQ(0, r);
174 ATF_REQUIRE_EQ(0, r);
177 ATF_REQUIRE(child != -1);
179 if (close(pip[1]) != 0)
182 if (grandchild == -1)
184 else if (grandchild == 0) {
185 if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
187 if (getppid() != parent)
194 r = sigwaitinfo(&mask, &info);
195 ATF_REQUIRE_EQ(SIGCHLD, r);
196 ATF_CHECK_EQ(SIGCHLD, info.si_signo);
197 ATF_CHECK_EQ(CLD_EXITED, info.si_code);
198 ATF_CHECK_EQ(3, info.si_status);
199 ATF_CHECK_EQ(child, info.si_pid);
201 pid = waitpid(child, NULL, 0);
202 ATF_REQUIRE_EQ(child, pid);
205 ATF_REQUIRE_EQ(0, r);
207 r = sigwaitinfo(&mask, &info);
208 ATF_REQUIRE_EQ(SIGCHLD, r);
209 ATF_CHECK_EQ(SIGCHLD, info.si_signo);
210 ATF_CHECK_EQ(CLD_EXITED, info.si_code);
211 ATF_CHECK_EQ(2, info.si_status);
212 grandchild = info.si_pid;
213 ATF_REQUIRE(grandchild > 0);
214 ATF_REQUIRE(grandchild != parent);
215 ATF_REQUIRE(grandchild != child);
217 pid = waitpid(-1, NULL, 0);
218 ATF_REQUIRE_EQ(grandchild, pid);
221 ATF_REQUIRE_EQ(0, r);
224 ATF_TC(reaper_sigchld_grandchild_first);
225 ATF_TC_HEAD(reaper_sigchld_grandchild_first, tc)
227 atf_tc_set_md_var(tc, "timeout", "2");
229 ATF_TC_BODY(reaper_sigchld_grandchild_first, tc)
231 struct sigaction act;
234 pid_t parent, child, grandchild, pid;
238 pid = waitpid(-1, NULL, WNOHANG);
239 ATF_REQUIRE(pid == -1 && errno == ECHILD);
241 act.sa_sigaction = dummy_sighandler;
242 act.sa_flags = SA_SIGINFO | SA_RESTART;
243 r = sigemptyset(&act.sa_mask);
244 ATF_REQUIRE_EQ(0, r);
245 r = sigaction(SIGCHLD, &act, NULL);
246 ATF_REQUIRE_EQ(0, r);
248 r = sigemptyset(&mask);
249 ATF_REQUIRE_EQ(0, r);
250 r = sigaddset(&mask, SIGCHLD);
251 ATF_REQUIRE_EQ(0, r);
252 r = sigprocmask(SIG_BLOCK, &mask, NULL);
253 ATF_REQUIRE_EQ(0, r);
256 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
257 ATF_REQUIRE_EQ(0, r);
260 ATF_REQUIRE(child != -1);
263 if (grandchild == -1)
265 else if (grandchild == 0)
268 if (waitid(P_PID, grandchild, NULL,
269 WNOWAIT | WEXITED) != 0)
275 pid = waitpid(child, NULL, 0);
276 ATF_REQUIRE_EQ(child, pid);
278 r = sigwaitinfo(&mask, &info);
279 ATF_REQUIRE_EQ(SIGCHLD, r);
280 ATF_CHECK_EQ(SIGCHLD, info.si_signo);
281 ATF_CHECK_EQ(CLD_EXITED, info.si_code);
282 ATF_CHECK_EQ(2, info.si_status);
283 grandchild = info.si_pid;
284 ATF_REQUIRE(grandchild > 0);
285 ATF_REQUIRE(grandchild != parent);
286 ATF_REQUIRE(grandchild != child);
288 pid = waitpid(-1, NULL, 0);
289 ATF_REQUIRE_EQ(grandchild, pid);
292 ATF_TC_WITHOUT_HEAD(reaper_status);
293 ATF_TC_BODY(reaper_status, tc)
295 struct procctl_reaper_status st;
297 pid_t parent, child, pid;
302 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
303 ATF_REQUIRE_EQ(0, r);
304 ATF_CHECK_EQ(0, st.rs_flags & REAPER_STATUS_OWNED);
305 ATF_CHECK(st.rs_children > 0);
306 ATF_CHECK(st.rs_descendants > 0);
307 ATF_CHECK(st.rs_descendants >= st.rs_children);
308 ATF_CHECK(st.rs_reaper != parent);
309 ATF_CHECK(st.rs_reaper > 0);
311 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
312 ATF_REQUIRE_EQ(0, r);
314 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
315 ATF_REQUIRE_EQ(0, r);
316 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
317 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
318 ATF_CHECK_EQ(0, st.rs_children);
319 ATF_CHECK_EQ(0, st.rs_descendants);
320 ATF_CHECK(st.rs_reaper == parent);
321 ATF_CHECK_EQ(-1, st.rs_pid);
324 ATF_REQUIRE_EQ(0, r);
326 ATF_REQUIRE(child != -1);
328 if (close(pip[0]) != 0)
330 if (procctl(P_PID, parent, PROC_REAP_STATUS, &st) != 0)
332 if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
334 if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &st) != 0)
336 if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
341 ATF_REQUIRE_EQ(0, r);
343 sr = read(pip[0], &st, sizeof(st));
344 ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
345 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
346 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
347 ATF_CHECK_EQ(1, st.rs_children);
348 ATF_CHECK_EQ(1, st.rs_descendants);
349 ATF_CHECK(st.rs_reaper == parent);
350 ATF_CHECK_EQ(child, st.rs_pid);
351 sr = read(pip[0], &st, sizeof(st));
352 ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
354 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
355 ATF_CHECK_EQ(1, st.rs_children);
356 ATF_CHECK_EQ(1, st.rs_descendants);
357 ATF_CHECK(st.rs_reaper == parent);
358 ATF_CHECK_EQ(child, st.rs_pid);
361 ATF_REQUIRE_EQ(0, r);
362 pid = waitpid(child, &status, 0);
363 ATF_REQUIRE_EQ(child, pid);
364 ATF_CHECK_EQ(0, status);
366 r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
367 ATF_REQUIRE_EQ(0, r);
368 ATF_CHECK_EQ(REAPER_STATUS_OWNED,
369 st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
370 ATF_CHECK_EQ(0, st.rs_children);
371 ATF_CHECK_EQ(0, st.rs_descendants);
372 ATF_CHECK(st.rs_reaper == parent);
373 ATF_CHECK_EQ(-1, st.rs_pid);
376 ATF_TC_WITHOUT_HEAD(reaper_getpids);
377 ATF_TC_BODY(reaper_getpids, tc)
379 struct procctl_reaper_pidinfo info[10];
381 pid_t parent, child, grandchild, pid;
382 int r, status, childidx;
383 int pipa[2], pipb[2];
386 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
387 ATF_REQUIRE_EQ(0, r);
389 memset(info, '\0', sizeof(info));
390 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
391 &(struct procctl_reaper_pids){
392 .rp_count = sizeof(info) / sizeof(info[0]),
396 ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
399 ATF_REQUIRE_EQ(0, r);
401 ATF_REQUIRE_EQ(0, r);
403 ATF_REQUIRE(child != -1);
405 if (close(pipa[1]) != 0)
407 if (close(pipb[0]) != 0)
409 if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
412 if (grandchild == -1)
414 if (grandchild == 0) {
415 if (write(pipb[1], &(uint8_t){ 0 }, 1) != 1)
417 if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
425 ATF_REQUIRE_EQ(0, r);
427 ATF_REQUIRE_EQ(0, r);
429 memset(info, '\0', sizeof(info));
430 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
431 &(struct procctl_reaper_pids){
432 .rp_count = sizeof(info) / sizeof(info[0]),
436 ATF_CHECK_EQ(REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD,
437 info[0].pi_flags & (REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD));
438 ATF_CHECK_EQ(child, info[0].pi_pid);
439 ATF_CHECK_EQ(child, info[0].pi_subtree);
440 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
442 sr = write(pipa[1], &(uint8_t){ 0 }, 1);
443 ATF_REQUIRE_EQ(1, sr);
444 sr = read(pipb[0], &(uint8_t){ 0 }, 1);
445 ATF_REQUIRE_EQ(1, sr);
447 memset(info, '\0', sizeof(info));
448 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
449 &(struct procctl_reaper_pids){
450 .rp_count = sizeof(info) / sizeof(info[0]),
454 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
455 info[0].pi_flags & REAPER_PIDINFO_VALID);
456 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
457 info[1].pi_flags & REAPER_PIDINFO_VALID);
458 ATF_CHECK_EQ(0, info[2].pi_flags & REAPER_PIDINFO_VALID);
459 ATF_CHECK_EQ(child, info[0].pi_subtree);
460 ATF_CHECK_EQ(child, info[1].pi_subtree);
461 childidx = info[1].pi_pid == child ? 1 : 0;
462 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
463 info[childidx].pi_flags & REAPER_PIDINFO_CHILD);
464 ATF_CHECK_EQ(0, info[childidx ^ 1].pi_flags & REAPER_PIDINFO_CHILD);
465 ATF_CHECK(info[childidx].pi_pid == child);
466 grandchild = info[childidx ^ 1].pi_pid;
467 ATF_CHECK(grandchild > 0);
468 ATF_CHECK(grandchild != child);
469 ATF_CHECK(grandchild != parent);
471 r = kill(child, SIGTERM);
472 ATF_REQUIRE_EQ(0, r);
474 pid = waitpid(child, &status, 0);
475 ATF_REQUIRE_EQ(child, pid);
476 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
478 memset(info, '\0', sizeof(info));
479 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
480 &(struct procctl_reaper_pids){
481 .rp_count = sizeof(info) / sizeof(info[0]),
485 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
486 info[0].pi_flags & REAPER_PIDINFO_VALID);
487 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
488 ATF_CHECK_EQ(child, info[0].pi_subtree);
489 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
490 info[0].pi_flags & REAPER_PIDINFO_CHILD);
491 ATF_CHECK_EQ(grandchild, info[0].pi_pid);
493 sr = write(pipa[1], &(uint8_t){ 0 }, 1);
494 ATF_REQUIRE_EQ(1, sr);
496 memset(info, '\0', sizeof(info));
497 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
498 &(struct procctl_reaper_pids){
499 .rp_count = sizeof(info) / sizeof(info[0]),
503 ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
504 info[0].pi_flags & REAPER_PIDINFO_VALID);
505 ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
506 ATF_CHECK_EQ(child, info[0].pi_subtree);
507 ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
508 info[0].pi_flags & REAPER_PIDINFO_CHILD);
509 ATF_CHECK_EQ(grandchild, info[0].pi_pid);
511 pid = waitpid(grandchild, &status, 0);
512 ATF_REQUIRE_EQ(grandchild, pid);
513 ATF_CHECK_EQ(0, status);
515 memset(info, '\0', sizeof(info));
516 r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
517 &(struct procctl_reaper_pids){
518 .rp_count = sizeof(info) / sizeof(info[0]),
522 ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
525 ATF_REQUIRE_EQ(0, r);
527 ATF_REQUIRE_EQ(0, r);
530 ATF_TC_WITHOUT_HEAD(reaper_kill_badsig);
531 ATF_TC_BODY(reaper_kill_badsig, tc)
533 struct procctl_reaper_kill params;
538 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
539 ATF_REQUIRE_EQ(0, r);
543 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
544 ATF_CHECK(r == -1 && errno == EINVAL);
547 ATF_TC_WITHOUT_HEAD(reaper_kill_sigzero);
548 ATF_TC_BODY(reaper_kill_sigzero, tc)
550 struct procctl_reaper_kill params;
555 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
556 ATF_REQUIRE_EQ(0, r);
560 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
561 ATF_CHECK(r == -1 && errno == EINVAL);
564 ATF_TC_WITHOUT_HEAD(reaper_kill_empty);
565 ATF_TC_BODY(reaper_kill_empty, tc)
567 struct procctl_reaper_kill params;
572 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
573 ATF_REQUIRE_EQ(0, r);
575 params.rk_sig = SIGTERM;
577 params.rk_killed = 77;
578 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
579 ATF_CHECK(r == -1 && errno == ESRCH);
580 ATF_CHECK_EQ(0, params.rk_killed);
583 ATF_TC_WITHOUT_HEAD(reaper_kill_normal);
584 ATF_TC_BODY(reaper_kill_normal, tc)
586 struct procctl_reaper_kill params;
588 pid_t parent, child, grandchild, pid;
593 r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
594 ATF_REQUIRE_EQ(0, r);
597 ATF_REQUIRE_EQ(0, r);
599 ATF_REQUIRE(child != -1);
601 if (close(pip[0]) != 0)
604 if (grandchild == -1)
606 if (grandchild == 0) {
607 if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
616 ATF_REQUIRE_EQ(0, r);
618 sr = read(pip[0], &(uint8_t){ 0 }, 1);
619 ATF_REQUIRE_EQ(1, sr);
621 params.rk_sig = SIGTERM;
623 params.rk_killed = 77;
624 r = procctl(P_PID, parent, PROC_REAP_KILL, ¶ms);
626 ATF_CHECK_EQ(2, params.rk_killed);
628 pid = waitpid(child, &status, 0);
629 ATF_REQUIRE_EQ(child, pid);
630 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
632 pid = waitpid(-1, &status, 0);
633 ATF_REQUIRE(pid > 0);
634 ATF_CHECK(pid != parent);
635 ATF_CHECK(pid != child);
636 ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
639 ATF_REQUIRE_EQ(0, r);
645 ATF_TP_ADD_TC(tp, reaper_wait_child_first);
646 ATF_TP_ADD_TC(tp, reaper_wait_grandchild_first);
647 ATF_TP_ADD_TC(tp, reaper_sigchld_child_first);
648 ATF_TP_ADD_TC(tp, reaper_sigchld_grandchild_first);
649 ATF_TP_ADD_TC(tp, reaper_status);
650 ATF_TP_ADD_TC(tp, reaper_getpids);
651 ATF_TP_ADD_TC(tp, reaper_kill_badsig);
652 ATF_TP_ADD_TC(tp, reaper_kill_sigzero);
653 ATF_TP_ADD_TC(tp, reaper_kill_empty);
654 ATF_TP_ADD_TC(tp, reaper_kill_normal);
655 return (atf_no_error());