xref: /openbsd-src/regress/lib/libc/sys/t_fork.c (revision 49a6e16f2c2c8e509184b1f777366d1a6f337e1c)
1*49a6e16fSderaadt /*	$OpenBSD: t_fork.c,v 1.5 2021/12/13 16:56:48 deraadt Exp $	*/
2abbaa274Smbuhl /*	$NetBSD: t_fork.c,v 1.4 2019/04/06 15:41:54 kamil Exp $	*/
3abbaa274Smbuhl 
4abbaa274Smbuhl /*-
5abbaa274Smbuhl  * Copyright (c) 2018, 2019 The NetBSD Foundation, Inc.
6abbaa274Smbuhl  * All rights reserved.
7abbaa274Smbuhl  *
8abbaa274Smbuhl  * Redistribution and use in source and binary forms, with or without
9abbaa274Smbuhl  * modification, are permitted provided that the following conditions
10abbaa274Smbuhl  * are met:
11abbaa274Smbuhl  * 1. Redistributions of source code must retain the above copyright
12abbaa274Smbuhl  *    notice, this list of conditions and the following disclaimer.
13abbaa274Smbuhl  * 2. Redistributions in binary form must reproduce the above copyright
14abbaa274Smbuhl  *    notice, this list of conditions and the following disclaimer in the
15abbaa274Smbuhl  *    documentation and/or other materials provided with the distribution.
16abbaa274Smbuhl  *
17abbaa274Smbuhl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18abbaa274Smbuhl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19abbaa274Smbuhl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20abbaa274Smbuhl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21abbaa274Smbuhl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22abbaa274Smbuhl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23abbaa274Smbuhl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24abbaa274Smbuhl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25abbaa274Smbuhl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26abbaa274Smbuhl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27abbaa274Smbuhl  * POSSIBILITY OF SUCH DAMAGE.
28abbaa274Smbuhl  */
29abbaa274Smbuhl #include "macros.h"
30abbaa274Smbuhl 
31*49a6e16fSderaadt #include <sys/types.h>
32*49a6e16fSderaadt #include <sys/signal.h>
33c32913b7Smbuhl #ifdef __OpenBSD__
34c32913b7Smbuhl #include <sys/proc.h>
35c32913b7Smbuhl #endif
36abbaa274Smbuhl #include <sys/sysctl.h>
37abbaa274Smbuhl #include <sys/wait.h>
38abbaa274Smbuhl #include <sched.h>
39abbaa274Smbuhl #include <signal.h>
40abbaa274Smbuhl #include <stdbool.h>
41abbaa274Smbuhl #include <stdlib.h>
42abbaa274Smbuhl #include <unistd.h>
43abbaa274Smbuhl #include <err.h>
44abbaa274Smbuhl #include <errno.h>
45abbaa274Smbuhl 
46abbaa274Smbuhl #include "atf-c.h"
47abbaa274Smbuhl 
48abbaa274Smbuhl #ifdef VFORK
49abbaa274Smbuhl #define FORK vfork
50abbaa274Smbuhl #else
51abbaa274Smbuhl #define FORK fork
52abbaa274Smbuhl #endif
53abbaa274Smbuhl 
54abbaa274Smbuhl /*
55abbaa274Smbuhl  * A child process cannot call atf functions and expect them to magically
56abbaa274Smbuhl  * work like in the parent.
57abbaa274Smbuhl  * The printf(3) messaging from a child will not work out of the box as well
58abbaa274Smbuhl  * without estabilishing a communication protocol with its parent. To not
59abbaa274Smbuhl  * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
60abbaa274Smbuhl  * wrapped with ASSERT_EQ()/ASSERT_NEQ() as that is guaranteed to work.
61abbaa274Smbuhl  */
62abbaa274Smbuhl #define ASSERT_EQ(x, y)								\
63abbaa274Smbuhl do {										\
64abbaa274Smbuhl 	uintmax_t vx = (x);							\
65abbaa274Smbuhl 	uintmax_t vy = (y);							\
66abbaa274Smbuhl 	int ret = vx == vy;							\
67abbaa274Smbuhl 	if (!ret)								\
68abbaa274Smbuhl 		errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "		\
69abbaa274Smbuhl 		    "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__,		\
70abbaa274Smbuhl 		    #x, vx, #y, vy);						\
71abbaa274Smbuhl } while (/*CONSTCOND*/0)
72abbaa274Smbuhl 
73abbaa274Smbuhl #define ASSERT_NEQ(x, y)							\
74abbaa274Smbuhl do {										\
75abbaa274Smbuhl 	uintmax_t vx = (x);							\
76abbaa274Smbuhl 	uintmax_t vy = (y);							\
77abbaa274Smbuhl 	int ret = vx != vy;							\
78abbaa274Smbuhl 	if (!ret)								\
79abbaa274Smbuhl 		errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: "		\
80abbaa274Smbuhl 		    "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__,		\
81abbaa274Smbuhl 		    #x, vx, #y, vy);						\
82abbaa274Smbuhl } while (/*CONSTCOND*/0)
83abbaa274Smbuhl 
84abbaa274Smbuhl static pid_t
await_stopped_child(pid_t process)85abbaa274Smbuhl await_stopped_child(pid_t process)
86abbaa274Smbuhl {
87abbaa274Smbuhl 	struct kinfo_proc2 *p = NULL;
88abbaa274Smbuhl 	size_t i, len;
89abbaa274Smbuhl 	pid_t child = -1;
90abbaa274Smbuhl 
91abbaa274Smbuhl 	int name[] = {
92abbaa274Smbuhl 		[0] = CTL_KERN,
93abbaa274Smbuhl 		[1] = KERN_PROC2,
94abbaa274Smbuhl 		[2] = KERN_PROC_ALL,
95abbaa274Smbuhl 		[3] = 0,
96abbaa274Smbuhl 		[4] = sizeof(struct kinfo_proc2),
97abbaa274Smbuhl 		[5] = 0
98abbaa274Smbuhl 	};
99abbaa274Smbuhl 
100abbaa274Smbuhl 	const size_t namelen = __arraycount(name);
101abbaa274Smbuhl 
102abbaa274Smbuhl 	/* Await the process becoming a zombie */
103abbaa274Smbuhl 	while(1) {
104abbaa274Smbuhl 		name[5] = 0;
105abbaa274Smbuhl 
106abbaa274Smbuhl 		ASSERT_EQ(sysctl(name, namelen, 0, &len, NULL, 0), 0);
107abbaa274Smbuhl 
108abbaa274Smbuhl 		ASSERT_EQ(reallocarr(&p, len, sizeof(struct kinfo_proc2)), 0);
109abbaa274Smbuhl 
110abbaa274Smbuhl 		name[5] = len;
111abbaa274Smbuhl 
112abbaa274Smbuhl 		ASSERT_EQ(sysctl(name, namelen, p, &len, NULL, 0), 0);
113abbaa274Smbuhl 
114abbaa274Smbuhl 		for (i = 0; i < len/sizeof(struct kinfo_proc2); i++) {
115abbaa274Smbuhl 			if (p[i].p_pid == getpid())
116abbaa274Smbuhl 				continue;
117abbaa274Smbuhl 			if (p[i].p_ppid != process)
118abbaa274Smbuhl 				continue;
119abbaa274Smbuhl 			if (p[i].p_stat != LSSTOP)
120abbaa274Smbuhl 				continue;
121abbaa274Smbuhl 			child = p[i].p_pid;
122abbaa274Smbuhl 			break;
123abbaa274Smbuhl 		}
124abbaa274Smbuhl 
125abbaa274Smbuhl 		if (child != -1)
126abbaa274Smbuhl 			break;
127abbaa274Smbuhl 
128abbaa274Smbuhl 		ASSERT_EQ(usleep(1000), 0);
129abbaa274Smbuhl 	}
130abbaa274Smbuhl 
131abbaa274Smbuhl 	/* Free the buffer */
132abbaa274Smbuhl 	ASSERT_EQ(reallocarr(&p, 0, sizeof(struct kinfo_proc2)), 0);
133abbaa274Smbuhl 
134abbaa274Smbuhl 	return child;
135abbaa274Smbuhl }
136abbaa274Smbuhl 
137abbaa274Smbuhl static void
raise_raw(int sig)138abbaa274Smbuhl raise_raw(int sig)
139abbaa274Smbuhl {
140abbaa274Smbuhl 	int rv, status;
141abbaa274Smbuhl 	pid_t child, parent, watcher, wpid;
142abbaa274Smbuhl 	int expect_core = (sig == SIGABRT) ? 1 : 0;
143abbaa274Smbuhl 
144abbaa274Smbuhl 	/*
145abbaa274Smbuhl 	 * Spawn a dedicated thread to watch for a stopped child and emit
146abbaa274Smbuhl 	 * the SIGKILL signal to it.
147abbaa274Smbuhl 	 *
148abbaa274Smbuhl 	 * This is required in vfork(2)ing parent and optional in fork(2).
149abbaa274Smbuhl 	 *
150abbaa274Smbuhl 	 * vfork(2) might clobber watcher, this means that it's safer and
151abbaa274Smbuhl 	 * simpler to reparent this process to initproc and forget about it.
152abbaa274Smbuhl 	 */
153abbaa274Smbuhl 	if (sig == SIGSTOP
154abbaa274Smbuhl #ifndef VFORK
155abbaa274Smbuhl 	    || (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
156abbaa274Smbuhl #endif
157abbaa274Smbuhl 	    ) {
158abbaa274Smbuhl 
159abbaa274Smbuhl 		parent = getpid();
160abbaa274Smbuhl 
161abbaa274Smbuhl 		watcher = fork();
162abbaa274Smbuhl 		ATF_REQUIRE(watcher != 1);
163abbaa274Smbuhl 		if (watcher == 0) {
164abbaa274Smbuhl 			/* Double fork(2) trick to reparent to initproc */
165abbaa274Smbuhl 			watcher = fork();
166abbaa274Smbuhl 			ASSERT_NEQ(watcher, -1);
167abbaa274Smbuhl 			if (watcher != 0)
168abbaa274Smbuhl 				_exit(0);
169abbaa274Smbuhl 
170abbaa274Smbuhl 			child = await_stopped_child(parent);
171abbaa274Smbuhl 
172abbaa274Smbuhl 			errno = 0;
173abbaa274Smbuhl 			rv = kill(child, SIGKILL);
174abbaa274Smbuhl 			ASSERT_EQ(rv, 0);
175abbaa274Smbuhl 			ASSERT_EQ(errno, 0);
176abbaa274Smbuhl 
177abbaa274Smbuhl 			/* This exit value will be collected by initproc */
178abbaa274Smbuhl 			_exit(0);
179abbaa274Smbuhl 		}
180abbaa274Smbuhl 
181abbaa274Smbuhl 		wpid = waitpid(watcher, &status, 0);
182abbaa274Smbuhl 
183abbaa274Smbuhl 		ATF_REQUIRE_EQ(wpid, watcher);
184abbaa274Smbuhl 
185abbaa274Smbuhl 		ATF_REQUIRE(WIFEXITED(status));
186abbaa274Smbuhl 		ATF_REQUIRE(!WIFCONTINUED(status));
187abbaa274Smbuhl 		ATF_REQUIRE(!WIFSIGNALED(status));
188abbaa274Smbuhl 		ATF_REQUIRE(!WIFSTOPPED(status));
189abbaa274Smbuhl 		ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
190abbaa274Smbuhl 	}
191abbaa274Smbuhl 
192abbaa274Smbuhl 	child = FORK();
193abbaa274Smbuhl 	ATF_REQUIRE(child != 1);
194abbaa274Smbuhl 	if (child == 0) {
195abbaa274Smbuhl 		rv = raise(sig);
196abbaa274Smbuhl 		ASSERT_EQ(rv, 0);
197abbaa274Smbuhl 		_exit(0);
198abbaa274Smbuhl 	}
199abbaa274Smbuhl 	wpid = waitpid(child, &status, 0);
200abbaa274Smbuhl 
201abbaa274Smbuhl 	ATF_REQUIRE_EQ(wpid, child);
202abbaa274Smbuhl 
203abbaa274Smbuhl 	switch (sig) {
204abbaa274Smbuhl 	case SIGKILL:
205abbaa274Smbuhl 	case SIGABRT:
206abbaa274Smbuhl 	case SIGHUP:
207abbaa274Smbuhl 		ATF_REQUIRE(!WIFEXITED(status));
208abbaa274Smbuhl 		ATF_REQUIRE(!WIFCONTINUED(status));
209abbaa274Smbuhl 		ATF_REQUIRE(WIFSIGNALED(status));
210abbaa274Smbuhl 		ATF_REQUIRE(!WIFSTOPPED(status));
211abbaa274Smbuhl 		ATF_REQUIRE_EQ(WTERMSIG(status), sig);
212abbaa274Smbuhl 		ATF_REQUIRE_EQ(!!WCOREDUMP(status), expect_core);
213abbaa274Smbuhl 		break;
214abbaa274Smbuhl #ifdef VFORK
215abbaa274Smbuhl 	case SIGTSTP:
216abbaa274Smbuhl 	case SIGTTIN:
217abbaa274Smbuhl 	case SIGTTOU:
218abbaa274Smbuhl #endif
219abbaa274Smbuhl 	case SIGCONT:
220abbaa274Smbuhl 		ATF_REQUIRE(WIFEXITED(status));
221abbaa274Smbuhl 		ATF_REQUIRE(!WIFCONTINUED(status));
222abbaa274Smbuhl 		ATF_REQUIRE(!WIFSIGNALED(status));
223abbaa274Smbuhl 		ATF_REQUIRE(!WIFSTOPPED(status));
224abbaa274Smbuhl 		ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
225abbaa274Smbuhl 		break;
226abbaa274Smbuhl #ifndef VFORK
227abbaa274Smbuhl 	case SIGTSTP:
228abbaa274Smbuhl 	case SIGTTIN:
229abbaa274Smbuhl 	case SIGTTOU:
230abbaa274Smbuhl #endif
231abbaa274Smbuhl 	case SIGSTOP:
232abbaa274Smbuhl 		ATF_REQUIRE(!WIFEXITED(status));
233abbaa274Smbuhl 		ATF_REQUIRE(!WIFCONTINUED(status));
234abbaa274Smbuhl 		ATF_REQUIRE(WIFSIGNALED(status));
235abbaa274Smbuhl 		ATF_REQUIRE(!WIFSTOPPED(status));
236abbaa274Smbuhl 		ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL);
237abbaa274Smbuhl 		ATF_REQUIRE_EQ(!!WCOREDUMP(status), 0);
238abbaa274Smbuhl 	}
239abbaa274Smbuhl }
240abbaa274Smbuhl 
241abbaa274Smbuhl #define RAISE(test, sig)							\
242abbaa274Smbuhl ATF_TC(test);									\
243abbaa274Smbuhl ATF_TC_HEAD(test, tc)								\
244abbaa274Smbuhl {										\
245abbaa274Smbuhl 										\
246abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr",						\
247abbaa274Smbuhl 	    "raise " #sig " in a child");					\
248abbaa274Smbuhl }										\
249abbaa274Smbuhl 										\
250abbaa274Smbuhl ATF_TC_BODY(test, tc)								\
251abbaa274Smbuhl {										\
252abbaa274Smbuhl 										\
253abbaa274Smbuhl 	raise_raw(sig);								\
254abbaa274Smbuhl }
255abbaa274Smbuhl 
RAISE(raise1,SIGKILL)256abbaa274Smbuhl RAISE(raise1, SIGKILL) /* non-maskable */
257abbaa274Smbuhl RAISE(raise2, SIGSTOP) /* non-maskable */
258abbaa274Smbuhl RAISE(raise3, SIGTSTP) /* ignored in vfork(2) */
259abbaa274Smbuhl RAISE(raise4, SIGTTIN) /* ignored in vfork(2) */
260abbaa274Smbuhl RAISE(raise5, SIGTTOU) /* ignored in vfork(2) */
261abbaa274Smbuhl RAISE(raise6, SIGABRT) /* regular abort trap */
262abbaa274Smbuhl RAISE(raise7, SIGHUP)  /* hangup */
263abbaa274Smbuhl RAISE(raise8, SIGCONT) /* continued? */
264abbaa274Smbuhl 
265abbaa274Smbuhl /// ----------------------------------------------------------------------------
266abbaa274Smbuhl 
267abbaa274Smbuhl static int
268abbaa274Smbuhl clone_func(void *arg __unused)
269abbaa274Smbuhl {
270abbaa274Smbuhl 
271abbaa274Smbuhl 	return 0;
272abbaa274Smbuhl }
273abbaa274Smbuhl 
274abbaa274Smbuhl static void
nested_raw(const char * fn,volatile int flags)275abbaa274Smbuhl nested_raw(const char *fn, volatile int flags)
276abbaa274Smbuhl {
277abbaa274Smbuhl 	int status;
278abbaa274Smbuhl 	pid_t child, child2, wpid;
279abbaa274Smbuhl 	const size_t stack_size = 1024 * 1024;
280abbaa274Smbuhl 	void *stack, *stack_base;
281abbaa274Smbuhl 
282abbaa274Smbuhl 	stack = malloc(stack_size);
283abbaa274Smbuhl 	ATF_REQUIRE(stack != NULL);
284abbaa274Smbuhl 
285abbaa274Smbuhl #ifdef __MACHINE_STACK_GROWS_UP
286abbaa274Smbuhl 	stack_base = stack;
287abbaa274Smbuhl #else
288abbaa274Smbuhl 	stack_base = (char *)stack + stack_size;
289abbaa274Smbuhl #endif
290abbaa274Smbuhl 
291abbaa274Smbuhl 	flags |= SIGCHLD;
292abbaa274Smbuhl 
293abbaa274Smbuhl 	child = FORK();
294abbaa274Smbuhl 	ATF_REQUIRE(child != 1);
295abbaa274Smbuhl 	if (child == 0) {
296abbaa274Smbuhl 		if (strcmp(fn, "fork") == 0)
297abbaa274Smbuhl 			child2 = fork();
298abbaa274Smbuhl 		else if (strcmp(fn, "vfork") == 0)
299abbaa274Smbuhl 			child2 = vfork();
300abbaa274Smbuhl #ifndef __OpenBSD__
301abbaa274Smbuhl 		else if (strcmp(fn, "clone") == 0)
302abbaa274Smbuhl 			child2 = __clone(clone_func, stack_base, flags, NULL);
303abbaa274Smbuhl #endif
304abbaa274Smbuhl 		else
305abbaa274Smbuhl 			__unreachable();
306abbaa274Smbuhl 
307abbaa274Smbuhl 		ASSERT_NEQ(child2, -1);
308abbaa274Smbuhl 
309abbaa274Smbuhl 		if ((strcmp(fn, "fork") == 0) || (strcmp(fn, "vfork") == 0)) {
310abbaa274Smbuhl 			if (child2 == 0)
311abbaa274Smbuhl 				_exit(0);
312abbaa274Smbuhl 		}
313abbaa274Smbuhl 
314abbaa274Smbuhl 		wpid = waitpid(child2, &status, 0);
315abbaa274Smbuhl 		ASSERT_EQ(child2, wpid);
316abbaa274Smbuhl 		ASSERT_EQ(!!WIFEXITED(status), true);
317abbaa274Smbuhl 		ASSERT_EQ(!!WIFCONTINUED(status), false);
318abbaa274Smbuhl 		ASSERT_EQ(!!WIFSIGNALED(status), false);
319abbaa274Smbuhl 		ASSERT_EQ(!!WIFSTOPPED(status), false);
320abbaa274Smbuhl 		ASSERT_EQ(WEXITSTATUS(status), 0);
321abbaa274Smbuhl 
322abbaa274Smbuhl 		_exit(0);
323abbaa274Smbuhl 	}
324abbaa274Smbuhl 	wpid = waitpid(child, &status, 0);
325abbaa274Smbuhl 
326abbaa274Smbuhl 	ATF_REQUIRE_EQ(wpid, child);
327abbaa274Smbuhl 	ATF_REQUIRE_EQ(!!WIFEXITED(status), true);
328abbaa274Smbuhl 	ATF_REQUIRE_EQ(!!WIFCONTINUED(status), false);
329abbaa274Smbuhl 	ATF_REQUIRE_EQ(!!WIFSIGNALED(status), false);
330abbaa274Smbuhl 	ATF_REQUIRE_EQ(!!WIFSTOPPED(status), false);
331abbaa274Smbuhl 	ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
332abbaa274Smbuhl }
333abbaa274Smbuhl 
334abbaa274Smbuhl #define NESTED(test, fn, flags)							\
335abbaa274Smbuhl ATF_TC(test);									\
336abbaa274Smbuhl ATF_TC_HEAD(test, tc)								\
337abbaa274Smbuhl {										\
338abbaa274Smbuhl 										\
339abbaa274Smbuhl 	atf_tc_set_md_var(tc, "descr",						\
340abbaa274Smbuhl 	    "Test nested " #fn " in a child");					\
341abbaa274Smbuhl }										\
342abbaa274Smbuhl 										\
343abbaa274Smbuhl ATF_TC_BODY(test, tc)								\
344abbaa274Smbuhl {										\
345abbaa274Smbuhl 										\
346abbaa274Smbuhl 	nested_raw(#fn, flags);							\
347abbaa274Smbuhl }
348abbaa274Smbuhl 
349abbaa274Smbuhl NESTED(nested_fork, fork, 0)
350abbaa274Smbuhl NESTED(nested_vfork, vfork, 0)
351abbaa274Smbuhl #ifndef __OpenBSD__
352abbaa274Smbuhl NESTED(nested_clone, clone, 0)
NESTED(nested_clone_vm,clone,CLONE_VM)353abbaa274Smbuhl NESTED(nested_clone_vm, clone, CLONE_VM)
354abbaa274Smbuhl NESTED(nested_clone_fs, clone, CLONE_FS)
355abbaa274Smbuhl NESTED(nested_clone_files, clone, CLONE_FILES)
356abbaa274Smbuhl //NESTED(nested_clone_sighand, clone, CLONE_SIGHAND) // XXX
357abbaa274Smbuhl NESTED(nested_clone_vfork, clone, CLONE_VFORK)
358abbaa274Smbuhl #endif
359abbaa274Smbuhl 
360abbaa274Smbuhl ATF_TP_ADD_TCS(tp)
361abbaa274Smbuhl {
362abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise1);
363abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise2);
364abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise3);
365abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise4);
366abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise5);
367abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise6);
368abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise7);
369abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, raise8);
370abbaa274Smbuhl 
371abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_fork);
372abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_vfork);
373abbaa274Smbuhl #ifndef __OpenBSD__
374abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_clone);
375abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_clone_vm);
376abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_clone_fs);
377abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_clone_files);
378abbaa274Smbuhl //	ATF_TP_ADD_TC(tp, nested_clone_sighand); // XXX
379abbaa274Smbuhl 	ATF_TP_ADD_TC(tp, nested_clone_vfork);
380abbaa274Smbuhl #endif
381abbaa274Smbuhl 
382abbaa274Smbuhl 	return atf_no_error();
383abbaa274Smbuhl }
384