1/*	$NetBSD: t_epoll.c,v 1.2 2023/07/30 18:31:14 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Theodore Preduta.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_epoll.c,v 1.2 2023/07/30 18:31:14 christos Exp $");
33
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/epoll.h>
37#include <sys/fcntl.h>
38#include <errno.h>
39
40#include <atf-c.h>
41
42#include "h_macros.h"
43
44ATF_TC(create_size);
45ATF_TC_HEAD(create_size, tc)
46{
47
48	atf_tc_set_md_var(tc, "descr",
49	    "Checks that epoll_create requires a non-positive size");
50}
51ATF_TC_BODY(create_size, tc)
52{
53	ATF_REQUIRE_EQ_MSG(epoll_create(-1), -1,
54	    "epoll_create succeeded unexpectedly");
55	ATF_REQUIRE_ERRNO(EINVAL, true);
56
57	ATF_REQUIRE_EQ_MSG(epoll_create(0), -1,
58	    "epoll_create succeeded unexpectedly");
59	ATF_REQUIRE_ERRNO(EINVAL, true);
60
61	RL(epoll_create(1));
62}
63
64ATF_TC(create_cloexec);
65ATF_TC_HEAD(create_cloexec, tc)
66{
67
68	atf_tc_set_md_var(tc, "descr",
69	    "Checks that epoll_create1 sets close on exec when desired");
70}
71ATF_TC_BODY(create_cloexec, tc)
72{
73	int fd;
74
75	RL(fd = epoll_create1(0));
76	ATF_REQUIRE_MSG((fcntl(fd, F_GETFD) & FD_CLOEXEC) == 0,
77	    "Close on exec set unexpectedly.");
78
79	RL(fd = epoll_create1(EPOLL_CLOEXEC));
80	ATF_REQUIRE_MSG((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0,
81	    "Close on exec was not set.");
82}
83
84ATF_TC(bad_epfd);
85ATF_TC_HEAD(bad_epfd, tc)
86{
87
88	atf_tc_set_md_var(tc, "descr",
89	    "Checks that epoll_ctl detects an invalid epfd");
90}
91ATF_TC_BODY(bad_epfd, tc)
92{
93	int fd;
94	struct epoll_event event;
95
96	RL(fd = epoll_create1(0));
97	event.events = EPOLLIN;
98
99	ATF_REQUIRE_EQ_MSG(epoll_ctl(-1, EPOLL_CTL_ADD, fd, &event), -1,
100	    "epoll_ctl succeeded unexpectedly");
101	ATF_REQUIRE_ERRNO(EBADF, true);
102}
103
104ATF_TC(bad_fd);
105ATF_TC_HEAD(bad_fd, tc)
106{
107
108	atf_tc_set_md_var(tc, "descr",
109	    "Checks that epoll_ctl detects an invalid fd");
110}
111ATF_TC_BODY(bad_fd, tc)
112{
113	int epfd;
114	struct epoll_event event;
115
116	RL(epfd = epoll_create1(0));
117	event.events = EPOLLIN;
118
119	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd, EPOLL_CTL_ADD, -1, &event), -1,
120	    "epoll_ctl succeeded unexpectedly");
121	ATF_REQUIRE_ERRNO(EBADF, true);
122}
123
124ATF_TC(double_add);
125ATF_TC_HEAD(double_add, tc)
126{
127
128	atf_tc_set_md_var(tc, "descr",
129	    "Checks that epoll_ctl detects if a fd has already been added");
130}
131ATF_TC_BODY(double_add, tc)
132{
133	int epfd, fd;
134	struct epoll_event event;
135
136	RL(epfd = epoll_create1(0));
137	RL(fd = epoll_create1(0));
138	event.events = EPOLLIN;
139
140	RL(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event));
141
142	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event), -1,
143	    "epoll_ctl succeeded unexpectedly");
144	ATF_REQUIRE_ERRNO(EEXIST, true);
145}
146
147ATF_TC(not_added);
148ATF_TC_HEAD(not_added, tc)
149{
150
151	atf_tc_set_md_var(tc, "descr",
152	    "Checks that epoll_ctl detects if a fd has not been added");
153}
154ATF_TC_BODY(not_added, tc)
155{
156	int epfd, fd;
157	struct epoll_event event;
158
159	RL(epfd = epoll_create1(0));
160	RL(fd = epoll_create1(0));
161	event.events = EPOLLIN;
162
163	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &event), -1,
164	    "epoll_ctl succeeded unexpectedly");
165	ATF_REQUIRE_ERRNO(ENOENT, true);
166
167	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL), -1,
168	    "epoll_ctl succeeded unexpectedly");
169	ATF_REQUIRE_ERRNO(ENOENT, true);
170}
171
172ATF_TC(watching_self);
173ATF_TC_HEAD(watching_self, tc)
174{
175
176	atf_tc_set_md_var(tc, "descr",
177	    "Checks that epoll disallows watching itself");
178}
179ATF_TC_BODY(watching_self, tc)
180{
181	int epfd;
182	struct epoll_event event;
183
184	RL(epfd = epoll_create1(0));
185	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd, EPOLL_CTL_ADD, epfd, &event), -1,
186	    "epoll_ctl succeeded unexpectedly");
187	ATF_REQUIRE_ERRNO(EINVAL, true);
188}
189
190ATF_TC(watch_loops);
191ATF_TC_HEAD(watch_loops, tc)
192{
193
194	atf_tc_set_md_var(tc, "descr", "Checks that epoll disallows loops");
195}
196ATF_TC_BODY(watch_loops, tc)
197{
198        int epfd1, epfd2;
199	struct epoll_event event;
200
201	event.events = EPOLLIN;
202	RL(epfd1 = epoll_create1(0));
203	RL(epfd2 = epoll_create1(0));
204	RL(epoll_ctl(epfd1, EPOLL_CTL_ADD, epfd2, &event));
205	ATF_REQUIRE_EQ_MSG(epoll_ctl(epfd2, EPOLL_CTL_ADD, epfd1, &event), -1,
206	    "epoll_ctl succeeded unexpectedly");
207	ATF_REQUIRE_ERRNO(ELOOP, true);
208}
209
210ATF_TC(watch_depth);
211ATF_TC_HEAD(watch_depth, tc)
212{
213
214	atf_tc_set_md_var(tc, "descr",
215	    "Checks that epoll fails when the watch depth exceeds 5");
216}
217ATF_TC_BODY(watch_depth, tc)
218{
219	int epfd, tmp;
220	struct epoll_event event;
221
222	event.events = EPOLLIN;
223	RL(epfd = epoll_create1(0));
224	for (size_t i = 0; i < 4; i++) {
225		RL(tmp = epoll_create1(0));
226		RL(epoll_ctl(tmp, EPOLL_CTL_ADD, epfd, &event));
227		epfd = tmp;
228	}
229	RL(tmp = epoll_create1(0));
230	ATF_REQUIRE_EQ_MSG(epoll_ctl(tmp, EPOLL_CTL_ADD, epfd, &event), -1,
231	    "epoll_ctl succeeded unexpectedly");
232	ATF_REQUIRE_ERRNO(EINVAL, true);
233}
234
235ATF_TP_ADD_TCS(tp)
236{
237	ATF_TP_ADD_TC(tp, create_size);
238	ATF_TP_ADD_TC(tp, create_cloexec);
239	ATF_TP_ADD_TC(tp, bad_epfd);
240	ATF_TP_ADD_TC(tp, bad_fd);
241	ATF_TP_ADD_TC(tp, not_added);
242	ATF_TP_ADD_TC(tp, watching_self);
243	ATF_TP_ADD_TC(tp, watch_loops);
244	ATF_TP_ADD_TC(tp, watch_depth);
245
246	return atf_no_error();
247}
248