1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: test fsnotify access off O_DIRECT read
4 */
5
6 #include "helpers.h"
7
8 #ifdef CONFIG_HAVE_FANOTIFY
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/fanotify.h>
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16
17 #include "liburing.h"
18
main(int argc,char * argv[])19 int main(int argc, char *argv[])
20 {
21 struct io_uring_sqe *sqe;
22 struct io_uring_cqe *cqe;
23 struct io_uring ring;
24 int fan, ret, fd, err;
25 char fname[64], *f;
26 struct stat sb;
27 void *buf;
28
29 fan = fanotify_init(FAN_CLASS_NOTIF|FAN_CLASS_CONTENT, 0);
30 if (fan < 0) {
31 if (errno == ENOSYS)
32 return T_EXIT_SKIP;
33 if (geteuid())
34 return T_EXIT_SKIP;
35 perror("fanotify_init");
36 return T_EXIT_FAIL;
37 }
38
39 err = T_EXIT_FAIL;
40 if (argc > 1) {
41 f = argv[1];
42 fd = open(argv[1], O_RDONLY | O_DIRECT);
43 if (fd < 0 && errno == EINVAL)
44 return T_EXIT_SKIP;
45 } else {
46 sprintf(fname, ".fsnotify.%d", getpid());
47 f = fname;
48 t_create_file(fname, 8192);
49 fd = open(fname, O_RDONLY | O_DIRECT);
50 if (fd < 0 && errno == EINVAL) {
51 unlink(fname);
52 return T_EXIT_SKIP;
53 }
54 }
55 if (fd < 0) {
56 perror("open");
57 goto out;
58 }
59
60 if (fstat(fd, &sb) < 0) {
61 perror("fstat");
62 goto out;
63 }
64 if ((sb.st_mode & S_IFMT) != S_IFREG) {
65 err = T_EXIT_SKIP;
66 close(fd);
67 goto out;
68 }
69
70 ret = fanotify_mark(fan, FAN_MARK_ADD, FAN_ACCESS|FAN_MODIFY, fd, NULL);
71 if (ret < 0) {
72 perror("fanotify_mark");
73 goto out;
74 }
75
76 if (fork()) {
77 int wstat;
78
79 io_uring_queue_init(1, &ring, 0);
80 if (posix_memalign(&buf, 4096, 4096))
81 goto out;
82 sqe = io_uring_get_sqe(&ring);
83 io_uring_prep_read(sqe, fd, buf, 4096, 0);
84 io_uring_submit(&ring);
85 ret = io_uring_wait_cqe(&ring, &cqe);
86 if (ret) {
87 fprintf(stderr, "wait_ret=%d\n", ret);
88 goto out;
89 }
90 wait(&wstat);
91 if (!WEXITSTATUS(wstat))
92 err = T_EXIT_PASS;
93 free(buf);
94 } else {
95 struct fanotify_event_metadata m;
96 int fret;
97
98 fret = read(fan, &m, sizeof(m));
99 if (fret < 0)
100 perror("fanotify read");
101 /* fail if mask isn't right or pid indicates non-task context */
102 else if (!(m.mask & 1) || !m.pid)
103 exit(1);
104 exit(0);
105 }
106
107 out:
108 if (f == fname)
109 unlink(fname);
110 return err;
111 }
112
113 #else /* #ifdef CONFIG_HAVE_FANOTIFY */
114
main(void)115 int main(void)
116 {
117 return T_EXIT_SKIP;
118 }
119 #endif /* #ifdef CONFIG_HAVE_FANOTIFY */
120