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

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