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..cd5c975c0c951e6f1e60905964acd1a80a4910f5 --- /dev/null +++ b/src/shell/pipe_exec/command_not_found.rs @@ -0,0 +1,35 @@ +use super::super::{Capture, Function, Shell}; +use parser::shell_expand::expand_string; +use std::io::Read; +use std::process; +use sys; + +pub(crate) fn command_not_found(shell: &mut Shell, command: &str) -> Option<String> { + let function = match shell.functions.get("COMMAND_NOT_FOUND") { + Some(func) => func as *const Function, + None => return None // TODO: Use ? on Option whenever we drop support for older rust versions + }; + + let mut output = None; + + match shell.fork(Capture::Stdout, |child| unsafe { + let _ = function.read().execute(child, &["ion", command]); + }) { + Ok(result) => { + let mut string = String::new(); + match result.stdout.unwrap().read_to_string(&mut string) { + Ok(_) => output = Some(string), + Err(err) => { + eprintln!("ion: error reading stdout of child: {}", err); + } + } + }, + Err(err) => { + eprintln!("ion: fork error: {}", err); + } + } + + // Ensure that the parent retains ownership of the terminal before exiting. + let _ = sys::tcsetpgrp(sys::STDIN_FILENO, process::id()); + output +} diff --git a/src/shell/pipe_exec/mod.rs b/src/shell/pipe_exec/mod.rs index 44123729583b639c76eb3ff1e4b3b5516ec193ae..88138508b32d50e02faf84a1d041f4f7cb0bbe64 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,11 @@ 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 let Some(output) = command_not_found(self, &short) { + print!("{}", output); + } else { + eprintln!("ion: command not found: {}", short); + } NO_SUCH_COMMAND } else { eprintln!("ion: error spawning process: {}", e); @@ -749,7 +755,11 @@ pub(crate) fn pipe( }, Err(e) => { return if e.kind() == io::ErrorKind::NotFound { - eprintln!("ion: command not found: {}", short); + if let Some(output) = command_not_found(shell, &short) { + print!("{}", output); + } else { + eprintln!("ion: command not found: {}", short); + } NO_SUCH_COMMAND } else { eprintln!("ion: error spawning process: {}", e);