#include <err.h>
#include <stdlib.h>
#include <spawn.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <sys/debug.h>
#include <fcntl.h>
#include <limits.h>
#include <libgen.h>
#include "posix_spawn_common.h"
void
posix_spawn_find_helper(char *buf, size_t bufsz, const char *name)
{
ssize_t ret;
char origin[PATH_MAX];
ret = readlink("/proc/self/path/a.out", origin, PATH_MAX - 1);
if (ret < 0) {
err(EXIT_FAILURE, "INTERNAL TEST FAILURE: "
"failed to read a.out path");
}
origin[ret] = '\0';
if (snprintf(buf, bufsz, "%s/%s", dirname(origin), name) >= bufsz) {
errx(EXIT_FAILURE, "INTERNAL TEST FAILURE: "
"failed to assemble %s path", name);
}
if (access(buf, X_OK) != 0) {
err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to access %s",
buf);
}
}
void
posix_spawn_pipe_setup(posix_spawn_file_actions_t *acts, int pipes[2])
{
int ret;
if (pipe2(pipes, O_NONBLOCK) != 0) {
err(EXIT_FAILURE,
"INTERNAL TEST FAILURE: failed to create a pipe");
}
VERIFY3S(pipes[0], >, STDERR_FILENO);
VERIFY3S(pipes[1], >, STDERR_FILENO);
if ((ret = posix_spawn_file_actions_init(acts)) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to initialize posix_spawn file actions");
}
if ((ret = posix_spawn_file_actions_addopen(acts, STDIN_FILENO,
"/dev/null", O_RDONLY, 0)) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to add /dev/null open action");
}
if ((ret = posix_spawn_file_actions_adddup2(acts, STDIN_FILENO,
STDERR_FILENO)) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to add stderr dup action");
}
if ((ret = posix_spawn_file_actions_adddup2(acts, pipes[1],
STDOUT_FILENO)) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to add stdout dup action");
}
if ((ret = posix_spawn_file_actions_addclose(acts, pipes[0])) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to add pipes[0] close action");
}
if ((ret = posix_spawn_file_actions_addclose(acts, pipes[1])) != 0) {
errc(EXIT_FAILURE, ret, "INTERNAL TEST FAILURE: "
"failed to add pipes[1] close action");
}
}
bool
posix_spawn_run_child(const char *desc, const char *path,
posix_spawn_file_actions_t *acts, posix_spawnattr_t *attr,
char *const argv[])
{
siginfo_t sig;
pid_t pid;
int ret;
ret = posix_spawn(&pid, path, acts, attr, argv, NULL);
if (ret != 0) {
warnx("TEST FAILED: %s: posix_spawn failed with %s",
desc, strerrorname_np(ret));
return (false);
}
if (waitid(P_PID, pid, &sig, WEXITED) != 0) {
err(EXIT_FAILURE, "INTERNAL TEST ERROR: %s: "
"failed to wait on child", desc);
}
if (sig.si_code != CLD_EXITED) {
warnx("TEST FAILED: %s: "
"child did not exit normally: si_code: %d",
desc, sig.si_code);
return (false);
}
if (sig.si_status != 0) {
warnx("TEST FAILED: %s: child exited with status %d",
desc, sig.si_status);
return (false);
}
return (true);
}