diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index af820ba6ab6c..3aa975ba5141 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -161,7 +161,11 @@ option(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS option(LIBC_CONFIG_PATH "The path to user provided folder that configures the build for the target system." OFF) if(LIBC_TARGET_OS_IS_LINUX) - set(kernel_headers "/usr/include") + if(LIBC_TARGET_TRIPLE AND EXISTS "/usr/${LIBC_TARGET_TRIPLE}/include") + set(kernel_headers "/usr/${LIBC_TARGET_TRIPLE}/include") + else() + set(kernel_headers "/usr/include") + endif() endif() set(LIBC_KERNEL_HEADERS "${kernel_headers}" CACHE STRING "Path to Linux kernel headers") diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index c97f906cb663..600df74f552b 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -243,11 +243,13 @@ function(_get_common_compile_options output_var flags) (LIBC_CC_SUPPORTS_NOSTDLIBINC OR COMPILER_RESOURCE_DIR)) # We use -idirafter to avoid preempting libc's own headers in case the # directory (e.g. /usr/include) contains other headers. - if(CMAKE_CROSSCOMPILING) - list(APPEND compile_options "-idirafter=${LIBC_KERNEL_HEADERS}") - else() - list(APPEND compile_options "-idirafter${LIBC_KERNEL_HEADERS}") - endif() + foreach(path IN LISTS LIBC_KERNEL_HEADERS) + if(CMAKE_CROSSCOMPILING) + list(APPEND compile_options "-idirafter=${path}") + else() + list(APPEND compile_options "-idirafter${path}") + endif() + endforeach() endif() endif() diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt index 9df87558046f..f2979866eafb 100644 --- a/libc/hdr/CMakeLists.txt +++ b/libc/hdr/CMakeLists.txt @@ -234,6 +234,14 @@ add_proxy_header_library( libc.include.llvm-libc-macros.sys_wait_macros ) +add_proxy_header_library( + termios_macros + HDRS + termios_macros.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-macros.termios_macros +) + add_header_library(unistd_overlay HDRS unistd_overlay.h) add_proxy_header_library( unistd_macros diff --git a/libc/hdr/termios_macros.h b/libc/hdr/termios_macros.h new file mode 100644 index 000000000000..9ccf917a293e --- /dev/null +++ b/libc/hdr/termios_macros.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for macros from termios.h. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TERMIOS_MACROS_H +#define LLVM_LIBC_HDR_TERMIOS_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/termios-macros.h" + +#else // Overlay mode + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TERMIOS_MACROS_H diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt index 0d9edd12799b..0c926050221f 100644 --- a/libc/hdr/types/CMakeLists.txt +++ b/libc/hdr/types/CMakeLists.txt @@ -1227,3 +1227,36 @@ add_proxy_header_library( FULL_BUILD_DEPENDS libc.include.llvm-libc-types.regmatch_t ) + +add_proxy_header_library( + speed_t + HDRS + speed_t.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.speed_t +) + +add_proxy_header_library( + struct_termios + HDRS + struct_termios.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.struct_termios +) + +add_proxy_header_library( + cc_t + HDRS + cc_t.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.cc_t +) + +add_proxy_header_library( + tcflag_t + HDRS + tcflag_t.h + FULL_BUILD_DEPENDS + libc.include.llvm-libc-types.tcflag_t +) + diff --git a/libc/hdr/types/cc_t.h b/libc/hdr/types/cc_t.h new file mode 100644 index 000000000000..b830fcd7baa0 --- /dev/null +++ b/libc/hdr/types/cc_t.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for cc_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_CC_T_H +#define LLVM_LIBC_HDR_TYPES_CC_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/cc_t.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_CC_T_H diff --git a/libc/hdr/types/speed_t.h b/libc/hdr/types/speed_t.h new file mode 100644 index 000000000000..93b4c239c02a --- /dev/null +++ b/libc/hdr/types/speed_t.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for speed_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_SPEED_T_H +#define LLVM_LIBC_HDR_TYPES_SPEED_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/speed_t.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_SPEED_T_H diff --git a/libc/hdr/types/struct_termios.h b/libc/hdr/types/struct_termios.h new file mode 100644 index 000000000000..88305a8809f4 --- /dev/null +++ b/libc/hdr/types/struct_termios.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for struct termios. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_TERMIOS_H +#define LLVM_LIBC_HDR_TYPES_STRUCT_TERMIOS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct_termios.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT_TERMIOS_H diff --git a/libc/hdr/types/tcflag_t.h b/libc/hdr/types/tcflag_t.h new file mode 100644 index 000000000000..461688946227 --- /dev/null +++ b/libc/hdr/types/tcflag_t.h @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Proxy header for tcflag_t. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_TCFLAG_T_H +#define LLVM_LIBC_HDR_TYPES_TCFLAG_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/tcflag_t.h" + +#else + +#include + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_TCFLAG_T_H diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt index 3e7e45e2d590..749a5f625c4d 100644 --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -190,7 +190,7 @@ add_header(tss_dtor_t HDR tss_dtor_t.h) add_header(__atexithandler_t HDR __atexithandler_t.h) add_header(speed_t HDR speed_t.h) add_header(tcflag_t HDR tcflag_t.h) -add_header(struct_termios HDR struct_termios.h DEPENDS .cc_t .speed_t .tcflag_t) +add_header(struct_termios HDR struct_termios.h DEPENDS .cc_t .speed_t .tcflag_t libc.include.llvm-libc-macros.termios_macros) add_header(struct_winsize HDR struct_winsize.h) add_header(__getoptargv_t HDR __getoptargv_t.h) add_header(wchar_t HDR wchar_t.h) diff --git a/libc/include/llvm-libc-types/struct_termios.h b/libc/include/llvm-libc-types/struct_termios.h index e3c5f2809e43..9fc820d0b1cc 100644 --- a/libc/include/llvm-libc-types/struct_termios.h +++ b/libc/include/llvm-libc-types/struct_termios.h @@ -9,6 +9,7 @@ #ifndef __LLVM_LIBC_TYPES_STRUCT_TERMIOS_H__ #define __LLVM_LIBC_TYPES_STRUCT_TERMIOS_H__ +#include "../llvm-libc-macros/termios-macros.h" #include "cc_t.h" #include "speed_t.h" #include "tcflag_t.h" diff --git a/libc/src/termios/cfgetispeed.h b/libc/src/termios/cfgetispeed.h index 56b0ab852cdb..fb058b197fca 100644 --- a/libc/src/termios/cfgetispeed.h +++ b/libc/src/termios/cfgetispeed.h @@ -9,12 +9,13 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_CFGETISPEED_H #define LLVM_LIBC_SRC_TERMIOS_CFGETISPEED_H +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -speed_t cfgetispeed(const struct termios *t); +speed_t cfgetispeed(const termios *t); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/cfgetospeed.h b/libc/src/termios/cfgetospeed.h index 9d8e6656b0e9..9126d0880f88 100644 --- a/libc/src/termios/cfgetospeed.h +++ b/libc/src/termios/cfgetospeed.h @@ -9,12 +9,13 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_CFGETOSPEED_H #define LLVM_LIBC_SRC_TERMIOS_CFGETOSPEED_H +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -speed_t cfgetospeed(const struct termios *t); +speed_t cfgetospeed(const termios *t); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/cfsetispeed.h b/libc/src/termios/cfsetispeed.h index 89b683e56048..5799bf1bf245 100644 --- a/libc/src/termios/cfsetispeed.h +++ b/libc/src/termios/cfsetispeed.h @@ -9,12 +9,13 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_CFSETISPEED_H #define LLVM_LIBC_SRC_TERMIOS_CFSETISPEED_H +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -int cfsetispeed(struct termios *t, speed_t speed); +int cfsetispeed(termios *t, speed_t speed); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/cfsetospeed.h b/libc/src/termios/cfsetospeed.h index 2f2c5315fb69..940e4d70ecff 100644 --- a/libc/src/termios/cfsetospeed.h +++ b/libc/src/termios/cfsetospeed.h @@ -9,12 +9,13 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_CFSETOSPEED_H #define LLVM_LIBC_SRC_TERMIOS_CFSETOSPEED_H +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -int cfsetospeed(struct termios *t, speed_t speed); +int cfsetospeed(termios *t, speed_t speed); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/linux/CMakeLists.txt b/libc/src/termios/linux/CMakeLists.txt index 5d5440ae6926..86565cf1294c 100644 --- a/libc/src/termios/linux/CMakeLists.txt +++ b/libc/src/termios/linux/CMakeLists.txt @@ -1,7 +1,17 @@ # There is no difference between input and output speeds on Linux. # However, since POSIX requires separate functions for setting and getting -# of the input and output speeds, we use different entrypoints wiht the +# of the input and output speeds, we use different entrypoints with the # same getter/setter logic. + +add_header_library( + speed_utils + HDRS + speed_utils.h + DEPENDS + libc.hdr.termios_macros + libc.hdr.types.speed_t +) + add_entrypoint_object( cfgetispeed SRCS @@ -9,7 +19,9 @@ add_entrypoint_object( HDRS ../cfgetispeed.h DEPENDS - libc.include.termios + libc.hdr.types.speed_t + libc.hdr.types.struct_termios + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -19,8 +31,11 @@ add_entrypoint_object( HDRS ../cfsetispeed.h DEPENDS - libc.include.termios + .speed_utils + libc.hdr.types.speed_t + libc.hdr.types.struct_termios libc.src.errno.errno + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -30,7 +45,9 @@ add_entrypoint_object( HDRS ../cfgetospeed.h DEPENDS - libc.include.termios + libc.hdr.types.speed_t + libc.hdr.types.struct_termios + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -40,8 +57,11 @@ add_entrypoint_object( HDRS ../cfsetospeed.h DEPENDS - libc.include.termios + .speed_utils + libc.hdr.types.speed_t + libc.hdr.types.struct_termios libc.src.errno.errno + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -51,7 +71,7 @@ add_entrypoint_object( HDRS ../tcgetsid.h DEPENDS - libc.include.termios + libc.hdr.types.pid_t libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno ) @@ -63,7 +83,6 @@ add_entrypoint_object( HDRS ../tcdrain.h DEPENDS - libc.include.termios libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno ) @@ -75,7 +94,7 @@ add_entrypoint_object( HDRS ../tcflush.h DEPENDS - libc.include.termios + libc.hdr.termios_macros libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno ) @@ -87,7 +106,7 @@ add_entrypoint_object( HDRS ../tcflow.h DEPENDS - libc.include.termios + libc.hdr.termios_macros libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno ) @@ -99,7 +118,6 @@ add_entrypoint_object( HDRS ../tcsendbreak.h DEPENDS - libc.include.termios libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno ) @@ -108,6 +126,9 @@ add_header_library( kernel_termios HDRS kernel_termios.h + DEPENDS + libc.hdr.types.cc_t + libc.hdr.types.tcflag_t ) add_entrypoint_object( @@ -118,9 +139,12 @@ add_entrypoint_object( ../tcgetattr.h DEPENDS .kernel_termios - libc.include.termios + .speed_utils + libc.hdr.termios_macros + libc.hdr.types.struct_termios libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno + libc.src.__support.macros.null_check ) add_entrypoint_object( @@ -131,7 +155,10 @@ add_entrypoint_object( ../tcsetattr.h DEPENDS .kernel_termios - libc.include.termios + .speed_utils + libc.hdr.termios_macros + libc.hdr.types.struct_termios libc.src.__support.OSUtil.linux.syscall_wrappers.ioctl libc.src.errno.errno + libc.src.__support.macros.null_check ) diff --git a/libc/src/termios/linux/cfgetispeed.cpp b/libc/src/termios/linux/cfgetispeed.cpp index 19e9b9140aa2..bb0f49a206f6 100644 --- a/libc/src/termios/linux/cfgetispeed.cpp +++ b/libc/src/termios/linux/cfgetispeed.cpp @@ -1,22 +1,27 @@ -//===-- Linux implementation of cfgetispeed -------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of cfgetispeed. +/// +//===----------------------------------------------------------------------===// #include "src/termios/cfgetispeed.h" - +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/common.h" -#include "src/__support/macros/config.h" - -#include +#include "src/__support/macros/null_check.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(speed_t, cfgetispeed, (const struct termios *t)) { - return t->c_cflag & CBAUD; +LLVM_LIBC_FUNCTION(speed_t, cfgetispeed, (const termios *t)) { + LIBC_CRASH_ON_NULLPTR(t); + return t->c_ispeed; } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/linux/cfgetospeed.cpp b/libc/src/termios/linux/cfgetospeed.cpp index d633beb8061f..3da0447f961a 100644 --- a/libc/src/termios/linux/cfgetospeed.cpp +++ b/libc/src/termios/linux/cfgetospeed.cpp @@ -1,22 +1,27 @@ -//===-- Linux implementation of cfgetospeed -------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of cfgetospeed. +/// +//===----------------------------------------------------------------------===// #include "src/termios/cfgetospeed.h" - +#include "hdr/types/speed_t.h" +#include "hdr/types/struct_termios.h" #include "src/__support/common.h" -#include "src/__support/macros/config.h" - -#include +#include "src/__support/macros/null_check.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(speed_t, cfgetospeed, (const struct termios *t)) { - return t->c_cflag & CBAUD; +LLVM_LIBC_FUNCTION(speed_t, cfgetospeed, (const termios *t)) { + LIBC_CRASH_ON_NULLPTR(t); + return t->c_ospeed; } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/linux/cfsetispeed.cpp b/libc/src/termios/linux/cfsetispeed.cpp index 47b19974d21b..d953e25427d9 100644 --- a/libc/src/termios/linux/cfsetispeed.cpp +++ b/libc/src/termios/linux/cfsetispeed.cpp @@ -1,30 +1,35 @@ -//===-- Linux implementation of cfsetispeed -------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of cfsetispeed. +/// +//===----------------------------------------------------------------------===// #include "src/termios/cfsetispeed.h" - +#include "hdr/types/struct_termios.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" -#include "src/__support/macros/config.h" - -#include +#include "src/__support/macros/null_check.h" +#include "src/termios/linux/speed_utils.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, cfsetispeed, (struct termios * t, speed_t speed)) { - constexpr speed_t NOT_SPEED_MASK = ~speed_t(CBAUD); +LLVM_LIBC_FUNCTION(int, cfsetispeed, (termios * t, speed_t speed)) { + LIBC_CRASH_ON_NULLPTR(t); + constexpr speed_t NOT_SPEED_MASK = ~static_cast(CBAUD); + speed_t encoded = encode_speed(speed); // A speed value is valid only if it is equal to one of the B values. - if (t == nullptr || ((speed & NOT_SPEED_MASK) != 0)) { + if ((encoded & NOT_SPEED_MASK) != 0) { libc_errno = EINVAL; return -1; } - t->c_cflag = (t->c_cflag & NOT_SPEED_MASK) | speed; t->c_ispeed = speed; return 0; } diff --git a/libc/src/termios/linux/cfsetospeed.cpp b/libc/src/termios/linux/cfsetospeed.cpp index d2f138257a47..38f4d3f31009 100644 --- a/libc/src/termios/linux/cfsetospeed.cpp +++ b/libc/src/termios/linux/cfsetospeed.cpp @@ -1,30 +1,36 @@ -//===-- Linux implementation of cfsetospeed -------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of cfsetospeed. +/// +//===----------------------------------------------------------------------===// #include "src/termios/cfsetospeed.h" -#include "src/__support/libc_errno.h" -#include "src/__support/macros/config.h" - +#include "hdr/types/struct_termios.h" #include "src/__support/common.h" - -#include +#include "src/__support/libc_errno.h" +#include "src/__support/macros/null_check.h" +#include "src/termios/linux/speed_utils.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, cfsetospeed, (struct termios * t, speed_t speed)) { - constexpr speed_t NOT_SPEED_MASK = ~speed_t(CBAUD); +LLVM_LIBC_FUNCTION(int, cfsetospeed, (termios * t, speed_t speed)) { + LIBC_CRASH_ON_NULLPTR(t); + constexpr speed_t NOT_SPEED_MASK = ~static_cast(CBAUD); + speed_t encoded = encode_speed(speed); // A speed value is valid only if it is equal to one of the B values. - if (t == nullptr || ((speed & NOT_SPEED_MASK) != 0)) { + if ((encoded & NOT_SPEED_MASK) != 0) { libc_errno = EINVAL; return -1; } - t->c_cflag = (t->c_cflag & NOT_SPEED_MASK) | speed; + t->c_cflag = (t->c_cflag & NOT_SPEED_MASK) | encoded; t->c_ospeed = speed; return 0; } diff --git a/libc/src/termios/linux/kernel_termios.h b/libc/src/termios/linux/kernel_termios.h index 5a3a9722789e..cc499e7ab42a 100644 --- a/libc/src/termios/linux/kernel_termios.h +++ b/libc/src/termios/linux/kernel_termios.h @@ -1,17 +1,23 @@ -//===-- Definition of kernel's version of struct termios --------*- 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Definition of the kernel's version of struct termios. +/// +//===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC_TERMIOS_LINUX_KERNEL_TERMIOS_H #define LLVM_LIBC_SRC_TERMIOS_LINUX_KERNEL_TERMIOS_H +#include "hdr/types/cc_t.h" +#include "hdr/types/tcflag_t.h" #include "src/__support/macros/config.h" #include -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/linux/speed_utils.h b/libc/src/termios/linux/speed_utils.h new file mode 100644 index 000000000000..5b731a00825e --- /dev/null +++ b/libc/src/termios/linux/speed_utils.h @@ -0,0 +1,186 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Speed translation utilities for termios. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_TERMIOS_LINUX_SPEED_UTILS_H +#define LLVM_LIBC_SRC_TERMIOS_LINUX_SPEED_UTILS_H + +#include "hdr/termios_macros.h" +#include "hdr/types/speed_t.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +constexpr speed_t INVALID_SPEED = ~static_cast(0); + +// glibc 2.42 changed the behavior of the termios Bxxx constants: +// - Before glibc 2.42, the Bxxx constants correspond to the kernel speed +// bitmasks +// directly (e.g. B50 = 1). +// - Starting from glibc 2.42, to support arbitrary baud rates numerically, the +// Bxxx constants are defined as their actual integer values (e.g. B50 = 50). +// In this case, we need to translate between the host's numerical speeds and +// the kernel's speed bitmasks. +// - If B50 == 1, then the host uses the kernel's bitmasks directly (no +// translation). +// - If B50 is not 1 (e.g. B50 == 50 in glibc >= 2.42), we apply +// translation. +#if (B50 == 1) + +LIBC_INLINE constexpr speed_t encode_speed(speed_t speed) { return speed; } +LIBC_INLINE constexpr speed_t decode_speed(speed_t speed) { return speed; } + +#else // Overlay mode with numerical speeds (e.g. glibc) + +LIBC_INLINE constexpr speed_t encode_speed(speed_t speed) { + switch (speed) { + case 0: + return 0; + case 50: + return 0000001; + case 75: + return 0000002; + case 110: + return 0000003; + case 134: + return 0000004; + case 150: + return 0000005; + case 200: + return 0000006; + case 300: + return 0000007; + case 600: + return 0000010; + case 1200: + return 0000011; + case 1800: + return 0000012; + case 2400: + return 0000013; + case 4800: + return 0000014; + case 9600: + return 0000015; + case 19200: + return 0000016; + case 38400: + return 0000017; + case 57600: + return 0010001; + case 115200: + return 0010002; + case 230400: + return 0010003; + case 460800: + return 0010004; + case 500000: + return 0010005; + case 576000: + return 0010006; + case 921600: + return 0010007; + case 1000000: + return 0010010; + case 1152000: + return 0010011; + case 1500000: + return 0010012; + case 2000000: + return 0010013; + case 2500000: + return 0010014; + case 3000000: + return 0010015; + case 3500000: + return 0010016; + case 4000000: + return 0010017; + default: + return INVALID_SPEED; + } +} + +LIBC_INLINE constexpr speed_t decode_speed(speed_t kernel_speed) { + switch (kernel_speed) { + case 0: + return 0; + case 0000001: + return 50; + case 0000002: + return 75; + case 0000003: + return 110; + case 0000004: + return 134; + case 0000005: + return 150; + case 0000006: + return 200; + case 0000007: + return 300; + case 0000010: + return 600; + case 0000011: + return 1200; + case 0000012: + return 1800; + case 0000013: + return 2400; + case 0000014: + return 4800; + case 0000015: + return 9600; + case 0000016: + return 19200; + case 0000017: + return 38400; + case 0010001: + return 57600; + case 0010002: + return 115200; + case 0010003: + return 230400; + case 0010004: + return 460800; + case 0010005: + return 500000; + case 0010006: + return 576000; + case 0010007: + return 921600; + case 0010010: + return 1000000; + case 0010011: + return 1152000; + case 0010012: + return 1500000; + case 0010013: + return 2000000; + case 0010014: + return 2500000; + case 0010015: + return 3000000; + case 0010016: + return 3500000; + case 0010017: + return 4000000; + default: + return kernel_speed; + } +} + +#endif // (B50 == 1) + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_TERMIOS_LINUX_SPEED_UTILS_H diff --git a/libc/src/termios/linux/tcdrain.cpp b/libc/src/termios/linux/tcdrain.cpp index 4fce89d65a76..ee4abd0f2d8a 100644 --- a/libc/src/termios/linux/tcdrain.cpp +++ b/libc/src/termios/linux/tcdrain.cpp @@ -1,10 +1,15 @@ -//===-- Linux implementation of tcdrain -----------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcdrain. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcdrain.h" @@ -14,7 +19,6 @@ #include "src/__support/macros/config.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/linux/tcflow.cpp b/libc/src/termios/linux/tcflow.cpp index 4ffd294997ad..7efc9dd4a4cb 100644 --- a/libc/src/termios/linux/tcflow.cpp +++ b/libc/src/termios/linux/tcflow.cpp @@ -1,20 +1,25 @@ -//===-- Linux implementation of tcflow -----------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcflow. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcflow.h" +#include "hdr/termios_macros.h" #include "src/__support/OSUtil/linux/syscall_wrappers/ioctl.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/linux/tcflush.cpp b/libc/src/termios/linux/tcflush.cpp index 8a4676d97454..684445a3d273 100644 --- a/libc/src/termios/linux/tcflush.cpp +++ b/libc/src/termios/linux/tcflush.cpp @@ -1,20 +1,25 @@ -//===-- Linux implementation of tcflush -----------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcflush. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcflush.h" +#include "hdr/termios_macros.h" #include "src/__support/OSUtil/linux/syscall_wrappers/ioctl.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/linux/tcgetattr.cpp b/libc/src/termios/linux/tcgetattr.cpp index 0569be4ae588..5e7f3d2f9c79 100644 --- a/libc/src/termios/linux/tcgetattr.cpp +++ b/libc/src/termios/linux/tcgetattr.cpp @@ -1,24 +1,33 @@ -//===-- Linux implementation of tcgetattr ---------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcgetattr. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcgetattr.h" +#include "hdr/termios_macros.h" +#include "hdr/types/struct_termios.h" +#include "src/__support/CPP/algorithm.h" #include "src/__support/OSUtil/linux/syscall_wrappers/ioctl.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" -#include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" #include "src/termios/linux/kernel_termios.h" +#include "src/termios/linux/speed_utils.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, tcgetattr, (int fd, struct termios *t)) { +LLVM_LIBC_FUNCTION(int, tcgetattr, (int fd, termios *t)) { + LIBC_CRASH_ON_NULLPTR(t); LIBC_NAMESPACE::kernel_termios kt; auto ret = linux_syscalls::ioctl(fd, TCGETS, &kt); if (!ret.has_value()) { @@ -29,10 +38,17 @@ LLVM_LIBC_FUNCTION(int, tcgetattr, (int fd, struct termios *t)) { t->c_oflag = kt.c_oflag; t->c_cflag = kt.c_cflag; t->c_lflag = kt.c_lflag; - t->c_ispeed = kt.c_cflag & CBAUD; - t->c_ospeed = kt.c_cflag & CBAUD; + t->c_line = kt.c_line; - size_t nccs = KERNEL_NCCS <= NCCS ? KERNEL_NCCS : NCCS; + speed_t ospeed_mask = kt.c_cflag & CBAUD; + speed_t ispeed_mask = (kt.c_cflag & CIBAUD) >> 16; + if (ispeed_mask == 0) + ispeed_mask = ospeed_mask; + + t->c_ospeed = decode_speed(ospeed_mask); + t->c_ispeed = decode_speed(ispeed_mask); + + size_t nccs = cpp::min(KERNEL_NCCS, static_cast(NCCS)); for (size_t i = 0; i < nccs; ++i) t->c_cc[i] = kt.c_cc[i]; if (NCCS > nccs) { diff --git a/libc/src/termios/linux/tcgetsid.cpp b/libc/src/termios/linux/tcgetsid.cpp index f80fd31b6586..087f7ba4f8c6 100644 --- a/libc/src/termios/linux/tcgetsid.cpp +++ b/libc/src/termios/linux/tcgetsid.cpp @@ -1,20 +1,25 @@ -//===-- Linux implementation of tcgetsid ----------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcgetsid. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcgetsid.h" +#include "hdr/types/pid_t.h" #include "src/__support/OSUtil/linux/syscall_wrappers/ioctl.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" #include "src/__support/macros/config.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/linux/tcsendbreak.cpp b/libc/src/termios/linux/tcsendbreak.cpp index e91ec7b74858..90866c4f54d8 100644 --- a/libc/src/termios/linux/tcsendbreak.cpp +++ b/libc/src/termios/linux/tcsendbreak.cpp @@ -1,10 +1,15 @@ -//===-- Linux implementation of tcsendbreak -------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcsendbreak. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcsendbreak.h" @@ -14,11 +19,10 @@ #include "src/__support/macros/config.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(pid_t, tcsendbreak, (int fd, int /* unused duration */)) { +LLVM_LIBC_FUNCTION(int, tcsendbreak, (int fd, int /* unused duration */)) { // POSIX leaves the behavior for non-zero duration implementation dependent. // Which means that the behavior can be the same as it is when duration is // zero. So, we just pass zero to the syscall. diff --git a/libc/src/termios/linux/tcsetattr.cpp b/libc/src/termios/linux/tcsetattr.cpp index b2f08d078ee8..e22810bbc5a6 100644 --- a/libc/src/termios/linux/tcsetattr.cpp +++ b/libc/src/termios/linux/tcsetattr.cpp @@ -1,25 +1,33 @@ -//===-- Linux implementation of tcsetattr ---------------------------------===// +//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Linux implementation of tcsetattr. +/// +//===----------------------------------------------------------------------===// #include "src/termios/tcsetattr.h" +#include "hdr/termios_macros.h" +#include "hdr/types/struct_termios.h" +#include "src/__support/CPP/algorithm.h" #include "src/__support/OSUtil/linux/syscall_wrappers/ioctl.h" #include "src/__support/common.h" #include "src/__support/libc_errno.h" -#include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" #include "src/termios/linux/kernel_termios.h" +#include "src/termios/linux/speed_utils.h" #include // Safe to include without the risk of name pollution. -#include namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, tcsetattr, - (int fd, int actions, const struct termios *t)) { +LLVM_LIBC_FUNCTION(int, tcsetattr, (int fd, int actions, const termios *t)) { + LIBC_CRASH_ON_NULLPTR(t); struct kernel_termios kt; long cmd; @@ -40,9 +48,17 @@ LLVM_LIBC_FUNCTION(int, tcsetattr, kt.c_iflag = t->c_iflag; kt.c_oflag = t->c_oflag; - kt.c_cflag = t->c_cflag; + + speed_t ospeed = encode_speed(t->c_ospeed); + speed_t ispeed = t->c_ispeed == 0 ? ospeed : encode_speed(t->c_ispeed); + + constexpr speed_t NOT_SPEED_MASK = ~static_cast(CBAUD | CIBAUD); + kt.c_cflag = (t->c_cflag & NOT_SPEED_MASK) | ospeed | (ispeed << 16); + kt.c_lflag = t->c_lflag; - size_t nccs = KERNEL_NCCS <= NCCS ? KERNEL_NCCS : NCCS; + kt.c_line = t->c_line; + + size_t nccs = cpp::min(KERNEL_NCCS, static_cast(NCCS)); for (size_t i = 0; i < nccs; ++i) kt.c_cc[i] = t->c_cc[i]; if (nccs < KERNEL_NCCS) { diff --git a/libc/src/termios/tcdrain.h b/libc/src/termios/tcdrain.h index f7fcd8c734bf..73a45b3f0107 100644 --- a/libc/src/termios/tcdrain.h +++ b/libc/src/termios/tcdrain.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_SRC_TERMIOS_TCDRAIN_H #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/tcflow.h b/libc/src/termios/tcflow.h index dbe63adea1ce..4b101b1ed169 100644 --- a/libc/src/termios/tcflow.h +++ b/libc/src/termios/tcflow.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_SRC_TERMIOS_TCFLOW_H #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/tcflush.h b/libc/src/termios/tcflush.h index 5c283a0203c8..7f92b9ab1a6d 100644 --- a/libc/src/termios/tcflush.h +++ b/libc/src/termios/tcflush.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_SRC_TERMIOS_TCFLUSH_H #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/tcgetattr.h b/libc/src/termios/tcgetattr.h index 54b169aedad8..fee34ad85983 100644 --- a/libc/src/termios/tcgetattr.h +++ b/libc/src/termios/tcgetattr.h @@ -9,12 +9,12 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_TCGETATTR_H #define LLVM_LIBC_SRC_TERMIOS_TCGETATTR_H +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -int tcgetattr(int fd, struct termios *t); +int tcgetattr(int fd, termios *t); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/termios/tcgetsid.h b/libc/src/termios/tcgetsid.h index a69db00a5dab..0d8de57668ae 100644 --- a/libc/src/termios/tcgetsid.h +++ b/libc/src/termios/tcgetsid.h @@ -9,8 +9,8 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_TCGETSID_H #define LLVM_LIBC_SRC_TERMIOS_TCGETSID_H +#include "hdr/types/pid_t.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/tcsendbreak.h b/libc/src/termios/tcsendbreak.h index 9edc602cff6c..bbf540e89e9a 100644 --- a/libc/src/termios/tcsendbreak.h +++ b/libc/src/termios/tcsendbreak.h @@ -10,7 +10,6 @@ #define LLVM_LIBC_SRC_TERMIOS_TCSENDBREAK_H #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { diff --git a/libc/src/termios/tcsetattr.h b/libc/src/termios/tcsetattr.h index 05c88f104836..28a75b883e0f 100644 --- a/libc/src/termios/tcsetattr.h +++ b/libc/src/termios/tcsetattr.h @@ -9,12 +9,12 @@ #ifndef LLVM_LIBC_SRC_TERMIOS_TCSETATTR_H #define LLVM_LIBC_SRC_TERMIOS_TCSETATTR_H +#include "hdr/types/struct_termios.h" #include "src/__support/macros/config.h" -#include namespace LIBC_NAMESPACE_DECL { -int tcsetattr(int fd, int actions, const struct termios *t); +int tcsetattr(int fd, int actions, const termios *t); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/src/termios/CMakeLists.txt b/libc/test/src/termios/CMakeLists.txt index 059c272c105c..2ff137e89ebc 100644 --- a/libc/test/src/termios/CMakeLists.txt +++ b/libc/test/src/termios/CMakeLists.txt @@ -8,6 +8,8 @@ add_libc_unittest( termios_test.cpp DEPENDS libc.include.termios + libc.hdr.termios_macros + libc.hdr.types.struct_termios libc.src.errno.errno libc.src.fcntl.open libc.src.termios.cfgetispeed diff --git a/libc/test/src/termios/termios_test.cpp b/libc/test/src/termios/termios_test.cpp index 7a8075997a4a..6cb2eeeebe66 100644 --- a/libc/test/src/termios/termios_test.cpp +++ b/libc/test/src/termios/termios_test.cpp @@ -1,11 +1,18 @@ -//===-- Unittests for a bunch of functions in termios.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 // //===----------------------------------------------------------------------===// +/// +/// \file +/// Unittests for functions in termios.h. +/// +//===----------------------------------------------------------------------===// +#include "hdr/termios_macros.h" +#include "hdr/types/struct_termios.h" #include "src/__support/libc_errno.h" #include "src/fcntl/open.h" #include "src/termios/cfgetispeed.h" @@ -20,8 +27,6 @@ #include "test/UnitTest/ErrnoSetterMatcher.h" #include "test/UnitTest/Test.h" -#include - using LlvmLibcTermiosTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest; using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; @@ -30,7 +35,7 @@ using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; // from ninja/make which change the terminal behavior. TEST_F(LlvmLibcTermiosTest, SpeedSmokeTest) { - struct termios t; + termios t; ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, B50), Succeeds(0)); ASSERT_EQ(LIBC_NAMESPACE::cfgetispeed(&t), speed_t(B50)); ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, B75), Succeeds(0)); @@ -38,10 +43,18 @@ TEST_F(LlvmLibcTermiosTest, SpeedSmokeTest) { ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, ~CBAUD), Fails(EINVAL)); ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, ~CBAUD), Fails(EINVAL)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, 12345), Fails(EINVAL)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, 12345), Fails(EINVAL)); +#if B50 != 1 + ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, 4096), Fails(EINVAL)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, 4096), Fails(EINVAL)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, 1), Fails(EINVAL)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, 1), Fails(EINVAL)); +#endif } TEST_F(LlvmLibcTermiosTest, GetAttrSmokeTest) { - struct termios t; + termios t; int fd = LIBC_NAMESPACE::open("/dev/tty", O_RDONLY); if (fd < 0) { // When /dev/tty is not available, no point continuing @@ -65,3 +78,39 @@ TEST_F(LlvmLibcTermiosTest, TcGetSidSmokeTest) { returns(GT(pid_t(0))).with_errno(EQ(0))); ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); } + +TEST_F(LlvmLibcTermiosTest, SplitSpeedTest) { + int fd = LIBC_NAMESPACE::open("/dev/ptmx", O_RDWR); + if (fd < 0) { + // Gracefully skip if /dev/ptmx is not available + libc_errno = 0; + return; + } + ASSERT_ERRNO_SUCCESS(); + + termios t; + ASSERT_THAT(LIBC_NAMESPACE::tcgetattr(fd, &t), Succeeds(0)); + + // 1. Test setting split speeds. + ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t, B50), Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::cfsetospeed(&t, B75), Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::tcsetattr(fd, TCSANOW, &t), Succeeds(0)); + + termios t2; + ASSERT_THAT(LIBC_NAMESPACE::tcgetattr(fd, &t2), Succeeds(0)); + ASSERT_EQ(LIBC_NAMESPACE::cfgetispeed(&t2), speed_t(B50)); + ASSERT_EQ(LIBC_NAMESPACE::cfgetospeed(&t2), speed_t(B75)); + + // 2. Test input speed 0 fallback. + ASSERT_THAT(LIBC_NAMESPACE::cfsetispeed(&t2, 0), Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::tcsetattr(fd, TCSANOW, &t2), Succeeds(0)); + + termios t3; + ASSERT_THAT(LIBC_NAMESPACE::tcgetattr(fd, &t3), Succeeds(0)); + ASSERT_EQ(LIBC_NAMESPACE::cfgetospeed(&t3), speed_t(B75)); + // Under POSIX, if input speed was set to 0, it must be the same as output + // speed. + ASSERT_EQ(LIBC_NAMESPACE::cfgetispeed(&t3), speed_t(B75)); + + ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); +}