[PATCH 1/1] linux/termios: clear c_cflag & CIBAUD for non-split speed
H. Peter Anvin
hpa@zytor.com
Mon Sep 8 15:34:17 GMT 2025
After getting more experience with the various broken direct-to-ioctl
termios2 hacks using Fedora 43 beta, I have found a fair number of
cases where the software would fail to set, or clear CIBAUD for
non-split-speed operation.
Therefore, I think it will help improve compatibility to clear the
CIBAUD flags for non-split-speed operation, rather than having it
equal CIBAUD.
This change is in tcsetattr() rather than
___termios2_canonicalize_speeds(), as it should not be run for
tcgetattr(); that would break split speed support for the legacy
interface versions of cfgetispeed() and cfsetispeed().
When writing the code that went into glibc 2.42 I had considered this
issue, and had to make an educated guess which way would be more
likely to break fewer things. Unfortunately, it appears I guessed
wrong.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
---
sysdeps/unix/sysv/linux/tcsetattr.c | 39 ++++++++++++++++-------------
1 file changed, 22 insertions(+), 17 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/tcsetattr.c b/sysdeps/unix/sysv/linux/tcsetattr.c
index 4f07a03e6657..d61c30d5ae9a 100644
--- a/sysdeps/unix/sysv/linux/tcsetattr.c
+++ b/sysdeps/unix/sysv/linux/tcsetattr.c
@@ -41,16 +41,6 @@ __tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
copy_c_cc (k_termios.c_cc, _TERMIOS2_NCCS, termios_p->c_cc, NCCS);
- /*
- * Choose the proper ioctl number to invoke.
- *
- * Alpha got TCSETS2 late (Linux 4.20), but has the same structure
- * format, and it only needs TCSETS2 if either it needs to use
- * __BOTHER or split speed. All other architectures have TCSETS2 as
- * far back as the current glibc supports. Calling TCSETS with
- * __BOTHER causes unpredictable results on old Alpha kernels and
- * could even crash them.
- */
static_assert_equal(TCSADRAIN, TCSANOW + 1);
static_assert_equal(TCSAFLUSH, TCSANOW + 2);
static_assert_equal(TCSETSW2, TCSETS2 + 1);
@@ -62,17 +52,32 @@ __tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
if (cmd > 2)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+ /*
+ * For compatibility with broken workaround hacks for the lack
+ * of arbitrary speed support in previous versions of glibc,
+ * clear CIBAUD if only one speed is used.
+ *
+ * This is also necessary for the Alpha compatibility hack below.
+ */
+ if (k_termios.c_ospeed == k_termios.c_ispeed)
+ k_termios.c_cflag &= ~CIBAUD;
+
+ /*
+ * Choose the proper ioctl number to invoke.
+ *
+ * Alpha got TCSETS2 late (Linux 4.20), but has the same structure
+ * format, and it only needs TCSETS2 if either it needs to use
+ * __BOTHER or split speed. All other architectures have TCSETS2 as
+ * far back as the current glibc supports. Calling TCSETS with
+ * __BOTHER causes unpredictable results on old Alpha kernels and
+ * could even crash them.
+ */
if (__ASSUME_TERMIOS2 ||
k_termios.c_ospeed != k_termios.c_ispeed ||
cbaud (k_termios.c_cflag) == __BOTHER)
- {
- cmd += TCSETS2;
- }
+ cmd += TCSETS2;
else
- {
- cmd += TCSETS;
- k_termios.c_cflag &= ~CIBAUD;
- }
+ cmd += TCSETS;
return INLINE_SYSCALL_CALL (ioctl, fd, cmd, &k_termios);
}
--
2.51.0
More information about the Libc-alpha
mailing list