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