[libc-commits] [libc] 7639ba6 - [libc] add isatty
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Mon Oct 10 15:20:53 PDT 2022
Author: Michael Jones
Date: 2022-10-10T15:20:46-07:00
New Revision: 7639ba690648fae2b2034aa842942419b2fdcad4
URL: https://github.com/llvm/llvm-project/commit/7639ba690648fae2b2034aa842942419b2fdcad4
DIFF: https://github.com/llvm/llvm-project/commit/7639ba690648fae2b2034aa842942419b2fdcad4.diff
LOG: [libc] add isatty
The isatty function uses the side effects of an ioctl call to determine
if a specific file descriptor is a terminal. I chose TIOCGETD (get line
discipline of terminal) because it didn't require any new structs.
Reviewed By: sivachandra, lntue
Differential Revision: https://reviews.llvm.org/D135618
Added:
libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
libc/include/llvm-libc-macros/sys-ioctl-macros.h
libc/include/sys/ioctl.h.def
libc/src/unistd/isatty.h
libc/src/unistd/linux/isatty.cpp
libc/test/src/unistd/isatty_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/config/linux/x86_64/headers.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/CMakeLists.txt
libc/include/llvm-libc-macros/linux/CMakeLists.txt
libc/spec/posix.td
libc/src/unistd/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/test/src/unistd/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 32ceb8f1f3434..2a2a03106ed74 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -156,6 +156,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.getpid
libc.src.unistd.getppid
libc.src.unistd.getuid
+ libc.src.unistd.isatty
libc.src.unistd.link
libc.src.unistd.linkat
libc.src.unistd.lseek
diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt
index 284f964b4ed27..a745bccbacb51 100644
--- a/libc/config/linux/x86_64/headers.txt
+++ b/libc/config/linux/x86_64/headers.txt
@@ -11,6 +11,7 @@ set(TARGET_PUBLIC_HEADERS
libc.include.stdio
libc.include.stdlib
libc.include.string
+ libc.include.sys_ioctl
libc.include.sys_mman
libc.include.sys_random
libc.include.sys_syscall
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 4df498c5ba168..a4a6a1477fdf7 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -218,6 +218,15 @@ add_gen_header(
# them.
file(MAKE_DIRECTORY "sys")
+add_gen_header(
+ sys_ioctl
+ DEF_FILE sys/ioctl.h.def
+ GEN_HDR sys/ioctl.h
+ DEPENDS
+ .llvm_libc_common_h
+ .llvm-libc-macros.sys_ioctl_macros
+)
+
add_gen_header(
sys_mman
DEF_FILE sys/mman.h.def
diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt
index def26a13b3a30..2b69a3b606440 100644
--- a/libc/include/llvm-libc-macros/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/CMakeLists.txt
@@ -36,6 +36,15 @@ add_header(
stdlib-macros.h
)
+add_header(
+ sys_ioctl_macros
+ HDR
+ sys-ioctl-macros.h
+ DEPENDS
+ .linux.sys_ioctl_macros
+)
+
+
add_header(
sys_stat_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
index e3c9392d34394..5857290f333a2 100644
--- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt
+++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt
@@ -10,6 +10,12 @@ add_header(
sched-macros.h
)
+add_header(
+ sys_ioctl_macros
+ HDR
+ sys-ioctl-macros.h
+)
+
add_header(
sys_mman_macros
HDR
diff --git a/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
new file mode 100644
index 0000000000000..8f13a0ef4ad30
--- /dev/null
+++ b/libc/include/llvm-libc-macros/linux/sys-ioctl-macros.h
@@ -0,0 +1,19 @@
+//===-- 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_MACROS_LINUX_SYS_IOCTL_MACROS_H
+#define __LLVM_LIBC_MACROS_LINUX_SYS_IOCTL_MACROS_H
+
+// TODO (michaelrj): Finish defining these macros.
+// Just defining this macro for the moment since it's all that we need right
+// now. The other macros are mostly just constants, but there's some complexity
+// 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
+
+#endif // __LLVM_LIBC_MACROS_LINUX_SYS_IOCTL_MACROS_H
diff --git a/libc/include/llvm-libc-macros/sys-ioctl-macros.h b/libc/include/llvm-libc-macros/sys-ioctl-macros.h
new file mode 100644
index 0000000000000..b3fbfe346f829
--- /dev/null
+++ b/libc/include/llvm-libc-macros/sys-ioctl-macros.h
@@ -0,0 +1,16 @@
+//===-- Macros defined in sys/ioctl.h header file -------------------------===//
+//
+// 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_MACROS_SYS_IOCTL_MACROS_H
+#define __LLVM_LIBC_MACROS_SYS_IOCTL_MACROS_H
+
+#ifdef __unix__
+#include "linux/sys-ioctl-macros.h"
+#endif
+
+#endif // __LLVM_LIBC_MACROS_SYS_IOCTL_MACROS_H
diff --git a/libc/include/sys/ioctl.h.def b/libc/include/sys/ioctl.h.def
new file mode 100644
index 0000000000000..90d91cf382913
--- /dev/null
+++ b/libc/include/sys/ioctl.h.def
@@ -0,0 +1,18 @@
+//===-- POSIX header 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_SYS_IOCTL_H
+#define LLVM_LIBC_SYS_IOCTL_H
+
+#include <__llvm-libc-common.h>
+
+#include <llvm-libc-macros/sys-ioctl-macros.h>
+
+%%public_api()
+
+#endif // LLVM_LIBC_SYS_IOCTL_H
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 61e7e4d425555..bab275089f99d 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -401,6 +401,11 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<UidT>,
[ArgSpec<VoidType>]
>,
+ FunctionSpec<
+ "isatty",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>]
+ >,
FunctionSpec<
"link",
RetValSpec<IntType>,
@@ -1030,6 +1035,16 @@ def POSIX : StandardSpec<"POSIX"> {
]
>;
+ HeaderSpec SysIOctl = HeaderSpec<
+ "sys/ioctl.h",
+ [
+ Macro<"TIOCGETD">,
+ ], // Macros
+ [], // Types
+ [], // Enumerations
+ [] // Functions
+ >;
+
let Headers = [
CType,
Dirent,
@@ -1039,6 +1054,7 @@ def POSIX : StandardSpec<"POSIX"> {
Signal,
StdIO,
StdLib,
+ SysIOctl,
SysMMan,
SysResource,
SysStat,
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index ae53763df8893..3d4fa3f13b386 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -114,6 +114,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.getuid
)
+add_entrypoint_object(
+ isatty
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.isatty
+)
+
add_entrypoint_object(
link
ALIAS
diff --git a/libc/src/unistd/isatty.h b/libc/src/unistd/isatty.h
new file mode 100644
index 0000000000000..cffee57e0f2ec
--- /dev/null
+++ b/libc/src/unistd/isatty.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for isatty ------------------------*- 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_UNISTD_ISATTY_H
+#define LLVM_LIBC_SRC_UNISTD_ISATTY_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+int isatty(int fd);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_ISATTY_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 2a6a0e66910df..af4585457e09b 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -207,6 +207,20 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
)
+add_entrypoint_object(
+ isatty
+ SRCS
+ isatty.cpp
+ HDRS
+ ../isatty.h
+ DEPENDS
+ libc.include.unistd
+ libc.include.errno
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
link
SRCS
diff --git a/libc/src/unistd/linux/isatty.cpp b/libc/src/unistd/linux/isatty.cpp
new file mode 100644
index 0000000000000..705d03cce113f
--- /dev/null
+++ b/libc/src/unistd/linux/isatty.cpp
@@ -0,0 +1,33 @@
+//===-- Linux implementation of isatty ------------------------------------===//
+//
+// 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/unistd/isatty.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/ioctl.h> // For ioctl numbers.
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, isatty, (int fd)) {
+ constexpr int INIT_VAL = 0x1234abcd;
+ int line_d_val = INIT_VAL;
+ // This gets the line dicipline of the terminal. When called on something that
+ // isn't a terminal it doesn't change line_d_val and returns -1.
+ int result = __llvm_libc::syscall_impl(SYS_ioctl, fd, TIOCGETD, &line_d_val);
+ if (result == 0)
+ return 1;
+
+ errno = -result;
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index 3b99acaddd87b..c6a78f084d2cb 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -352,6 +352,20 @@ add_libc_unittest(
libc.src.unistd.getuid
)
+add_libc_unittest(
+ isatty_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ isatty_test.cpp
+ DEPENDS
+ libc.src.unistd.isatty
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.include.errno
+ libc.src.errno.errno
+)
+
add_libc_unittest(
geteuid_test
SUITE
diff --git a/libc/test/src/unistd/isatty_test.cpp b/libc/test/src/unistd/isatty_test.cpp
new file mode 100644
index 0000000000000..28e4659dc2a69
--- /dev/null
+++ b/libc/test/src/unistd/isatty_test.cpp
@@ -0,0 +1,54 @@
+//===-- Unittests for isatty ----------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/isatty.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST(LlvmLibcIsATTYTest, StdInOutTests) {
+ // If stdin is connected to a terminal, assume that all of the standard i/o
+ // fds are.
+ if (__llvm_libc::isatty(0)) {
+ EXPECT_THAT(__llvm_libc::isatty(0), Succeeds(1)); // stdin
+ EXPECT_THAT(__llvm_libc::isatty(1), Succeeds(1)); // stdout
+ EXPECT_THAT(__llvm_libc::isatty(2), Succeeds(1)); // stderr
+ } else {
+ EXPECT_THAT(__llvm_libc::isatty(0), Fails(ENOTTY, 0)); // stdin
+ EXPECT_THAT(__llvm_libc::isatty(1), Fails(ENOTTY, 0)); // stdout
+ EXPECT_THAT(__llvm_libc::isatty(2), Fails(ENOTTY, 0)); // stderr
+ }
+}
+
+TEST(LlvmLibcIsATTYTest, BadFdTest) {
+ EXPECT_THAT(__llvm_libc::isatty(-1), Fails(EBADF, 0)); // invalid fd
+}
+
+TEST(LlvmLibcIsATTYTest, DevTTYTest) {
+ constexpr const char *TTY_FILE = "/dev/tty";
+ int fd = __llvm_libc::open(TTY_FILE, O_RDONLY);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(fd, 0);
+ EXPECT_THAT(__llvm_libc::isatty(fd), Succeeds(1));
+ ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
+}
+
+TEST(LlvmLibcIsATTYTest, FileTest) {
+ constexpr const char *TEST_FILE = "testdata/isatty.test";
+ int fd = __llvm_libc::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(fd, 0);
+ EXPECT_THAT(__llvm_libc::isatty(fd), Fails(ENOTTY, 0));
+ ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
+}
More information about the libc-commits
mailing list