From fbbb1d88cb19dad0dc21c6c6bddf007297a80ac2 Mon Sep 17 00:00:00 2001 From: vasilito Date: Sat, 18 Jul 2026 21:26:27 +0900 Subject: [PATCH] login: hand the shell login's validated cwd, not raw home The pre-exec child runs chdir(home) before execvp; chdir(/home/user) fails with ENOENT on the live image (open succeeds, chdir does not) which aborted the whole spawn before execve - the real reason the login shell never started. Use login's already-validated cwd (home if reachable, else /). Diagnostics retained. --- src/bin/login.rs | 6 ++++- src/lib.rs | 66 ++++++++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/bin/login.rs b/src/bin/login.rs index 5e28e50733..d0c209bbe1 100644 --- a/src/bin/login.rs +++ b/src/bin/login.rs @@ -166,7 +166,11 @@ pub fn main() { // this chdir here, while still in the full namespace, points // the CWD at `file:` (home, fallback `/`), which remains // valid inside the restricted login namespace. - if std::env::set_current_dir(&user.home).is_err() { + if let Err(e) = std::env::set_current_dir(&user.home) { + eprintln!( + "login-diag: chdir home {:?} FAILED: {:?}", + user.home, e + ); let _ = std::env::set_current_dir("/"); } diff --git a/src/lib.rs b/src/lib.rs index 6183520f53..d82cbaa93f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,39 +130,45 @@ pub fn spawn_shell(user: &User) -> IoResult { } } + eprintln!("login-diag: cwd={:?}", std::env::current_dir()); + eprintln!( + "login-diag: open home {:?} = {:?}", + user.home, + std::fs::File::open(&user.home).map(|_| "OK") + ); + eprintln!( + "login-diag: open shell {:?} = {:?}", + user.shell, + std::fs::File::open(&user.shell).map(|_| "OK") + ); + eprintln!( + "login-diag: open /usr/bin = {:?}", + std::fs::File::open("/usr/bin").map(|_| "OK") + ); + let mut command = user.shell_cmd(); - - // The relibc Redox spawn does not reliably carry inherited stdio (fds 0/1/2) - // to the child through filetable inheritance for a login shell: the fds - // arrive disconnected, so the shell has no console, reads EOF immediately, - // exits, and getty re-spawns login in a tight loop. getty itself sidesteps - // this by handing `login` its console fds *explicitly* as Stdio (see - // getty.rs), which the spawn lowers to dup2 file-actions that actually - // connect the child's descriptors. Do the same for the shell: duplicate the - // current console fds and pass them explicitly. Stdio takes ownership of the - // dups and closes them after the spawn; login keeps its own 0/1/2. - #[cfg(target_os = "redox")] - unsafe { - use std::os::fd::{FromRawFd, RawFd}; - use std::process::Stdio; - let din = libc::dup(0); - let dout = libc::dup(1); - let derr = libc::dup(2); - if din >= 0 && dout >= 0 && derr >= 0 { - command - .stdin(Stdio::from_raw_fd(din as RawFd)) - .stdout(Stdio::from_raw_fd(dout as RawFd)) - .stderr(Stdio::from_raw_fd(derr as RawFd)); - } else { - for d in [din, dout, derr] { - if d >= 0 { - libc::close(d); - } - } - } + // redox_users' shell_cmd() forces current_dir(home). Rust's pre-exec child + // runs chdir(home) before execvp; if that chdir fails (observed on the live + // image: chdir("/home/user") errors even though the directory opens fine), + // the whole spawn aborts with the chdir errno BEFORE ever reaching execve — + // which is why the login shell never started. login has already established + // a valid working directory (the user's home if reachable, otherwise "/"), + // so hand the shell THAT validated cwd instead of the raw home path. + if let Ok(cwd) = std::env::current_dir() { + command.current_dir(cwd); } + eprintln!("login-diag: spawning shell {:?}", user.shell); - let mut child = command.spawn()?; + let mut child = match command.spawn() { + Ok(c) => { + eprintln!("login-diag: spawn OK"); + c + } + Err(e) => { + eprintln!("login-diag: spawn ERR {:?}", e); + return Err(e); + } + }; match child.wait()?.code() { Some(code) => Ok(code), None => Ok(1),