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