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