reaper.c revision 310610
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: stable/10/tests/sys/kern/reaper.c 310610 2016-12-26 17:26:25Z jilles $");
29
30#include <sys/procctl.h>
31#include <sys/wait.h>
32
33#include <atf-c.h>
34#include <errno.h>
35#include <signal.h>
36#include <unistd.h>
37
38static void
39dummy_sighandler(int sig __unused, siginfo_t *info __unused, void *ctx __unused)
40{
41}
42
43ATF_TC_WITHOUT_HEAD(reaper_wait_child_first);
44ATF_TC_BODY(reaper_wait_child_first, tc)
45{
46	pid_t parent, child, grandchild, pid;
47	int status, r;
48	int pip[2];
49
50	/* Be paranoid. */
51	pid = waitpid(-1, NULL, WNOHANG);
52	ATF_REQUIRE(pid == -1 && errno == ECHILD);
53
54	parent = getpid();
55	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
56	ATF_REQUIRE_EQ(0, r);
57
58	r = pipe(pip);
59	ATF_REQUIRE_EQ(0, r);
60
61	child = fork();
62	ATF_REQUIRE(child != -1);
63	if (child == 0) {
64		if (close(pip[1]) != 0)
65			_exit(100);
66		grandchild = fork();
67		if (grandchild == -1)
68			_exit(101);
69		else if (grandchild == 0) {
70			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
71				_exit(102);
72			if (getppid() != parent)
73				_exit(103);
74			_exit(2);
75		} else
76			_exit(3);
77	}
78
79	pid = waitpid(child, &status, 0);
80	ATF_REQUIRE_EQ(child, pid);
81	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
82	ATF_CHECK_EQ(3, r);
83
84	r = close(pip[1]);
85	ATF_REQUIRE_EQ(0, r);
86
87	pid = waitpid(-1, &status, 0);
88	ATF_REQUIRE(pid > 0 && pid != child);
89	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
90	ATF_CHECK_EQ(2, r);
91
92	r = close(pip[0]);
93	ATF_REQUIRE_EQ(0, r);
94}
95
96ATF_TC_WITHOUT_HEAD(reaper_wait_grandchild_first);
97ATF_TC_BODY(reaper_wait_grandchild_first, tc)
98{
99	pid_t parent, child, grandchild, pid;
100	int status, r;
101
102	/* Be paranoid. */
103	pid = waitpid(-1, NULL, WNOHANG);
104	ATF_REQUIRE(pid == -1 && errno == ECHILD);
105
106	parent = getpid();
107	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
108	ATF_REQUIRE_EQ(0, r);
109
110	child = fork();
111	ATF_REQUIRE(child != -1);
112	if (child == 0) {
113		grandchild = fork();
114		if (grandchild == -1)
115			_exit(101);
116		else if (grandchild == 0)
117			_exit(2);
118		else {
119			if (waitid(P_PID, grandchild, NULL,
120			    WNOWAIT | WEXITED) != 0)
121				_exit(102);
122			_exit(3);
123		}
124	}
125
126	pid = waitpid(child, &status, 0);
127	ATF_REQUIRE_EQ(child, pid);
128	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
129	ATF_CHECK_EQ(3, r);
130
131	pid = waitpid(-1, &status, 0);
132	ATF_REQUIRE(pid > 0 && pid != child);
133	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
134	ATF_CHECK_EQ(2, r);
135}
136
137ATF_TC(reaper_sigchld_child_first);
138ATF_TC_HEAD(reaper_sigchld_child_first, tc)
139{
140	atf_tc_set_md_var(tc, "timeout", "2");
141}
142ATF_TC_BODY(reaper_sigchld_child_first, tc)
143{
144	struct sigaction act;
145	sigset_t mask;
146	siginfo_t info;
147	pid_t parent, child, grandchild, pid;
148	int r;
149	int pip[2];
150
151	/* Be paranoid. */
152	pid = waitpid(-1, NULL, WNOHANG);
153	ATF_REQUIRE(pid == -1 && errno == ECHILD);
154
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);
161
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);
168
169	parent = getpid();
170	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
171	ATF_REQUIRE_EQ(0, r);
172
173	r = pipe(pip);
174	ATF_REQUIRE_EQ(0, r);
175
176	child = fork();
177	ATF_REQUIRE(child != -1);
178	if (child == 0) {
179		if (close(pip[1]) != 0)
180			_exit(100);
181		grandchild = fork();
182		if (grandchild == -1)
183			_exit(101);
184		else if (grandchild == 0) {
185			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
186				_exit(102);
187			if (getppid() != parent)
188				_exit(103);
189			_exit(2);
190		} else
191			_exit(3);
192	}
193
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);
200
201	pid = waitpid(child, NULL, 0);
202	ATF_REQUIRE_EQ(child, pid);
203
204	r = close(pip[1]);
205	ATF_REQUIRE_EQ(0, r);
206
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);
216
217	pid = waitpid(-1, NULL, 0);
218	ATF_REQUIRE_EQ(grandchild, pid);
219
220	r = close(pip[0]);
221	ATF_REQUIRE_EQ(0, r);
222}
223
224ATF_TC(reaper_sigchld_grandchild_first);
225ATF_TC_HEAD(reaper_sigchld_grandchild_first, tc)
226{
227	atf_tc_set_md_var(tc, "timeout", "2");
228}
229ATF_TC_BODY(reaper_sigchld_grandchild_first, tc)
230{
231	struct sigaction act;
232	sigset_t mask;
233	siginfo_t info;
234	pid_t parent, child, grandchild, pid;
235	int r;
236
237	/* Be paranoid. */
238	pid = waitpid(-1, NULL, WNOHANG);
239	ATF_REQUIRE(pid == -1 && errno == ECHILD);
240
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);
247
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);
254
255	parent = getpid();
256	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
257	ATF_REQUIRE_EQ(0, r);
258
259	child = fork();
260	ATF_REQUIRE(child != -1);
261	if (child == 0) {
262		grandchild = fork();
263		if (grandchild == -1)
264			_exit(101);
265		else if (grandchild == 0)
266			_exit(2);
267		else {
268			if (waitid(P_PID, grandchild, NULL,
269			    WNOWAIT | WEXITED) != 0)
270				_exit(102);
271			_exit(3);
272		}
273	}
274
275	pid = waitpid(child, NULL, 0);
276	ATF_REQUIRE_EQ(child, pid);
277
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);
287
288	pid = waitpid(-1, NULL, 0);
289	ATF_REQUIRE_EQ(grandchild, pid);
290}
291
292ATF_TC_WITHOUT_HEAD(reaper_status);
293ATF_TC_BODY(reaper_status, tc)
294{
295	struct procctl_reaper_status st;
296	ssize_t sr;
297	pid_t parent, child, pid;
298	int r, status;
299	int pip[2];
300
301	parent = getpid();
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);
310
311	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
312	ATF_REQUIRE_EQ(0, r);
313
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);
322
323	r = pipe(pip);
324	ATF_REQUIRE_EQ(0, r);
325	child = fork();
326	ATF_REQUIRE(child != -1);
327	if (child == 0) {
328		if (close(pip[0]) != 0)
329			_exit(100);
330		if (procctl(P_PID, parent, PROC_REAP_STATUS, &st) != 0)
331			_exit(101);
332		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
333			_exit(102);
334		if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &st) != 0)
335			_exit(103);
336		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
337			_exit(104);
338		_exit(0);
339	}
340	r = close(pip[1]);
341	ATF_REQUIRE_EQ(0, r);
342
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);
353	ATF_CHECK_EQ(0,
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);
359
360	r = close(pip[0]);
361	ATF_REQUIRE_EQ(0, r);
362	pid = waitpid(child, &status, 0);
363	ATF_REQUIRE_EQ(child, pid);
364	ATF_CHECK_EQ(0, status);
365
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);
374}
375
376ATF_TC_WITHOUT_HEAD(reaper_getpids);
377ATF_TC_BODY(reaper_getpids, tc)
378{
379	struct procctl_reaper_pidinfo info[10];
380	ssize_t sr;
381	pid_t parent, child, grandchild, pid;
382	int r, status, childidx;
383	int pipa[2], pipb[2];
384
385	parent = getpid();
386	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
387	ATF_REQUIRE_EQ(0, r);
388
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]),
393	    .rp_pids = info
394	    });
395	ATF_CHECK_EQ(0, r);
396	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
397
398	r = pipe(pipa);
399	ATF_REQUIRE_EQ(0, r);
400	r = pipe(pipb);
401	ATF_REQUIRE_EQ(0, r);
402	child = fork();
403	ATF_REQUIRE(child != -1);
404	if (child == 0) {
405		if (close(pipa[1]) != 0)
406			_exit(100);
407		if (close(pipb[0]) != 0)
408			_exit(100);
409		if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
410			_exit(101);
411		grandchild = fork();
412		if (grandchild == -1)
413			_exit(102);
414		if (grandchild == 0) {
415			if (write(pipb[1], &(uint8_t){ 0 }, 1) != 1)
416				_exit(103);
417			if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
418				_exit(104);
419			_exit(0);
420		}
421		for (;;)
422			pause();
423	}
424	r = close(pipa[0]);
425	ATF_REQUIRE_EQ(0, r);
426	r = close(pipb[1]);
427	ATF_REQUIRE_EQ(0, r);
428
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]),
433	    .rp_pids = info
434	    });
435	ATF_CHECK_EQ(0, r);
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);
441
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);
446
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]),
451	    .rp_pids = info
452	    });
453	ATF_CHECK_EQ(0, r);
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);
470
471	r = kill(child, SIGTERM);
472	ATF_REQUIRE_EQ(0, r);
473
474	pid = waitpid(child, &status, 0);
475	ATF_REQUIRE_EQ(child, pid);
476	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
477
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]),
482	    .rp_pids = info
483	    });
484	ATF_CHECK_EQ(0, r);
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);
492
493	sr = write(pipa[1], &(uint8_t){ 0 }, 1);
494	ATF_REQUIRE_EQ(1, sr);
495
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]),
500	    .rp_pids = info
501	    });
502	ATF_CHECK_EQ(0, r);
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);
510
511	pid = waitpid(grandchild, &status, 0);
512	ATF_REQUIRE_EQ(grandchild, pid);
513	ATF_CHECK_EQ(0, status);
514
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]),
519	    .rp_pids = info
520	    });
521	ATF_CHECK_EQ(0, r);
522	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
523
524	r = close(pipa[1]);
525	ATF_REQUIRE_EQ(0, r);
526	r = close(pipb[0]);
527	ATF_REQUIRE_EQ(0, r);
528}
529
530ATF_TC_WITHOUT_HEAD(reaper_kill_badsig);
531ATF_TC_BODY(reaper_kill_badsig, tc)
532{
533	struct procctl_reaper_kill params;
534	pid_t parent;
535	int r;
536
537	parent = getpid();
538	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
539	ATF_REQUIRE_EQ(0, r);
540
541	params.rk_sig = -1;
542	params.rk_flags = 0;
543	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
544	ATF_CHECK(r == -1 && errno == EINVAL);
545}
546
547ATF_TC_WITHOUT_HEAD(reaper_kill_sigzero);
548ATF_TC_BODY(reaper_kill_sigzero, tc)
549{
550	struct procctl_reaper_kill params;
551	pid_t parent;
552	int r;
553
554	parent = getpid();
555	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
556	ATF_REQUIRE_EQ(0, r);
557
558	params.rk_sig = 0;
559	params.rk_flags = 0;
560	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
561	ATF_CHECK(r == -1 && errno == EINVAL);
562}
563
564ATF_TC_WITHOUT_HEAD(reaper_kill_empty);
565ATF_TC_BODY(reaper_kill_empty, tc)
566{
567	struct procctl_reaper_kill params;
568	pid_t parent;
569	int r;
570
571	parent = getpid();
572	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
573	ATF_REQUIRE_EQ(0, r);
574
575	params.rk_sig = SIGTERM;
576	params.rk_flags = 0;
577	params.rk_killed = 77;
578	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
579	ATF_CHECK(r == -1 && errno == ESRCH);
580	ATF_CHECK_EQ(0, params.rk_killed);
581}
582
583ATF_TC_WITHOUT_HEAD(reaper_kill_normal);
584ATF_TC_BODY(reaper_kill_normal, tc)
585{
586	struct procctl_reaper_kill params;
587	ssize_t sr;
588	pid_t parent, child, grandchild, pid;
589	int r, status;
590	int pip[2];
591
592	parent = getpid();
593	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
594	ATF_REQUIRE_EQ(0, r);
595
596	r = pipe(pip);
597	ATF_REQUIRE_EQ(0, r);
598	child = fork();
599	ATF_REQUIRE(child != -1);
600	if (child == 0) {
601		if (close(pip[0]) != 0)
602			_exit(100);
603		grandchild = fork();
604		if (grandchild == -1)
605			_exit(101);
606		if (grandchild == 0) {
607			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
608				_exit(102);
609			for (;;)
610				pause();
611		}
612		for (;;)
613			pause();
614	}
615	r = close(pip[1]);
616	ATF_REQUIRE_EQ(0, r);
617
618	sr = read(pip[0], &(uint8_t){ 0 }, 1);
619	ATF_REQUIRE_EQ(1, sr);
620
621	params.rk_sig = SIGTERM;
622	params.rk_flags = 0;
623	params.rk_killed = 77;
624	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
625	ATF_CHECK_EQ(0, r);
626	ATF_CHECK_EQ(2, params.rk_killed);
627
628	pid = waitpid(child, &status, 0);
629	ATF_REQUIRE_EQ(child, pid);
630	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
631
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);
637
638	r = close(pip[0]);
639	ATF_REQUIRE_EQ(0, r);
640}
641
642ATF_TP_ADD_TCS(tp)
643{
644
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());
656}
657