login: reset the console terminal to canonical mode before the shell

The username is read with the liner line editor, which puts the console
pty into raw mode (ICANON/ECHO cleared) and does not restore it. In raw
mode the pty line discipline never flushes a completed line into the
slave read buffer the way a shell's canonical read_line expects, so the
interactive shell (brush) never receives a typed command even though
getty forwards it to the pty master. Reset stdin to sane cooked settings
(ICANON|ECHO|ISIG, ICRNL, OPOST|ONLCR, VMIN=1/VTIME=0) via tcsetattr
before spawning the shell.
This commit is contained in:
2026-07-18 14:33:37 +09:00
parent e440bf86c1
commit 1cce5020ad
+24
View File
@@ -86,6 +86,30 @@ pub fn spawn_shell<T: Default>(user: &User<T>) -> IoResult<i32> {
}
}
// The login name is read with the `liner` line editor, which switches the
// console pty into raw mode (ICANON/ECHO cleared) and does not restore it.
// In raw mode the pty's line discipline never flushes a completed line to
// the slave's read buffer the way a shell's canonical `read_line` expects,
// so the interactive shell can never receive a typed command. Reset the
// terminal to sane canonical/cooked settings before exec'ing the shell.
#[cfg(target_os = "redox")]
unsafe {
let mut t: libc::termios = core::mem::zeroed();
if libc::tcgetattr(0, &mut t) == 0 {
t.c_iflag |= (libc::ICRNL | libc::IXON) as _;
t.c_oflag |= (libc::OPOST | libc::ONLCR) as _;
t.c_lflag |= (libc::ICANON
| libc::ECHO
| libc::ECHOE
| libc::ECHOK
| libc::ISIG
| libc::IEXTEN) as _;
t.c_cc[libc::VMIN] = 1;
t.c_cc[libc::VTIME] = 0;
let _ = libc::tcsetattr(0, libc::TCSANOW, &t);
}
}
let mut command = user.shell_cmd();
let mut child = command.spawn()?;