[libc-commits] [libc] 4039fdb - [libc] add ioctl (#141393)
via libc-commits
libc-commits at lists.llvm.org
Thu Jun 12 09:20:36 PDT 2025
Author: W. Turner Abney
Date: 2025-06-12T09:20:32-07:00
New Revision: 4039fdb7ba5a0d9ead5bdc0404f036063a4ca95d
URL: https://github.com/llvm/llvm-project/commit/4039fdb7ba5a0d9ead5bdc0404f036063a4ca95d
DIFF: https://github.com/llvm/llvm-project/commit/4039fdb7ba5a0d9ead5bdc0404f036063a4ca95d.diff
LOG: [libc] add ioctl (#141393)
Closes #85275
Closes #90317
Updates #97191
---------
Co-authored-by: Joseph Huber <huberjn at outlook.com>
Co-authored-by: Michael Jones <michaelrj at google.com>
Added:
libc/hdr/sys_ioctl_macros.h
libc/src/sys/ioctl/CMakeLists.txt
libc/src/sys/ioctl/ioctl.h
libc/src/sys/ioctl/linux/CMakeLists.txt
libc/src/sys/ioctl/linux/ioctl.cpp
libc/test/src/sys/ioctl/CMakeLists.txt
libc/test/src/sys/ioctl/linux/CMakeLists.txt
libc/test/src/sys/ioctl/linux/ioctl_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/arm/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/hdr/CMakeLists.txt
libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
libc/src/sys/CMakeLists.txt
libc/test/src/sys/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 520046f768b5d..fcf1278eae723 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -245,6 +245,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.mincore
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 7432a7e912e81..1161ae260be2e 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -172,6 +172,9 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.free
libc.src.stdlib.malloc
+ # sys/ioctl.h entrypoints
+ libc.src.sys.ioctl.ioctl
+
# sys/mman.h entrypoints
libc.src.sys.mman.mmap
libc.src.sys.mman.munmap
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 0b645a2d2fb8b..050fc2672a57e 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -246,6 +246,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.mincore
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 959bdbf08dbea..6c9d83708b92f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -246,6 +246,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.mincore
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 209fcb965242f..1e9f59621a8e5 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -126,6 +126,15 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sys_epoll_macros
)
+add_proxy_header_library(
+ sys_ioctl_macros
+ HDRS
+ sys_ioctl_macros.h
+ FULL_BUILD_DEPENDS
+ libc.include.sys_ioctl
+ libc.include.llvm-libc-macros.sys_ioctl_macros
+)
+
add_proxy_header_library(
sys_stat_macros
HDRS
diff --git a/libc/hdr/sys_ioctl_macros.h b/libc/hdr/sys_ioctl_macros.h
new file mode 100644
index 0000000000000..935d436273465
--- /dev/null
+++ b/libc/hdr/sys_ioctl_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/ioctl.h -----------------------------===//
+//
+// 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_HDR_SYS_IOCTL_MACROS_H
+#define LLVM_LIBC_HDR_SYS_IOCTL_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/sys-ioctl-macros.h"
+
+#else // Overlay mode
+
+#include <sys/ioctl.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_IOCTL_MACROS_H
diff --git a/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
index 5eb779aeeca56..41226080084c3 100644
--- a/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
@@ -15,5 +15,6 @@
// around the definitions of macros like _IO, _IOR, _IOW, and _IOWR that I don't
// think is worth digging into right now.
#define TIOCGETD 0x5424
+#define FIONREAD 0x541B
#endif // LLVM_LIBC_MACROS_LINUX_SYS_IOCTL_MACROS_H
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index 9a73b80d35d2f..0fa11e9eee696 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -13,3 +13,4 @@ add_subdirectory(utsname)
add_subdirectory(wait)
add_subdirectory(prctl)
add_subdirectory(uio)
+add_subdirectory(ioctl)
diff --git a/libc/src/sys/ioctl/CMakeLists.txt b/libc/src/sys/ioctl/CMakeLists.txt
new file mode 100644
index 0000000000000..099a1b96389fc
--- /dev/null
+++ b/libc/src/sys/ioctl/CMakeLists.txt
@@ -0,0 +1,10 @@
+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..62323ba7dd4dc
--- /dev/null
+++ b/libc/src/sys/ioctl/ioctl.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for ioctl ---------------------------*-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
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int ioctl(int fd, unsigned long request, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#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..876f35aaee66c
--- /dev/null
+++ b/libc/src/sys/ioctl/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+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..f03fea21c75bd
--- /dev/null
+++ b/libc/src/sys/ioctl/linux/ioctl.cpp
@@ -0,0 +1,36 @@
+//===---------- Linux implementation of the 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 <stdarg.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, ioctl, (int fd, unsigned long request, ...)) {
+ va_list vargs;
+ va_start(vargs, request);
+ void *data_pointer = va_arg(vargs, void *);
+ int ret =
+ LIBC_NAMESPACE::syscall_impl<int>(SYS_ioctl, fd, request, data_pointer);
+ va_end(vargs);
+
+ // Some ioctls can be expected to return positive values
+ if (ret >= 0)
+ return ret;
+
+ // If there is an error, errno is set and -1 is returned.
+ libc_errno = -ret;
+ return -1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt
index 224cc7905ad31..13bf91eef04be 100644
--- a/libc/test/src/sys/CMakeLists.txt
+++ b/libc/test/src/sys/CMakeLists.txt
@@ -13,3 +13,4 @@ add_subdirectory(auxv)
add_subdirectory(epoll)
add_subdirectory(uio)
add_subdirectory(time)
+add_subdirectory(ioctl)
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..e5095c54a729f
--- /dev/null
+++ b/libc/test/src/sys/ioctl/linux/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_custom_target(libc_sys_ioctl_unittests)
+
+add_libc_unittest(
+ ioctl_test
+ SUITE
+ libc_sys_ioctl_unittests
+ SRCS
+ ioctl_test.cpp
+ DEPENDS
+ libc.hdr.ioctl_macros
+ libc.src.sys.ioctl.ioctl
+ libc.src.errno.errno
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.read
+ libc.src.unistd.write
+)
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..9c56a4689b186
--- /dev/null
+++ b/libc/test/src/sys/ioctl/linux/ioctl_test.cpp
@@ -0,0 +1,75 @@
+//===-- 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/errno/libc_errno.h"
+#include "src/fcntl/open.h"
+#include "src/sys/ioctl/ioctl.h"
+#include "src/unistd/close.h"
+#include "src/unistd/read.h"
+#include "src/unistd/write.h"
+
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+#include "hdr/sys_stat_macros.h"
+
+#include "hdr/sys_ioctl_macros.h"
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST(LlvmLibcSysIoctlTest, InvalidCommandAndFIONREAD) {
+ LIBC_NAMESPACE::libc_errno = 0;
+
+ // Setup the test file
+ constexpr const char *TEST_FILE_NAME = "ioctl.test";
+ constexpr const char TEST_MSG[] = "ioctl test";
+ constexpr int TEST_MSG_SIZE = sizeof(TEST_MSG) - 1;
+ auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);
+ int new_test_file_fd = LIBC_NAMESPACE::open(
+ TEST_FILE, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ ASSERT_THAT(
+ (int)LIBC_NAMESPACE::write(new_test_file_fd, TEST_MSG, TEST_MSG_SIZE),
+ Succeeds(TEST_MSG_SIZE));
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_THAT(LIBC_NAMESPACE::close(new_test_file_fd), Succeeds(0));
+ ASSERT_ERRNO_SUCCESS();
+
+ // Reopen the file for testing
+ int fd = LIBC_NAMESPACE::open(TEST_FILE, O_RDONLY);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(fd, 0);
+
+ // FIONREAD reports the number of available bytes to read for the passed fd
+ // This will report the full size of the file, as we haven't read anything yet
+ int n = -1;
+ int ret = LIBC_NAMESPACE::ioctl(fd, FIONREAD, &n);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(ret, -1);
+ ASSERT_EQ(n, TEST_MSG_SIZE);
+
+ // But if we read some bytes...
+ constexpr int READ_COUNT = 5;
+ char read_buffer[READ_COUNT];
+ ASSERT_THAT((int)LIBC_NAMESPACE::read(fd, read_buffer, READ_COUNT),
+ Succeeds(READ_COUNT));
+
+ // ... n should have decreased by the number of bytes we've read
+ int n_after_reading = -1;
+ ret = LIBC_NAMESPACE::ioctl(fd, FIONREAD, &n_after_reading);
+ ASSERT_ERRNO_SUCCESS();
+ ASSERT_GT(ret, -1);
+ ASSERT_EQ(n - READ_COUNT, n_after_reading);
+
+ // 0xDEADBEEF is just a random nonexistent command;
+ // calling this should always fail with ENOTTY
+ ret = LIBC_NAMESPACE::ioctl(fd, 0xDEADBEEF, NULL);
+ ASSERT_ERRNO_EQ(ENOTTY);
+ ASSERT_EQ(ret, -1);
+
+ ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
+}
More information about the libc-commits
mailing list