chore: clean diagnostics; brush login+shell fix (validated cwd)

This commit is contained in:
2026-07-18 23:08:02 +09:00
parent d3e5fc0a82
commit 1c15425e7e
4 changed files with 55 additions and 3 deletions
@@ -1,3 +1,55 @@
diff --git a/brush-interactive/src/minimal/input_backend.rs b/brush-interactive/src/minimal/input_backend.rs
index 48732fb..d0026db 100644
--- a/brush-interactive/src/minimal/input_backend.rs
+++ b/brush-interactive/src/minimal/input_backend.rs
@@ -48,15 +48,38 @@ impl MinimalInputBackend {
}
fn read_input_line() -> Result<ReadResult, ShellError> {
- let mut input = String::new();
- let bytes_read = std::io::stdin()
- .read_line(&mut input)
- .map_err(ShellError::InputError)?;
-
- if bytes_read == 0 {
- Ok(ReadResult::Eof)
- } else {
- Ok(ReadResult::Input(input))
+ // On Redox the interactive console is a pty slave whose reads can
+ // return Ok(0) with no bytes even though the master side is still open
+ // (e.g. a non-blocking read with no data currently queued). std's
+ // `read_line` reports that as end-of-input; if the shell treated it as
+ // EOF it would exit immediately and getty would respawn login in a
+ // tight loop. Distinguish a *spurious* empty read (retry, briefly
+ // yielding to avoid a busy spin) from a real terminal by only treating
+ // 0 bytes as EOF when stdin is not a tty.
+ use std::io::ErrorKind;
+ loop {
+ let mut input = String::new();
+ match std::io::stdin().read_line(&mut input) {
+ // Got a line.
+ Ok(n) if n != 0 => return Ok(ReadResult::Input(input)),
+ // Zero bytes: real EOF only on a non-interactive input. On an
+ // interactive Redox pty a non-blocking read with no data queued
+ // can also surface as Ok(0); retry rather than exiting (which
+ // would drop back to a getty login loop).
+ Ok(_) => {
+ if !std::io::stdin().is_terminal() {
+ return Ok(ReadResult::Eof);
+ }
+ }
+ // A non-blocking read with no data currently available (or an
+ // interrupted syscall) is not fatal on an interactive terminal;
+ // keep polling for input.
+ Err(e)
+ if std::io::stdin().is_terminal()
+ && matches!(e.kind(), ErrorKind::WouldBlock | ErrorKind::Interrupted) => {}
+ Err(e) => return Err(ShellError::InputError(e)),
+ }
+ std::thread::sleep(std::time::Duration::from_millis(20));
}
}
}
diff --git a/brush-shell/src/entry.rs b/brush-shell/src/entry.rs
index 15340ad..384f0ca 100644
--- a/brush-shell/src/entry.rs