Skip to content

Commit 16dcb8d

Browse files
authored
Fall back to TCGETS if TCGETS2 fails (#1147)
Android and some other seccomp environments don't recognize `TCGETS2`/`TCSETS2` and fail them with `Errno::ACCESS`, and WSL doesn't recognize them either and fails them with `Errno::NOTTY`, so add code to fall back to `TCGETS`/`TCSETS` in those cases, and manually initialize the missing speed fields. Doing the `TCGETS2`/`TCSETS2` first means we can do more of the fallback code in `#[cold]` functions, and makes the code easier to follow. Also, fix some bugs in QEMU related to the handling of termios syscalls. This eliminates the need for having rustix do extra fixups on PowerPC. And this fixes the tests on MIPS. Add more tests for `tcgetattr`/`tcsetattr` covering more speed cases, input/output/local/control modes, and special codes. Define more `SpecialCodeIndex` constants for bsd and solarish platforms. And fix capitalization of MIPS and SPARC in various comments. This fixes crossterm-rs/crossterm#912.
1 parent dfae7aa commit 16dcb8d

File tree

15 files changed

+675
-202
lines changed

15 files changed

+675
-202
lines changed

ci/tcgets2-tcsets2.patch

Lines changed: 81 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@ This implements the `TCGETS2` and `TCSETS2` ioctls.
66
diff -ur a/linux-user/ioctls.h b/linux-user/ioctls.h
77
--- a/linux-user/ioctls.h
88
+++ b/linux-user/ioctls.h
9-
@@ -2,6 +2,8 @@
9+
@@ -1,5 +1,15 @@
10+
/* emulated ioctl list */
1011

11-
IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
12-
IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
12+
+ /*
13+
+ * Put `TCGETS2`/`TCGETS2` before `TCGETS`/`TCSETS` so that on targets
14+
+ * where these have the same value, we find the `TCGETS2`/`TCSETS2`
15+
+ * entries first, which ensures that we set the `c_ispeed` and `c_ospeed`
16+
+ * fields if the target needed them.
17+
+ */
1318
+ IOCTL(TCGETS2, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios2)))
1419
+ IOCTL(TCSETS2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2)))
20+
+ IOCTL(TCSETSF2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2)))
21+
+ IOCTL(TCSETSW2, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios2)))
22+
IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
23+
IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
1524
IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
16-
IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
17-
IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
1825
diff -ur a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h
1926
--- a/linux-user/ppc/termbits.h
2027
+++ b/linux-user/ppc/termbits.h
@@ -53,12 +60,14 @@ diff -ur a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h
5360

5461
#define TARGET_CSIZE 00001400
5562
#define TARGET_CS5 00000000
56-
@@ -178,6 +192,8 @@
63+
@@ -178,6 +192,10 @@
5764
#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios)
5865
#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios)
5966
#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios)
6067
+#define TARGET_TCGETS2 TARGET_TCGETS
6168
+#define TARGET_TCSETS2 TARGET_TCSETS
69+
+#define TARGET_TCSETSW2 TARGET_TCSETSW
70+
+#define TARGET_TCSETSF2 TARGET_TCSETSF
6271

6372
#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio)
6473
#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio)
@@ -157,6 +166,15 @@ diff -ur a/linux-user/strace.c b/linux-user/strace.c
157166

158167
#undef UNUSED
159168

169+
@@ -4161,7 +4161,7 @@
170+
int target_size;
171+
172+
for (ie = ioctl_entries; ie->target_cmd != 0; ie++) {
173+
- if (ie->target_cmd == arg1) {
174+
+ if (ie->target_cmd == (int)arg1) {
175+
break;
176+
}
177+
}
160178
diff -ur a/linux-user/syscall.c b/linux-user/syscall.c
161179
--- a/linux-user/syscall.c
162180
+++ b/linux-user/syscall.c
@@ -326,3 +344,60 @@ diff -ur a/linux-user/user-internals.h b/linux-user/user-internals.h
326344

327345
/* ARM EABI and MIPS expect 64bit types aligned even on pairs or registers */
328346
#ifdef TARGET_ARM
347+
diff -ur -x build -x roms a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h
348+
--- a/linux-user/mips/termbits.h
349+
+++ b/linux-user/mips/termbits.h
350+
@@ -18,6 +18,17 @@
351+
target_cc_t c_cc[TARGET_NCCS]; /* control characters */
352+
};
353+
354+
+struct target_termios2 {
355+
+ target_tcflag_t c_iflag; /* input mode flags */
356+
+ target_tcflag_t c_oflag; /* output mode flags */
357+
+ target_tcflag_t c_cflag; /* control mode flags */
358+
+ target_tcflag_t c_lflag; /* local mode flags */
359+
+ target_cc_t c_line; /* line discipline */
360+
+ target_cc_t c_cc[TARGET_NCCS]; /* control characters */
361+
+ target_speed_t c_ispeed; /* input speed */
362+
+ target_speed_t c_ospeed; /* output speed */
363+
+};
364+
+
365+
/* c_iflag bits */
366+
#define TARGET_IGNBRK 0000001
367+
#define TARGET_BRKINT 0000002
368+
@@ -117,6 +128,7 @@
369+
#define TARGET_B3500000 0010016
370+
#define TARGET_B4000000 0010017
371+
#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
372+
+#define TARGET_IBSHIFT 16
373+
#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */
374+
#define TARGET_CRTSCTS 020000000000 /* flow control */
375+
376+
@@ -217,9 +229,9 @@
377+
#define TARGET_TIOCSETP 0x7409
378+
#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */
379+
380+
-/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */
381+
-/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */
382+
-/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
383+
+/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct target_termios) set termios struct */
384+
+/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct target_termios) drain output, set */
385+
+/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct target_termios) drn out, fls in, set */
386+
/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */
387+
/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */
388+
/* 127-124 compat */
389+
@@ -227,10 +239,10 @@
390+
#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
391+
#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
392+
#define TARGET_TIOCGSID 0x7416 /* Return the session ID of FD */
393+
-#define TARGET_TCGETS2 TARGET_IOR('T', 0x2A, struct termios2)
394+
-#define TARGET_TCSETS2 TARGET_IOW('T', 0x2B, struct termios2)
395+
-#define TARGET_TCSETSW2 TARGET_IOW('T', 0x2C, struct termios2)
396+
-#define TARGET_TCSETSF2 TARGET_IOW('T', 0x2D, struct termios2)
397+
+#define TARGET_TCGETS2 TARGET_IOR('T', 0x2A, struct target_termios2)
398+
+#define TARGET_TCSETS2 TARGET_IOW('T', 0x2B, struct target_termios2)
399+
+#define TARGET_TCSETSW2 TARGET_IOW('T', 0x2C, struct target_termios2)
400+
+#define TARGET_TCSETSF2 TARGET_IOW('T', 0x2D, struct target_termios2)
401+
#define TARGET_TIOCGRS485 TARGET_IOR('T', 0x2E, struct serial_rs485)
402+
#define TARGET_TIOCSRS485 TARGET_IOWR('T', 0x2F, struct serial_rs485)
403+
#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */

src/backend/libc/c.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,26 @@ pub(crate) const O_LARGEFILE: c_int = 0x2000;
102102
pub(crate) const MAP_DROPPABLE: u32 = 0x8;
103103

104104
// On PowerPC, the regular `termios` has the `termios2` fields and there is no
105-
// `termios2`. linux-raw-sys has aliases `termios2` to `termios` to cover this
106-
// difference, but we still need to manually import it since `libc` doesn't
107-
// have this.
105+
// `termios2`, so we define aliases.
108106
#[cfg(all(
109107
linux_kernel,
110108
feature = "termios",
111109
any(target_arch = "powerpc", target_arch = "powerpc64")
112110
))]
113-
pub(crate) use {
114-
linux_raw_sys::general::{termios2, CIBAUD},
115-
linux_raw_sys::ioctl::{TCGETS2, TCSETS2, TCSETSF2, TCSETSW2},
111+
pub(crate) use libc::{
112+
termios as termios2, TCGETS as TCGETS2, TCSETS as TCSETS2, TCSETSF as TCSETSF2,
113+
TCSETSW as TCSETSW2,
116114
};
117115

116+
// And PowerPC doesn't define `CIBAUD`, but it does define `IBSHIFT`, so we can
117+
// compute `CIBAUD` ourselves.
118+
#[cfg(all(
119+
linux_kernel,
120+
feature = "termios",
121+
any(target_arch = "powerpc", target_arch = "powerpc64")
122+
))]
123+
pub(crate) const CIBAUD: u32 = libc::CBAUD << libc::IBSHIFT;
124+
118125
// Automatically enable “large file” support (LFS) features.
119126

120127
#[cfg(target_os = "vxworks")]

0 commit comments

Comments
 (0)