xref: /aosp_15_r20/external/ltp/lib/tst_fd.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (C) 2023 Cyril Hrubis <[email protected]>
5  */
6 
7 #define TST_NO_DEFAULT_MAIN
8 
9 #include <sys/epoll.h>
10 #include <sys/eventfd.h>
11 #include <sys/signalfd.h>
12 #include <sys/timerfd.h>
13 #include <sys/inotify.h>
14 #include <linux/perf_event.h>
15 #include <linux/fanotify.h>
16 
17 #include "tst_test.h"
18 #include "tst_safe_macros.h"
19 
20 #include "lapi/pidfd.h"
21 #include "lapi/io_uring.h"
22 #include "lapi/bpf.h"
23 #include "lapi/fsmount.h"
24 
25 #include "tst_fd.h"
26 
27 struct tst_fd_desc {
28 	void (*open_fd)(struct tst_fd *fd);
29 	void (*destroy)(struct tst_fd *fd);
30 	const char *desc;
31 };
32 
open_file(struct tst_fd * fd)33 static void open_file(struct tst_fd *fd)
34 {
35 	fd->fd = SAFE_OPEN("fd_file", O_RDWR | O_CREAT, 0666);
36 	SAFE_UNLINK("fd_file");
37 }
38 
open_path(struct tst_fd * fd)39 static void open_path(struct tst_fd *fd)
40 {
41 	int tfd;
42 
43 	tfd = SAFE_CREAT("fd_file", 0666);
44 	SAFE_CLOSE(tfd);
45 
46 	fd->fd = SAFE_OPEN("fd_file", O_PATH);
47 
48 	SAFE_UNLINK("fd_file");
49 }
50 
open_dir(struct tst_fd * fd)51 static void open_dir(struct tst_fd *fd)
52 {
53 	SAFE_MKDIR("fd_dir", 0700);
54 	fd->fd = SAFE_OPEN("fd_dir", O_DIRECTORY);
55 	SAFE_RMDIR("fd_dir");
56 }
57 
open_dev_zero(struct tst_fd * fd)58 static void open_dev_zero(struct tst_fd *fd)
59 {
60 	fd->fd = SAFE_OPEN("/dev/zero", O_RDONLY);
61 }
62 
open_proc_self_maps(struct tst_fd * fd)63 static void open_proc_self_maps(struct tst_fd *fd)
64 {
65 	fd->fd = SAFE_OPEN("/proc/self/maps", O_RDONLY);
66 }
67 
open_pipe_read(struct tst_fd * fd)68 static void open_pipe_read(struct tst_fd *fd)
69 {
70 	int pipe[2];
71 
72 	SAFE_PIPE(pipe);
73 	fd->fd = pipe[0];
74 	fd->priv = pipe[1];
75 }
76 
open_pipe_write(struct tst_fd * fd)77 static void open_pipe_write(struct tst_fd *fd)
78 {
79 	int pipe[2];
80 
81 	SAFE_PIPE(pipe);
82 	fd->fd = pipe[1];
83 	fd->priv = pipe[0];
84 }
85 
destroy_pipe(struct tst_fd * fd)86 static void destroy_pipe(struct tst_fd *fd)
87 {
88 	SAFE_CLOSE(fd->priv);
89 }
90 
open_unix_sock(struct tst_fd * fd)91 static void open_unix_sock(struct tst_fd *fd)
92 {
93 	fd->fd = SAFE_SOCKET(AF_UNIX, SOCK_STREAM, 0);
94 }
95 
open_inet_sock(struct tst_fd * fd)96 static void open_inet_sock(struct tst_fd *fd)
97 {
98 	fd->fd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
99 }
100 
open_epoll(struct tst_fd * fd)101 static void open_epoll(struct tst_fd *fd)
102 {
103 	fd->fd = epoll_create(1);
104 
105 	if (fd->fd < 0)
106 		tst_res(TCONF | TERRNO, "epoll_create()");
107 }
108 
open_eventfd(struct tst_fd * fd)109 static void open_eventfd(struct tst_fd *fd)
110 {
111 	fd->fd = eventfd(0, 0);
112 
113 	if (fd->fd < 0)
114 		tst_res(TCONF | TERRNO, "Skipping %s", tst_fd_desc(fd));
115 }
116 
open_signalfd(struct tst_fd * fd)117 static void open_signalfd(struct tst_fd *fd)
118 {
119 	sigset_t sfd_mask;
120 
121 	sigemptyset(&sfd_mask);
122 
123 	fd->fd = signalfd(-1, &sfd_mask, 0);
124 	if (fd->fd < 0) {
125 		tst_res(TCONF | TERRNO,
126 			"Skipping %s", tst_fd_desc(fd));
127 	}
128 }
129 
open_timerfd(struct tst_fd * fd)130 static void open_timerfd(struct tst_fd *fd)
131 {
132 	fd->fd = timerfd_create(CLOCK_REALTIME, 0);
133 
134 	if (fd->fd < 0) {
135 		tst_res(TCONF | TERRNO,
136 			"Skipping %s", tst_fd_desc(fd));
137 	}
138 }
139 
open_pidfd(struct tst_fd * fd)140 static void open_pidfd(struct tst_fd *fd)
141 {
142 	fd->fd = syscall(__NR_pidfd_open, getpid(), 0);
143 	if (fd->fd < 0)
144 		tst_res(TCONF | TERRNO, "pidfd_open()");
145 }
146 
open_fanotify(struct tst_fd * fd)147 static void open_fanotify(struct tst_fd *fd)
148 {
149 	fd->fd = syscall(__NR_fanotify_init, FAN_CLASS_NOTIF, O_RDONLY);
150 	if (fd->fd < 0) {
151 		tst_res(TCONF | TERRNO,
152 			"Skipping %s", tst_fd_desc(fd));
153 	}
154 }
155 
open_inotify(struct tst_fd * fd)156 static void open_inotify(struct tst_fd *fd)
157 {
158 	fd->fd = inotify_init();
159 	if (fd->fd < 0) {
160 		tst_res(TCONF | TERRNO,
161 			"Skipping %s", tst_fd_desc(fd));
162 	}
163 }
164 
open_userfaultfd(struct tst_fd * fd)165 static void open_userfaultfd(struct tst_fd *fd)
166 {
167 	fd->fd = syscall(__NR_userfaultfd, 0);
168 
169 	if (fd->fd < 0) {
170 		tst_res(TCONF | TERRNO,
171 			"Skipping %s", tst_fd_desc(fd));
172 	}
173 }
174 
open_perf_event(struct tst_fd * fd)175 static void open_perf_event(struct tst_fd *fd)
176 {
177 	struct perf_event_attr pe_attr = {
178 		.type = PERF_TYPE_SOFTWARE,
179 		.size = sizeof(struct perf_event_attr),
180 		.config = PERF_COUNT_SW_CPU_CLOCK,
181 		.disabled = 1,
182 		.exclude_kernel = 1,
183 		.exclude_hv = 1,
184 	};
185 
186 	fd->fd = syscall(__NR_perf_event_open, &pe_attr, 0, -1, -1, 0);
187 	if (fd->fd < 0) {
188 		tst_res(TCONF | TERRNO,
189 			"Skipping %s", tst_fd_desc(fd));
190 	}
191 }
192 
open_io_uring(struct tst_fd * fd)193 static void open_io_uring(struct tst_fd *fd)
194 {
195 	struct io_uring_params uring_params = {};
196 
197 	fd->fd = syscall(__NR_io_uring_setup, 1, &uring_params);
198 	if (fd->fd < 0) {
199 		tst_res(TCONF | TERRNO,
200 			"Skipping %s", tst_fd_desc(fd));
201 	}
202 }
203 
open_bpf_map(struct tst_fd * fd)204 static void open_bpf_map(struct tst_fd *fd)
205 {
206 	union bpf_attr array_attr = {
207 		.map_type = BPF_MAP_TYPE_ARRAY,
208 		.key_size = 4,
209 		.value_size = 8,
210 		.max_entries = 1,
211 	};
212 
213 	fd->fd = syscall(__NR_bpf, BPF_MAP_CREATE, &array_attr, sizeof(array_attr));
214 	if (fd->fd < 0) {
215 		tst_res(TCONF | TERRNO,
216 			"Skipping %s", tst_fd_desc(fd));
217 	}
218 }
219 
open_fsopen(struct tst_fd * fd)220 static void open_fsopen(struct tst_fd *fd)
221 {
222 	fd->fd = syscall(__NR_fsopen, "ext2", 0);
223 	if (fd->fd < 0) {
224 		tst_res(TCONF | TERRNO,
225 			"Skipping %s", tst_fd_desc(fd));
226 	}
227 }
228 
open_fspick(struct tst_fd * fd)229 static void open_fspick(struct tst_fd *fd)
230 {
231 	fd->fd = syscall(__NR_fspick, AT_FDCWD, "/", 0);
232 	if (fd->fd < 0) {
233 		tst_res(TCONF | TERRNO,
234 			"Skipping %s", tst_fd_desc(fd));
235 	}
236 }
237 
open_open_tree(struct tst_fd * fd)238 static void open_open_tree(struct tst_fd *fd)
239 {
240 	fd->fd = syscall(__NR_open_tree, AT_FDCWD, "/", 0);
241 	if (fd->fd < 0) {
242 		tst_res(TCONF | TERRNO,
243 			"Skipping %s", tst_fd_desc(fd));
244 	}
245 }
246 
open_memfd(struct tst_fd * fd)247 static void open_memfd(struct tst_fd *fd)
248 {
249 	fd->fd = syscall(__NR_memfd_create, "ltp_memfd", 0);
250 	if (fd->fd < 0) {
251 		tst_res(TCONF | TERRNO,
252 			"Skipping %s", tst_fd_desc(fd));
253 	}
254 }
255 
open_memfd_secret(struct tst_fd * fd)256 static void open_memfd_secret(struct tst_fd *fd)
257 {
258 	fd->fd = syscall(__NR_memfd_secret, 0);
259 	if (fd->fd < 0) {
260 		tst_res(TCONF | TERRNO,
261 			"Skipping %s", tst_fd_desc(fd));
262 	}
263 }
264 
265 static struct tst_fd_desc fd_desc[] = {
266 	[TST_FD_FILE] = {.open_fd = open_file, .desc = "file"},
267 	[TST_FD_PATH] = {.open_fd = open_path, .desc = "O_PATH file"},
268 	[TST_FD_DIR] = {.open_fd = open_dir, .desc = "directory"},
269 	[TST_FD_DEV_ZERO] = {.open_fd = open_dev_zero, .desc = "/dev/zero"},
270 	[TST_FD_PROC_MAPS] = {.open_fd = open_proc_self_maps, .desc = "/proc/self/maps"},
271 	[TST_FD_PIPE_READ] = {.open_fd = open_pipe_read, .desc = "pipe read end", .destroy = destroy_pipe},
272 	[TST_FD_PIPE_WRITE] = {.open_fd = open_pipe_write, .desc = "pipe write end", .destroy = destroy_pipe},
273 	[TST_FD_UNIX_SOCK] = {.open_fd = open_unix_sock, .desc = "unix socket"},
274 	[TST_FD_INET_SOCK] = {.open_fd = open_inet_sock, .desc = "inet socket"},
275 	[TST_FD_EPOLL] = {.open_fd = open_epoll, .desc = "epoll"},
276 	[TST_FD_EVENTFD] = {.open_fd = open_eventfd, .desc = "eventfd"},
277 	[TST_FD_SIGNALFD] = {.open_fd = open_signalfd, .desc = "signalfd"},
278 	[TST_FD_TIMERFD] = {.open_fd = open_timerfd, .desc = "timerfd"},
279 	[TST_FD_PIDFD] = {.open_fd = open_pidfd, .desc = "pidfd"},
280 	[TST_FD_FANOTIFY] = {.open_fd = open_fanotify, .desc = "fanotify"},
281 	[TST_FD_INOTIFY] = {.open_fd = open_inotify, .desc = "inotify"},
282 	[TST_FD_USERFAULTFD] = {.open_fd = open_userfaultfd, .desc = "userfaultfd"},
283 	[TST_FD_PERF_EVENT] = {.open_fd = open_perf_event, .desc = "perf event"},
284 	[TST_FD_IO_URING] = {.open_fd = open_io_uring, .desc = "io uring"},
285 	[TST_FD_BPF_MAP] = {.open_fd = open_bpf_map, .desc = "bpf map"},
286 	[TST_FD_FSOPEN] = {.open_fd = open_fsopen, .desc = "fsopen"},
287 	[TST_FD_FSPICK] = {.open_fd = open_fspick, .desc = "fspick"},
288 	[TST_FD_OPEN_TREE] = {.open_fd = open_open_tree, .desc = "open_tree"},
289 	[TST_FD_MEMFD] = {.open_fd = open_memfd, .desc = "memfd"},
290 	[TST_FD_MEMFD_SECRET] = {.open_fd = open_memfd_secret, .desc = "memfd secret"},
291 };
292 
tst_fd_desc(struct tst_fd * fd)293 const char *tst_fd_desc(struct tst_fd *fd)
294 {
295 	if (fd->type >= ARRAY_SIZE(fd_desc))
296 		return "invalid";
297 
298 	return fd_desc[fd->type].desc;
299 }
300 
tst_fd_next(struct tst_fd * fd)301 int tst_fd_next(struct tst_fd *fd)
302 {
303 	size_t len = ARRAY_SIZE(fd_desc);
304 
305 	if (fd->fd >= 0) {
306 		SAFE_CLOSE(fd->fd);
307 
308 		if (fd_desc[fd->type].destroy)
309 			fd_desc[fd->type].destroy(fd);
310 
311 		fd->type++;
312 	}
313 
314 	for (;;) {
315 		if (fd->type >= len)
316 			return 0;
317 
318 		fd_desc[fd->type].open_fd(fd);
319 
320 		if (fd->fd >= 0)
321 			return 1;
322 
323 		fd->type++;
324 	}
325 }
326