1 /*-
2  * Copyright (c) 2023 Klara, Inc.
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <sys/wait.h>
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 
13 #include <atf-c.h>
14 
15 static void func_a(void)
16 {
17 	if (write(STDOUT_FILENO, "a", 1) != 1)
18 		_Exit(1);
19 }
20 
21 static void func_b(void)
22 {
23 	if (write(STDOUT_FILENO, "b", 1) != 1)
24 		_Exit(1);
25 }
26 
27 static void func_c(void)
28 {
29 	if (write(STDOUT_FILENO, "c", 1) != 1)
30 		_Exit(1);
31 }
32 
33 static void child(void)
34 {
35 	// this will be received by the parent
36 	printf("hello, ");
37 	fflush(stdout);
38 	// this won't, because quick_exit() does not flush
39 	printf("world");
40 	// these will be called in reverse order, producing "abc"
41 	if (at_quick_exit(func_c) != 0 ||
42 	    at_quick_exit(func_b) != 0 ||
43 	    at_quick_exit(func_a) != 0)
44 		_Exit(1);
45 	quick_exit(0);
46 }
47 
48 ATF_TC_WITHOUT_HEAD(quick_exit);
49 ATF_TC_BODY(quick_exit, tc)
50 {
51 	char buf[100] = "";
52 	ssize_t len;
53 	int p[2], wstatus = 0;
54 	pid_t pid;
55 
56 	ATF_REQUIRE(pipe(p) == 0);
57 	pid = fork();
58 	if (pid == 0) {
59 		if (dup2(p[1], STDOUT_FILENO) < 0)
60 			_Exit(1);
61 		(void)close(p[1]);
62 		(void)close(p[0]);
63 		child();
64 		_Exit(1);
65 	}
66 	ATF_REQUIRE_MSG(pid > 0,
67 	    "expect fork() to succeed");
68 	ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
69 	    "expect to collect child process");
70 	ATF_CHECK_EQ_MSG(0, wstatus,
71 	    "expect child to exit cleanly");
72 	ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0,
73 	    "expect to receive output from child");
74 	ATF_CHECK_STREQ("hello, abc", buf);
75 }
76 
77 ATF_TP_ADD_TCS(tp)
78 {
79 	ATF_TP_ADD_TC(tp, quick_exit);
80 	return (atf_no_error());
81 }
82