#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <err.h>
#include "config.h"
#include "test.h"
static
void
wait_badpid(int pid, const char *desc)
{
int rv, x;
rv = waitpid(pid, &x, 0);
report_test2(rv, errno, EINVAL, NOSUCHPID_ERROR, desc);
}
static
void
wait_badstatus(void *ptr, const char *desc)
{
int rv, pid, x;
pid = fork();
if (pid<0) {
warn("UH-OH: fork failed");
return;
}
if (pid==0) {
exit(0);
}
rv = waitpid(pid, ptr, 0);
report_test(rv, errno, EFAULT, desc);
waitpid(pid, &x, 0);
}
static
void
wait_unaligned(void)
{
int rv, pid, x;
int status[2];
char *ptr;
pid = fork();
if (pid<0) {
warn("UH-OH: fork failed");
return;
}
if (pid==0) {
exit(0);
}
ptr = (char *)(&status[0]);
ptr++;
rv = waitpid(pid, (int *)ptr, 0);
report_survival(rv, errno, "wait with unaligned status");
if (rv<0) {
waitpid(pid, &x, 0);
}
}
static
void
wait_badflags(void)
{
int rv, x, pid;
pid = fork();
if (pid<0) {
warn("UH-OH: fork failed");
return;
}
if (pid==0) {
exit(0);
}
rv = waitpid(pid, &x, 309429);
report_test(rv, errno, EINVAL, "wait with bad flags");
waitpid(pid, &x, 0);
}
static
void
wait_self(void)
{
int rv, x;
rv = waitpid(getpid(), &x, 0);
report_survival(rv, errno, "wait for self");
}
static
void
wait_parent(void)
{
int mypid, childpid, rv, x;
mypid = getpid();
childpid = fork();
if (childpid<0) {
warn("UH-OH: can't fork");
return;
}
if (childpid==0) {
rv = waitpid(mypid, &x, 0);
report_survival(rv, errno, "wait for parent (from child)");
_exit(0);
}
rv = waitpid(childpid, &x, 0);
report_survival(rv, errno, "wait for parent test (from parent)");
}
static
void
wait_siblings_child(void)
{
int pids[2], mypid, otherpid, fd, rv, x;
mypid = getpid();
fd = open(TESTFILE, O_RDONLY);
if (fd<0) {
warn("UH-OH: child process (pid %d) can't open %s",
mypid, TESTFILE);
return;
}
do {
rv = lseek(fd, 0, SEEK_SET);
if (rv<0) {
warn("UH-OH: child process (pid %d) lseek error",
mypid);
return;
}
rv = read(fd, pids, sizeof(pids));
if (rv<0) {
warn("UH-OH: child process (pid %d) read error",
mypid);
return;
}
} while (rv < (int)sizeof(pids));
if (mypid==pids[0]) {
otherpid = pids[1];
}
else if (mypid==pids[1]) {
otherpid = pids[0];
}
else {
warn("UH-OH: child process (pid %d) got garbage in comm file",
mypid);
return;
}
close(fd);
rv = waitpid(otherpid, &x, 0);
report_survival(rv, errno, "sibling wait");
}
static
void
wait_siblings(void)
{
int pids[2], fd, rv, x;
fd = open_testfile(NULL);
if (fd<0) {
return;
}
pids[0] = fork();
if (pids[0]<0) {
warn("UH-OH: can't fork");
return;
}
if (pids[0]==0) {
close(fd);
wait_siblings_child();
_exit(0);
}
pids[1] = fork();
if (pids[1]<0) {
warn("UH-OH: can't fork");
return;
}
if (pids[1]==0) {
close(fd);
wait_siblings_child();
_exit(0);
}
rv = write(fd, pids, sizeof(pids));
if (rv < 0) {
warn("UH-OH: write error on %s", TESTFILE);
return;
}
if (rv != (int)sizeof(pids)) {
warnx("UH-OH: write error on %s: short count", TESTFILE);
return;
}
rv = waitpid(pids[0], &x, 0);
if (rv<0) {
warn("UH-OH: error waiting for child 0 (pid %d)", pids[0]);
}
rv = waitpid(pids[1], &x, 0);
if (rv<0) {
warn("UH-OH: error waiting for child 1 (pid %d)", pids[1]);
}
warnx("passed: siblings wait for each other");
close(fd);
remove(TESTFILE);
}
void
test_waitpid(void)
{
wait_badpid(-8, "wait for pid -8");
wait_badpid(-1, "wait for pid -1");
wait_badpid(0, "pid zero");
wait_badpid(NONEXIST_PID, "nonexistent pid");
wait_badstatus(NULL, "wait with NULL status");
wait_badstatus(INVAL_PTR, "wait with invalid pointer status");
wait_badstatus(KERN_PTR, "wait with kernel pointer status");
wait_unaligned();
wait_badflags();
wait_self();
wait_parent();
wait_siblings();
}