Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable_raw_mode() error in version 0.28.0 under WSL and Android #912

Open
tajkhan opened this issue Aug 13, 2024 · 10 comments · Fixed by bytecodealliance/rustix#1147 · May be fixed by #926
Open

enable_raw_mode() error in version 0.28.0 under WSL and Android #912

tajkhan opened this issue Aug 13, 2024 · 10 comments · Fixed by bytecodealliance/rustix#1147 · May be fixed by #926

Comments

@tajkhan
Copy link

tajkhan commented Aug 13, 2024

Solution

rustix has released 0.38.36, which fixes this bug. Crossterm 0.28.1 is compatible with this version of rustix. Run cargo update to update your dependencies in your lock file.


Problem

Describe the bug
Was following the hecto tutorial which uses crossterm and found that the enable_raw_mode() function in bash under WSL in the latest version "0.28.0" returns an error. Apparently was working fine in version "0.27.0".

To Reproduce
Steps to reproduce the behavior:

  1. Go to bash in Ubuntu under WSL and create a new binary crate with the following code in src/main.rs:
use std::io::{self, Read};
use crossterm::terminal::enable_raw_mode;
use crossterm::terminal::disable_raw_mode;

fn main() {
    enable_raw_mode().unwrap();
    for b in io::stdin().bytes() {
        let c = b.unwrap() as char;
        println!("{}", c);
        if c == 'q' {
	    disable_raw_mode().unwrap();
            break;
        }
    }
}
  1. Do cargo add crossterm. By default it will add the latest version "0.28.0".
  2. Run cargo run
  3. The output contains the error: 'called Result::unwrap() on an Err value: Os { code: 25, kind: Uncategorized, message: "Inappropriate ioctl for device" }'
  4. Moving the dependency version to "0.27.0" as used by the tutorial works fine though.

Expected behavior
Calling enable_raw_mode() should return Ok(()) and switch the terminal to raw mode.

OS
I am running bash in Ubuntu in WSL under Windows 10 home edition; The terminal is xterm-256color.

@jbncode
Copy link

jbncode commented Aug 28, 2024

I'm experiencing the same issue. I found that enabling the libc feature of crossterm makes it work again. It looks like 0.27 always uses the "libc" method, but in 0.28 a new way that does not require libc was added as the default. It is this new non-libc version of the function that doesn't work under WSL.

@joshka
Copy link
Collaborator

joshka commented Aug 28, 2024

Please post a full error message including backtrace for this if you can.

Good to hear switching back to libc works. I pushed to keep the libc code in place when the rustix implementation was added, and was starting to second guess myself about being a little over cautious.

@sunfishcode
Copy link

I don't have a WSL environment to test this in, however a notable difference in the strace output between the rustix and libc versions here is that rustix is using TCGETS2 (introduced in Linux 2.6.20) for the ioctl, while libc is using TCGETS. I found a report that WSL doesn't support TCGETS2 on serial ports, so it's plausible that the explanation here is that WSL doesn't support TCGETS2 on its terminal either. I'll look into having rustix use TCGETS.

The full error message would help confirm this. And if anyone who is able to reproduce this is able to run the program under strace and post the output, that would be helpful as well. Thanks!

@jbncode
Copy link

jbncode commented Aug 28, 2024

Thanks for looking into this. For the following program:

fn main() {
    crossterm::terminal::enable_raw_mode().unwrap();
}

I get this output from strace, which does indeed point to TCGETS2 being the issue:

execve("./target/debug/crossterm-test", ["./target/debug/crossterm-test"...], 0x7fffde974aa0 /* 49 vars */) = 0
brk(NULL)                               = 0x7fffe62fa000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffeeed12f0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f55805d0000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=129419, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 129419, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5580570000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=125488, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 127720, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5580550000
mmap(0x7f5580553000, 94208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f5580553000
mmap(0x7f558056a000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7f558056a000
mmap(0x7f558056e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0x7f558056e000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0I\17\357\204\3$\f\221\2039x\324\224\323\236S"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5580320000
mprotect(0x7f5580348000, 2023424, PROT_NONE) = 0
mmap(0x7f5580348000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7f5580348000
mmap(0x7f55804dd000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f55804dd000
mmap(0x7f5580536000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7f5580536000
mmap(0x7f558053c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f558053c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5580310000
arch_prctl(ARCH_SET_FS, 0x7f55803107c0) = 0
set_tid_address(0x7f5580310a90)         = 3291
set_robust_list(0x7f5580310aa0, 24)     = 0
rseq(0x7f5580311160, 0x20, 0, 0x53053053) = -1 ENOSYS (Function not implemented)
mprotect(0x7f5580536000, 16384, PROT_READ) = 0
mprotect(0x7f558056e000, 4096, PROT_READ) = 0
mprotect(0x7f5580643000, 16384, PROT_READ) = 0
mprotect(0x7f55805c8000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=8192*1024}) = 0
munmap(0x7f5580570000, 129419)          = 0
poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0
x7f5580362520}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7fc25d7d2520}, 8) = 0
getrandom("\x4f\xc8\xee\xb0\x5d\x3a\x97\x3f", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x7fffe62fa000
brk(0x7fffe631b000)                     = 0x7fffe631b000
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=8192*1024}) = 0
newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
read(3, "7f5580310000-7f5580313000 rw-p 0"..., 4096) = 3572
close(3)                                = 0
sched_getaffinity(3291, 32, [0, 1, 2, 3, 4, 5, 6, 7]) = 32
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fc25d7d2520}, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x7f5580610440, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f5580362520}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7fc25d7d2520}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x7f5580610440, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f5580362520}, NULL, 8) = 0
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f5580580000
mprotect(0x7f5580580000, 4096, PROT_NONE) = 0
sigaltstack({ss_sp=0x7f5580581000, ss_flags=0, ss_size=8192}, NULL) = 0
ioctl(0, TIOCGWINSZ, {ws_row=51, ws_col=105, ws_xpixel=1680, ws_ypixel=1632}) = 0
ioctl(0, TCGETS2, 0x7fffeeed0ddc)       = -1 ENOTTY (Inappropriate ioctl for device)
write(2, "thread '", 8thread ')                 = 8
write(2, "main", 4main)                     = 4
write(2, "' panicked at ", 14' panicked at )          = 14
write(2, "src/main.rs", 11src/main.rs)             = 11
write(2, ":", 1:)                        = 1
write(2, "2", 12)                        = 1
write(2, ":", 1:)                        = 1
write(2, "44", 244)                       = 2
write(2, ":\n", 2:
)                      = 2
write(2, "called `Result::unwrap()` on an "..., 124called `Result::unwrap()` on an `Err` value: Os { code: 25, kind: Uncategorized, message: "Inappropriate ioctl for device" }) = 124
write(2, "\n", 1
)                       = 1
write(2, "note: run with `RUST_BACKTRACE=1"..., 78note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
) = 78
futex(0x7f558056f210, FUTEX_WAKE_PRIVATE, 2147483647) = 0
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7f5580580000, 12288)           = 0
exit_group(101)                         = ?
+++ exited with 101 +++

The backtrace doesn't go any deeper than the call to enable_raw_mode, but in case it's still helpful it is:

thread 'main' panicked at src/main.rs:2:44:
called `Result::unwrap()` on an `Err` value: Os { code: 25, kind: Uncategorized, message: "Inappropriate ioctl for device" }
stack backtrace:
   0: rust_begin_unwind
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/std/src/panicking.rs:652:5
   1: core::panicking::panic_fmt
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/panicking.rs:72:14
   2: core::result::unwrap_failed
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/result.rs:1679:5
   3: core::result::Result<T,E>::unwrap
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/result.rs:1102:23
   4: crossterm_test::main
             at ./src/main.rs:2:5
   5: core::ops::function::FnOnce::call_once
             at /rustc/3f5fd8dd41153bc5fdca9427e9e05be2c767ba23/library/core/src/ops/function.rs:250:5

The calling sequence that causes the error is:
enable_raw_mode -> get_terminal_attr -> rustix::termios::tcgetattr.

@joshka
Copy link
Collaborator

joshka commented Aug 28, 2024

Thanks for the diagnosis. Can you also try to get strace output for the libc feature too? It would be a useful comparison to see where they differ.

@jbncode
Copy link

jbncode commented Aug 28, 2024

Here's the strace output with the libc feature:

execve("./target/debug/crossterm-test", ["./target/debug/crossterm-test"], 0x7fffecb9dcd0 /* 49 vars */) = 0
brk(NULL)                               = 0x7fffe2a39000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffe9e0e8a0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5a02ef0000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=129419, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 129419, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5a02ed0000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libgcc_s.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=125488, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 127720, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5a02eb0000
mmap(0x7f5a02eb3000, 94208, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f5a02eb3000
mmap(0x7f5a02eca000, 16384, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7f5a02eca000
mmap(0x7f5a02ece000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d000) = 0x7f5a02ece000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0I\17\357\204\3$\f\221\2039x\324\224\323\236S"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2264656, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f5a02c80000
mprotect(0x7f5a02ca8000, 2023424, PROT_NONE) = 0
mmap(0x7f5a02ca8000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7f5a02ca8000
mmap(0x7f5a02e3d000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f5a02e3d000
mmap(0x7f5a02e96000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x215000) = 0x7f5a02e96000
mmap(0x7f5a02e9c000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f5a02e9c000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5a02c70000
arch_prctl(ARCH_SET_FS, 0x7f5a02c707c0) = 0
set_tid_address(0x7f5a02c70a90)         = 5557
set_robust_list(0x7f5a02c70aa0, 24)     = 0
rseq(0x7f5a02c71160, 0x20, 0, 0x53053053) = -1 ENOSYS (Function not implemented)
mprotect(0x7f5a02e96000, 16384, PROT_READ) = 0
mprotect(0x7f5a02ece000, 4096, PROT_READ) = 0
mprotect(0x7f5a02fa3000, 16384, PROT_READ) = 0
mprotect(0x7f5a02f38000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=8192*1024}) = 0
munmap(0x7f5a02ed0000, 129419)          = 0
poll([{fd=0, events=0}, {fd=1, events=0}, {fd=2, events=0}], 3, 0) = 0 (Timeout)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f5a02cc2520}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f79694a2520}, 8) = 0
getrandom("\x87\xd5\xa7\x88\xd4\x50\x9e\xa6", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x7fffe2a39000
brk(0x7fffe2a5a000)                     = 0x7fffe2a5a000
openat(AT_FDCWD, "/proc/self/maps", O_RDONLY|O_CLOEXEC) = 3
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=8192*1024}) = 0
newfstatat(3, "", {st_mode=S_IFREG|0444, st_size=0, ...}, AT_EMPTY_PATH) = 0
read(3, "7f5a02c70000-7f5a02c73000 rw-p 0"..., 4096) = 3516
close(3)                                = 0
sched_getaffinity(5557, 32, [0, 1, 2, 3, 4, 5, 6, 7]) = 32
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f79694a2520}, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x7f5a02f72240, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f5a02cc2520}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=SA_RESTORER, sa_restorer=0x7f79694a2520}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x7f5a02f72240, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f5a02cc2520}, NULL, 8) = 0
sigaltstack(NULL, {ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=0}) = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f5a02ee0000
mprotect(0x7f5a02ee0000, 4096, PROT_NONE) = 0
sigaltstack({ss_sp=0x7f5a02ee1000, ss_flags=0, ss_size=8192}, NULL) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(0, SNDCTL_TMR_START or TCSETS, {B38400 -opost -isig -icanon -echo ...}) = 0
ioctl(0, TCGETS, {B38400 -opost -isig -icanon -echo ...}) = 0
sigaltstack({ss_sp=NULL, ss_flags=SS_DISABLE, ss_size=8192}, NULL) = 0
munmap(0x7f5a02ee0000, 12288)           = 0
exit_group(0)                           = ?
+++ exited with 0 +++

sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Aug 29, 2024
WSL appears to be lacking support for `TCGETS2` and `TCSETS2`, so teach
rustix's `tcgetattr` and `tcsetattr` how to fall back to `TCGETS` and
`TCSETS` as needed.

This approach preserves rustix's ability to support arbitrary speed values,
while falling back as needed to support WSL.

This is expected to fix crossterm-rs/crossterm#912.
sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Aug 29, 2024
WSL appears to be lacking support for `TCGETS2` and `TCSETS2`, so teach
rustix's `tcgetattr` and `tcsetattr` how to fall back to `TCGETS` and
`TCSETS` as needed.

This approach preserves rustix's ability to support arbitrary speed values,
while falling back as needed to support WSL.

This is expected to fix crossterm-rs/crossterm#912.
@sunfishcode
Copy link

I've now posted bytecodealliance/rustix#1146 with a possible fix. I don't have a WSL environment to test it in myself, but if anyone who does would like to try it, it should be sufficient to add these lines to Cargo.toml:

[patch.crates-io]
rustix = { git = "https://github.com/bytecodealliance/rustix", rev = "4d1f3eaaae138138817dcaaabf5eaea6d9b93a08" }

@jbncode
Copy link

jbncode commented Aug 29, 2024

Yes, that rustix patch seems to fix it for me. Thanks!

sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Aug 31, 2024
WSL appears to be lacking support for `TCGETS2` and `TCSETS2`, so teach
rustix's `tcgetattr` and `tcsetattr` how to fall back to `TCGETS` and
`TCSETS` as needed.

This approach preserves rustix's ability to support arbitrary speed values,
while falling back as needed to support WSL.

This is expected to fix crossterm-rs/crossterm#912.
sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Sep 3, 2024
Switch `tcgetattr`/`tcsetattr` from using `TCGETS2`/`TCSETS2` first to using
`TCGETS`/`TCSETS` first. Have `tcgetattr` fall back to `TCGETS2` if the
`TCGETS` flags indicate that a custom speed is in used.

glibc and musl have not yet migrated to `TCGETS2`/`TCSETS2`, and as a
result, seccomp sandboxes and Linux-like environments such as WSL don't always
support them.

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.

This is expected to fix crossterm-rs/crossterm#912.
sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Sep 3, 2024
Switch `tcgetattr`/`tcsetattr` from using `TCGETS2`/`TCSETS2` first to using
`TCGETS`/`TCSETS` first. Have `tcgetattr` fall back to `TCGETS2` if the
`TCGETS` flags indicate that a custom speed is in used.

glibc and musl have not yet migrated to `TCGETS2`/`TCSETS2`, and as a
result, seccomp sandboxes and Linux-like environments such as WSL don't always
support them.

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.

This is expected to fix crossterm-rs/crossterm#912.
sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Sep 3, 2024
Switch `tcgetattr`/`tcsetattr` from using `TCGETS2`/`TCSETS2` first to using
`TCGETS`/`TCSETS` first. Have `tcgetattr` fall back to `TCGETS2` if the
`TCGETS` flags indicate that a custom speed is in used.

glibc and musl have not yet migrated to `TCGETS2`/`TCSETS2`, and as a
result, seccomp sandboxes and Linux-like environments such as WSL don't always
support them.

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.

This is expected to fix crossterm-rs/crossterm#912.
sunfishcode added a commit to bytecodealliance/rustix that referenced this issue Sep 5, 2024
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.
@sunfishcode
Copy link

Thanks for testing! I've now released rustix 0.38.36 with the fix.

@joshka
Copy link
Collaborator

joshka commented Sep 6, 2024

Added a note to the first comment for anyone that finds this issue marking the solution as run cargo update (until #926 is merged and released).

@joshka joshka changed the title enable_raw_mode() error in version 0.28.0 under WSL enable_raw_mode() error in version 0.28.0 under WSL and Android Sep 6, 2024
@joshka joshka pinned this issue Sep 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants