olga / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

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

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