login: add spawn_shell diagnostics to pinpoint shell-spawn ENOENT

Probe the shell binary and home directory in the (possibly restricted)
login namespace before spawning, and print the exact spawn error with
raw_os_error. This isolates whether a failed login shell spawn is due to
a missing binary, an unreachable cwd/home, or an exec-time error.
This commit is contained in:
2026-07-18 08:08:20 +09:00
parent 0dc0cb73d1
commit 123649e200
+34 -1
View File
@@ -72,9 +72,42 @@ impl AllGroupsExt for AllGroups {
/// spawn_shell(user).unwrap();
/// ```
pub fn spawn_shell<T: Default>(user: &User<T>) -> IoResult<i32> {
// DIAGNOSTIC: probe the shell binary and home directory in the (possibly
// restricted) login namespace before spawning, so a spawn failure can be
// pinpointed (missing binary vs. missing/unreachable cwd vs. exec error).
match std::fs::metadata(&user.shell) {
Ok(m) => eprintln!(
"login-diag: shell '{}' present (len={}, mode={:o})",
user.shell,
m.len(),
m.permissions().readonly() as u32
),
Err(e) => eprintln!("login-diag: shell '{}' NOT accessible: {}", user.shell, e),
}
match std::fs::metadata(&user.home) {
Ok(_) => eprintln!("login-diag: home '{}' present", user.home),
Err(e) => eprintln!("login-diag: home '{}' NOT accessible: {}", user.home, e),
}
match std::fs::File::open(&user.shell) {
Ok(_) => eprintln!("login-diag: shell '{}' opened OK", user.shell),
Err(e) => eprintln!("login-diag: shell '{}' open FAILED: {}", user.shell, e),
}
let mut command = user.shell_cmd();
let mut child = command.spawn()?;
let mut child = match command.spawn() {
Ok(child) => child,
Err(e) => {
eprintln!(
"login-diag: spawn of shell '{}' (cwd '{}') FAILED: {} (raw_os_error={:?})",
user.shell,
user.home,
e,
e.raw_os_error()
);
return Err(e);
}
};
match child.wait()?.code() {
Some(code) => Ok(code),
None => Ok(1),