#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <signal.h>
#include <err.h>
#include <sys/wait.h>
static int sigchild;
static void
usage(const char *progname)
{
fprintf(stderr,
"%s [-d] [-s success_count] [-c child_count] [-t timeout]\n"
"if no options are specified program opens '/dev/pf'\n"
"and waits for 5s before it exits\n"
"\t-s how many children should successfully open /dev/pf\n"
"\t-c children to fork, each child opens /dev/pf\n"
"\t-t timeout in seconds each child should wait\n"
"after successfully opening /dev/pf. Child exits immediately\n"
"if /dev/pf can not be opened\n", progname);
exit(1);
}
static void
handle_sigchild(int signum)
{
if (signum == SIGCHLD)
sigchild = 1;
}
static void
open_pf_and_exit(unsigned int sleep_time)
{
if (open("/dev/pf", O_RDONLY) == -1)
exit(1);
sleep(sleep_time);
exit(0);
}
int
main(int argc, char *const argv[])
{
pid_t *pids;
unsigned int chld_count = 0;
unsigned int sleep_time = 5;
unsigned int expect_success = 0;
unsigned int success, errors, i;
const char *errstr, *sleep_arg;
int status;
int c;
while ((c = getopt(argc, argv, "t:c:s:")) != -1) {
switch (c) {
case 't':
sleep_arg = (char *const)optarg;
sleep_time = strtonum(optarg, 1, 60, &errstr);
if (errstr != NULL) {
fprintf(stderr,
"%s invalid sleep time %s: %s, must be in "
"range <1, 60>\n", argv[0], errstr, optarg);
usage(argv[0]);
}
break;
case 'c':
chld_count = strtonum(optarg, 1, 32768, &errstr);
if (errstr != NULL) {
fprintf(stderr,
"%s invalid children count %s: %s, must be "
"in range <1, 32768>\n", argv[0], optarg,
errstr);
usage(argv[0]);
}
break;
case 's':
expect_success = strtonum(optarg, 0, 32768, &errstr);
if (errstr != NULL) {
fprintf(stderr,
"%s invalid expect success count %s: %s "
"must be in range <1, 32768>\n", argv[0],
optarg, errstr);
usage(argv[0]);
}
break;
default:
usage(argv[0]);
}
}
if (chld_count == 0)
open_pf_and_exit(sleep_time);
signal(SIGCHLD, handle_sigchild);
pids = (pid_t *)malloc(sizeof(pid_t) * chld_count);
if (pids == 0)
err(1, NULL);
i = 0;
while ((sigchild == 0) && (i < chld_count)) {
pid_t pid;
pid = fork();
pids[i++] = pid;
if (pid == -1)
warn("fork");
else if (pid == 0)
execl(argv[0], argv[0], "-t", sleep_arg, NULL);
}
chld_count = i;
success = 0;
errors = 0;
for (i = 0; i < chld_count; i++) {
waitpid(pids[i], &status, 0);
if (status == 0)
success++;
else
errors++;
}
free(pids);
if (success != expect_success) {
printf("Successful opens: %u\n", success);
printf("Failures: %u\n", errors);
printf("Expected opens: %u\n", expect_success);
printf("%u vs %u = %u + %u\n",
chld_count, errors + success, errors, success);
return (1);
}
return (0);
}