1 /* SPDX-License-Identifier: MIT */
2 /*
3 * Description: run various statx(2) tests
4 *
5 */
6 #include <errno.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <sys/types.h>
13 #include <sys/syscall.h>
14 #include <sys/stat.h>
15
16 #include "helpers.h"
17 #include "liburing.h"
18
19 #ifdef __NR_statx
do_statx(int dfd,const char * path,int flags,unsigned mask,struct statx * statxbuf)20 static int do_statx(int dfd, const char *path, int flags, unsigned mask,
21 struct statx *statxbuf)
22 {
23 return syscall(__NR_statx, dfd, path, flags, mask, statxbuf);
24 }
25 #else
do_statx(int dfd,const char * path,int flags,unsigned mask,struct statx * statxbuf)26 static int do_statx(int dfd, const char *path, int flags, unsigned mask,
27 struct statx *statxbuf)
28 {
29 errno = ENOSYS;
30 return -1;
31 }
32 #endif
33
statx_syscall_supported(void)34 static int statx_syscall_supported(void)
35 {
36 return errno == ENOSYS ? 0 : -1;
37 }
38
test_statx_invalid_buf(struct io_uring * ring,const char * path)39 static int test_statx_invalid_buf(struct io_uring *ring, const char *path)
40 {
41 struct io_uring_cqe *cqe;
42 struct io_uring_sqe *sqe;
43 struct statx *x = (struct statx *) (uintptr_t) 0x1234;
44 int ret;
45
46 sqe = io_uring_get_sqe(ring);
47 if (!sqe) {
48 fprintf(stderr, "get sqe failed\n");
49 goto err;
50 }
51 io_uring_prep_statx(sqe, -1, path, 0, STATX_ALL, x);
52
53 ret = io_uring_submit(ring);
54 if (ret <= 0) {
55 fprintf(stderr, "sqe submit failed: %d\n", ret);
56 goto err;
57 }
58
59 ret = io_uring_wait_cqe(ring, &cqe);
60 if (ret < 0) {
61 fprintf(stderr, "wait completion %d\n", ret);
62 goto err;
63 }
64 ret = cqe->res;
65 io_uring_cqe_seen(ring, cqe);
66 if (ret != -EFAULT) {
67 fprintf(stderr, "Invalid address didn't fail\n");
68 goto err;
69 }
70
71 return 0;
72 err:
73 return -1;
74 }
75
test_statx_invalid_path(struct io_uring * ring)76 static int test_statx_invalid_path(struct io_uring *ring)
77 {
78 const char *path = (const char *) (uintptr_t) 0x1234;
79 struct io_uring_cqe *cqe;
80 struct io_uring_sqe *sqe;
81 struct statx x1 = { };
82 int ret;
83
84 sqe = io_uring_get_sqe(ring);
85 if (!sqe) {
86 fprintf(stderr, "get sqe failed\n");
87 goto err;
88 }
89 io_uring_prep_statx(sqe, -1, path, 0, STATX_ALL, &x1);
90
91 ret = io_uring_submit(ring);
92 if (ret <= 0) {
93 fprintf(stderr, "sqe submit failed: %d\n", ret);
94 goto err;
95 }
96
97 ret = io_uring_wait_cqe(ring, &cqe);
98 if (ret < 0) {
99 fprintf(stderr, "wait completion %d\n", ret);
100 goto err;
101 }
102 ret = cqe->res;
103 io_uring_cqe_seen(ring, cqe);
104 if (ret != -EFAULT) {
105 fprintf(stderr, "Invalid address didn't fail\n");
106 goto err;
107 }
108
109 return 0;
110 err:
111 return -1;
112 }
113
test_statx(struct io_uring * ring,const char * path)114 static int test_statx(struct io_uring *ring, const char *path)
115 {
116 struct io_uring_cqe *cqe;
117 struct io_uring_sqe *sqe;
118 struct statx x1 = { }, x2 = { };
119 int ret;
120
121 sqe = io_uring_get_sqe(ring);
122 if (!sqe) {
123 fprintf(stderr, "get sqe failed\n");
124 goto err;
125 }
126 io_uring_prep_statx(sqe, -1, path, 0, STATX_ALL, &x1);
127
128 ret = io_uring_submit(ring);
129 if (ret <= 0) {
130 fprintf(stderr, "sqe submit failed: %d\n", ret);
131 goto err;
132 }
133
134 ret = io_uring_wait_cqe(ring, &cqe);
135 if (ret < 0) {
136 fprintf(stderr, "wait completion %d\n", ret);
137 goto err;
138 }
139 ret = cqe->res;
140 io_uring_cqe_seen(ring, cqe);
141 if (ret)
142 return ret;
143 ret = do_statx(-1, path, 0, STATX_ALL, &x2);
144 if (ret < 0)
145 return statx_syscall_supported();
146 if (memcmp(&x1, &x2, sizeof(x1))) {
147 fprintf(stderr, "Miscompare between io_uring and statx\n");
148 goto err;
149 }
150 return 0;
151 err:
152 return -1;
153 }
154
test_statx_fd(struct io_uring * ring,const char * path)155 static int test_statx_fd(struct io_uring *ring, const char *path)
156 {
157 struct io_uring_cqe *cqe;
158 struct io_uring_sqe *sqe;
159 struct statx x1, x2;
160 int ret, fd;
161
162 fd = open(path, O_RDONLY);
163 if (fd < 0) {
164 if (errno == EPERM || errno == EACCES)
165 return 0;
166 perror("open");
167 return 1;
168 }
169
170 memset(&x1, 0, sizeof(x1));
171
172 sqe = io_uring_get_sqe(ring);
173 if (!sqe) {
174 fprintf(stderr, "get sqe failed\n");
175 goto err;
176 }
177 io_uring_prep_statx(sqe, fd, "", AT_EMPTY_PATH, STATX_ALL, &x1);
178
179 ret = io_uring_submit(ring);
180 if (ret <= 0) {
181 fprintf(stderr, "sqe submit failed: %d\n", ret);
182 goto err;
183 }
184
185 ret = io_uring_wait_cqe(ring, &cqe);
186 if (ret < 0) {
187 fprintf(stderr, "wait completion %d\n", ret);
188 goto err;
189 }
190 ret = cqe->res;
191 io_uring_cqe_seen(ring, cqe);
192 if (ret)
193 return ret;
194 memset(&x2, 0, sizeof(x2));
195 ret = do_statx(fd, "", AT_EMPTY_PATH, STATX_ALL, &x2);
196 if (ret < 0)
197 return statx_syscall_supported();
198 if (memcmp(&x1, &x2, sizeof(x1))) {
199 fprintf(stderr, "Miscompare between io_uring and statx\n");
200 goto err;
201 }
202 return 0;
203 err:
204 return -1;
205 }
206
main(int argc,char * argv[])207 int main(int argc, char *argv[])
208 {
209 struct io_uring ring;
210 const char *fname;
211 int ret;
212
213 ret = io_uring_queue_init(8, &ring, 0);
214 if (ret) {
215 fprintf(stderr, "ring setup failed\n");
216 return 1;
217 }
218
219 if (argc > 1) {
220 fname = argv[1];
221 } else {
222 fname = "/tmp/.statx";
223 t_create_file(fname, 4096);
224 }
225
226 ret = test_statx(&ring, fname);
227 if (ret) {
228 if (ret == -EINVAL) {
229 fprintf(stdout, "statx not supported, skipping\n");
230 goto done;
231 }
232 fprintf(stderr, "test_statx failed: %d\n", ret);
233 goto err;
234 }
235
236 ret = test_statx_invalid_path(&ring);
237 if (ret) {
238 fprintf(stderr, "test_statx_invalid_path failed: %d\n", ret);
239 goto err;
240 }
241
242 ret = test_statx_invalid_buf(&ring, fname);
243 if (ret) {
244 fprintf(stderr, "test_statx_invalid_buf failed: %d\n", ret);
245 goto err;
246 }
247
248 ret = test_statx_fd(&ring, fname);
249 if (ret) {
250 fprintf(stderr, "test_statx_fd failed: %d\n", ret);
251 goto err;
252 }
253 done:
254 if (fname != argv[1])
255 unlink(fname);
256 return 0;
257 err:
258 if (fname != argv[1])
259 unlink(fname);
260 return 1;
261 }
262