1570af302Sopenharmony_ci#define _GNU_SOURCE
2570af302Sopenharmony_ci#include <unistd.h>
3570af302Sopenharmony_ci#include <sys/wait.h>
4570af302Sopenharmony_ci#include <errno.h>
5570af302Sopenharmony_ci#include <string.h>
6570af302Sopenharmony_ci#include "test.h"
7570af302Sopenharmony_ci
8570af302Sopenharmony_ci#define TEST(c, ...) ( (c) || (t_error(#c " failed: " __VA_ARGS__),0) )
9570af302Sopenharmony_ci
10570af302Sopenharmony_cistatic int w(pid_t pid)
11570af302Sopenharmony_ci{
12570af302Sopenharmony_ci	int r, s;
13570af302Sopenharmony_ci	r = waitpid(pid, &s, 0);
14570af302Sopenharmony_ci	if (r == -1)
15570af302Sopenharmony_ci		t_error("waitpid failed: %s\n", strerror(errno));
16570af302Sopenharmony_ci	else if (r != pid)
17570af302Sopenharmony_ci		t_error("child pid was %d, waitpid returned %d\n", pid, r);
18570af302Sopenharmony_ci	else
19570af302Sopenharmony_ci		return s;
20570af302Sopenharmony_ci	return -1;
21570af302Sopenharmony_ci}
22570af302Sopenharmony_ci
23570af302Sopenharmony_cistatic void test_exit(int code)
24570af302Sopenharmony_ci{
25570af302Sopenharmony_ci	pid_t pid;
26570af302Sopenharmony_ci	if((pid = vfork()) == 0) {
27570af302Sopenharmony_ci		_exit(code);
28570af302Sopenharmony_ci		t_error("exit failed: %s\n", strerror(errno));
29570af302Sopenharmony_ci	}
30570af302Sopenharmony_ci	if (pid == -1) {
31570af302Sopenharmony_ci		t_error("vfork failed: %s\n", strerror(errno));
32570af302Sopenharmony_ci		return;
33570af302Sopenharmony_ci	}
34570af302Sopenharmony_ci	int r = w(pid);
35570af302Sopenharmony_ci	TEST(WIFEXITED(r), "child terminated abnormally\n");
36570af302Sopenharmony_ci	TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code);
37570af302Sopenharmony_ci}
38570af302Sopenharmony_ci
39570af302Sopenharmony_cistatic int sh(const char *cmd)
40570af302Sopenharmony_ci{
41570af302Sopenharmony_ci	pid_t pid;
42570af302Sopenharmony_ci	if((pid = vfork()) == 0) {
43570af302Sopenharmony_ci		execl("/bin/sh", "/bin/sh", "-c", cmd, (char*)0);
44570af302Sopenharmony_ci		t_error("execl failed: %s\n", strerror(errno));
45570af302Sopenharmony_ci		_exit(1);
46570af302Sopenharmony_ci	}
47570af302Sopenharmony_ci	if (pid == -1) {
48570af302Sopenharmony_ci		t_error("vfork failed: %s\n", strerror(errno));
49570af302Sopenharmony_ci		return -1;
50570af302Sopenharmony_ci	}
51570af302Sopenharmony_ci	return w(pid);
52570af302Sopenharmony_ci}
53570af302Sopenharmony_ci
54570af302Sopenharmony_cistatic void test_shell_exit(const char *cmd, int code)
55570af302Sopenharmony_ci{
56570af302Sopenharmony_ci	int r = sh(cmd);
57570af302Sopenharmony_ci	TEST(WIFEXITED(r), "child terminated abnormally\n");
58570af302Sopenharmony_ci	TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code);
59570af302Sopenharmony_ci}
60570af302Sopenharmony_ci
61570af302Sopenharmony_cistatic void test_shell_kill(const char *cmd, int sig)
62570af302Sopenharmony_ci{
63570af302Sopenharmony_ci	int r = sh(cmd);
64570af302Sopenharmony_ci	TEST(WIFSIGNALED(r), "child did not get killed\n");
65570af302Sopenharmony_ci	TEST(WTERMSIG(r) == sig, "child is killed by %d, expected %d\n", WTERMSIG(r), sig);
66570af302Sopenharmony_ci}
67570af302Sopenharmony_ci
68570af302Sopenharmony_ciint main() {
69570af302Sopenharmony_ci	test_exit(0);
70570af302Sopenharmony_ci	test_exit(1);
71570af302Sopenharmony_ci	test_shell_exit("exit 0", 0);
72570af302Sopenharmony_ci	test_shell_exit("exit 1", 1);
73570af302Sopenharmony_ci	test_shell_kill("kill -9 $$", 9);
74570af302Sopenharmony_ci	return t_status;
75570af302Sopenharmony_ci}
76