diff --git a/src/functional/vfork.c b/src/functional/vfork.c new file mode 100644 index 0000000..7ace682 --- /dev/null +++ b/src/functional/vfork.c @@ -0,0 +1,92 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "test.h" + +#define TEST(c, ...) ( (c) || (t_error(#c " failed: " __VA_ARGS__),0) ) + +static int w(pid_t pid) +{ + int r, s; + r = waitpid(pid, &s, 0); + if (r == -1) + t_error("waitpid failed: %s\n", strerror(errno)); + else if (r != pid) + t_error("child pid was %d, waitpid returned %d\n", pid, r); + else + return s; + return -1; +} + +static void test_exit(int code) +{ + pid_t pid; + if((pid = vfork()) == 0) { + _exit(code); + t_error("exit failed: %s\n", strerror(errno)); + } + if (pid == -1) { + t_error("vfork failed: %s\n", strerror(errno)); + return; + } + int r = w(pid); + TEST(WIFEXITED(r), "child terminated abnormally\n"); + TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code); +} + +static void test_kill(int sig) +{ + pid_t pid; + if((pid = vfork()) == 0) { + raise(sig); + t_error("raise failed: %s\n", strerror(errno)); + } + if (pid == -1) { + t_error("vfork failed: %s\n", strerror(errno)); + return; + } + int r = w(pid); + TEST(WIFSIGNALED(r), "child did not get killed\n"); + TEST(WTERMSIG(r) == sig, "child is killed by %d, expected %d\n", WTERMSIG(r), sig); +} + +static int sh(const char *cmd) +{ + pid_t pid; + if((pid = vfork()) == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmd, (char*)0); + t_error("execl failed: %s\n", strerror(errno)); + _exit(1); + } + if (pid == -1) { + t_error("vfork failed: %s\n", strerror(errno)); + return -1; + } + return w(pid); +} + +static void test_shell_exit(const char *cmd, int code) +{ + int r = sh(cmd); + TEST(WIFEXITED(r), "child terminated abnormally\n"); + TEST(WEXITSTATUS(r) == code, "child exited with %d, expected %d\n", WEXITSTATUS(r), code); +} + +static void test_shell_kill(const char *cmd, int sig) +{ + int r = sh(cmd); + TEST(WIFSIGNALED(r), "child did not get killed\n"); + TEST(WTERMSIG(r) == sig, "child is killed by %d, expected %d\n", WTERMSIG(r), sig); +} + +int main() { + test_exit(0); + test_exit(1); + test_kill(SIGKILL); + test_shell_exit("exit 0", 0); + test_shell_exit("exit 1", 1); + test_shell_kill("kill -s HUP $$", SIGHUP); + return t_status; +}