File: local-tcsetaddr.diff

package info (click to toggle)
glibc 2.42-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 311,572 kB
  • sloc: ansic: 1,060,594; asm: 238,093; makefile: 20,949; python: 13,508; sh: 11,823; cpp: 5,188; awk: 1,794; perl: 317; yacc: 292; pascal: 182; sed: 19
file content (91 lines) | stat: -rw-r--r-- 3,018 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# All lines beginning with `# DP:' are a description of the patch.
# DP: Description: tcsetattr sanity check on PARENB/CREAD/CSIZE for ptys
# DP: Related bugs: 218131
# DP: Author: Jeff Licquia <licquia@progeny.com>
# DP: Upstream status: [In CVS | Debian-Specific | Pending | Not submitted ]
# DP: Status Details: 
# DP: Date: 2003-10-29

---
 sysdeps/unix/sysv/linux/tcsetattr.c |   62 +++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

--- a/sysdeps/unix/sysv/linux/tcsetattr.c
+++ b/sysdeps/unix/sysv/linux/tcsetattr.c
@@ -24,7 +24,9 @@
 __tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
 {
   struct termios2 k_termios;
+  struct termios2 k_termios_old;
   unsigned long cmd;
+  int retval, old_retval;
 
   memset (&k_termios, 0, sizeof k_termios);
 
@@ -74,7 +76,65 @@
       k_termios.c_cflag &= ~CIBAUD;
     }
 
-  return INLINE_SYSCALL_CALL (ioctl, fd, cmd, &k_termios);
+  /* Preserve the previous termios state if we can. */
+  if (__ASSUME_TERMIOS2)
+    old_retval = INLINE_SYSCALL_CALL (ioctl, fd, TCGETS2, &k_termios_old);
+  else
+    old_retval = INLINE_SYSCALL_CALL (ioctl, fd, TCGETS, &k_termios_old);
+
+  retval = INLINE_SYSCALL_CALL (ioctl, fd, cmd, &k_termios);
+
+  /* The Linux kernel silently ignores the invalid c_cflag on pty.
+     We have to check it here, and return an error.  But if some other
+     setting was successfully changed, POSIX requires us to report
+     success. */
+  if ((retval == 0) && (old_retval == 0))
+    {
+      int save = errno;
+      if (__ASSUME_TERMIOS2)
+	retval = INLINE_SYSCALL_CALL (ioctl, fd, TCGETS2, &k_termios);
+      else
+	retval = INLINE_SYSCALL_CALL (ioctl, fd, TCGETS, &k_termios);
+
+      if (retval)
+	{
+	  /* We cannot verify if the setting is ok. We don't return
+	     an error (?). */
+	  __set_errno (save);
+	  retval = 0;
+	}
+      else if ((k_termios_old.c_oflag != k_termios.c_oflag) ||
+	       (k_termios_old.c_lflag != k_termios.c_lflag) ||
+	       (k_termios_old.c_line != k_termios.c_line) ||
+	       (k_termios_old.c_iflag != k_termios.c_iflag))
+	{
+	  /* Some other setting was successfully changed, which
+	     means we should not return an error. */
+	  __set_errno (save);
+	  retval = 0;
+	}
+      else if ((k_termios_old.c_cflag & ~(PARENB | CREAD | CSIZE)) !=
+	       (k_termios.c_cflag & ~(PARENB | CREAD | CSIZE)))
+	{
+	  /* Some other c_cflag setting was successfully changed, which
+	     means we should not return an error. */
+	  __set_errno (save);
+	  retval = 0;
+	}
+      else if ((termios_p->c_cflag & (PARENB | CREAD))
+			!= (k_termios.c_cflag & (PARENB | CREAD))
+	       || ((termios_p->c_cflag & CSIZE)
+		   && (termios_p->c_cflag & CSIZE)
+			!= (k_termios.c_cflag & CSIZE)))
+	{
+	  /* It looks like the Linux kernel silently changed the
+	     PARENB/CREAD/CSIZE bits in c_cflag. Report it as an
+	     error. */
+	  __set_errno (EINVAL);
+	  retval = -1;
+	}
+    }
+  return retval;
 }
 libc_hidden_def (__tcsetattr)