xref: /openbsd-src/regress/sys/net/pf_trans/dev-limit.c (revision 4c75a3c1c1a141259ac481058647142f0ff729b2)
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