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

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