diff --git a/src/builtins/job_control.rs b/src/builtins/job_control.rs index cc7c3109cd30d306f00260fa2ed7184c7c0b4a72..b5190a222007ae927d0a6ddc2a4b29b48db86c97 100644 --- a/src/builtins/job_control.rs +++ b/src/builtins/job_control.rs @@ -77,7 +77,7 @@ pub fn jobs(shell: &mut Shell) { for (id, process) in shell.background.lock().unwrap().iter().enumerate() { match process.state { ProcessState::Empty => (), - _ => { let _ = writeln!(stderr, "[{}] {} {}", id, process.pid, process.state); } + _ => { let _ = writeln!(stderr, "[{}] {} {}\t{}", id, process.pid, process.state, process.name); } } } } diff --git a/src/shell/fork.rs b/src/shell/fork.rs index 8da1162f9aa8e626d1975cf59ac744bb62e0e53c..5b81545989a31e87afb8da2adc36ca71fb230d08 100644 --- a/src/shell/fork.rs +++ b/src/shell/fork.rs @@ -60,11 +60,15 @@ use super::pipe::pipe; /// Forks the shell, adding the child to the parent's background list, and executing /// the given commands in the child fork. -pub fn fork_pipe(shell: &mut Shell, commands: Vec<(Command, JobKind)>) -> i32 { +pub fn fork_pipe ( + shell: &mut Shell, + commands: Vec<(Command, JobKind)>, + command_name: String +) -> i32 { match ion_fork() { Ok(Fork::Parent(pid)) => { // The parent process should add the child fork's PID to the background. - shell.send_to_background(pid, ProcessState::Running); + shell.send_to_background(pid, ProcessState::Running, command_name); SUCCESS }, Ok(Fork::Child) => { diff --git a/src/shell/job_control.rs b/src/shell/job_control.rs index 806d69e98563505d754e882fef8f98f78fdb104b..e8ea8897c01fb6c9321ddbae5c10da8d9ca35836 100644 --- a/src/shell/job_control.rs +++ b/src/shell/job_control.rs @@ -35,8 +35,8 @@ pub trait JobControl { fn handle_signal(&self, signal: i32); fn foreground_send(&self, signal: i32); fn background_send(&self, signal: i32); - fn watch_foreground(&mut self, pid: u32) -> i32; - fn send_to_background(&mut self, child: u32, state: ProcessState); + fn watch_foreground<F: Fn() -> String>(&mut self, pid: u32, get_command: F) -> i32; + fn send_to_background(&mut self, child: u32, state: ProcessState, command: String); } #[derive(Clone, Copy, Debug, PartialEq)] @@ -128,17 +128,28 @@ pub fn watch_background ( pub fn add_to_background ( processes: Arc<Mutex<Vec<BackgroundProcess>>>, pid: u32, - state: ProcessState + state: ProcessState, + command: String ) -> usize { let mut processes = processes.lock().unwrap(); match (*processes).iter().position(|x| x.state == ProcessState::Empty) { Some(id) => { - (*processes)[id] = BackgroundProcess { pid: pid, ignore_sighup: false, state: state }; + (*processes)[id] = BackgroundProcess { + pid: pid, + ignore_sighup: false, + state: state, + name: command + }; id }, None => { let njobs = (*processes).len(); - (*processes).push(BackgroundProcess { pid: pid, ignore_sighup: false, state: state }); + (*processes).push(BackgroundProcess { + pid: pid, + ignore_sighup: false, + state: state, + name: command + }); njobs } } @@ -152,9 +163,8 @@ pub fn add_to_background ( pub struct BackgroundProcess { pub pid: u32, pub ignore_sighup: bool, - pub state: ProcessState - // TODO: Each process should have the command registered to it - // pub command: String + pub state: ProcessState, + pub name: String } impl<'a> JobControl for Shell<'a> { @@ -207,7 +217,11 @@ impl<'a> JobControl for Shell<'a> { } #[cfg(all(unix, not(target_os = "redox")))] - fn watch_foreground(&mut self, pid: u32) -> i32 { + fn watch_foreground <F: Fn() -> String> ( + &mut self, + pid: u32, + get_command: F + ) -> i32 { use nix::sys::wait::{waitpid, WaitStatus, WUNTRACED}; use nix::sys::signal::Signal; loop { @@ -225,7 +239,7 @@ impl<'a> JobControl for Shell<'a> { break TERMINATED; }, Ok(WaitStatus::Stopped(pid, _)) => { - self.send_to_background(pid as u32, ProcessState::Stopped); + self.send_to_background(pid as u32, ProcessState::Stopped, get_command()); self.received_sigtstp = true; break TERMINATED }, @@ -307,11 +321,11 @@ impl<'a> JobControl for Shell<'a> { // TODO: Redox doesn't support signals yet } - fn send_to_background(&mut self, pid: u32, state: ProcessState) { + fn send_to_background(&mut self, pid: u32, state: ProcessState, command: String) { let processes = self.background.clone(); let fg_signals = self.foreground_signals.clone(); let _ = spawn(move || { - let njob = add_to_background(processes.clone(), pid, state); + let njob = add_to_background(processes.clone(), pid, state, command); eprintln!("ion: bg [{}] {}", njob, pid); watch_background(fg_signals, processes, pid, njob); }); diff --git a/src/shell/pipe.rs b/src/shell/pipe.rs index 2f31a50a3c105686b20ea081bfa9f525adcfa95c..60483125fe2b0d2ad354ef0d1bac4e1cf151f091 100644 --- a/src/shell/pipe.rs +++ b/src/shell/pipe.rs @@ -128,12 +128,25 @@ pub mod crossplat { } } +// This function serves two purposes: +// 1. If the result is `Some`, then we will fork the pipeline executing into the background. +// 2. The value stored within `Some` will be that background job's command name. +fn check_if_background_job(pipeline: &Pipeline) -> Option<String> { + if pipeline.jobs[pipeline.jobs.len()-1].kind == JobKind::Background { + Some(pipeline.to_string()) + } else { + None + } +} + pub trait PipelineExecution { fn execute_pipeline(&mut self, pipeline: &mut Pipeline) -> i32; } impl<'a> PipelineExecution for Shell<'a> { fn execute_pipeline(&mut self, pipeline: &mut Pipeline) -> i32 { + let background_string = check_if_background_job(&pipeline); + // Generate a list of commands from the given pipeline let mut piped_commands: Vec<(Command, JobKind)> = pipeline.jobs .drain(..).map(|mut job| { @@ -187,8 +200,8 @@ impl<'a> PipelineExecution for Shell<'a> { self.foreground.clear(); // If the given pipeline is a background task, fork the shell. - if piped_commands[piped_commands.len()-1].1 == JobKind::Background { - fork_pipe(self, piped_commands) + if let Some(command_name) = background_string { + fork_pipe(self, piped_commands, command_name) } else { // While active, the SIGTTOU signal will be ignored. let _sig_ignore = SignalHandler::new(); @@ -320,7 +333,7 @@ fn execute_command(shell: &mut Shell, command: &mut Command, foreground: bool) - }).spawn() { Ok(child) => { if foreground { set_foreground(child.id()); } - shell.watch_foreground(child.id()) + shell.watch_foreground(child.id(), || get_full_command(command)) }, Err(_) => { let stderr = io::stderr(); @@ -335,16 +348,16 @@ fn execute_command(shell: &mut Shell, command: &mut Command, foreground: bool) - fn wait ( shell: &mut Shell, children: &mut Vec<Option<Child>>, - commands: Vec<Command>, + mut commands: Vec<Command>, foreground: bool ) -> i32 { let end = children.len() - 1; - for entry in children.drain(..end).zip(commands.into_iter()) { - // _cmd is never used here, but it is important that it gets dropped at the end of this + for entry in children.drain(..end).zip(commands.drain(..)) { + // It is important that `cmd` gets dropped at the end of this // block in order to write EOF to the pipes that it owns. - if let (Some(child), _cmd) = entry { + if let (Some(child), cmd) = entry { if foreground { set_foreground(child.id()); } - let status = shell.watch_foreground(child.id()); + let status = shell.watch_foreground(child.id(), || get_full_command(&cmd)); if status == TERMINATED { return status } @@ -352,8 +365,9 @@ fn wait ( } if let Some(child) = children.pop().unwrap() { + let cmd = commands.pop().unwrap(); if foreground { set_foreground(child.id()); } - shell.watch_foreground(child.id()) + shell.watch_foreground(child.id(), || get_full_command(&cmd)) } else { NO_SUCH_COMMAND } @@ -362,3 +376,15 @@ fn wait ( fn get_command_name(command: &Command) -> String { format!("{:?}", command).split('"').nth(1).unwrap_or("").to_string() } + +fn get_full_command(command: &Command) -> String { + let command = format!("{:?}", command); + let mut arg_iter = command.split_whitespace(); + let command = arg_iter.next().unwrap(); + let mut output = String::from(&command[1..command.len()-1]); + for argument in arg_iter { + output.push(' '); + output.push_str(&argument[1..argument.len()-1]); + } + output +}