1*4c75a3c1Santon /* $OpenBSD: dev-limit.c,v 1.3 2023/07/12 18:21:39 anton Exp $ */
2e8c6dd7bSsashan
3e8c6dd7bSsashan /*
4e8c6dd7bSsashan * Copyright (c) 2023 Alexandr Nedvedicky <sashan@openbsd.org>
5e8c6dd7bSsashan *
6e8c6dd7bSsashan * Permission to use, copy, modify, and distribute this software for any
7e8c6dd7bSsashan * purpose with or without fee is hereby granted, provided that the above
8e8c6dd7bSsashan * copyright notice and this permission notice appear in all copies.
9e8c6dd7bSsashan *
10e8c6dd7bSsashan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11e8c6dd7bSsashan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12e8c6dd7bSsashan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13e8c6dd7bSsashan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14e8c6dd7bSsashan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15e8c6dd7bSsashan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16e8c6dd7bSsashan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17e8c6dd7bSsashan */
18e8c6dd7bSsashan
19e8c6dd7bSsashan #include <stdio.h>
20e8c6dd7bSsashan #include <unistd.h>
21e8c6dd7bSsashan #include <fcntl.h>
22e8c6dd7bSsashan #include <stdint.h>
23e8c6dd7bSsashan #include <stdlib.h>
24e8c6dd7bSsashan #include <signal.h>
25e8c6dd7bSsashan #include <err.h>
26e8c6dd7bSsashan #include <sys/wait.h>
27e8c6dd7bSsashan
28e8c6dd7bSsashan static int sigchild;
29e8c6dd7bSsashan
30e8c6dd7bSsashan static void
usage(const char * progname)31e8c6dd7bSsashan usage(const char *progname)
32e8c6dd7bSsashan {
33e8c6dd7bSsashan fprintf(stderr,
34e8c6dd7bSsashan "%s [-d] [-s success_count] [-c child_count] [-t timeout]\n"
35e8c6dd7bSsashan "if no options are specified program opens '/dev/pf'\n"
36e8c6dd7bSsashan "and waits for 5s before it exits\n"
37e8c6dd7bSsashan "\t-s how many children should successfully open /dev/pf\n"
38e8c6dd7bSsashan "\t-c children to fork, each child opens /dev/pf\n"
39e8c6dd7bSsashan "\t-t timeout in seconds each child should wait\n"
40e8c6dd7bSsashan "after successfully opening /dev/pf. Child exits immediately\n"
41e8c6dd7bSsashan "if /dev/pf can not be opened\n", progname);
42e8c6dd7bSsashan exit(1);
43e8c6dd7bSsashan }
44e8c6dd7bSsashan
45e8c6dd7bSsashan static void
handle_sigchild(int signum)46e8c6dd7bSsashan handle_sigchild(int signum)
47e8c6dd7bSsashan {
48e8c6dd7bSsashan if (signum == SIGCHLD)
49e8c6dd7bSsashan sigchild = 1;
50e8c6dd7bSsashan }
51e8c6dd7bSsashan
52e8c6dd7bSsashan static void
open_pf_and_exit(unsigned int sleep_time)53e8c6dd7bSsashan open_pf_and_exit(unsigned int sleep_time)
54e8c6dd7bSsashan {
55e8c6dd7bSsashan if (open("/dev/pf", O_RDONLY) == -1)
56e8c6dd7bSsashan exit(1);
57e8c6dd7bSsashan
58e8c6dd7bSsashan sleep(sleep_time);
59e8c6dd7bSsashan exit(0);
60e8c6dd7bSsashan }
61e8c6dd7bSsashan
62e8c6dd7bSsashan int
main(int argc,char * const argv[])63e8c6dd7bSsashan main(int argc, char *const argv[])
64e8c6dd7bSsashan {
65e8c6dd7bSsashan pid_t *pids;
66e8c6dd7bSsashan unsigned int chld_count = 0;
67e8c6dd7bSsashan unsigned int sleep_time = 5;
68e8c6dd7bSsashan unsigned int expect_success = 0;
69e8c6dd7bSsashan unsigned int success, errors, i;
70e8c6dd7bSsashan const char *errstr, *sleep_arg;
71e8c6dd7bSsashan int status;
72e8c6dd7bSsashan int c;
73e8c6dd7bSsashan
74e8c6dd7bSsashan while ((c = getopt(argc, argv, "t:c:s:")) != -1) {
75e8c6dd7bSsashan switch (c) {
76e8c6dd7bSsashan case 't':
77e8c6dd7bSsashan sleep_arg = (char *const)optarg;
78e8c6dd7bSsashan sleep_time = strtonum(optarg, 1, 60, &errstr);
79e8c6dd7bSsashan if (errstr != NULL) {
80e8c6dd7bSsashan fprintf(stderr,
81e8c6dd7bSsashan "%s invalid sleep time %s: %s, must be in "
82e8c6dd7bSsashan "range <1, 60>\n", argv[0], errstr, optarg);
83e8c6dd7bSsashan usage(argv[0]);
84e8c6dd7bSsashan }
85e8c6dd7bSsashan break;
86e8c6dd7bSsashan case 'c':
87e8c6dd7bSsashan chld_count = strtonum(optarg, 1, 32768, &errstr);
88e8c6dd7bSsashan if (errstr != NULL) {
89e8c6dd7bSsashan fprintf(stderr,
90e8c6dd7bSsashan "%s invalid children count %s: %s, must be "
91e8c6dd7bSsashan "in range <1, 32768>\n", argv[0], optarg,
92e8c6dd7bSsashan errstr);
93e8c6dd7bSsashan usage(argv[0]);
94e8c6dd7bSsashan }
95e8c6dd7bSsashan break;
96e8c6dd7bSsashan case 's':
97e8c6dd7bSsashan expect_success = strtonum(optarg, 0, 32768, &errstr);
98e8c6dd7bSsashan if (errstr != NULL) {
99e8c6dd7bSsashan fprintf(stderr,
100e8c6dd7bSsashan "%s invalid expect success count %s: %s "
101e8c6dd7bSsashan "must be in range <1, 32768>\n", argv[0],
102e8c6dd7bSsashan optarg, errstr);
103e8c6dd7bSsashan usage(argv[0]);
104e8c6dd7bSsashan }
105e8c6dd7bSsashan break;
106e8c6dd7bSsashan default:
107e8c6dd7bSsashan usage(argv[0]);
108e8c6dd7bSsashan }
109e8c6dd7bSsashan }
110e8c6dd7bSsashan
111e8c6dd7bSsashan if (chld_count == 0)
112e8c6dd7bSsashan open_pf_and_exit(sleep_time);
113e8c6dd7bSsashan
114e8c6dd7bSsashan signal(SIGCHLD, handle_sigchild);
115e8c6dd7bSsashan pids = (pid_t *)malloc(sizeof(pid_t) * chld_count);
116e8c6dd7bSsashan if (pids == 0)
117b6a86f14Santon err(1, NULL);
118e8c6dd7bSsashan
119e8c6dd7bSsashan i = 0;
120e8c6dd7bSsashan while ((sigchild == 0) && (i < chld_count)) {
121*4c75a3c1Santon pid_t pid;
122*4c75a3c1Santon
123*4c75a3c1Santon pid = fork();
124*4c75a3c1Santon pids[i++] = pid;
125*4c75a3c1Santon if (pid == -1)
126*4c75a3c1Santon warn("fork");
127*4c75a3c1Santon else if (pid == 0)
128e8c6dd7bSsashan execl(argv[0], argv[0], "-t", sleep_arg, NULL);
129e8c6dd7bSsashan }
130e8c6dd7bSsashan chld_count = i;
131e8c6dd7bSsashan
132e8c6dd7bSsashan success = 0;
133e8c6dd7bSsashan errors = 0;
134e8c6dd7bSsashan for (i = 0; i < chld_count; i++) {
135e8c6dd7bSsashan waitpid(pids[i], &status, 0);
136e8c6dd7bSsashan if (status == 0)
137e8c6dd7bSsashan success++;
138e8c6dd7bSsashan else
139e8c6dd7bSsashan errors++;
140e8c6dd7bSsashan }
141e8c6dd7bSsashan
142e8c6dd7bSsashan free(pids);
143e8c6dd7bSsashan
144e8c6dd7bSsashan if (success != expect_success) {
145e8c6dd7bSsashan printf("Successful opens: %u\n", success);
146e8c6dd7bSsashan printf("Failures: %u\n", errors);
147e8c6dd7bSsashan printf("Expected opens: %u\n", expect_success);
148e8c6dd7bSsashan printf("%u vs %u = %u + %u\n",
149e8c6dd7bSsashan chld_count, errors + success, errors, success);
150e8c6dd7bSsashan return (1);
151e8c6dd7bSsashan }
152e8c6dd7bSsashan
153e8c6dd7bSsashan return (0);
154e8c6dd7bSsashan }
155