t_fork.c revision 1.3.2.2 1 1.3.2.2 pgoyette /* $NetBSD: t_fork.c,v 1.3.2.2 2018/05/21 04:36:17 pgoyette Exp $ */
2 1.3.2.2 pgoyette
3 1.3.2.2 pgoyette /*-
4 1.3.2.2 pgoyette * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 1.3.2.2 pgoyette * All rights reserved.
6 1.3.2.2 pgoyette *
7 1.3.2.2 pgoyette * Redistribution and use in source and binary forms, with or without
8 1.3.2.2 pgoyette * modification, are permitted provided that the following conditions
9 1.3.2.2 pgoyette * are met:
10 1.3.2.2 pgoyette * 1. Redistributions of source code must retain the above copyright
11 1.3.2.2 pgoyette * notice, this list of conditions and the following disclaimer.
12 1.3.2.2 pgoyette * 2. Redistributions in binary form must reproduce the above copyright
13 1.3.2.2 pgoyette * notice, this list of conditions and the following disclaimer in the
14 1.3.2.2 pgoyette * documentation and/or other materials provided with the distribution.
15 1.3.2.2 pgoyette *
16 1.3.2.2 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.3.2.2 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.3.2.2 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.3.2.2 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.3.2.2 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.3.2.2 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.3.2.2 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.3.2.2 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.3.2.2 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.3.2.2 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.3.2.2 pgoyette * POSSIBILITY OF SUCH DAMAGE.
27 1.3.2.2 pgoyette */
28 1.3.2.2 pgoyette
29 1.3.2.2 pgoyette #include <sys/cdefs.h>
30 1.3.2.2 pgoyette __COPYRIGHT("@(#) Copyright (c) 2018\
31 1.3.2.2 pgoyette The NetBSD Foundation, inc. All rights reserved.");
32 1.3.2.2 pgoyette __RCSID("$NetBSD: t_fork.c,v 1.3.2.2 2018/05/21 04:36:17 pgoyette Exp $");
33 1.3.2.2 pgoyette
34 1.3.2.2 pgoyette #include <sys/param.h>
35 1.3.2.2 pgoyette #include <sys/types.h>
36 1.3.2.2 pgoyette #include <sys/sysctl.h>
37 1.3.2.2 pgoyette #include <sys/wait.h>
38 1.3.2.2 pgoyette #include <signal.h>
39 1.3.2.2 pgoyette #include <stdlib.h>
40 1.3.2.2 pgoyette #include <unistd.h>
41 1.3.2.2 pgoyette #include <err.h>
42 1.3.2.2 pgoyette #include <errno.h>
43 1.3.2.2 pgoyette
44 1.3.2.2 pgoyette #include <atf-c.h>
45 1.3.2.2 pgoyette
46 1.3.2.2 pgoyette #ifdef VFORK
47 1.3.2.2 pgoyette #define FORK vfork
48 1.3.2.2 pgoyette #else
49 1.3.2.2 pgoyette #define FORK fork
50 1.3.2.2 pgoyette #endif
51 1.3.2.2 pgoyette
52 1.3.2.2 pgoyette /*
53 1.3.2.2 pgoyette * A child process cannot call atf functions and expect them to magically
54 1.3.2.2 pgoyette * work like in the parent.
55 1.3.2.2 pgoyette * The printf(3) messaging from a child will not work out of the box as well
56 1.3.2.2 pgoyette * without estabilishing a communication protocol with its parent. To not
57 1.3.2.2 pgoyette * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
58 1.3.2.2 pgoyette * wrapped with ASSERT_EQ()/ASSERT_NEQ() as that is guaranteed to work.
59 1.3.2.2 pgoyette */
60 1.3.2.2 pgoyette #define ASSERT_EQ(x, y) \
61 1.3.2.2 pgoyette do { \
62 1.3.2.2 pgoyette uintmax_t vx = (x); \
63 1.3.2.2 pgoyette uintmax_t vy = (y); \
64 1.3.2.2 pgoyette int ret = vx == vy; \
65 1.3.2.2 pgoyette if (!ret) \
66 1.3.2.2 pgoyette errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
67 1.3.2.2 pgoyette "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \
68 1.3.2.2 pgoyette #x, vx, #y, vy); \
69 1.3.2.2 pgoyette } while (/*CONSTCOND*/0)
70 1.3.2.2 pgoyette
71 1.3.2.2 pgoyette #define ASSERT_NEQ(x, y) \
72 1.3.2.2 pgoyette do { \
73 1.3.2.2 pgoyette uintmax_t vx = (x); \
74 1.3.2.2 pgoyette uintmax_t vy = (y); \
75 1.3.2.2 pgoyette int ret = vx != vy; \
76 1.3.2.2 pgoyette if (!ret) \
77 1.3.2.2 pgoyette errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
78 1.3.2.2 pgoyette "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__, \
79 1.3.2.2 pgoyette #x, vx, #y, vy); \
80 1.3.2.2 pgoyette } while (/*CONSTCOND*/0)
81 1.3.2.2 pgoyette
82 1.3.2.2 pgoyette static pid_t
83 1.3.2.2 pgoyette await_stopped_child(pid_t process)
84 1.3.2.2 pgoyette {
85 1.3.2.2 pgoyette struct kinfo_proc2 *p = NULL;
86 1.3.2.2 pgoyette size_t i, len;
87 1.3.2.2 pgoyette pid_t child = -1;
88 1.3.2.2 pgoyette
89 1.3.2.2 pgoyette int name[] = {
90 1.3.2.2 pgoyette [0] = CTL_KERN,
91 1.3.2.2 pgoyette [1] = KERN_PROC2,
92 1.3.2.2 pgoyette [2] = KERN_PROC_ALL,
93 1.3.2.2 pgoyette [3] = 0,
94 1.3.2.2 pgoyette [4] = sizeof(struct kinfo_proc2),
95 1.3.2.2 pgoyette [5] = 0
96 1.3.2.2 pgoyette };
97 1.3.2.2 pgoyette
98 1.3.2.2 pgoyette const size_t namelen = __arraycount(name);
99 1.3.2.2 pgoyette
100 1.3.2.2 pgoyette /* Await the process becoming a zombie */
101 1.3.2.2 pgoyette while(1) {
102 1.3.2.2 pgoyette name[5] = 0;
103 1.3.2.2 pgoyette
104 1.3.2.2 pgoyette ASSERT_EQ(sysctl(name, namelen, 0, &len, NULL, 0), 0);
105 1.3.2.2 pgoyette
106 1.3.2.2 pgoyette ASSERT_EQ(reallocarr(&p, len, sizeof(struct kinfo_proc2)), 0);
107 1.3.2.2 pgoyette
108 1.3.2.2 pgoyette name[5] = len;
109 1.3.2.2 pgoyette
110 1.3.2.2 pgoyette ASSERT_EQ(sysctl(name, namelen, p, &len, NULL, 0), 0);
111 1.3.2.2 pgoyette
112 1.3.2.2 pgoyette for (i = 0; i < len/sizeof(struct kinfo_proc2); i++) {
113 1.3.2.2 pgoyette if (p[i].p_pid == getpid())
114 1.3.2.2 pgoyette continue;
115 1.3.2.2 pgoyette if (p[i].p_ppid != process)
116 1.3.2.2 pgoyette continue;
117 1.3.2.2 pgoyette if (p[i].p_stat != LSSTOP)
118 1.3.2.2 pgoyette continue;
119 1.3.2.2 pgoyette child = p[i].p_pid;
120 1.3.2.2 pgoyette break;
121 1.3.2.2 pgoyette }
122 1.3.2.2 pgoyette
123 1.3.2.2 pgoyette if (child != -1)
124 1.3.2.2 pgoyette break;
125 1.3.2.2 pgoyette
126 1.3.2.2 pgoyette ASSERT_EQ(usleep(1000), 0);
127 1.3.2.2 pgoyette }
128 1.3.2.2 pgoyette
129 1.3.2.2 pgoyette /* Free the buffer */
130 1.3.2.2 pgoyette ASSERT_EQ(reallocarr(&p, 0, sizeof(struct kinfo_proc2)), 0);
131 1.3.2.2 pgoyette
132 1.3.2.2 pgoyette return child;
133 1.3.2.2 pgoyette }
134 1.3.2.2 pgoyette
135 1.3.2.2 pgoyette static void
136 1.3.2.2 pgoyette raise_raw(int sig)
137 1.3.2.2 pgoyette {
138 1.3.2.2 pgoyette int rv, status;
139 1.3.2.2 pgoyette pid_t child, parent, watcher, wpid;
140 1.3.2.2 pgoyette int expect_core = (sig == SIGABRT) ? 1 : 0;
141 1.3.2.2 pgoyette
142 1.3.2.2 pgoyette /*
143 1.3.2.2 pgoyette * Spawn a dedicated thread to watch for a stopped child and emit
144 1.3.2.2 pgoyette * the SIGKILL signal to it.
145 1.3.2.2 pgoyette *
146 1.3.2.2 pgoyette * This is required in vfork(2)ing parent and optional in fork(2).
147 1.3.2.2 pgoyette *
148 1.3.2.2 pgoyette * vfork(2) might clobber watcher, this means that it's safer and
149 1.3.2.2 pgoyette * simpler to reparent this process to initproc and forget about it.
150 1.3.2.2 pgoyette */
151 1.3.2.2 pgoyette if (sig == SIGSTOP
152 1.3.2.2 pgoyette #ifndef VFORK
153 1.3.2.2 pgoyette || (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
154 1.3.2.2 pgoyette #endif
155 1.3.2.2 pgoyette ) {
156 1.3.2.2 pgoyette
157 1.3.2.2 pgoyette parent = getpid();
158 1.3.2.2 pgoyette
159 1.3.2.2 pgoyette watcher = fork();
160 1.3.2.2 pgoyette ATF_REQUIRE(watcher != 1);
161 1.3.2.2 pgoyette if (watcher == 0) {
162 1.3.2.2 pgoyette /* Double fork(2) trick to reparent to initproc */
163 1.3.2.2 pgoyette watcher = fork();
164 1.3.2.2 pgoyette ASSERT_NEQ(watcher, -1);
165 1.3.2.2 pgoyette if (watcher != 0)
166 1.3.2.2 pgoyette _exit(0);
167 1.3.2.2 pgoyette
168 1.3.2.2 pgoyette child = await_stopped_child(parent);
169 1.3.2.2 pgoyette
170 1.3.2.2 pgoyette errno = 0;
171 1.3.2.2 pgoyette rv = kill(child, SIGKILL);
172 1.3.2.2 pgoyette ASSERT_EQ(rv, 0);
173 1.3.2.2 pgoyette ASSERT_EQ(errno, 0);
174 1.3.2.2 pgoyette
175 1.3.2.2 pgoyette /* This exit value will be collected by initproc */
176 1.3.2.2 pgoyette _exit(0);
177 1.3.2.2 pgoyette }
178 1.3.2.2 pgoyette
179 1.3.2.2 pgoyette wpid = waitpid(watcher, &status, 0);
180 1.3.2.2 pgoyette
181 1.3.2.2 pgoyette ATF_REQUIRE_EQ(wpid, watcher);
182 1.3.2.2 pgoyette
183 1.3.2.2 pgoyette ATF_REQUIRE(WIFEXITED(status));
184 1.3.2.2 pgoyette ATF_REQUIRE(!WIFCONTINUED(status));
185 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSIGNALED(status));
186 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSTOPPED(status));
187 1.3.2.2 pgoyette ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
188 1.3.2.2 pgoyette }
189 1.3.2.2 pgoyette
190 1.3.2.2 pgoyette child = FORK();
191 1.3.2.2 pgoyette ATF_REQUIRE(child != 1);
192 1.3.2.2 pgoyette if (child == 0) {
193 1.3.2.2 pgoyette rv = raise(sig);
194 1.3.2.2 pgoyette ASSERT_EQ(rv, 0);
195 1.3.2.2 pgoyette _exit(0);
196 1.3.2.2 pgoyette }
197 1.3.2.2 pgoyette wpid = waitpid(child, &status, 0);
198 1.3.2.2 pgoyette
199 1.3.2.2 pgoyette ATF_REQUIRE_EQ(wpid, child);
200 1.3.2.2 pgoyette
201 1.3.2.2 pgoyette switch (sig) {
202 1.3.2.2 pgoyette case SIGKILL:
203 1.3.2.2 pgoyette case SIGABRT:
204 1.3.2.2 pgoyette case SIGHUP:
205 1.3.2.2 pgoyette ATF_REQUIRE(!WIFEXITED(status));
206 1.3.2.2 pgoyette ATF_REQUIRE(!WIFCONTINUED(status));
207 1.3.2.2 pgoyette ATF_REQUIRE(WIFSIGNALED(status));
208 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSTOPPED(status));
209 1.3.2.2 pgoyette ATF_REQUIRE_EQ(WTERMSIG(status), sig);
210 1.3.2.2 pgoyette ATF_REQUIRE_EQ(!!WCOREDUMP(status), expect_core);
211 1.3.2.2 pgoyette break;
212 1.3.2.2 pgoyette #ifdef VFORK
213 1.3.2.2 pgoyette case SIGTSTP:
214 1.3.2.2 pgoyette case SIGTTIN:
215 1.3.2.2 pgoyette case SIGTTOU:
216 1.3.2.2 pgoyette #endif
217 1.3.2.2 pgoyette case SIGCONT:
218 1.3.2.2 pgoyette ATF_REQUIRE(WIFEXITED(status));
219 1.3.2.2 pgoyette ATF_REQUIRE(!WIFCONTINUED(status));
220 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSIGNALED(status));
221 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSTOPPED(status));
222 1.3.2.2 pgoyette ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
223 1.3.2.2 pgoyette break;
224 1.3.2.2 pgoyette #ifndef VFORK
225 1.3.2.2 pgoyette case SIGTSTP:
226 1.3.2.2 pgoyette case SIGTTIN:
227 1.3.2.2 pgoyette case SIGTTOU:
228 1.3.2.2 pgoyette #endif
229 1.3.2.2 pgoyette case SIGSTOP:
230 1.3.2.2 pgoyette ATF_REQUIRE(!WIFEXITED(status));
231 1.3.2.2 pgoyette ATF_REQUIRE(!WIFCONTINUED(status));
232 1.3.2.2 pgoyette ATF_REQUIRE(WIFSIGNALED(status));
233 1.3.2.2 pgoyette ATF_REQUIRE(!WIFSTOPPED(status));
234 1.3.2.2 pgoyette ATF_REQUIRE_EQ(WTERMSIG(status), SIGKILL);
235 1.3.2.2 pgoyette ATF_REQUIRE_EQ(!!WCOREDUMP(status), 0);
236 1.3.2.2 pgoyette }
237 1.3.2.2 pgoyette }
238 1.3.2.2 pgoyette
239 1.3.2.2 pgoyette #define RAISE(test, sig) \
240 1.3.2.2 pgoyette ATF_TC(test); \
241 1.3.2.2 pgoyette ATF_TC_HEAD(test, tc) \
242 1.3.2.2 pgoyette { \
243 1.3.2.2 pgoyette \
244 1.3.2.2 pgoyette atf_tc_set_md_var(tc, "descr", \
245 1.3.2.2 pgoyette "raise " #sig " in vfork(2)ed child"); \
246 1.3.2.2 pgoyette } \
247 1.3.2.2 pgoyette \
248 1.3.2.2 pgoyette ATF_TC_BODY(test, tc) \
249 1.3.2.2 pgoyette { \
250 1.3.2.2 pgoyette \
251 1.3.2.2 pgoyette raise_raw(sig); \
252 1.3.2.2 pgoyette }
253 1.3.2.2 pgoyette
254 1.3.2.2 pgoyette RAISE(raise1, SIGKILL) /* non-maskable */
255 1.3.2.2 pgoyette RAISE(raise2, SIGSTOP) /* non-maskable */
256 1.3.2.2 pgoyette RAISE(raise3, SIGTSTP) /* ignored in vfork(2) */
257 1.3.2.2 pgoyette RAISE(raise4, SIGTTIN) /* ignored in vfork(2) */
258 1.3.2.2 pgoyette RAISE(raise5, SIGTTOU) /* ignored in vfork(2) */
259 1.3.2.2 pgoyette RAISE(raise6, SIGABRT) /* regular abort trap */
260 1.3.2.2 pgoyette RAISE(raise7, SIGHUP) /* hangup */
261 1.3.2.2 pgoyette RAISE(raise8, SIGCONT) /* continued? */
262 1.3.2.2 pgoyette
263 1.3.2.2 pgoyette ATF_TP_ADD_TCS(tp)
264 1.3.2.2 pgoyette {
265 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise1);
266 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise2);
267 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise3);
268 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise4);
269 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise5);
270 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise6);
271 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise7);
272 1.3.2.2 pgoyette ATF_TP_ADD_TC(tp, raise8);
273 1.3.2.2 pgoyette
274 1.3.2.2 pgoyette return atf_no_error();
275 1.3.2.2 pgoyette }
276