Carlos O'Donell 0e17ea2
Short description: Fedora-specific workaround for kernel pty bug.
Carlos O'Donell 0e17ea2
Author(s): Fedora glibc team <glibc@lists.fedoraproject.org>
Carlos O'Donell 0e17ea2
Origin: PATCH
Carlos O'Donell 0e17ea2
Upstream status: not-submitted
Carlos O'Donell 0e17ea2
Carlos O'Donell 0e17ea2
This is a Fedora-specific workaround for a kernel bug where calling
Carlos O'Donell 0e17ea2
ioctl on a pty will silently ignore the invalid c_cflag. The
Carlos O'Donell 0e17ea2
workaround is to use TCGETS to verify the setting matches. This is
Carlos O'Donell 0e17ea2
not upstream and needs to either be removed or submitted upstream
Carlos O'Donell 0e17ea2
after analysis.
Carlos O'Donell 0e17ea2
dcf3eeb
Index: b/sysdeps/unix/sysv/linux/tcsetattr.c
dcf3eeb
===================================================================
dcf3eeb
--- a/sysdeps/unix/sysv/linux/tcsetattr.c
dcf3eeb
+++ b/sysdeps/unix/sysv/linux/tcsetattr.c
dcf3eeb
@@ -45,6 +45,7 @@ __tcsetattr (int fd, int optional_action
fb633ea
 {
fb633ea
   struct __kernel_termios k_termios;
fb633ea
   unsigned long int cmd;
fb633ea
+  int retval;
fb633ea
 
fb633ea
   switch (optional_actions)
fb633ea
     {
dcf3eeb
@@ -75,7 +76,36 @@ __tcsetattr (int fd, int optional_action
fb633ea
   memcpy (&k_termios.c_cc[0], &termios_p->c_cc[0],
fb633ea
 	  __KERNEL_NCCS * sizeof (cc_t));
fb633ea
 
fb633ea
-  return INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
fb633ea
+  retval = INLINE_SYSCALL (ioctl, 3, fd, cmd, &k_termios);
fb633ea
+
fb633ea
+  if (retval == 0 && cmd == TCSETS)
fb633ea
+    {
fb633ea
+      /* The Linux kernel has a bug which silently ignore the invalid
fb633ea
+        c_cflag on pty. We have to check it here. */
fb633ea
+      int save = errno;
fb633ea
+      retval = INLINE_SYSCALL (ioctl, 3, fd, TCGETS, &k_termios);
fb633ea
+      if (retval)
fb633ea
+       {
fb633ea
+         /* We cannot verify if the setting is ok. We don't return
fb633ea
+            an error (?). */
fb633ea
+         __set_errno (save);
fb633ea
+         retval = 0;
fb633ea
+       }
fb633ea
+      else if ((termios_p->c_cflag & (PARENB | CREAD))
fb633ea
+              != (k_termios.c_cflag & (PARENB | CREAD))
fb633ea
+              || ((termios_p->c_cflag & CSIZE)
fb633ea
+                  && ((termios_p->c_cflag & CSIZE)
fb633ea
+                      != (k_termios.c_cflag & CSIZE))))
fb633ea
+       {
fb633ea
+         /* It looks like the Linux kernel silently changed the
fb633ea
+            PARENB/CREAD/CSIZE bits in c_cflag. Report it as an
fb633ea
+            error. */
fb633ea
+         __set_errno (EINVAL);
fb633ea
+         retval = -1;
fb633ea
+       }
fb633ea
+    }
fb633ea
+
fb633ea
+  return retval;
fb633ea
 }
dcf3eeb
 weak_alias (__tcsetattr, tcsetattr)
fb633ea
 libc_hidden_def (tcsetattr)