diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index db96a80051a8d..6d4fddc73b72e 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -205,6 +205,9 @@ set(TARGET_LIBC_ENTRYPOINTS #libc.src.stdio.scanf #libc.src.stdio.fscanf + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mmap diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 67abf851b4d50..370cf9786c903 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -210,6 +210,9 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.stdio.scanf libc.src.stdio.fscanf + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mmap diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 355eaf33ace6d..38bb83b15d455 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -225,6 +225,9 @@ set(TARGET_LIBC_ENTRYPOINTS # https://github.com/llvm/llvm-project/issues/80060 # libc.src.sys.epoll.epoll_pwait2 + # sys/ioctl.h entrypoints + libc.src.sys.ioctl.ioctl + # sys/mman.h entrypoints libc.src.sys.mman.madvise libc.src.sys.mman.mmap diff --git a/libc/spec/linux.td b/libc/spec/linux.td index f91f55ddac784..6e9b64f5a6b4a 100644 --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -79,6 +79,24 @@ def Linux : StandardSpec<"Linux"> { [] // Functions >; + HeaderSpec SysIoctl = HeaderSpec< + "sys/ioctl.h", + [Macro<"MAP_ANONYMOUS">], + [], // Types + [], // Enumerations + [ + FunctionSpec< + "ioctl", + RetValSpec, + [ + ArgSpec, + ArgSpec, + ArgSpec, + ] + >, + ] // Functions + >; + HeaderSpec SysMMan = HeaderSpec< "sys/mman.h", [Macro<"MAP_ANONYMOUS">], diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt index adc666b94202f..ac54df35284a7 100644 --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(auxv) add_subdirectory(epoll) +add_subdirectory(ioctl) add_subdirectory(mman) add_subdirectory(random) add_subdirectory(resource) diff --git a/libc/src/sys/ioctl/CMakeLists.txt b/libc/src/sys/ioctl/CMakeLists.txt new file mode 100644 index 0000000000000..4b50c278c7871 --- /dev/null +++ b/libc/src/sys/ioctl/CMakeLists.txt @@ -0,0 +1,12 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) +endif() + +add_entrypoint_object( + ioctl + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.ioctl +) + + diff --git a/libc/src/sys/ioctl/ioctl.h b/libc/src/sys/ioctl/ioctl.h new file mode 100644 index 0000000000000..8365678276a42 --- /dev/null +++ b/libc/src/sys/ioctl/ioctl.h @@ -0,0 +1,17 @@ +//===-- Implementation header for mmap function -----------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H +#define LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H +namespace LIBC_NAMESPACE { + +int ioctl(int fd, unsigned long request, ...); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_SYS_IOCTL_IOCTL_H diff --git a/libc/src/sys/ioctl/linux/CMakeLists.txt b/libc/src/sys/ioctl/linux/CMakeLists.txt new file mode 100644 index 0000000000000..8a23505d4e9d1 --- /dev/null +++ b/libc/src/sys/ioctl/linux/CMakeLists.txt @@ -0,0 +1,13 @@ +add_entrypoint_object( + ioctl + SRCS + ioctl.cpp + HDRS + ../ioctl.h + DEPENDS + libc.include.sys_ioctl + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + diff --git a/libc/src/sys/ioctl/linux/ioctl.cpp b/libc/src/sys/ioctl/linux/ioctl.cpp new file mode 100644 index 0000000000000..e41df2bbedae4 --- /dev/null +++ b/libc/src/sys/ioctl/linux/ioctl.cpp @@ -0,0 +1,39 @@ +//===---------- Linux implementation of the POSIX ioctl function --------===// +// +// 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/sys/ioctl/ioctl.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" +#include +#include // For syscall numbers. + +namespace LIBC_NAMESPACE { + +// This function is currently linux only. It has to be refactored suitably if +// ioctl is to be supported on non-linux operating systems also. +LLVM_LIBC_FUNCTION(int, ioctl, (int fd, unsigned long request, ...)) { + va_list ptr_to_memory; + va_start(ptr_to_memory, request); + va_arg(ptr_to_memory, void *); + int ret = + LIBC_NAMESPACE::syscall_impl(SYS_ioctl, fd, request, ptr_to_memory); + va_end(ptr_to_memory); + + // A negative return value indicates an error with the magnitude of the + // value being the error code. + if (ret < 0) { + libc_errno = -ret; + return -1; + } + + return 0; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt index dc0aa8bf7b75d..b58644e60f578 100644 --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -1,4 +1,8 @@ +add_subdirectory(auxv) +add_subdirectory(epoll) +add_subdirectory(ioctl) add_subdirectory(mman) +add_subdirectory(prctl) add_subdirectory(random) add_subdirectory(resource) add_subdirectory(select) @@ -8,6 +12,4 @@ add_subdirectory(stat) add_subdirectory(statvfs) add_subdirectory(utsname) add_subdirectory(wait) -add_subdirectory(prctl) -add_subdirectory(auxv) -add_subdirectory(epoll) + diff --git a/libc/test/src/sys/ioctl/CMakeLists.txt b/libc/test/src/sys/ioctl/CMakeLists.txt new file mode 100644 index 0000000000000..b4bbe81c92ff2 --- /dev/null +++ b/libc/test/src/sys/ioctl/CMakeLists.txt @@ -0,0 +1,3 @@ +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}) + add_subdirectory(${LIBC_TARGET_OS}) +endif() diff --git a/libc/test/src/sys/ioctl/linux/CMakeLists.txt b/libc/test/src/sys/ioctl/linux/CMakeLists.txt new file mode 100644 index 0000000000000..3f82d1765433f --- /dev/null +++ b/libc/test/src/sys/ioctl/linux/CMakeLists.txt @@ -0,0 +1,15 @@ +add_custom_target(libc_sys_ioctl_unittests) + +add_libc_unittest( + ioctl_test + SUITE + libc_sys_ioctl_unittests + SRCS + ioctl_test.cpp + DEPENDS + libc.src.sys.ioctl.ioctl + libc.src.errno.errno + libc.src.fcntl.open + libc.src.unistd.close +) + diff --git a/libc/test/src/sys/ioctl/linux/ioctl_test.cpp b/libc/test/src/sys/ioctl/linux/ioctl_test.cpp new file mode 100644 index 0000000000000..68326879b895b --- /dev/null +++ b/libc/test/src/sys/ioctl/linux/ioctl_test.cpp @@ -0,0 +1,40 @@ +//===-- Unittests for ioctl -----------------------------------------------===// +// +// 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/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/errno/libc_errno.h" +#include "src/fcntl/open.h" +#include "src/sys/ioctl/ioctl.h" +#include "src/unistd/close.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/LibcTest.h" +#include "test/UnitTest/Test.h" + +#include + +TEST(LlvmLibcIoctlTest, InvalidFileDescriptor) { + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; + int fd = 10; + unsigned long request = 10; + int res = LIBC_NAMESPACE::ioctl(fd, request, NULL); + EXPECT_THAT(res, Fails(EBADF, -1)); +} + +TEST(LlvmLibcIoctlTest, ValidFileDescriptor) { + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + LIBC_NAMESPACE::libc_errno = 0; + constexpr const char *FILENAME = "ioctl.test"; + auto TEST_FILE = libc_make_test_file_path(FILENAME); + int fd = LIBC_NAMESPACE::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(fd, 0); + int data; + int res = LIBC_NAMESPACE::ioctl(fd, FS_IOC_GETFLAGS, &data); + EXPECT_THAT(res, Succeeds()); + ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); +}