diff --git a/src/parser/shell_expand/ranges.rs b/src/parser/shell_expand/ranges.rs index b755f5c2a7f95259afa5452bb5c957a746d1e624..dd1aa903256592bc8f3456a6949a3be559b51c92 100644 --- a/src/parser/shell_expand/ranges.rs +++ b/src/parser/shell_expand/ranges.rs @@ -75,13 +75,12 @@ fn char_range(start: u8, mut end: u8, step: isize, inclusive: bool) -> Option<Ve return None; } - let char_step = match step.checked_abs() { - Some(v) => if v > u8::MAX as isize { + let char_step = { + let v = step.checked_abs()?; + if v > u8::MAX as isize { return None; - } else { - v as u8 - }, - None => return None, + } + v as u8 }; if start < end { diff --git a/src/shell/binary/prompt.rs b/src/shell/binary/prompt.rs index f0c058bd05d1b9678dfbfc0a2367892523dc8e94..176fe083153b4517fb94c6b4ab72b423be45541e 100644 --- a/src/shell/binary/prompt.rs +++ b/src/shell/binary/prompt.rs @@ -17,10 +17,7 @@ pub(crate) fn prompt(shell: &mut Shell) -> String { } pub(crate) fn prompt_fn(shell: &mut Shell) -> Option<String> { - let function = match shell.functions.get("PROMPT") { - Some(func) => func as *const Function, - None => return None, - }; + let function = shell.functions.get("PROMPT")? as *const Function; let mut output = None; diff --git a/src/shell/pipe_exec/command_not_found.rs b/src/shell/pipe_exec/command_not_found.rs new file mode 100644 index 0000000000000000000000000000000000000000..55954949b9e9d2c91c589edd646114f43cc49793 --- /dev/null +++ b/src/shell/pipe_exec/command_not_found.rs @@ -0,0 +1,24 @@ +use super::super::{Capture, Function, Shell}; +use std::process; +use sys; + +pub(crate) fn command_not_found(shell: &mut Shell, command: &str) -> bool { + let function = match shell.functions.get("COMMAND_NOT_FOUND") { + Some(func) => func as *const Function, + None => return false + }; + + if let Err(err) = shell.fork(Capture::None, |child| { + let result = unsafe { function.read() }.execute(child, &["ion", command]); + if let Err(err) = result { + eprintln!("ion: COMMAND_NOT_FOUND function call: {}", err); + } + }) { + eprintln!("ion: fork error: {}", err); + return false; + } + + // Ensure that the parent retains ownership of the terminal before exiting. + let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id()); + true +} diff --git a/src/shell/pipe_exec/mod.rs b/src/shell/pipe_exec/mod.rs index 44123729583b639c76eb3ff1e4b3b5516ec193ae..84d1c10c7b9805bb60d1ee9e3180de16d7584dc9 100644 --- a/src/shell/pipe_exec/mod.rs +++ b/src/shell/pipe_exec/mod.rs @@ -4,11 +4,13 @@ //! IDs, watching foreground and background tasks, sending foreground tasks to the background, //! handling pipeline and conditional operators, and std{in,out,err} redirections. +mod command_not_found; pub mod foreground; mod fork; pub mod job_control; mod streams; +use self::command_not_found::command_not_found; use self::fork::{create_process_group, fork_pipe}; use self::job_control::JobControl; use self::streams::{duplicate_streams, redir, redirect_streams}; @@ -495,7 +497,9 @@ impl PipelineExecution for Shell { self.watch_foreground(child.id(), child.id(), move || long, |_| ()) } Err(e) => if e.kind() == io::ErrorKind::NotFound { - eprintln!("ion: command not found: {}", short); + if !command_not_found(self, &short) { + eprintln!("ion: command not found: {}", short); + } NO_SUCH_COMMAND } else { eprintln!("ion: error spawning process: {}", e); @@ -749,7 +753,9 @@ pub(crate) fn pipe( }, Err(e) => { return if e.kind() == io::ErrorKind::NotFound { - eprintln!("ion: command not found: {}", short); + if !command_not_found(shell, &short) { + eprintln!("ion: command not found: {}", short); + } NO_SUCH_COMMAND } else { eprintln!("ion: error spawning process: {}", e);