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
15static void func_a(void)
16{
17	if (write(STDOUT_FILENO, "a", 1) != 1)
18		_Exit(1);
19}
20
21static void func_b(void)
22{
23	if (write(STDOUT_FILENO, "b", 1) != 1)
24		_Exit(1);
25}
26
27static void func_c(void)
28{
29	if (write(STDOUT_FILENO, "c", 1) != 1)
30		_Exit(1);
31}
32
33static 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
48ATF_TC_WITHOUT_HEAD(quick_exit);
49ATF_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
77ATF_TP_ADD_TCS(tp)
78{
79	ATF_TP_ADD_TC(tp, quick_exit);
80	return (atf_no_error());
81}
82