• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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