[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