[libc][termios] Make termios hermetic and fix its compatibility with glibc 2.42 or after. (#211039)

Make termios hermetic and address its compatibility with glibc 2.42
breaking change
with baud rate definitions:

https://inbox.sourceware.org/libc-announce/5906001.DvuYhMxLoT@pinacolada/T/

Fixes include:
- Baud rate translation utilities.
- Add proxy headers for termios.h macros and types.
- Update tests.

Assisted-by: Gemini 3.5 Flash.
This commit is contained in:
lntue 2026-07-24 13:31:41 -04:00 committed by GitHub
parent 11996d6729
commit 995e2af535
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
38 changed files with 630 additions and 101 deletions

View file

@ -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")

View file

@ -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()

View file

@ -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

27
libc/hdr/termios_macros.h Normal file
View file

@ -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 <termios.h>
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TERMIOS_MACROS_H

View file

@ -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
)

27
libc/hdr/types/cc_t.h Normal file
View file

@ -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 <termios.h>
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TYPES_CC_T_H

27
libc/hdr/types/speed_t.h Normal file
View file

@ -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 <termios.h>
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TYPES_SPEED_T_H

View file

@ -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 <termios.h>
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TYPES_STRUCT_TERMIOS_H

27
libc/hdr/types/tcflag_t.h Normal file
View file

@ -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 <termios.h>
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TYPES_TCFLAG_T_H

View file

@ -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)

View file

@ -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"

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {
speed_t cfgetispeed(const struct termios *t);
speed_t cfgetispeed(const termios *t);
} // namespace LIBC_NAMESPACE_DECL

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {
speed_t cfgetospeed(const struct termios *t);
speed_t cfgetospeed(const termios *t);
} // namespace LIBC_NAMESPACE_DECL

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {
int cfsetispeed(struct termios *t, speed_t speed);
int cfsetispeed(termios *t, speed_t speed);
} // namespace LIBC_NAMESPACE_DECL

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {
int cfsetospeed(struct termios *t, speed_t speed);
int cfsetospeed(termios *t, speed_t speed);
} // namespace LIBC_NAMESPACE_DECL

View file

@ -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
)

View file

@ -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 <termios.h>
#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

View file

@ -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 <termios.h>
#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

View file

@ -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 <termios.h>
#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<speed_t>(CBAUD);
speed_t encoded = encode_speed(speed);
// A speed value is valid only if it is equal to one of the B<NN+> 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;
}

View file

@ -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 <termios.h>
#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<speed_t>(CBAUD);
speed_t encoded = encode_speed(speed);
// A speed value is valid only if it is equal to one of the B<NN+> 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;
}

View file

@ -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 <stddef.h>
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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<speed_t>(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

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
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<size_t>(NCCS));
for (size_t i = 0; i < nccs; ++i)
t->c_cc[i] = kt.c_cc[i];
if (NCCS > nccs) {

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
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.

View file

@ -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 <asm/ioctls.h> // Safe to include without the risk of name pollution.
#include <termios.h>
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<speed_t>(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<size_t>(NCCS));
for (size_t i = 0; i < nccs; ++i)
kt.c_cc[i] = t->c_cc[i];
if (nccs < KERNEL_NCCS) {

View file

@ -10,7 +10,6 @@
#define LLVM_LIBC_SRC_TERMIOS_TCDRAIN_H
#include "src/__support/macros/config.h"
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -10,7 +10,6 @@
#define LLVM_LIBC_SRC_TERMIOS_TCFLOW_H
#include "src/__support/macros/config.h"
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -10,7 +10,6 @@
#define LLVM_LIBC_SRC_TERMIOS_TCFLUSH_H
#include "src/__support/macros/config.h"
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {
int tcgetattr(int fd, struct termios *t);
int tcgetattr(int fd, termios *t);
} // namespace LIBC_NAMESPACE_DECL

View file

@ -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 <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -10,7 +10,6 @@
#define LLVM_LIBC_SRC_TERMIOS_TCSENDBREAK_H
#include "src/__support/macros/config.h"
#include <termios.h>
namespace LIBC_NAMESPACE_DECL {

View file

@ -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 <termios.h>
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

View file

@ -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

View file

@ -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 <termios.h>
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));
}