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
19using 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.
29TEST(LlvmLibcSyscallTest, TrivialCall) {
30 LIBC_NAMESPACE::libc_errno = 0;
31
32 ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_gettid), 0l);
33 ASSERT_ERRNO_SUCCESS();
34}
35
36TEST(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
71TEST(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
100TEST(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

source code of libc/test/src/unistd/syscall_test.cpp