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:
+24
@@ -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()?;
|
||||
|
||||
Reference in New Issue
Block a user