xref: /freebsd/tests/sys/kern/reaper.c (revision 4f4b548b1d21ae16955b09f9b717524167a7d97e)
1 /*-
2  * Copyright (c) 2016 Jilles Tjoelker
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/procctl.h>
31 #include <sys/procdesc.h>
32 #include <sys/wait.h>
33 
34 #include <atf-c.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <unistd.h>
38 
39 static void
40 dummy_sighandler(int sig __unused, siginfo_t *info __unused, void *ctx __unused)
41 {
42 }
43 
44 ATF_TC_WITHOUT_HEAD(reaper_wait_child_first);
45 ATF_TC_BODY(reaper_wait_child_first, tc)
46 {
47 	pid_t parent, child, grandchild, pid;
48 	int status, r;
49 	int pip[2];
50 
51 	/* Be paranoid. */
52 	pid = waitpid(-1, NULL, WNOHANG);
53 	ATF_REQUIRE(pid == -1 && errno == ECHILD);
54 
55 	parent = getpid();
56 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
57 	ATF_REQUIRE_EQ(0, r);
58 
59 	r = pipe(pip);
60 	ATF_REQUIRE_EQ(0, r);
61 
62 	child = fork();
63 	ATF_REQUIRE(child != -1);
64 	if (child == 0) {
65 		if (close(pip[1]) != 0)
66 			_exit(100);
67 		grandchild = fork();
68 		if (grandchild == -1)
69 			_exit(101);
70 		else if (grandchild == 0) {
71 			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
72 				_exit(102);
73 			if (getppid() != parent)
74 				_exit(103);
75 			_exit(2);
76 		} else
77 			_exit(3);
78 	}
79 
80 	pid = waitpid(child, &status, 0);
81 	ATF_REQUIRE_EQ(child, pid);
82 	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
83 	ATF_CHECK_EQ(3, r);
84 
85 	r = close(pip[1]);
86 	ATF_REQUIRE_EQ(0, r);
87 
88 	pid = waitpid(-1, &status, 0);
89 	ATF_REQUIRE(pid > 0 && pid != child);
90 	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
91 	ATF_CHECK_EQ(2, r);
92 
93 	r = close(pip[0]);
94 	ATF_REQUIRE_EQ(0, r);
95 }
96 
97 ATF_TC_WITHOUT_HEAD(reaper_wait_grandchild_first);
98 ATF_TC_BODY(reaper_wait_grandchild_first, tc)
99 {
100 	pid_t parent, child, grandchild, pid;
101 	int status, r;
102 
103 	/* Be paranoid. */
104 	pid = waitpid(-1, NULL, WNOHANG);
105 	ATF_REQUIRE(pid == -1 && errno == ECHILD);
106 
107 	parent = getpid();
108 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
109 	ATF_REQUIRE_EQ(0, r);
110 
111 	child = fork();
112 	ATF_REQUIRE(child != -1);
113 	if (child == 0) {
114 		grandchild = fork();
115 		if (grandchild == -1)
116 			_exit(101);
117 		else if (grandchild == 0)
118 			_exit(2);
119 		else {
120 			if (waitid(P_PID, grandchild, NULL,
121 			    WNOWAIT | WEXITED) != 0)
122 				_exit(102);
123 			_exit(3);
124 		}
125 	}
126 
127 	pid = waitpid(child, &status, 0);
128 	ATF_REQUIRE_EQ(child, pid);
129 	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
130 	ATF_CHECK_EQ(3, r);
131 
132 	pid = waitpid(-1, &status, 0);
133 	ATF_REQUIRE(pid > 0 && pid != child);
134 	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
135 	ATF_CHECK_EQ(2, r);
136 }
137 
138 ATF_TC(reaper_sigchld_child_first);
139 ATF_TC_HEAD(reaper_sigchld_child_first, tc)
140 {
141 	atf_tc_set_md_var(tc, "timeout", "2");
142 }
143 ATF_TC_BODY(reaper_sigchld_child_first, tc)
144 {
145 	struct sigaction act;
146 	sigset_t mask;
147 	siginfo_t info;
148 	pid_t parent, child, grandchild, pid;
149 	int r;
150 	int pip[2];
151 
152 	/* Be paranoid. */
153 	pid = waitpid(-1, NULL, WNOHANG);
154 	ATF_REQUIRE(pid == -1 && errno == ECHILD);
155 
156 	act.sa_sigaction = dummy_sighandler;
157 	act.sa_flags = SA_SIGINFO | SA_RESTART;
158 	r = sigemptyset(&act.sa_mask);
159 	ATF_REQUIRE_EQ(0, r);
160 	r = sigaction(SIGCHLD, &act, NULL);
161 	ATF_REQUIRE_EQ(0, r);
162 
163 	r = sigemptyset(&mask);
164 	ATF_REQUIRE_EQ(0, r);
165 	r = sigaddset(&mask, SIGCHLD);
166 	ATF_REQUIRE_EQ(0, r);
167 	r = sigprocmask(SIG_BLOCK, &mask, NULL);
168 	ATF_REQUIRE_EQ(0, r);
169 
170 	parent = getpid();
171 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
172 	ATF_REQUIRE_EQ(0, r);
173 
174 	r = pipe(pip);
175 	ATF_REQUIRE_EQ(0, r);
176 
177 	child = fork();
178 	ATF_REQUIRE(child != -1);
179 	if (child == 0) {
180 		if (close(pip[1]) != 0)
181 			_exit(100);
182 		grandchild = fork();
183 		if (grandchild == -1)
184 			_exit(101);
185 		else if (grandchild == 0) {
186 			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
187 				_exit(102);
188 			if (getppid() != parent)
189 				_exit(103);
190 			_exit(2);
191 		} else
192 			_exit(3);
193 	}
194 
195 	r = sigwaitinfo(&mask, &info);
196 	ATF_REQUIRE_EQ(SIGCHLD, r);
197 	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
198 	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
199 	ATF_CHECK_EQ(3, info.si_status);
200 	ATF_CHECK_EQ(child, info.si_pid);
201 
202 	pid = waitpid(child, NULL, 0);
203 	ATF_REQUIRE_EQ(child, pid);
204 
205 	r = close(pip[1]);
206 	ATF_REQUIRE_EQ(0, r);
207 
208 	r = sigwaitinfo(&mask, &info);
209 	ATF_REQUIRE_EQ(SIGCHLD, r);
210 	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
211 	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
212 	ATF_CHECK_EQ(2, info.si_status);
213 	grandchild = info.si_pid;
214 	ATF_REQUIRE(grandchild > 0);
215 	ATF_REQUIRE(grandchild != parent);
216 	ATF_REQUIRE(grandchild != child);
217 
218 	pid = waitpid(-1, NULL, 0);
219 	ATF_REQUIRE_EQ(grandchild, pid);
220 
221 	r = close(pip[0]);
222 	ATF_REQUIRE_EQ(0, r);
223 }
224 
225 ATF_TC(reaper_sigchld_grandchild_first);
226 ATF_TC_HEAD(reaper_sigchld_grandchild_first, tc)
227 {
228 	atf_tc_set_md_var(tc, "timeout", "2");
229 }
230 ATF_TC_BODY(reaper_sigchld_grandchild_first, tc)
231 {
232 	struct sigaction act;
233 	sigset_t mask;
234 	siginfo_t info;
235 	pid_t parent, child, grandchild, pid;
236 	int r;
237 
238 	/* Be paranoid. */
239 	pid = waitpid(-1, NULL, WNOHANG);
240 	ATF_REQUIRE(pid == -1 && errno == ECHILD);
241 
242 	act.sa_sigaction = dummy_sighandler;
243 	act.sa_flags = SA_SIGINFO | SA_RESTART;
244 	r = sigemptyset(&act.sa_mask);
245 	ATF_REQUIRE_EQ(0, r);
246 	r = sigaction(SIGCHLD, &act, NULL);
247 	ATF_REQUIRE_EQ(0, r);
248 
249 	r = sigemptyset(&mask);
250 	ATF_REQUIRE_EQ(0, r);
251 	r = sigaddset(&mask, SIGCHLD);
252 	ATF_REQUIRE_EQ(0, r);
253 	r = sigprocmask(SIG_BLOCK, &mask, NULL);
254 	ATF_REQUIRE_EQ(0, r);
255 
256 	parent = getpid();
257 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
258 	ATF_REQUIRE_EQ(0, r);
259 
260 	child = fork();
261 	ATF_REQUIRE(child != -1);
262 	if (child == 0) {
263 		grandchild = fork();
264 		if (grandchild == -1)
265 			_exit(101);
266 		else if (grandchild == 0)
267 			_exit(2);
268 		else {
269 			if (waitid(P_PID, grandchild, NULL,
270 			    WNOWAIT | WEXITED) != 0)
271 				_exit(102);
272 			_exit(3);
273 		}
274 	}
275 
276 	pid = waitpid(child, NULL, 0);
277 	ATF_REQUIRE_EQ(child, pid);
278 
279 	r = sigwaitinfo(&mask, &info);
280 	ATF_REQUIRE_EQ(SIGCHLD, r);
281 	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
282 	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
283 	ATF_CHECK_EQ(2, info.si_status);
284 	grandchild = info.si_pid;
285 	ATF_REQUIRE(grandchild > 0);
286 	ATF_REQUIRE(grandchild != parent);
287 	ATF_REQUIRE(grandchild != child);
288 
289 	pid = waitpid(-1, NULL, 0);
290 	ATF_REQUIRE_EQ(grandchild, pid);
291 }
292 
293 ATF_TC_WITHOUT_HEAD(reaper_status);
294 ATF_TC_BODY(reaper_status, tc)
295 {
296 	struct procctl_reaper_status st;
297 	ssize_t sr;
298 	pid_t parent, child, pid;
299 	int r, status;
300 	int pip[2];
301 
302 	parent = getpid();
303 	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
304 	ATF_REQUIRE_EQ(0, r);
305 	ATF_CHECK_EQ(0, st.rs_flags & REAPER_STATUS_OWNED);
306 	ATF_CHECK(st.rs_children > 0);
307 	ATF_CHECK(st.rs_descendants > 0);
308 	ATF_CHECK(st.rs_descendants >= st.rs_children);
309 	ATF_CHECK(st.rs_reaper != parent);
310 	ATF_CHECK(st.rs_reaper > 0);
311 
312 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
313 	ATF_REQUIRE_EQ(0, r);
314 
315 	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
316 	ATF_REQUIRE_EQ(0, r);
317 	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
318 	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
319 	ATF_CHECK_EQ(0, st.rs_children);
320 	ATF_CHECK_EQ(0, st.rs_descendants);
321 	ATF_CHECK(st.rs_reaper == parent);
322 	ATF_CHECK_EQ(-1, st.rs_pid);
323 
324 	r = pipe(pip);
325 	ATF_REQUIRE_EQ(0, r);
326 	child = fork();
327 	ATF_REQUIRE(child != -1);
328 	if (child == 0) {
329 		if (close(pip[0]) != 0)
330 			_exit(100);
331 		if (procctl(P_PID, parent, PROC_REAP_STATUS, &st) != 0)
332 			_exit(101);
333 		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
334 			_exit(102);
335 		if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &st) != 0)
336 			_exit(103);
337 		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
338 			_exit(104);
339 		_exit(0);
340 	}
341 	r = close(pip[1]);
342 	ATF_REQUIRE_EQ(0, r);
343 
344 	sr = read(pip[0], &st, sizeof(st));
345 	ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
346 	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
347 	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
348 	ATF_CHECK_EQ(1, st.rs_children);
349 	ATF_CHECK_EQ(1, st.rs_descendants);
350 	ATF_CHECK(st.rs_reaper == parent);
351 	ATF_CHECK_EQ(child, st.rs_pid);
352 	sr = read(pip[0], &st, sizeof(st));
353 	ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
354 	ATF_CHECK_EQ(0,
355 	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
356 	ATF_CHECK_EQ(1, st.rs_children);
357 	ATF_CHECK_EQ(1, st.rs_descendants);
358 	ATF_CHECK(st.rs_reaper == parent);
359 	ATF_CHECK_EQ(child, st.rs_pid);
360 
361 	r = close(pip[0]);
362 	ATF_REQUIRE_EQ(0, r);
363 	pid = waitpid(child, &status, 0);
364 	ATF_REQUIRE_EQ(child, pid);
365 	ATF_CHECK_EQ(0, status);
366 
367 	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
368 	ATF_REQUIRE_EQ(0, r);
369 	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
370 	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
371 	ATF_CHECK_EQ(0, st.rs_children);
372 	ATF_CHECK_EQ(0, st.rs_descendants);
373 	ATF_CHECK(st.rs_reaper == parent);
374 	ATF_CHECK_EQ(-1, st.rs_pid);
375 }
376 
377 ATF_TC_WITHOUT_HEAD(reaper_getpids);
378 ATF_TC_BODY(reaper_getpids, tc)
379 {
380 	struct procctl_reaper_pidinfo info[10];
381 	ssize_t sr;
382 	pid_t parent, child, grandchild, pid;
383 	int r, status, childidx;
384 	int pipa[2], pipb[2];
385 
386 	parent = getpid();
387 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
388 	ATF_REQUIRE_EQ(0, r);
389 
390 	memset(info, '\0', sizeof(info));
391 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
392 	    &(struct procctl_reaper_pids){
393 	    .rp_count = sizeof(info) / sizeof(info[0]),
394 	    .rp_pids = info
395 	    });
396 	ATF_CHECK_EQ(0, r);
397 	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
398 
399 	r = pipe(pipa);
400 	ATF_REQUIRE_EQ(0, r);
401 	r = pipe(pipb);
402 	ATF_REQUIRE_EQ(0, r);
403 	child = fork();
404 	ATF_REQUIRE(child != -1);
405 	if (child == 0) {
406 		if (close(pipa[1]) != 0)
407 			_exit(100);
408 		if (close(pipb[0]) != 0)
409 			_exit(100);
410 		if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
411 			_exit(101);
412 		grandchild = fork();
413 		if (grandchild == -1)
414 			_exit(102);
415 		if (grandchild == 0) {
416 			if (write(pipb[1], &(uint8_t){ 0 }, 1) != 1)
417 				_exit(103);
418 			if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
419 				_exit(104);
420 			_exit(0);
421 		}
422 		for (;;)
423 			pause();
424 	}
425 	r = close(pipa[0]);
426 	ATF_REQUIRE_EQ(0, r);
427 	r = close(pipb[1]);
428 	ATF_REQUIRE_EQ(0, r);
429 
430 	memset(info, '\0', sizeof(info));
431 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
432 	    &(struct procctl_reaper_pids){
433 	    .rp_count = sizeof(info) / sizeof(info[0]),
434 	    .rp_pids = info
435 	    });
436 	ATF_CHECK_EQ(0, r);
437 	ATF_CHECK_EQ(REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD,
438 	    info[0].pi_flags & (REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD));
439 	ATF_CHECK_EQ(child, info[0].pi_pid);
440 	ATF_CHECK_EQ(child, info[0].pi_subtree);
441 	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
442 
443 	sr = write(pipa[1], &(uint8_t){ 0 }, 1);
444 	ATF_REQUIRE_EQ(1, sr);
445 	sr = read(pipb[0], &(uint8_t){ 0 }, 1);
446 	ATF_REQUIRE_EQ(1, sr);
447 
448 	memset(info, '\0', sizeof(info));
449 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
450 	    &(struct procctl_reaper_pids){
451 	    .rp_count = sizeof(info) / sizeof(info[0]),
452 	    .rp_pids = info
453 	    });
454 	ATF_CHECK_EQ(0, r);
455 	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
456 	    info[0].pi_flags & REAPER_PIDINFO_VALID);
457 	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
458 	    info[1].pi_flags & REAPER_PIDINFO_VALID);
459 	ATF_CHECK_EQ(0, info[2].pi_flags & REAPER_PIDINFO_VALID);
460 	ATF_CHECK_EQ(child, info[0].pi_subtree);
461 	ATF_CHECK_EQ(child, info[1].pi_subtree);
462 	childidx = info[1].pi_pid == child ? 1 : 0;
463 	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
464 	    info[childidx].pi_flags & REAPER_PIDINFO_CHILD);
465 	ATF_CHECK_EQ(0, info[childidx ^ 1].pi_flags & REAPER_PIDINFO_CHILD);
466 	ATF_CHECK(info[childidx].pi_pid == child);
467 	grandchild = info[childidx ^ 1].pi_pid;
468 	ATF_CHECK(grandchild > 0);
469 	ATF_CHECK(grandchild != child);
470 	ATF_CHECK(grandchild != parent);
471 
472 	r = kill(child, SIGTERM);
473 	ATF_REQUIRE_EQ(0, r);
474 
475 	pid = waitpid(child, &status, 0);
476 	ATF_REQUIRE_EQ(child, pid);
477 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
478 
479 	memset(info, '\0', sizeof(info));
480 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
481 	    &(struct procctl_reaper_pids){
482 	    .rp_count = sizeof(info) / sizeof(info[0]),
483 	    .rp_pids = info
484 	    });
485 	ATF_CHECK_EQ(0, r);
486 	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
487 	    info[0].pi_flags & REAPER_PIDINFO_VALID);
488 	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
489 	ATF_CHECK_EQ(child, info[0].pi_subtree);
490 	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
491 	    info[0].pi_flags & REAPER_PIDINFO_CHILD);
492 	ATF_CHECK_EQ(grandchild, info[0].pi_pid);
493 
494 	sr = write(pipa[1], &(uint8_t){ 0 }, 1);
495 	ATF_REQUIRE_EQ(1, sr);
496 
497 	memset(info, '\0', sizeof(info));
498 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
499 	    &(struct procctl_reaper_pids){
500 	    .rp_count = sizeof(info) / sizeof(info[0]),
501 	    .rp_pids = info
502 	    });
503 	ATF_CHECK_EQ(0, r);
504 	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
505 	    info[0].pi_flags & REAPER_PIDINFO_VALID);
506 	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
507 	ATF_CHECK_EQ(child, info[0].pi_subtree);
508 	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
509 	    info[0].pi_flags & REAPER_PIDINFO_CHILD);
510 	ATF_CHECK_EQ(grandchild, info[0].pi_pid);
511 
512 	pid = waitpid(grandchild, &status, 0);
513 	ATF_REQUIRE_EQ(grandchild, pid);
514 	ATF_CHECK_EQ(0, status);
515 
516 	memset(info, '\0', sizeof(info));
517 	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
518 	    &(struct procctl_reaper_pids){
519 	    .rp_count = sizeof(info) / sizeof(info[0]),
520 	    .rp_pids = info
521 	    });
522 	ATF_CHECK_EQ(0, r);
523 	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
524 
525 	r = close(pipa[1]);
526 	ATF_REQUIRE_EQ(0, r);
527 	r = close(pipb[0]);
528 	ATF_REQUIRE_EQ(0, r);
529 }
530 
531 ATF_TC_WITHOUT_HEAD(reaper_kill_badsig);
532 ATF_TC_BODY(reaper_kill_badsig, tc)
533 {
534 	struct procctl_reaper_kill params;
535 	pid_t parent;
536 	int r;
537 
538 	parent = getpid();
539 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
540 	ATF_REQUIRE_EQ(0, r);
541 
542 	params.rk_sig = -1;
543 	params.rk_flags = 0;
544 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
545 	ATF_CHECK(r == -1 && errno == EINVAL);
546 }
547 
548 ATF_TC_WITHOUT_HEAD(reaper_kill_sigzero);
549 ATF_TC_BODY(reaper_kill_sigzero, tc)
550 {
551 	struct procctl_reaper_kill params;
552 	pid_t parent;
553 	int r;
554 
555 	parent = getpid();
556 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
557 	ATF_REQUIRE_EQ(0, r);
558 
559 	params.rk_sig = 0;
560 	params.rk_flags = 0;
561 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
562 	ATF_CHECK(r == -1 && errno == EINVAL);
563 }
564 
565 ATF_TC_WITHOUT_HEAD(reaper_kill_empty);
566 ATF_TC_BODY(reaper_kill_empty, tc)
567 {
568 	struct procctl_reaper_kill params;
569 	pid_t parent;
570 	int r;
571 
572 	parent = getpid();
573 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
574 	ATF_REQUIRE_EQ(0, r);
575 
576 	params.rk_sig = SIGTERM;
577 	params.rk_flags = 0;
578 	params.rk_killed = 77;
579 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
580 	ATF_CHECK(r == -1 && errno == ESRCH);
581 	ATF_CHECK_EQ(0, params.rk_killed);
582 }
583 
584 ATF_TC_WITHOUT_HEAD(reaper_kill_normal);
585 ATF_TC_BODY(reaper_kill_normal, tc)
586 {
587 	struct procctl_reaper_kill params;
588 	ssize_t sr;
589 	pid_t parent, child, grandchild, pid;
590 	int r, status;
591 	int pip[2];
592 
593 	parent = getpid();
594 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
595 	ATF_REQUIRE_EQ(0, r);
596 
597 	r = pipe(pip);
598 	ATF_REQUIRE_EQ(0, r);
599 	child = fork();
600 	ATF_REQUIRE(child != -1);
601 	if (child == 0) {
602 		if (close(pip[0]) != 0)
603 			_exit(100);
604 		grandchild = fork();
605 		if (grandchild == -1)
606 			_exit(101);
607 		if (grandchild == 0) {
608 			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
609 				_exit(102);
610 			for (;;)
611 				pause();
612 		}
613 		for (;;)
614 			pause();
615 	}
616 	r = close(pip[1]);
617 	ATF_REQUIRE_EQ(0, r);
618 
619 	sr = read(pip[0], &(uint8_t){ 0 }, 1);
620 	ATF_REQUIRE_EQ(1, sr);
621 
622 	params.rk_sig = SIGTERM;
623 	params.rk_flags = 0;
624 	params.rk_killed = 77;
625 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
626 	ATF_CHECK_EQ(0, r);
627 	ATF_CHECK_EQ(2, params.rk_killed);
628 
629 	pid = waitpid(child, &status, 0);
630 	ATF_REQUIRE_EQ(child, pid);
631 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
632 
633 	pid = waitpid(-1, &status, 0);
634 	ATF_REQUIRE(pid > 0);
635 	ATF_CHECK(pid != parent);
636 	ATF_CHECK(pid != child);
637 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
638 
639 	r = close(pip[0]);
640 	ATF_REQUIRE_EQ(0, r);
641 }
642 
643 ATF_TC_WITHOUT_HEAD(reaper_kill_subtree);
644 ATF_TC_BODY(reaper_kill_subtree, tc)
645 {
646 	struct procctl_reaper_kill params;
647 	ssize_t sr;
648 	pid_t parent, child1, child2, grandchild1, grandchild2, pid;
649 	int r, status;
650 	int pip[2];
651 
652 	parent = getpid();
653 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
654 	ATF_REQUIRE_EQ(0, r);
655 
656 	r = pipe(pip);
657 	ATF_REQUIRE_EQ(0, r);
658 	child1 = fork();
659 	ATF_REQUIRE(child1 != -1);
660 	if (child1 == 0) {
661 		if (close(pip[0]) != 0)
662 			_exit(100);
663 		grandchild1 = fork();
664 		if (grandchild1 == -1)
665 			_exit(101);
666 		if (grandchild1 == 0) {
667 			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
668 				_exit(102);
669 			for (;;)
670 				pause();
671 		}
672 		for (;;)
673 			pause();
674 	}
675 	child2 = fork();
676 	ATF_REQUIRE(child2 != -1);
677 	if (child2 == 0) {
678 		if (close(pip[0]) != 0)
679 			_exit(100);
680 		grandchild2 = fork();
681 		if (grandchild2 == -1)
682 			_exit(101);
683 		if (grandchild2 == 0) {
684 			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
685 				_exit(102);
686 			for (;;)
687 				pause();
688 		}
689 		for (;;)
690 			pause();
691 	}
692 	r = close(pip[1]);
693 	ATF_REQUIRE_EQ(0, r);
694 
695 	sr = read(pip[0], &(uint8_t){ 0 }, 1);
696 	ATF_REQUIRE_EQ(1, sr);
697 	sr = read(pip[0], &(uint8_t){ 0 }, 1);
698 	ATF_REQUIRE_EQ(1, sr);
699 
700 	params.rk_sig = SIGUSR1;
701 	params.rk_flags = REAPER_KILL_SUBTREE;
702 	params.rk_subtree = child1;
703 	params.rk_killed = 77;
704 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
705 	ATF_REQUIRE_EQ(0, r);
706 	ATF_REQUIRE_EQ(2, params.rk_killed);
707 	ATF_CHECK_EQ(-1, params.rk_fpid);
708 
709 	pid = waitpid(child1, &status, 0);
710 	ATF_REQUIRE_EQ(child1, pid);
711 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR1);
712 
713 	pid = waitpid(-1, &status, 0);
714 	ATF_REQUIRE(pid > 0);
715 	ATF_CHECK(pid != parent);
716 	ATF_CHECK(pid != child1);
717 	ATF_CHECK(pid != child2);
718 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR1);
719 
720 	params.rk_sig = SIGUSR2;
721 	params.rk_flags = REAPER_KILL_SUBTREE;
722 	params.rk_subtree = child2;
723 	params.rk_killed = 77;
724 	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
725 	ATF_REQUIRE_EQ(0, r);
726 	ATF_REQUIRE_EQ(2, params.rk_killed);
727 	ATF_CHECK_EQ(-1, params.rk_fpid);
728 
729 	pid = waitpid(child2, &status, 0);
730 	ATF_REQUIRE_EQ(child2, pid);
731 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR2);
732 
733 	pid = waitpid(-1, &status, 0);
734 	ATF_REQUIRE(pid > 0);
735 	ATF_CHECK(pid != parent);
736 	ATF_CHECK(pid != child1);
737 	ATF_CHECK(pid != child2);
738 	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR2);
739 
740 	r = close(pip[0]);
741 	ATF_REQUIRE_EQ(0, r);
742 }
743 
744 ATF_TC_WITHOUT_HEAD(reaper_pdfork);
745 ATF_TC_BODY(reaper_pdfork, tc)
746 {
747 	struct procctl_reaper_status st;
748 	pid_t child, grandchild, parent, pid;
749 	int pd, r, status;
750 
751 	parent = getpid();
752 	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
753 	ATF_REQUIRE_EQ(r, 0);
754 
755 	child = pdfork(&pd, 0);
756 	ATF_REQUIRE(child != -1);
757 	if (child == 0) {
758 		grandchild = pdfork(&pd, 0);
759 		if (grandchild == -1)
760 			_exit(1);
761 		if (grandchild == 0)
762 			pause();
763 		_exit(0);
764 	}
765 	pid = waitpid(child, &status, 0);
766 	ATF_REQUIRE_EQ(pid, child);
767 	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
768 	ATF_REQUIRE_EQ(r, 0);
769 
770 	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
771 	ATF_REQUIRE_EQ(r, 0);
772 	ATF_CHECK((st.rs_flags & REAPER_STATUS_OWNED) != 0);
773 	ATF_CHECK(st.rs_reaper == parent);
774 	ATF_CHECK(st.rs_children == 1);
775 	ATF_CHECK(st.rs_descendants == 1);
776 }
777 
778 ATF_TP_ADD_TCS(tp)
779 {
780 
781 	ATF_TP_ADD_TC(tp, reaper_wait_child_first);
782 	ATF_TP_ADD_TC(tp, reaper_wait_grandchild_first);
783 	ATF_TP_ADD_TC(tp, reaper_sigchld_child_first);
784 	ATF_TP_ADD_TC(tp, reaper_sigchld_grandchild_first);
785 	ATF_TP_ADD_TC(tp, reaper_status);
786 	ATF_TP_ADD_TC(tp, reaper_getpids);
787 	ATF_TP_ADD_TC(tp, reaper_kill_badsig);
788 	ATF_TP_ADD_TC(tp, reaper_kill_sigzero);
789 	ATF_TP_ADD_TC(tp, reaper_kill_empty);
790 	ATF_TP_ADD_TC(tp, reaper_kill_normal);
791 	ATF_TP_ADD_TC(tp, reaper_kill_subtree);
792 	ATF_TP_ADD_TC(tp, reaper_pdfork);
793 	return (atf_no_error());
794 }
795