[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