1 | //===-- Unittests for syscalls --------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "src/errno/libc_errno.h" |
10 | #include "src/unistd/syscall.h" |
11 | #include "test/UnitTest/ErrnoSetterMatcher.h" |
12 | #include "test/UnitTest/Test.h" |
13 | |
14 | #include <fcntl.h> |
15 | #include <sys/stat.h> // For S_* flags. |
16 | #include <sys/syscall.h> // For syscall numbers. |
17 | #include <unistd.h> |
18 | |
19 | using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; |
20 | |
21 | // We only do a smoke test here. Actual functionality tests are |
22 | // done by the unit tests of the syscall wrappers like mmap. |
23 | // The goal is to test syscalls with a wide number of args. |
24 | |
25 | // There is no function named "syscall" in llvm-libc, we instead use a macro to |
26 | // set up the arguments properly. We still need to specify the namespace though |
27 | // because the macro generates a call to the actual internal function |
28 | // (__llvm_libc_syscall) which is inside the namespace. |
29 | TEST(LlvmLibcSyscallTest, TrivialCall) { |
30 | LIBC_NAMESPACE::libc_errno = 0; |
31 | |
32 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_gettid), 0l); |
33 | ASSERT_ERRNO_SUCCESS(); |
34 | } |
35 | |
36 | TEST(LlvmLibcSyscallTest, SymlinkCreateDestroy) { |
37 | constexpr const char LINK_VAL[] = "syscall_readlink_test_value" ; |
38 | constexpr const char LINK[] = "testdata/syscall_readlink.test.link" ; |
39 | |
40 | #ifdef SYS_symlink |
41 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlink, LINK_VAL, LINK), 0l); |
42 | #elif defined(SYS_symlinkat) |
43 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlinkat, LINK_VAL, AT_FDCWD, LINK), |
44 | 0l); |
45 | #else |
46 | #error "symlink and symlinkat syscalls not available." |
47 | #endif |
48 | ASSERT_ERRNO_SUCCESS(); |
49 | |
50 | char buf[sizeof(LINK_VAL)]; |
51 | |
52 | #ifdef SYS_readlink |
53 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_readlink, LINK, buf, sizeof(buf)), 0l); |
54 | #elif defined(SYS_readlinkat) |
55 | ASSERT_GE( |
56 | LIBC_NAMESPACE::syscall(SYS_readlinkat, AT_FDCWD, LINK, buf, sizeof(buf)), |
57 | 0l); |
58 | #endif |
59 | ASSERT_ERRNO_SUCCESS(); |
60 | |
61 | #ifdef SYS_unlink |
62 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, LINK), 0l); |
63 | #elif defined(SYS_unlinkat) |
64 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, LINK, 0), 0l); |
65 | #else |
66 | #error "unlink and unlinkat syscalls not available." |
67 | #endif |
68 | ASSERT_ERRNO_SUCCESS(); |
69 | } |
70 | |
71 | TEST(LlvmLibcSyscallTest, FileReadWrite) { |
72 | constexpr const char HELLO[] = "hello" ; |
73 | constexpr int HELLO_SIZE = sizeof(HELLO); |
74 | |
75 | constexpr const char *TEST_FILE = "testdata/syscall_pread_pwrite.test" ; |
76 | |
77 | #ifdef SYS_open |
78 | int fd = |
79 | LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU); |
80 | #elif defined(SYS_openat) |
81 | int fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE, |
82 | O_WRONLY | O_CREAT, S_IRWXU); |
83 | #else |
84 | #error "open and openat syscalls not available." |
85 | #endif |
86 | ASSERT_GT(fd, 0); |
87 | ASSERT_ERRNO_SUCCESS(); |
88 | |
89 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_pwrite64, fd, HELLO, HELLO_SIZE, 0), |
90 | 0l); |
91 | ASSERT_ERRNO_SUCCESS(); |
92 | |
93 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_fsync, fd), 0l); |
94 | ASSERT_ERRNO_SUCCESS(); |
95 | |
96 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, fd), 0l); |
97 | ASSERT_ERRNO_SUCCESS(); |
98 | } |
99 | |
100 | TEST(LlvmLibcSyscallTest, FileLinkCreateDestroy) { |
101 | constexpr const char *TEST_DIR = "testdata" ; |
102 | constexpr const char *TEST_FILE = "syscall_linkat.test" ; |
103 | constexpr const char *TEST_FILE_PATH = "testdata/syscall_linkat.test" ; |
104 | constexpr const char *TEST_FILE_LINK = "syscall_linkat.test.link" ; |
105 | constexpr const char *TEST_FILE_LINK_PATH = |
106 | "testdata/syscall_linkat.test.link" ; |
107 | |
108 | // The test strategy is as follows: |
109 | // 1. Create a normal file |
110 | // 2. Create a link to that file. |
111 | // 3. Open the link to check that the link was created. |
112 | // 4. Cleanup the file and its link. |
113 | |
114 | #ifdef SYS_open |
115 | int write_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_PATH, |
116 | O_WRONLY | O_CREAT, S_IRWXU); |
117 | #elif defined(SYS_openat) |
118 | int write_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE_PATH, |
119 | O_WRONLY | O_CREAT, S_IRWXU); |
120 | #else |
121 | #error "open and openat syscalls not available." |
122 | #endif |
123 | ASSERT_GT(write_fd, 0); |
124 | ASSERT_ERRNO_SUCCESS(); |
125 | |
126 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, write_fd), 0l); |
127 | ASSERT_ERRNO_SUCCESS(); |
128 | |
129 | #ifdef SYS_open |
130 | int dir_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_DIR, O_DIRECTORY, 0); |
131 | #elif defined(SYS_openat) |
132 | int dir_fd = |
133 | LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_DIR, O_DIRECTORY, 0); |
134 | #else |
135 | #error "open and openat syscalls not available." |
136 | #endif |
137 | ASSERT_GT(dir_fd, 0); |
138 | ASSERT_ERRNO_SUCCESS(); |
139 | |
140 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_linkat, dir_fd, TEST_FILE, dir_fd, |
141 | TEST_FILE_LINK, 0), |
142 | 0l); |
143 | ASSERT_ERRNO_SUCCESS(); |
144 | #ifdef SYS_open |
145 | int link_fd = |
146 | LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_LINK_PATH, O_PATH, 0); |
147 | #elif defined(SYS_openat) |
148 | int link_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, |
149 | TEST_FILE_LINK_PATH, O_PATH, 0); |
150 | #else |
151 | #error "open and openat syscalls not available." |
152 | #endif |
153 | ASSERT_GT(link_fd, 0); |
154 | ASSERT_ERRNO_SUCCESS(); |
155 | |
156 | #ifdef SYS_unlink |
157 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_PATH), 0l); |
158 | #elif defined(SYS_unlinkat) |
159 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_PATH, 0), |
160 | 0l); |
161 | #else |
162 | #error "unlink and unlinkat syscalls not available." |
163 | #endif |
164 | ASSERT_ERRNO_SUCCESS(); |
165 | |
166 | #ifdef SYS_unlink |
167 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_LINK_PATH), 0l); |
168 | #elif defined(SYS_unlinkat) |
169 | ASSERT_GE( |
170 | LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_LINK_PATH, 0), |
171 | 0l); |
172 | #else |
173 | #error "unlink and unlinkat syscalls not available." |
174 | #endif |
175 | ASSERT_ERRNO_SUCCESS(); |
176 | |
177 | ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, dir_fd), 0l); |
178 | ASSERT_ERRNO_SUCCESS(); |
179 | } |
180 | |