[PATCH v2 3/3] linux/termios: test the kernel-side termios canonicalization

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Wed Sep 17 12:53:23 GMT 2025



On 10/09/25 18:36, H. Peter Anvin wrote:
> 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 */

This breaks tst-termios-linux on at least alpha (still testing other
archs):

In file included from ../sysdeps/unix/sysv/linux/k_termios.h:27,
                 from ../sysdeps/unix/sysv/linux/tst-termios-linux.c:41:
../sysdeps/unix/sysv/linux/alpha/termios_arch.h:21:3: error: #error "<termios_arch.h> should only be included from <termios_internals.h>"
   21 | # error "<termios_arch.h> should only be included from <termios_internals.h>"
      |   ^~~~~

> +
>  /* 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 */



More information about the Libc-alpha mailing list