diff --git a/src/bin/login.rs b/src/bin/login.rs index 17ee844c41..5e28e50733 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -176,16 +176,19 @@ pub fn main() { stdout.flush().r#try(&mut stderr); } - // DIAGNOSTIC: temporarily skip the login namespace - // restriction (apply_login_schemes). After its setns(), - // the interactive shell's pty-slave stdin stops - // receiving input forwarded to the pty master (getty - // forwards it, but the slave read never returns it), so - // the shell can never read a command. Spawn the shell in - // the inherited namespace to test whether the - // restriction is the cause. - let _ = apply_login_schemes; // keep import used + let before_ns_fd = + apply_login_schemes(user, &DEFAULT_SCHEMES).unwrap_or_exit(1); + + let _ = syscall::fcntl( + before_ns_fd.raw(), + syscall::F_SETFD, + syscall::O_CLOEXEC, + ); spawn_shell(user).unwrap_or_exit(1); + let _ = syscall::fcntl(before_ns_fd.raw(), syscall::F_SETFD, 0); + let _ = libredox::call::close( + libredox::call::setns(before_ns_fd.into_raw()).unwrap_or_exit(1), + ); break; } diff --git a/src/lib.rs b/src/lib.rs index 2789547063..3dd8d4ec5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,9 +18,9 @@ use std::io::Result as IoResult; -use libredox::call::{fchown, open}; +use libredox::call::{fchown, fcntl, open}; use libredox::error::Result as SysResult; -use libredox::flag::{O_CLOEXEC, O_CREAT, O_DIRECTORY}; +use libredox::flag::{O_CLOEXEC, O_CREAT, O_DIRECTORY, O_NONBLOCK}; use redox_users::{All, AllGroups, Error, Result, User, auth}; const DEFAULT_MODE: u16 = 0o700; @@ -72,6 +72,20 @@ impl AllGroupsExt for AllGroups { /// spawn_shell(user).unwrap(); /// ``` pub fn spawn_shell(user: &User) -> IoResult { + // The login name is read by a line editor (liner) that puts the console + // fd into non-blocking (and raw) mode and does not always restore it. The + // shell inherits fd 0, and an interactive shell that does blocking line + // reads on a non-blocking pty slave never receives forwarded input (the + // read returns empty). Restore blocking mode on stdin/stdout/stderr before + // spawning the shell. + const F_GETFL: usize = 3; + const F_SETFL: usize = 4; + for fd in 0..=2 { + if let Ok(flags) = fcntl(fd, F_GETFL, 0) { + let _ = fcntl(fd, F_SETFL, flags & !(O_NONBLOCK as usize)); + } + } + let mut command = user.shell_cmd(); let mut child = command.spawn()?;