[PATCH v2 3/3] linux/termios: test the kernel-side termios canonicalization
H. Peter Anvin
hpa@zytor.com
Wed Sep 10 21:36:46 GMT 2025
Verify that the kernel side of the termios interface gets the various
speed fields get set according to our current canonicalization policy.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
---
sysdeps/unix/sysv/linux/tst-termios-linux.c | 65 +++++++++++++++++++--
1 file changed, 60 insertions(+), 5 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/tst-termios-linux.c b/sysdeps/unix/sysv/linux/tst-termios-linux.c
index e4b0c8bcd6ed..2474ebe630b4 100644
--- a/sysdeps/unix/sysv/linux/tst-termios-linux.c
+++ b/sysdeps/unix/sysv/linux/tst-termios-linux.c
@@ -38,6 +38,8 @@
#include <support/test-driver.h>
#include <support/tty.h>
+#include <k_termios.h> /* Definitions for the raw ioctl interface */
+
/* Evaluate an expression and make sure errno did not get set; return
the value of the expression */
#define CHECKERR(expr) \
@@ -226,18 +228,71 @@ static void check_speeds_cf (const struct termios *tio_p,
CHECKERR (cfgetibaud (tio_p)), 'i');
}
-/* Use this after tc[gs]etattr () */
+/* Access the raw kernel interface and verify that the result is
+ canonicalized properly; this should be run after tcsetattr (). */
+static void
+check_speeds_kernel (int fd, speed_t ospeed, speed_t ispeed)
+{
+ struct termios2 k_termios;
+ tcflag_t expect_cbaud = speed_to_cbaud (ospeed);
+ tcflag_t expect_cibaud;
+
+ if (!ispeed)
+ ispeed = ospeed;
+
+ /* If ospeed == ispeed, tcsetattr() should set the kernel CIBAUD to 0,
+ for compatibility with programs that use the direct ioctl interface
+ but fail to account for CIBAUD. c_ispeed should still be correct. */
+ if (ospeed == ispeed)
+ expect_cibaud = 0;
+ else
+ expect_cibaud = speed_to_cbaud (ispeed);
+
+ memset(&k_termios, 0xed, sizeof k_termios); /* Fill with nonsense */
+ CHECKZERO (ioctl(fd, TCGETS2, &k_termios));
+
+ tcflag_t k_cbaud = k_termios.c_cflag & CBAUD;
+ tcflag_t k_cibaud = (k_termios.c_cflag >> IBSHIFT) & CBAUD;
+
+ if (k_termios.c_ospeed != ospeed)
+ FAIL ("opeed %u ispeed %u: kernel c_ospeed = %u, expected %u",
+ ospeed, ispeed,
+ k_termios.c_ospeed, ospeed);
+
+ if (k_cbaud != expect_cbaud)
+ FAIL ("ospeed %u ispeed %u: kernel CBAUD = %s (%06o), expected %s (%06o)",
+ ospeed, ispeed,
+ cbaud_name (k_cbaud), k_cbaud,
+ cbaud_name (expect_cbaud), expect_cbaud);
+
+ if (k_termios.c_ispeed != ispeed)
+ FAIL ("ospeed %u ispeed %u: kernel c_ispeed == %u, expected %u",
+ ospeed, ispeed,
+ k_termios.c_ispeed, ispeed);
+
+ if (k_cibaud != expect_cibaud)
+ FAIL ("ospeed %u ispeed %u: kernel CIBAUD = %s (%06o), expected %s (%06o)",
+ ospeed, ispeed,
+ cbaud_name (k_cibaud), k_cibaud,
+ cbaud_name (expect_cibaud), expect_cibaud);
+}
+
+/* Use this after tcsetattr () */
static void check_speeds_tc (int fd, speed_t ospeed, speed_t ispeed)
{
struct termios tio;
+ if (!ispeed)
+ ispeed = ospeed;
+
CHECKZERO (tcgetattr (fd, &tio));
- check_speeds_cf (&tio, ospeed, ispeed ? ispeed : ospeed);
+ check_speeds_cf (&tio, ospeed, ispeed);
+ check_speeds_kernel(fd, ospeed, ispeed);
}
/* For search and replace convenience */
-#define check_bauds_cf check_speeds_cf
-#define check_bauds_tc check_speeds_tc
+#define check_bauds_cf check_speeds_cf
+#define check_bauds_tc check_speeds_tc
/* Common routine for setting speeds, with checking */
static void
@@ -250,7 +305,7 @@ set_speeds (int fd, speed_t ospeed, speed_t ispeed)
CHECKZERO (cfsetispeed (&tio, ispeed));
check_speeds_cf (&tio, ospeed, ispeed);
CHECKZERO (tcsetattr (fd, TCSANOW, &tio));
- check_speeds_tc (fd, ospeed, ispeed ? ispeed : ospeed);
+ check_speeds_tc (fd, ospeed, ispeed);
}
/* Actual tests */
--
2.51.0
More information about the Libc-alpha
mailing list