1#define _GNU_SOURCE
2#include <unistd.h>
3#include <sys/wait.h>
4#include <errno.h>
5#include <string.h>
6#include "test.h"
7
8#define TEST(c, ...) ( (c) || (t_error(#c " failed: " __VA_ARGS__),0) )
9
10static int w(pid_t pid)
11{
12	int r, s;
13	r = waitpid(pid, &s, 0);
14	if (r == -1)
15		t_error("waitpid failed: %s\n", strerror(errno));
16	else if (r != pid)
17		t_error("child pid was %d, waitpid returned %d\n", pid, r);
18	else
19		return s;
20	return -1;
21}
22
23static void test_exit(int code)
24{
25	pid_t pid;
26	if((pid = vfork()) == 0) {
27		_exit(code);
28		t_error("exit failed: %s\n", strerror(errno));
29	}
30	if (pid == -1) {
31		t_error("vfork failed: %s\n", strerror(errno));
32		return;
33	}
34	int r = w(pid);
35	TEST(WIFEXITED(r), "child terminated abnormally\n");
36	TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code);
37}
38
39static int sh(const char *cmd)
40{
41	pid_t pid;
42	if((pid = vfork()) == 0) {
43		execl("/bin/sh", "/bin/sh", "-c", cmd, (char*)0);
44		t_error("execl failed: %s\n", strerror(errno));
45		_exit(1);
46	}
47	if (pid == -1) {
48		t_error("vfork failed: %s\n", strerror(errno));
49		return -1;
50	}
51	return w(pid);
52}
53
54static void test_shell_exit(const char *cmd, int code)
55{
56	int r = sh(cmd);
57	TEST(WIFEXITED(r), "child terminated abnormally\n");
58	TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code);
59}
60
61static void test_shell_kill(const char *cmd, int sig)
62{
63	int r = sh(cmd);
64	TEST(WIFSIGNALED(r), "child did not get killed\n");
65	TEST(WTERMSIG(r) == sig, "child is killed by %d, expected %d\n", WTERMSIG(r), sig);
66}
67
68int main() {
69	test_exit(0);
70	test_exit(1);
71	test_shell_exit("exit 0", 0);
72	test_shell_exit("exit 1", 1);
73	test_shell_kill("kill -9 $$", 9);
74	return t_status;
75}
76