Blame SOURCES/glibc-fedora-linux-tcsetattr.patch

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