11711b5ajilles/*-
21711b5ajilles * Copyright (c) 2016 Jilles Tjoelker
31711b5ajilles * All rights reserved.
41711b5ajilles *
51711b5ajilles * Redistribution and use in source and binary forms, with or without
61711b5ajilles * modification, are permitted provided that the following conditions
71711b5ajilles * are met:
81711b5ajilles * 1. Redistributions of source code must retain the above copyright
91711b5ajilles *    notice, this list of conditions and the following disclaimer.
101711b5ajilles * 2. Redistributions in binary form must reproduce the above copyright
111711b5ajilles *    notice, this list of conditions and the following disclaimer in the
121711b5ajilles *    documentation and/or other materials provided with the distribution.
131711b5ajilles *
141711b5ajilles * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151711b5ajilles * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161711b5ajilles * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171711b5ajilles * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181711b5ajilles * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191711b5ajilles * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201711b5ajilles * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211711b5ajilles * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221711b5ajilles * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231711b5ajilles * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241711b5ajilles * SUCH DAMAGE.
251711b5ajilles */
261711b5ajilles
271711b5ajilles#include <sys/cdefs.h>
281711b5ajilles__FBSDID("$FreeBSD$");
291711b5ajilles
301711b5ajilles#include <sys/procctl.h>
316ccc1b5markj#include <sys/procdesc.h>
321711b5ajilles#include <sys/wait.h>
331711b5ajilles
341711b5ajilles#include <atf-c.h>
351711b5ajilles#include <errno.h>
361711b5ajilles#include <signal.h>
371711b5ajilles#include <unistd.h>
381711b5ajilles
39598ba72jillesstatic void
40598ba72jillesdummy_sighandler(int sig __unused, siginfo_t *info __unused, void *ctx __unused)
41598ba72jilles{
42598ba72jilles}
43598ba72jilles
441711b5ajillesATF_TC_WITHOUT_HEAD(reaper_wait_child_first);
451711b5ajillesATF_TC_BODY(reaper_wait_child_first, tc)
461711b5ajilles{
471711b5ajilles	pid_t parent, child, grandchild, pid;
481711b5ajilles	int status, r;
491711b5ajilles	int pip[2];
501711b5ajilles
511711b5ajilles	/* Be paranoid. */
521711b5ajilles	pid = waitpid(-1, NULL, WNOHANG);
531711b5ajilles	ATF_REQUIRE(pid == -1 && errno == ECHILD);
541711b5ajilles
551711b5ajilles	parent = getpid();
561711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
571711b5ajilles	ATF_REQUIRE_EQ(0, r);
581711b5ajilles
591711b5ajilles	r = pipe(pip);
601711b5ajilles	ATF_REQUIRE_EQ(0, r);
611711b5ajilles
621711b5ajilles	child = fork();
631711b5ajilles	ATF_REQUIRE(child != -1);
641711b5ajilles	if (child == 0) {
651711b5ajilles		if (close(pip[1]) != 0)
661711b5ajilles			_exit(100);
671711b5ajilles		grandchild = fork();
681711b5ajilles		if (grandchild == -1)
691711b5ajilles			_exit(101);
701711b5ajilles		else if (grandchild == 0) {
711711b5ajilles			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
721711b5ajilles				_exit(102);
731711b5ajilles			if (getppid() != parent)
741711b5ajilles				_exit(103);
751711b5ajilles			_exit(2);
761711b5ajilles		} else
771711b5ajilles			_exit(3);
781711b5ajilles	}
791711b5ajilles
801711b5ajilles	pid = waitpid(child, &status, 0);
811711b5ajilles	ATF_REQUIRE_EQ(child, pid);
821711b5ajilles	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
831711b5ajilles	ATF_CHECK_EQ(3, r);
841711b5ajilles
851711b5ajilles	r = close(pip[1]);
861711b5ajilles	ATF_REQUIRE_EQ(0, r);
871711b5ajilles
881711b5ajilles	pid = waitpid(-1, &status, 0);
891711b5ajilles	ATF_REQUIRE(pid > 0 && pid != child);
901711b5ajilles	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
911711b5ajilles	ATF_CHECK_EQ(2, r);
921711b5ajilles
931711b5ajilles	r = close(pip[0]);
941711b5ajilles	ATF_REQUIRE_EQ(0, r);
951711b5ajilles}
961711b5ajilles
971711b5ajillesATF_TC_WITHOUT_HEAD(reaper_wait_grandchild_first);
981711b5ajillesATF_TC_BODY(reaper_wait_grandchild_first, tc)
991711b5ajilles{
1001711b5ajilles	pid_t parent, child, grandchild, pid;
1011711b5ajilles	int status, r;
1021711b5ajilles
1031711b5ajilles	/* Be paranoid. */
1041711b5ajilles	pid = waitpid(-1, NULL, WNOHANG);
1051711b5ajilles	ATF_REQUIRE(pid == -1 && errno == ECHILD);
1061711b5ajilles
1071711b5ajilles	parent = getpid();
1081711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
1091711b5ajilles	ATF_REQUIRE_EQ(0, r);
1101711b5ajilles
1111711b5ajilles	child = fork();
1121711b5ajilles	ATF_REQUIRE(child != -1);
1131711b5ajilles	if (child == 0) {
1141711b5ajilles		grandchild = fork();
1151711b5ajilles		if (grandchild == -1)
1161711b5ajilles			_exit(101);
1171711b5ajilles		else if (grandchild == 0)
1181711b5ajilles			_exit(2);
1191711b5ajilles		else {
1201711b5ajilles			if (waitid(P_PID, grandchild, NULL,
1211711b5ajilles			    WNOWAIT | WEXITED) != 0)
1221711b5ajilles				_exit(102);
1231711b5ajilles			_exit(3);
1241711b5ajilles		}
1251711b5ajilles	}
1261711b5ajilles
1271711b5ajilles	pid = waitpid(child, &status, 0);
1281711b5ajilles	ATF_REQUIRE_EQ(child, pid);
1291711b5ajilles	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1301711b5ajilles	ATF_CHECK_EQ(3, r);
1311711b5ajilles
1321711b5ajilles	pid = waitpid(-1, &status, 0);
1331711b5ajilles	ATF_REQUIRE(pid > 0 && pid != child);
1341711b5ajilles	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1351711b5ajilles	ATF_CHECK_EQ(2, r);
1361711b5ajilles}
1371711b5ajilles
138598ba72jillesATF_TC(reaper_sigchld_child_first);
139598ba72jillesATF_TC_HEAD(reaper_sigchld_child_first, tc)
140598ba72jilles{
141598ba72jilles	atf_tc_set_md_var(tc, "timeout", "2");
142598ba72jilles}
143598ba72jillesATF_TC_BODY(reaper_sigchld_child_first, tc)
144598ba72jilles{
145598ba72jilles	struct sigaction act;
146598ba72jilles	sigset_t mask;
147598ba72jilles	siginfo_t info;
148598ba72jilles	pid_t parent, child, grandchild, pid;
149598ba72jilles	int r;
150598ba72jilles	int pip[2];
151598ba72jilles
152598ba72jilles	/* Be paranoid. */
153598ba72jilles	pid = waitpid(-1, NULL, WNOHANG);
154598ba72jilles	ATF_REQUIRE(pid == -1 && errno == ECHILD);
155598ba72jilles
156598ba72jilles	act.sa_sigaction = dummy_sighandler;
157598ba72jilles	act.sa_flags = SA_SIGINFO | SA_RESTART;
158598ba72jilles	r = sigemptyset(&act.sa_mask);
159598ba72jilles	ATF_REQUIRE_EQ(0, r);
160598ba72jilles	r = sigaction(SIGCHLD, &act, NULL);
161598ba72jilles	ATF_REQUIRE_EQ(0, r);
162598ba72jilles
163598ba72jilles	r = sigemptyset(&mask);
164598ba72jilles	ATF_REQUIRE_EQ(0, r);
165598ba72jilles	r = sigaddset(&mask, SIGCHLD);
166598ba72jilles	ATF_REQUIRE_EQ(0, r);
167598ba72jilles	r = sigprocmask(SIG_BLOCK, &mask, NULL);
168598ba72jilles	ATF_REQUIRE_EQ(0, r);
169598ba72jilles
170598ba72jilles	parent = getpid();
171598ba72jilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
172598ba72jilles	ATF_REQUIRE_EQ(0, r);
173598ba72jilles
174598ba72jilles	r = pipe(pip);
175598ba72jilles	ATF_REQUIRE_EQ(0, r);
176598ba72jilles
177598ba72jilles	child = fork();
178598ba72jilles	ATF_REQUIRE(child != -1);
179598ba72jilles	if (child == 0) {
180598ba72jilles		if (close(pip[1]) != 0)
181598ba72jilles			_exit(100);
182598ba72jilles		grandchild = fork();
183598ba72jilles		if (grandchild == -1)
184598ba72jilles			_exit(101);
185598ba72jilles		else if (grandchild == 0) {
186598ba72jilles			if (read(pip[0], &(uint8_t){ 0 }, 1) != 0)
187598ba72jilles				_exit(102);
188598ba72jilles			if (getppid() != parent)
189598ba72jilles				_exit(103);
190598ba72jilles			_exit(2);
191598ba72jilles		} else
192598ba72jilles			_exit(3);
193598ba72jilles	}
194598ba72jilles
195598ba72jilles	r = sigwaitinfo(&mask, &info);
196598ba72jilles	ATF_REQUIRE_EQ(SIGCHLD, r);
197598ba72jilles	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
198598ba72jilles	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
199598ba72jilles	ATF_CHECK_EQ(3, info.si_status);
200598ba72jilles	ATF_CHECK_EQ(child, info.si_pid);
201598ba72jilles
202598ba72jilles	pid = waitpid(child, NULL, 0);
203598ba72jilles	ATF_REQUIRE_EQ(child, pid);
204598ba72jilles
205598ba72jilles	r = close(pip[1]);
206598ba72jilles	ATF_REQUIRE_EQ(0, r);
207598ba72jilles
208598ba72jilles	r = sigwaitinfo(&mask, &info);
209598ba72jilles	ATF_REQUIRE_EQ(SIGCHLD, r);
210598ba72jilles	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
211598ba72jilles	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
212598ba72jilles	ATF_CHECK_EQ(2, info.si_status);
213598ba72jilles	grandchild = info.si_pid;
214598ba72jilles	ATF_REQUIRE(grandchild > 0);
215598ba72jilles	ATF_REQUIRE(grandchild != parent);
216598ba72jilles	ATF_REQUIRE(grandchild != child);
217598ba72jilles
218598ba72jilles	pid = waitpid(-1, NULL, 0);
219598ba72jilles	ATF_REQUIRE_EQ(grandchild, pid);
220598ba72jilles
221598ba72jilles	r = close(pip[0]);
222598ba72jilles	ATF_REQUIRE_EQ(0, r);
223598ba72jilles}
224598ba72jilles
225598ba72jillesATF_TC(reaper_sigchld_grandchild_first);
226598ba72jillesATF_TC_HEAD(reaper_sigchld_grandchild_first, tc)
227598ba72jilles{
228598ba72jilles	atf_tc_set_md_var(tc, "timeout", "2");
229598ba72jilles}
230598ba72jillesATF_TC_BODY(reaper_sigchld_grandchild_first, tc)
231598ba72jilles{
232598ba72jilles	struct sigaction act;
233598ba72jilles	sigset_t mask;
234598ba72jilles	siginfo_t info;
235598ba72jilles	pid_t parent, child, grandchild, pid;
236598ba72jilles	int r;
237598ba72jilles
238598ba72jilles	/* Be paranoid. */
239598ba72jilles	pid = waitpid(-1, NULL, WNOHANG);
240598ba72jilles	ATF_REQUIRE(pid == -1 && errno == ECHILD);
241598ba72jilles
242598ba72jilles	act.sa_sigaction = dummy_sighandler;
243598ba72jilles	act.sa_flags = SA_SIGINFO | SA_RESTART;
244598ba72jilles	r = sigemptyset(&act.sa_mask);
245598ba72jilles	ATF_REQUIRE_EQ(0, r);
246598ba72jilles	r = sigaction(SIGCHLD, &act, NULL);
247598ba72jilles	ATF_REQUIRE_EQ(0, r);
248598ba72jilles
249598ba72jilles	r = sigemptyset(&mask);
250598ba72jilles	ATF_REQUIRE_EQ(0, r);
251598ba72jilles	r = sigaddset(&mask, SIGCHLD);
252598ba72jilles	ATF_REQUIRE_EQ(0, r);
253598ba72jilles	r = sigprocmask(SIG_BLOCK, &mask, NULL);
254598ba72jilles	ATF_REQUIRE_EQ(0, r);
255598ba72jilles
256598ba72jilles	parent = getpid();
257598ba72jilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
258598ba72jilles	ATF_REQUIRE_EQ(0, r);
259598ba72jilles
260598ba72jilles	child = fork();
261598ba72jilles	ATF_REQUIRE(child != -1);
262598ba72jilles	if (child == 0) {
263598ba72jilles		grandchild = fork();
264598ba72jilles		if (grandchild == -1)
265598ba72jilles			_exit(101);
266598ba72jilles		else if (grandchild == 0)
267598ba72jilles			_exit(2);
268598ba72jilles		else {
269598ba72jilles			if (waitid(P_PID, grandchild, NULL,
270598ba72jilles			    WNOWAIT | WEXITED) != 0)
271598ba72jilles				_exit(102);
272598ba72jilles			_exit(3);
273598ba72jilles		}
274598ba72jilles	}
275598ba72jilles
276598ba72jilles	pid = waitpid(child, NULL, 0);
277598ba72jilles	ATF_REQUIRE_EQ(child, pid);
278598ba72jilles
279598ba72jilles	r = sigwaitinfo(&mask, &info);
280598ba72jilles	ATF_REQUIRE_EQ(SIGCHLD, r);
281598ba72jilles	ATF_CHECK_EQ(SIGCHLD, info.si_signo);
282598ba72jilles	ATF_CHECK_EQ(CLD_EXITED, info.si_code);
283598ba72jilles	ATF_CHECK_EQ(2, info.si_status);
284598ba72jilles	grandchild = info.si_pid;
285598ba72jilles	ATF_REQUIRE(grandchild > 0);
286598ba72jilles	ATF_REQUIRE(grandchild != parent);
287598ba72jilles	ATF_REQUIRE(grandchild != child);
288598ba72jilles
289598ba72jilles	pid = waitpid(-1, NULL, 0);
290598ba72jilles	ATF_REQUIRE_EQ(grandchild, pid);
291598ba72jilles}
292598ba72jilles
2931711b5ajillesATF_TC_WITHOUT_HEAD(reaper_status);
2941711b5ajillesATF_TC_BODY(reaper_status, tc)
2951711b5ajilles{
2961711b5ajilles	struct procctl_reaper_status st;
2971711b5ajilles	ssize_t sr;
2981711b5ajilles	pid_t parent, child, pid;
2991711b5ajilles	int r, status;
3001711b5ajilles	int pip[2];
3011711b5ajilles
3021711b5ajilles	parent = getpid();
3031711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
3041711b5ajilles	ATF_REQUIRE_EQ(0, r);
3051711b5ajilles	ATF_CHECK_EQ(0, st.rs_flags & REAPER_STATUS_OWNED);
3061711b5ajilles	ATF_CHECK(st.rs_children > 0);
3071711b5ajilles	ATF_CHECK(st.rs_descendants > 0);
3081711b5ajilles	ATF_CHECK(st.rs_descendants >= st.rs_children);
3091711b5ajilles	ATF_CHECK(st.rs_reaper != parent);
3101711b5ajilles	ATF_CHECK(st.rs_reaper > 0);
3111711b5ajilles
3121711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
3131711b5ajilles	ATF_REQUIRE_EQ(0, r);
3141711b5ajilles
3151711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
3161711b5ajilles	ATF_REQUIRE_EQ(0, r);
3171711b5ajilles	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
3181711b5ajilles	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
3191711b5ajilles	ATF_CHECK_EQ(0, st.rs_children);
3201711b5ajilles	ATF_CHECK_EQ(0, st.rs_descendants);
3211711b5ajilles	ATF_CHECK(st.rs_reaper == parent);
3221711b5ajilles	ATF_CHECK_EQ(-1, st.rs_pid);
3231711b5ajilles
3241711b5ajilles	r = pipe(pip);
3251711b5ajilles	ATF_REQUIRE_EQ(0, r);
3261711b5ajilles	child = fork();
3271711b5ajilles	ATF_REQUIRE(child != -1);
3281711b5ajilles	if (child == 0) {
3291711b5ajilles		if (close(pip[0]) != 0)
3301711b5ajilles			_exit(100);
3311711b5ajilles		if (procctl(P_PID, parent, PROC_REAP_STATUS, &st) != 0)
3321711b5ajilles			_exit(101);
3331711b5ajilles		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
3341711b5ajilles			_exit(102);
3351711b5ajilles		if (procctl(P_PID, getpid(), PROC_REAP_STATUS, &st) != 0)
3361711b5ajilles			_exit(103);
3371711b5ajilles		if (write(pip[1], &st, sizeof(st)) != (ssize_t)sizeof(st))
3381711b5ajilles			_exit(104);
3391711b5ajilles		_exit(0);
3401711b5ajilles	}
3411711b5ajilles	r = close(pip[1]);
3421711b5ajilles	ATF_REQUIRE_EQ(0, r);
3431711b5ajilles
3441711b5ajilles	sr = read(pip[0], &st, sizeof(st));
3451711b5ajilles	ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
3461711b5ajilles	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
3471711b5ajilles	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
3481711b5ajilles	ATF_CHECK_EQ(1, st.rs_children);
3491711b5ajilles	ATF_CHECK_EQ(1, st.rs_descendants);
3501711b5ajilles	ATF_CHECK(st.rs_reaper == parent);
3511711b5ajilles	ATF_CHECK_EQ(child, st.rs_pid);
3521711b5ajilles	sr = read(pip[0], &st, sizeof(st));
3531711b5ajilles	ATF_REQUIRE_EQ((ssize_t)sizeof(st), sr);
3541711b5ajilles	ATF_CHECK_EQ(0,
3551711b5ajilles	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
3561711b5ajilles	ATF_CHECK_EQ(1, st.rs_children);
3571711b5ajilles	ATF_CHECK_EQ(1, st.rs_descendants);
3581711b5ajilles	ATF_CHECK(st.rs_reaper == parent);
3591711b5ajilles	ATF_CHECK_EQ(child, st.rs_pid);
3601711b5ajilles
3611711b5ajilles	r = close(pip[0]);
3621711b5ajilles	ATF_REQUIRE_EQ(0, r);
3631711b5ajilles	pid = waitpid(child, &status, 0);
3641711b5ajilles	ATF_REQUIRE_EQ(child, pid);
3651711b5ajilles	ATF_CHECK_EQ(0, status);
3661711b5ajilles
3671711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
3681711b5ajilles	ATF_REQUIRE_EQ(0, r);
3691711b5ajilles	ATF_CHECK_EQ(REAPER_STATUS_OWNED,
3701711b5ajilles	    st.rs_flags & (REAPER_STATUS_OWNED | REAPER_STATUS_REALINIT));
3711711b5ajilles	ATF_CHECK_EQ(0, st.rs_children);
3721711b5ajilles	ATF_CHECK_EQ(0, st.rs_descendants);
3731711b5ajilles	ATF_CHECK(st.rs_reaper == parent);
3741711b5ajilles	ATF_CHECK_EQ(-1, st.rs_pid);
3751711b5ajilles}
3761711b5ajilles
3771711b5ajillesATF_TC_WITHOUT_HEAD(reaper_getpids);
3781711b5ajillesATF_TC_BODY(reaper_getpids, tc)
3791711b5ajilles{
3801711b5ajilles	struct procctl_reaper_pidinfo info[10];
3811711b5ajilles	ssize_t sr;
3821711b5ajilles	pid_t parent, child, grandchild, pid;
3831711b5ajilles	int r, status, childidx;
3841711b5ajilles	int pipa[2], pipb[2];
3851711b5ajilles
3861711b5ajilles	parent = getpid();
3871711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
3881711b5ajilles	ATF_REQUIRE_EQ(0, r);
3891711b5ajilles
3901711b5ajilles	memset(info, '\0', sizeof(info));
3911711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
3921711b5ajilles	    &(struct procctl_reaper_pids){
3931711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
3941711b5ajilles	    .rp_pids = info
3951711b5ajilles	    });
3961711b5ajilles	ATF_CHECK_EQ(0, r);
3971711b5ajilles	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
3981711b5ajilles
3991711b5ajilles	r = pipe(pipa);
4001711b5ajilles	ATF_REQUIRE_EQ(0, r);
4011711b5ajilles	r = pipe(pipb);
4021711b5ajilles	ATF_REQUIRE_EQ(0, r);
4031711b5ajilles	child = fork();
4041711b5ajilles	ATF_REQUIRE(child != -1);
4051711b5ajilles	if (child == 0) {
4061711b5ajilles		if (close(pipa[1]) != 0)
4071711b5ajilles			_exit(100);
4081711b5ajilles		if (close(pipb[0]) != 0)
4091711b5ajilles			_exit(100);
4101711b5ajilles		if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
4111711b5ajilles			_exit(101);
4121711b5ajilles		grandchild = fork();
4131711b5ajilles		if (grandchild == -1)
4141711b5ajilles			_exit(102);
4151711b5ajilles		if (grandchild == 0) {
4161711b5ajilles			if (write(pipb[1], &(uint8_t){ 0 }, 1) != 1)
4171711b5ajilles				_exit(103);
4181711b5ajilles			if (read(pipa[0], &(uint8_t){ 0 }, 1) != 1)
4191711b5ajilles				_exit(104);
4201711b5ajilles			_exit(0);
4211711b5ajilles		}
4221711b5ajilles		for (;;)
4231711b5ajilles			pause();
4241711b5ajilles	}
4251711b5ajilles	r = close(pipa[0]);
4261711b5ajilles	ATF_REQUIRE_EQ(0, r);
4271711b5ajilles	r = close(pipb[1]);
4281711b5ajilles	ATF_REQUIRE_EQ(0, r);
4291711b5ajilles
4301711b5ajilles	memset(info, '\0', sizeof(info));
4311711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
4321711b5ajilles	    &(struct procctl_reaper_pids){
4331711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
4341711b5ajilles	    .rp_pids = info
4351711b5ajilles	    });
4361711b5ajilles	ATF_CHECK_EQ(0, r);
4371711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD,
4381711b5ajilles	    info[0].pi_flags & (REAPER_PIDINFO_VALID | REAPER_PIDINFO_CHILD));
4391711b5ajilles	ATF_CHECK_EQ(child, info[0].pi_pid);
4401711b5ajilles	ATF_CHECK_EQ(child, info[0].pi_subtree);
4411711b5ajilles	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
4421711b5ajilles
4431711b5ajilles	sr = write(pipa[1], &(uint8_t){ 0 }, 1);
4441711b5ajilles	ATF_REQUIRE_EQ(1, sr);
4451711b5ajilles	sr = read(pipb[0], &(uint8_t){ 0 }, 1);
4461711b5ajilles	ATF_REQUIRE_EQ(1, sr);
4471711b5ajilles
4481711b5ajilles	memset(info, '\0', sizeof(info));
4491711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
4501711b5ajilles	    &(struct procctl_reaper_pids){
4511711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
4521711b5ajilles	    .rp_pids = info
4531711b5ajilles	    });
4541711b5ajilles	ATF_CHECK_EQ(0, r);
4551711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
4561711b5ajilles	    info[0].pi_flags & REAPER_PIDINFO_VALID);
4571711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
4581711b5ajilles	    info[1].pi_flags & REAPER_PIDINFO_VALID);
4591711b5ajilles	ATF_CHECK_EQ(0, info[2].pi_flags & REAPER_PIDINFO_VALID);
4601711b5ajilles	ATF_CHECK_EQ(child, info[0].pi_subtree);
4611711b5ajilles	ATF_CHECK_EQ(child, info[1].pi_subtree);
4621711b5ajilles	childidx = info[1].pi_pid == child ? 1 : 0;
4631711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
4641711b5ajilles	    info[childidx].pi_flags & REAPER_PIDINFO_CHILD);
4651711b5ajilles	ATF_CHECK_EQ(0, info[childidx ^ 1].pi_flags & REAPER_PIDINFO_CHILD);
4661711b5ajilles	ATF_CHECK(info[childidx].pi_pid == child);
4671711b5ajilles	grandchild = info[childidx ^ 1].pi_pid;
4681711b5ajilles	ATF_CHECK(grandchild > 0);
4691711b5ajilles	ATF_CHECK(grandchild != child);
4701711b5ajilles	ATF_CHECK(grandchild != parent);
4711711b5ajilles
4721711b5ajilles	r = kill(child, SIGTERM);
4731711b5ajilles	ATF_REQUIRE_EQ(0, r);
4741711b5ajilles
4751711b5ajilles	pid = waitpid(child, &status, 0);
4761711b5ajilles	ATF_REQUIRE_EQ(child, pid);
4771711b5ajilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
4781711b5ajilles
4791711b5ajilles	memset(info, '\0', sizeof(info));
4801711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
4811711b5ajilles	    &(struct procctl_reaper_pids){
4821711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
4831711b5ajilles	    .rp_pids = info
4841711b5ajilles	    });
4851711b5ajilles	ATF_CHECK_EQ(0, r);
4861711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
4871711b5ajilles	    info[0].pi_flags & REAPER_PIDINFO_VALID);
4881711b5ajilles	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
4891711b5ajilles	ATF_CHECK_EQ(child, info[0].pi_subtree);
4901711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
4911711b5ajilles	    info[0].pi_flags & REAPER_PIDINFO_CHILD);
4921711b5ajilles	ATF_CHECK_EQ(grandchild, info[0].pi_pid);
4931711b5ajilles
4941711b5ajilles	sr = write(pipa[1], &(uint8_t){ 0 }, 1);
4951711b5ajilles	ATF_REQUIRE_EQ(1, sr);
4961711b5ajilles
4971711b5ajilles	memset(info, '\0', sizeof(info));
4981711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
4991711b5ajilles	    &(struct procctl_reaper_pids){
5001711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
5011711b5ajilles	    .rp_pids = info
5021711b5ajilles	    });
5031711b5ajilles	ATF_CHECK_EQ(0, r);
5041711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_VALID,
5051711b5ajilles	    info[0].pi_flags & REAPER_PIDINFO_VALID);
5061711b5ajilles	ATF_CHECK_EQ(0, info[1].pi_flags & REAPER_PIDINFO_VALID);
5071711b5ajilles	ATF_CHECK_EQ(child, info[0].pi_subtree);
5081711b5ajilles	ATF_CHECK_EQ(REAPER_PIDINFO_CHILD,
5091711b5ajilles	    info[0].pi_flags & REAPER_PIDINFO_CHILD);
5101711b5ajilles	ATF_CHECK_EQ(grandchild, info[0].pi_pid);
5111711b5ajilles
5121711b5ajilles	pid = waitpid(grandchild, &status, 0);
5131711b5ajilles	ATF_REQUIRE_EQ(grandchild, pid);
5141711b5ajilles	ATF_CHECK_EQ(0, status);
5151711b5ajilles
5161711b5ajilles	memset(info, '\0', sizeof(info));
5171711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_GETPIDS,
5181711b5ajilles	    &(struct procctl_reaper_pids){
5191711b5ajilles	    .rp_count = sizeof(info) / sizeof(info[0]),
5201711b5ajilles	    .rp_pids = info
5211711b5ajilles	    });
5221711b5ajilles	ATF_CHECK_EQ(0, r);
5231711b5ajilles	ATF_CHECK_EQ(0, info[0].pi_flags & REAPER_PIDINFO_VALID);
5241711b5ajilles
5251711b5ajilles	r = close(pipa[1]);
5261711b5ajilles	ATF_REQUIRE_EQ(0, r);
5271711b5ajilles	r = close(pipb[0]);
5281711b5ajilles	ATF_REQUIRE_EQ(0, r);
5291711b5ajilles}
5301711b5ajilles
5311711b5ajillesATF_TC_WITHOUT_HEAD(reaper_kill_badsig);
5321711b5ajillesATF_TC_BODY(reaper_kill_badsig, tc)
5331711b5ajilles{
5341711b5ajilles	struct procctl_reaper_kill params;
5351711b5ajilles	pid_t parent;
5361711b5ajilles	int r;
5371711b5ajilles
5381711b5ajilles	parent = getpid();
5391711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
5401711b5ajilles	ATF_REQUIRE_EQ(0, r);
5411711b5ajilles
5421711b5ajilles	params.rk_sig = -1;
5431711b5ajilles	params.rk_flags = 0;
5441711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
5451711b5ajilles	ATF_CHECK(r == -1 && errno == EINVAL);
5461711b5ajilles}
5471711b5ajilles
5481711b5ajillesATF_TC_WITHOUT_HEAD(reaper_kill_sigzero);
5491711b5ajillesATF_TC_BODY(reaper_kill_sigzero, tc)
5501711b5ajilles{
5511711b5ajilles	struct procctl_reaper_kill params;
5521711b5ajilles	pid_t parent;
5531711b5ajilles	int r;
5541711b5ajilles
5551711b5ajilles	parent = getpid();
5561711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
5571711b5ajilles	ATF_REQUIRE_EQ(0, r);
5581711b5ajilles
5591711b5ajilles	params.rk_sig = 0;
5601711b5ajilles	params.rk_flags = 0;
5611711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
5621711b5ajilles	ATF_CHECK(r == -1 && errno == EINVAL);
5631711b5ajilles}
5641711b5ajilles
5651711b5ajillesATF_TC_WITHOUT_HEAD(reaper_kill_empty);
5661711b5ajillesATF_TC_BODY(reaper_kill_empty, tc)
5671711b5ajilles{
5681711b5ajilles	struct procctl_reaper_kill params;
5691711b5ajilles	pid_t parent;
5701711b5ajilles	int r;
5711711b5ajilles
5721711b5ajilles	parent = getpid();
5731711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
5741711b5ajilles	ATF_REQUIRE_EQ(0, r);
5751711b5ajilles
5761711b5ajilles	params.rk_sig = SIGTERM;
5771711b5ajilles	params.rk_flags = 0;
5781711b5ajilles	params.rk_killed = 77;
5791711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
5801711b5ajilles	ATF_CHECK(r == -1 && errno == ESRCH);
5811711b5ajilles	ATF_CHECK_EQ(0, params.rk_killed);
5821711b5ajilles}
5831711b5ajilles
5841711b5ajillesATF_TC_WITHOUT_HEAD(reaper_kill_normal);
5851711b5ajillesATF_TC_BODY(reaper_kill_normal, tc)
5861711b5ajilles{
5871711b5ajilles	struct procctl_reaper_kill params;
5881711b5ajilles	ssize_t sr;
5891711b5ajilles	pid_t parent, child, grandchild, pid;
5901711b5ajilles	int r, status;
5911711b5ajilles	int pip[2];
5921711b5ajilles
5931711b5ajilles	parent = getpid();
5941711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
5951711b5ajilles	ATF_REQUIRE_EQ(0, r);
5961711b5ajilles
5971711b5ajilles	r = pipe(pip);
5981711b5ajilles	ATF_REQUIRE_EQ(0, r);
5991711b5ajilles	child = fork();
6001711b5ajilles	ATF_REQUIRE(child != -1);
6011711b5ajilles	if (child == 0) {
6021711b5ajilles		if (close(pip[0]) != 0)
6031711b5ajilles			_exit(100);
6041711b5ajilles		grandchild = fork();
6051711b5ajilles		if (grandchild == -1)
6061711b5ajilles			_exit(101);
6071711b5ajilles		if (grandchild == 0) {
6081711b5ajilles			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
6091711b5ajilles				_exit(102);
6101711b5ajilles			for (;;)
6111711b5ajilles				pause();
6121711b5ajilles		}
6131711b5ajilles		for (;;)
6141711b5ajilles			pause();
6151711b5ajilles	}
6161711b5ajilles	r = close(pip[1]);
6171711b5ajilles	ATF_REQUIRE_EQ(0, r);
6181711b5ajilles
6191711b5ajilles	sr = read(pip[0], &(uint8_t){ 0 }, 1);
6201711b5ajilles	ATF_REQUIRE_EQ(1, sr);
6211711b5ajilles
6221711b5ajilles	params.rk_sig = SIGTERM;
6231711b5ajilles	params.rk_flags = 0;
6241711b5ajilles	params.rk_killed = 77;
6251711b5ajilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
6261711b5ajilles	ATF_CHECK_EQ(0, r);
6271711b5ajilles	ATF_CHECK_EQ(2, params.rk_killed);
6281711b5ajilles
6291711b5ajilles	pid = waitpid(child, &status, 0);
6301711b5ajilles	ATF_REQUIRE_EQ(child, pid);
6311711b5ajilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
6321711b5ajilles
6331711b5ajilles	pid = waitpid(-1, &status, 0);
6341711b5ajilles	ATF_REQUIRE(pid > 0);
6351711b5ajilles	ATF_CHECK(pid != parent);
6361711b5ajilles	ATF_CHECK(pid != child);
6371711b5ajilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM);
6381711b5ajilles
6391711b5ajilles	r = close(pip[0]);
6401711b5ajilles	ATF_REQUIRE_EQ(0, r);
6411711b5ajilles}
6421711b5ajilles
643ea79716jillesATF_TC_WITHOUT_HEAD(reaper_kill_subtree);
644ea79716jillesATF_TC_BODY(reaper_kill_subtree, tc)
645ea79716jilles{
646ea79716jilles	struct procctl_reaper_kill params;
647ea79716jilles	ssize_t sr;
648ea79716jilles	pid_t parent, child1, child2, grandchild1, grandchild2, pid;
649ea79716jilles	int r, status;
650ea79716jilles	int pip[2];
651ea79716jilles
652ea79716jilles	parent = getpid();
653ea79716jilles	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
654ea79716jilles	ATF_REQUIRE_EQ(0, r);
655ea79716jilles
656ea79716jilles	r = pipe(pip);
657ea79716jilles	ATF_REQUIRE_EQ(0, r);
658ea79716jilles	child1 = fork();
659ea79716jilles	ATF_REQUIRE(child1 != -1);
660ea79716jilles	if (child1 == 0) {
661ea79716jilles		if (close(pip[0]) != 0)
662ea79716jilles			_exit(100);
663ea79716jilles		grandchild1 = fork();
664ea79716jilles		if (grandchild1 == -1)
665ea79716jilles			_exit(101);
666ea79716jilles		if (grandchild1 == 0) {
667ea79716jilles			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
668ea79716jilles				_exit(102);
669ea79716jilles			for (;;)
670ea79716jilles				pause();
671ea79716jilles		}
672ea79716jilles		for (;;)
673ea79716jilles			pause();
674ea79716jilles	}
675ea79716jilles	child2 = fork();
676ea79716jilles	ATF_REQUIRE(child2 != -1);
677ea79716jilles	if (child2 == 0) {
678ea79716jilles		if (close(pip[0]) != 0)
679ea79716jilles			_exit(100);
680ea79716jilles		grandchild2 = fork();
681ea79716jilles		if (grandchild2 == -1)
682ea79716jilles			_exit(101);
683ea79716jilles		if (grandchild2 == 0) {
684ea79716jilles			if (write(pip[1], &(uint8_t){ 0 }, 1) != 1)
685ea79716jilles				_exit(102);
686ea79716jilles			for (;;)
687ea79716jilles				pause();
688ea79716jilles		}
689ea79716jilles		for (;;)
690ea79716jilles			pause();
691ea79716jilles	}
692ea79716jilles	r = close(pip[1]);
693ea79716jilles	ATF_REQUIRE_EQ(0, r);
694ea79716jilles
695ea79716jilles	sr = read(pip[0], &(uint8_t){ 0 }, 1);
696ea79716jilles	ATF_REQUIRE_EQ(1, sr);
697ea79716jilles	sr = read(pip[0], &(uint8_t){ 0 }, 1);
698ea79716jilles	ATF_REQUIRE_EQ(1, sr);
699ea79716jilles
700ea79716jilles	params.rk_sig = SIGUSR1;
701ea79716jilles	params.rk_flags = REAPER_KILL_SUBTREE;
702ea79716jilles	params.rk_subtree = child1;
703ea79716jilles	params.rk_killed = 77;
704ea79716jilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
705ea79716jilles	ATF_REQUIRE_EQ(0, r);
706ea79716jilles	ATF_REQUIRE_EQ(2, params.rk_killed);
707ea79716jilles	ATF_CHECK_EQ(-1, params.rk_fpid);
708ea79716jilles
709ea79716jilles	pid = waitpid(child1, &status, 0);
710ea79716jilles	ATF_REQUIRE_EQ(child1, pid);
711ea79716jilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR1);
712ea79716jilles
713ea79716jilles	pid = waitpid(-1, &status, 0);
714ea79716jilles	ATF_REQUIRE(pid > 0);
715ea79716jilles	ATF_CHECK(pid != parent);
716ea79716jilles	ATF_CHECK(pid != child1);
717ea79716jilles	ATF_CHECK(pid != child2);
718ea79716jilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR1);
719ea79716jilles
720ea79716jilles	params.rk_sig = SIGUSR2;
721ea79716jilles	params.rk_flags = REAPER_KILL_SUBTREE;
722ea79716jilles	params.rk_subtree = child2;
723ea79716jilles	params.rk_killed = 77;
724ea79716jilles	r = procctl(P_PID, parent, PROC_REAP_KILL, &params);
725ea79716jilles	ATF_REQUIRE_EQ(0, r);
726ea79716jilles	ATF_REQUIRE_EQ(2, params.rk_killed);
727ea79716jilles	ATF_CHECK_EQ(-1, params.rk_fpid);
728ea79716jilles
729ea79716jilles	pid = waitpid(child2, &status, 0);
730ea79716jilles	ATF_REQUIRE_EQ(child2, pid);
731ea79716jilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR2);
732ea79716jilles
733ea79716jilles	pid = waitpid(-1, &status, 0);
734ea79716jilles	ATF_REQUIRE(pid > 0);
735ea79716jilles	ATF_CHECK(pid != parent);
736ea79716jilles	ATF_CHECK(pid != child1);
737ea79716jilles	ATF_CHECK(pid != child2);
738ea79716jilles	ATF_CHECK(WIFSIGNALED(status) && WTERMSIG(status) == SIGUSR2);
739ea79716jilles
740ea79716jilles	r = close(pip[0]);
741ea79716jilles	ATF_REQUIRE_EQ(0, r);
742ea79716jilles}
743ea79716jilles
7446ccc1b5markjATF_TC_WITHOUT_HEAD(reaper_pdfork);
7456ccc1b5markjATF_TC_BODY(reaper_pdfork, tc)
7466ccc1b5markj{
7476ccc1b5markj	struct procctl_reaper_status st;
7486ccc1b5markj	pid_t child, grandchild, parent, pid;
7496ccc1b5markj	int pd, r, status;
7506ccc1b5markj
7516ccc1b5markj	parent = getpid();
7526ccc1b5markj	r = procctl(P_PID, parent, PROC_REAP_ACQUIRE, NULL);
7536ccc1b5markj	ATF_REQUIRE_EQ(r, 0);
7546ccc1b5markj
7556ccc1b5markj	child = pdfork(&pd, 0);
7566ccc1b5markj	ATF_REQUIRE(child != -1);
7576ccc1b5markj	if (child == 0) {
7586ccc1b5markj		grandchild = pdfork(&pd, 0);
7596ccc1b5markj		if (grandchild == -1)
7606ccc1b5markj			_exit(1);
7616ccc1b5markj		if (grandchild == 0)
7626ccc1b5markj			pause();
7636ccc1b5markj		_exit(0);
7646ccc1b5markj	}
7656ccc1b5markj	pid = waitpid(child, &status, 0);
7666ccc1b5markj	ATF_REQUIRE_EQ(pid, child);
7676ccc1b5markj	r = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
7686ccc1b5markj	ATF_REQUIRE_EQ(r, 0);
7696ccc1b5markj
7706ccc1b5markj	r = procctl(P_PID, parent, PROC_REAP_STATUS, &st);
7716ccc1b5markj	ATF_REQUIRE_EQ(r, 0);
7726ccc1b5markj	ATF_CHECK((st.rs_flags & REAPER_STATUS_OWNED) != 0);
7736ccc1b5markj	ATF_CHECK(st.rs_reaper == parent);
7746ccc1b5markj	ATF_CHECK(st.rs_children == 1);
7756ccc1b5markj	ATF_CHECK(st.rs_descendants == 1);
7766ccc1b5markj}
7776ccc1b5markj
7781711b5ajillesATF_TP_ADD_TCS(tp)
7791711b5ajilles{
7801711b5ajilles
7811711b5ajilles	ATF_TP_ADD_TC(tp, reaper_wait_child_first);
7821711b5ajilles	ATF_TP_ADD_TC(tp, reaper_wait_grandchild_first);
783598ba72jilles	ATF_TP_ADD_TC(tp, reaper_sigchld_child_first);
784598ba72jilles	ATF_TP_ADD_TC(tp, reaper_sigchld_grandchild_first);
7851711b5ajilles	ATF_TP_ADD_TC(tp, reaper_status);
7861711b5ajilles	ATF_TP_ADD_TC(tp, reaper_getpids);
7871711b5ajilles	ATF_TP_ADD_TC(tp, reaper_kill_badsig);
7881711b5ajilles	ATF_TP_ADD_TC(tp, reaper_kill_sigzero);
7891711b5ajilles	ATF_TP_ADD_TC(tp, reaper_kill_empty);
7901711b5ajilles	ATF_TP_ADD_TC(tp, reaper_kill_normal);
791ea79716jilles	ATF_TP_ADD_TC(tp, reaper_kill_subtree);
7926ccc1b5markj	ATF_TP_ADD_TC(tp, reaper_pdfork);
7931711b5ajilles	return (atf_no_error());
7941711b5ajilles}
795