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