180 lines
5.9 KiB
C++
180 lines
5.9 KiB
C++
//===-- Unittests for syscalls --------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "src/errno/libc_errno.h"
|
|
#include "src/unistd/syscall.h"
|
|
#include "test/UnitTest/ErrnoSetterMatcher.h"
|
|
#include "test/UnitTest/Test.h"
|
|
|
|
#include "hdr/fcntl_macros.h"
|
|
#include <sys/stat.h> // For S_* flags.
|
|
#include <sys/syscall.h> // For syscall numbers.
|
|
#include <unistd.h>
|
|
|
|
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
|
|
|
|
// We only do a smoke test here. Actual functionality tests are
|
|
// done by the unit tests of the syscall wrappers like mmap.
|
|
// The goal is to test syscalls with a wide number of args.
|
|
|
|
// There is no function named "syscall" in llvm-libc, we instead use a macro to
|
|
// set up the arguments properly. We still need to specify the namespace though
|
|
// because the macro generates a call to the actual internal function
|
|
// (__llvm_libc_syscall) which is inside the namespace.
|
|
TEST(LlvmLibcSyscallTest, TrivialCall) {
|
|
LIBC_NAMESPACE::libc_errno = 0;
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_gettid), 0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
}
|
|
|
|
TEST(LlvmLibcSyscallTest, SymlinkCreateDestroy) {
|
|
constexpr const char LINK_VAL[] = "syscall_readlink_test_value";
|
|
constexpr const char LINK[] = "testdata/syscall_readlink.test.link";
|
|
|
|
#ifdef SYS_symlink
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlink, LINK_VAL, LINK), 0l);
|
|
#elif defined(SYS_symlinkat)
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_symlinkat, LINK_VAL, AT_FDCWD, LINK),
|
|
0l);
|
|
#else
|
|
#error "symlink and symlinkat syscalls not available."
|
|
#endif
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
char buf[sizeof(LINK_VAL)];
|
|
|
|
#ifdef SYS_readlink
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_readlink, LINK, buf, sizeof(buf)), 0l);
|
|
#elif defined(SYS_readlinkat)
|
|
ASSERT_GE(
|
|
LIBC_NAMESPACE::syscall(SYS_readlinkat, AT_FDCWD, LINK, buf, sizeof(buf)),
|
|
0l);
|
|
#endif
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
#ifdef SYS_unlink
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, LINK), 0l);
|
|
#elif defined(SYS_unlinkat)
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, LINK, 0), 0l);
|
|
#else
|
|
#error "unlink and unlinkat syscalls not available."
|
|
#endif
|
|
ASSERT_ERRNO_SUCCESS();
|
|
}
|
|
|
|
TEST(LlvmLibcSyscallTest, FileReadWrite) {
|
|
constexpr const char HELLO[] = "hello";
|
|
constexpr int HELLO_SIZE = sizeof(HELLO);
|
|
|
|
constexpr const char *TEST_FILE = "testdata/syscall_pread_pwrite.test";
|
|
|
|
#ifdef SYS_open
|
|
int fd =
|
|
LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
|
|
#elif defined(SYS_openat)
|
|
int fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE,
|
|
O_WRONLY | O_CREAT, S_IRWXU);
|
|
#else
|
|
#error "open and openat syscalls not available."
|
|
#endif
|
|
ASSERT_GT(fd, 0);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_pwrite64, fd, HELLO, HELLO_SIZE, 0),
|
|
0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_fsync, fd), 0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, fd), 0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
}
|
|
|
|
TEST(LlvmLibcSyscallTest, FileLinkCreateDestroy) {
|
|
constexpr const char *TEST_DIR = "testdata";
|
|
constexpr const char *TEST_FILE = "syscall_linkat.test";
|
|
constexpr const char *TEST_FILE_PATH = "testdata/syscall_linkat.test";
|
|
constexpr const char *TEST_FILE_LINK = "syscall_linkat.test.link";
|
|
constexpr const char *TEST_FILE_LINK_PATH =
|
|
"testdata/syscall_linkat.test.link";
|
|
|
|
// The test strategy is as follows:
|
|
// 1. Create a normal file
|
|
// 2. Create a link to that file.
|
|
// 3. Open the link to check that the link was created.
|
|
// 4. Cleanup the file and its link.
|
|
|
|
#ifdef SYS_open
|
|
int write_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_PATH,
|
|
O_WRONLY | O_CREAT, S_IRWXU);
|
|
#elif defined(SYS_openat)
|
|
int write_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_FILE_PATH,
|
|
O_WRONLY | O_CREAT, S_IRWXU);
|
|
#else
|
|
#error "open and openat syscalls not available."
|
|
#endif
|
|
ASSERT_GT(write_fd, 0);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, write_fd), 0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
#ifdef SYS_open
|
|
int dir_fd = LIBC_NAMESPACE::syscall(SYS_open, TEST_DIR, O_DIRECTORY, 0);
|
|
#elif defined(SYS_openat)
|
|
int dir_fd =
|
|
LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD, TEST_DIR, O_DIRECTORY, 0);
|
|
#else
|
|
#error "open and openat syscalls not available."
|
|
#endif
|
|
ASSERT_GT(dir_fd, 0);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_linkat, dir_fd, TEST_FILE, dir_fd,
|
|
TEST_FILE_LINK, 0),
|
|
0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
#ifdef SYS_open
|
|
int link_fd =
|
|
LIBC_NAMESPACE::syscall(SYS_open, TEST_FILE_LINK_PATH, O_PATH, 0);
|
|
#elif defined(SYS_openat)
|
|
int link_fd = LIBC_NAMESPACE::syscall(SYS_openat, AT_FDCWD,
|
|
TEST_FILE_LINK_PATH, O_PATH, 0);
|
|
#else
|
|
#error "open and openat syscalls not available."
|
|
#endif
|
|
ASSERT_GT(link_fd, 0);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
#ifdef SYS_unlink
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_PATH), 0l);
|
|
#elif defined(SYS_unlinkat)
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_PATH, 0),
|
|
0l);
|
|
#else
|
|
#error "unlink and unlinkat syscalls not available."
|
|
#endif
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
#ifdef SYS_unlink
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_unlink, TEST_FILE_LINK_PATH), 0l);
|
|
#elif defined(SYS_unlinkat)
|
|
ASSERT_GE(
|
|
LIBC_NAMESPACE::syscall(SYS_unlinkat, AT_FDCWD, TEST_FILE_LINK_PATH, 0),
|
|
0l);
|
|
#else
|
|
#error "unlink and unlinkat syscalls not available."
|
|
#endif
|
|
ASSERT_ERRNO_SUCCESS();
|
|
|
|
ASSERT_GE(LIBC_NAMESPACE::syscall(SYS_close, dir_fd), 0l);
|
|
ASSERT_ERRNO_SUCCESS();
|
|
}
|