diff --git a/local/recipes/shells/brush/patches/brush-redox-runtime-and-input.patch b/local/recipes/shells/brush/patches/brush-redox-runtime-and-input.patch index 6e5e50727c..f41b556f00 100644 --- a/local/recipes/shells/brush/patches/brush-redox-runtime-and-input.patch +++ b/local/recipes/shells/brush/patches/brush-redox-runtime-and-input.patch @@ -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 { +- 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 diff --git a/local/sources/base b/local/sources/base index d20557f726..75229a5789 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit d20557f72688ab91d68c2e7a882901526803172f +Subproject commit 75229a5789597f494f3045164371c4bfcf21119a diff --git a/local/sources/relibc b/local/sources/relibc index 20d4e8746f..c6f8a2c208 160000 --- a/local/sources/relibc +++ b/local/sources/relibc @@ -1 +1 @@ -Subproject commit 20d4e8746fc26a246bdd83cfeb3596379c724f6a +Subproject commit c6f8a2c208c492aebc14dd649dd9951324f3325c diff --git a/local/sources/userutils b/local/sources/userutils index fbbb1d88cb..b0cfab717e 160000 --- a/local/sources/userutils +++ b/local/sources/userutils @@ -1 +1 @@ -Subproject commit fbbb1d88cb19dad0dc21c6c6bddf007297a80ac2 +Subproject commit b0cfab717ed207e2bffd02b82eef56619d7acc6e