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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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