33#include <sys/syscall.h>
37#define AT_EMPTY_PATH 0x1000
42static void status(
const char* s) {
47#define OK status("OK\n")
49static void test_positional_io(
void) {
50 static const char initial[] =
"abcdefghij";
51 static const char replacement[] =
"XYZ";
52 static const char expected[] =
"aXYZefghij";
53 char buffer[
sizeof(initial)] = {0};
55 status(
"Testing positional file I/O... ");
56 int fd = open(
"/testing/positional-io", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
57 if (fd < 0 || write(fd, initial,
sizeof(initial) - 1) != (ssize_t)(
sizeof(initial) - 1) ||
58 lseek(fd, 3, SEEK_SET) != 3)
61 if (syscall(SYS_pread64, fd, buffer, 3, 6) != 3 || memcmp(buffer,
"ghi", 3) ||
62 lseek(fd, 0, SEEK_CUR) != 3)
64 if (syscall(SYS_pwrite64, fd, replacement,
sizeof(replacement) - 1, 1) !=
65 (ssize_t)(
sizeof(replacement) - 1) ||
66 lseek(fd, 0, SEEK_CUR) != 3)
69 memset(buffer, 0,
sizeof(buffer));
70 if (syscall(SYS_pread64, fd, buffer,
sizeof(expected) - 1, 0) !=
71 (ssize_t)(
sizeof(expected) - 1) ||
72 memcmp(buffer, expected,
sizeof(expected) - 1))
76 if (syscall(SYS_pread64, fd, buffer, 1, (off_t)-1) != -1 || errno != EINVAL)
79 if (syscall(SYS_pwrite64, fd, buffer, 2, INT64_MAX) != -1 || errno != EINVAL)
82 if (syscall(SYS_pread64, fd, buffer, (
size_t)INT64_MAX + 1, 0) != -1 || errno != EINVAL)
85 if (syscall(SYS_pwrite64, fd, (
const void*)UINTPTR_MAX, 2, 0) != -1 || errno != EFAULT)
92 if (syscall(SYS_pread64, pipefd[0], buffer, 1, 0) != -1 || errno != ESPIPE)
95 if (syscall(SYS_pwrite64, pipefd[1], buffer, 1, 0) != -1 || errno != ESPIPE)
97 if (close(pipefd[0]) || close(pipefd[1]))
100 int readOnly = open(
"/testing/positional-io", O_RDONLY);
101 int writeOnly = open(
"/testing/positional-io", O_WRONLY);
102 if (readOnly < 0 || writeOnly < 0)
105 if (syscall(SYS_pwrite64, readOnly, buffer, 1, 0) != -1 || errno != EBADF)
108 if (syscall(SYS_pread64, writeOnly, buffer, 1, 0) != -1 || errno != EBADF)
111 if (close(readOnly) || close(writeOnly) || close(fd) || unlink(
"/testing/positional-io"))
116static void test_positional_vector_io(
void) {
117 static const char initial[] =
"abcdefghij";
118 static const char expected[] =
"aXRS123hijQ";
120 char second[2] = {0};
121 char buffer[
sizeof(expected)] = {0};
122 struct iovec read_vectors[2] = {
126 struct iovec xyz_vectors[2] = {
130 struct iovec numeric_vectors[2] = {
134 struct iovec one_vector = {(
void*)
"Q", 1};
136 status(
"Testing positional vector file I/O... ");
137 int fd = open(
"/testing/positional-vector-io", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
138 if (fd < 0 || write(fd, initial,
sizeof(initial) - 1) != (ssize_t)(
sizeof(initial) - 1) ||
139 lseek(fd, 3, SEEK_SET) != 3)
142 if (preadv(fd, read_vectors, 2, 6) != 3 || memcmp(first,
"gh", 2) || second[0] !=
'i' ||
143 lseek(fd, 0, SEEK_CUR) != 3)
148 if (pwritev(fd, xyz_vectors, 2, 1) != 3 || lseek(fd, 0, SEEK_CUR) != 3)
150 if (syscall(SYS_pwritev, fd, numeric_vectors, 2, 4L, 0L) != 3 || lseek(fd, 0, SEEK_CUR) != 3)
155 if (syscall(SYS_pwritev2, fd, &one_vector, 1, 2L, 0L, 0) != 1 || lseek(fd, 0, SEEK_CUR) != 3)
157 one_vector.iov_base = (
void*)
"R";
158 if (syscall(SYS_pwritev2, fd, &one_vector, 1, 2L, 0L, RWF_NOAPPEND) != 1 ||
159 lseek(fd, 0, SEEK_CUR) != 3)
162 one_vector.iov_base = (
void*)
"S";
163 if (syscall(SYS_pwritev2, fd, &one_vector, 1, -1L, -1L, RWF_NOAPPEND) != 1 ||
164 lseek(fd, 0, SEEK_CUR) != 4)
167 memset(first, 0,
sizeof(first));
168 struct iovec current_read = {first, 2};
169 if (syscall(SYS_preadv2, fd, ¤t_read, 1, -1L, -1L, 0) != 2 || memcmp(first,
"12", 2) ||
170 lseek(fd, 0, SEEK_CUR) != 6)
173 memset(buffer, 0,
sizeof(buffer));
174 if (preadv(fd, &(
struct iovec){buffer,
sizeof(expected) - 1}, 1, 0) !=
175 (ssize_t)(
sizeof(expected) - 1) ||
176 memcmp(buffer, expected,
sizeof(expected) - 1) || lseek(fd, 0, SEEK_CUR) != 6)
180 if (syscall(SYS_preadv, fd, ¤t_read, 1, -1L, -1L) != -1 || errno != EINVAL)
183 if (syscall(SYS_preadv2, fd, ¤t_read, 1, 0L, 0L, RWF_NOWAIT) != -1 || errno != EOPNOTSUPP)
186 if (syscall(SYS_pwritev2, fd, &one_vector, 1, 0L, 0L, RWF_NOWAIT) != -1 || errno != EOPNOTSUPP)
193 if (preadv(pipefd[0], ¤t_read, 1, 0) != -1 || errno != ESPIPE)
196 if (pwritev(pipefd[1], &one_vector, 1, 0) != -1 || errno != ESPIPE)
199 if (close(pipefd[0]) || close(pipefd[1]) || close(fd) || unlink(
"/testing/positional-vector-io"))
204static void expect_lock_failure(
int result,
int expectedError) {
205 if (result != -1 || errno != expectedError)
209static void test_advisory_locks(
void) {
210 struct flock lock = {
212 .l_whence = SEEK_SET,
218 status(
"Testing advisory lock failure behavior... ");
219 int fd = open(
"/testing/advisory-locks", O_RDWR | O_CREAT | O_TRUNC, 0666);
224 expect_lock_failure(fcntl(fd, F_GETLK, &lock), ENOSYS);
225 if (lock.l_type != F_WRLCK || lock.l_whence != SEEK_SET || lock.l_start != 0 || lock.l_len != 0 ||
229 expect_lock_failure(fcntl(fd, F_SETLK, &lock), ENOSYS);
231 expect_lock_failure(fcntl(fd, F_SETLKW, &lock), ENOSYS);
234 expect_lock_failure(fcntl(-1, F_GETLK, &lock), EBADF);
236 expect_lock_failure(fcntl(-1, F_SETLK, &lock), EBADF);
238 expect_lock_failure(fcntl(-1, F_SETLKW, &lock), EBADF);
241 expect_lock_failure(flock(fd, LOCK_SH), ENOSYS);
243 expect_lock_failure(flock(fd, LOCK_EX | LOCK_NB), ENOSYS);
245 expect_lock_failure(flock(fd, LOCK_UN), ENOSYS);
247 expect_lock_failure(flock(fd, LOCK_SH | LOCK_EX), EINVAL);
249 expect_lock_failure(flock(-1, LOCK_SH | LOCK_EX), EINVAL);
251 expect_lock_failure(flock(-1, LOCK_EX), EBADF);
254 expect_lock_failure(lockf(fd, F_TEST, 0), ENOSYS);
256 expect_lock_failure(lockf(fd, F_ULOCK, 0), ENOSYS);
258 expect_lock_failure(lockf(fd, F_TLOCK, 0), ENOSYS);
260 expect_lock_failure(lockf(fd, F_LOCK, 0), ENOSYS);
262 expect_lock_failure(lockf(fd, -1, 0), EINVAL);
265 expect_lock_failure(lockf(-1, F_TEST, 0), EBADF);
267 expect_lock_failure(lockf(-1, F_ULOCK, 0), EBADF);
269 expect_lock_failure(lockf(-1, F_TLOCK, 0), EBADF);
271 expect_lock_failure(lockf(-1, F_LOCK, 0), EBADF);
273 if (close(fd) || unlink(
"/testing/advisory-locks"))
278static void expect_access_failure(
int result,
int expected_error) {
279 if (result != -1 || errno != expected_error)
283static void test_faccessat2(
void) {
284 static const char path[] =
"/testing/access-semantics";
285 static const char link_path[] =
"/testing/access-link";
287 status(
"Testing faccessat2 semantics... ");
288 int fd = open(path, O_RDONLY | O_CREAT | O_TRUNC, 0400);
289 int dirfd = open(
"/testing", O_RDONLY | O_DIRECTORY);
290 if (fd < 0 || dirfd < 0)
292 if (chmod(path, 0400))
295 if (syscall(SYS_faccessat2, -1, path, F_OK, 0) ||
296 syscall(SYS_faccessat2, dirfd,
"access-semantics", F_OK, 0))
299 expect_access_failure(syscall(SYS_faccessat2, -1,
"access-semantics", F_OK, 0), EBADF);
301 expect_access_failure(syscall(SYS_faccessat2, fd,
"access-semantics", F_OK, 0), ENOTDIR);
303 expect_access_failure(syscall(SYS_faccessat2, -1,
"/testing/access-missing", F_OK, 0), ENOENT);
306 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, path, 8, 0), EINVAL);
308 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, path, F_OK, 0x40000000), EINVAL);
310 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, (
const char*)UINTPTR_MAX, F_OK, 0),
314 expect_access_failure(syscall(SYS_faccessat2, fd,
"", F_OK, 0), ENOENT);
315 if (syscall(SYS_faccessat2, fd,
"", F_OK, AT_EMPTY_PATH))
317 if (syscall(SYS_faccessat2, AT_FDCWD,
"", F_OK, AT_EMPTY_PATH))
320 expect_access_failure(syscall(SYS_faccessat2, -1,
"", F_OK, AT_EMPTY_PATH), EBADF);
323 if (symlink(path, link_path))
326 const uid_t original_real = getuid();
327 const uid_t original_effective = geteuid();
328 const uid_t alternate_real = original_effective == 123 ? 124 : 123;
329 if (syscall(SYS_setresuid, alternate_real, original_effective, (uid_t)-1))
333 expect_access_failure(access(path, R_OK), EACCES);
335 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, path, R_OK, 0), EACCES);
336 if (syscall(SYS_faccessat2, AT_FDCWD, path, R_OK, AT_EACCESS))
339 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, path, X_OK, AT_EACCESS), EACCES);
342 expect_access_failure(syscall(SYS_faccessat2, AT_FDCWD, link_path, R_OK, 0), EACCES);
343 if (syscall(SYS_faccessat2, AT_FDCWD, link_path, R_OK, AT_SYMLINK_NOFOLLOW) ||
344 syscall(SYS_faccessat2, AT_FDCWD, link_path, R_OK, AT_EACCESS))
347 if (syscall(SYS_setresuid, original_real, original_effective, (uid_t)-1))
349 if (close(dirfd) || close(fd) || unlink(link_path) || unlink(path))
360 printf(
"Testing filesystem...\n");
362 int urandom_fd = open(
"/dev/urandom", O_RDONLY);
368 status(
"Creating directory for fsck test... ");
369 rc = mkdir(
"/fscktest", 0777);
375 status(
"Creating directory for main test... ");
376 rc = mkdir(
"/testing", 0777);
381 test_positional_io();
382 test_positional_vector_io();
383 test_advisory_locks();
387 status(
"Testing file creation... ");
388 for (
size_t i = 0; i < 10; ++i) {
389 size_t sz = rand() % 8192;
392 void* p = malloc(sz);
395 size_t bytesRead = 0;
396 while (bytesRead < sz) {
397 ssize_t n = read(urandom_fd, (
char*)p + bytesRead, sz - bytesRead);
398 if (n < 0 && errno == EINTR)
404 bytesRead += (size_t)n;
410 sprintf(fn,
"/testing/f%zu", i);
411 fd = open(fn, O_RDWR | O_CREAT, 0666);
416 if (write(fd, p, sz) != (ssize_t)sz) {
424 sprintf(fn,
"/fscktest/f%zu", i);
425 fd = open(fn, O_RDWR | O_CREAT, 0666);
430 if (write(fd, p, sz) != (ssize_t)sz) {
440 status(
"Testing file deletion... ");
441 for (
size_t i = 0; i < 5; ++i) {
443 sprintf(fn,
"/testing/f%zu", i);
448 status(
"Testing a failed rmdir... ");
449 rc = rmdir(
"/testing");
454 status(
"Testing further file deletion... ");
455 for (
size_t i = 5; i < 10; ++i) {
457 sprintf(fn,
"/testing/f%zu", i);
462 status(
"Testing rmdir... ");
463 rc = rmdir(
"/testing");