diff --git a/src/lib/shell/job.rs b/src/lib/shell/job.rs index a08d86ad1c0bc781b5b05db633aa2d2e010f1ec7..a822004fdcb8183cfb46c0c9e4c5a7a38e07b1f8 100644 --- a/src/lib/shell/job.rs +++ b/src/lib/shell/job.rs @@ -67,16 +67,17 @@ pub struct RefinedJob<'a> { pub stdin: Option<File>, pub stdout: Option<File>, pub stderr: Option<File>, + pub args: types::Args, pub var: JobVariant<'a>, } pub enum JobVariant<'a> { /// An external program that is executed by this shell - External { args: types::Args }, + External, /// A procedure embedded into Ion - Builtin { main: BuiltinFunction<'a>, args: types::Args }, + Builtin { main: BuiltinFunction<'a> }, /// Functions can act as commands too! - Function { args: types::Args }, + Function, /// Represents redirection into stdin from more than one source Cat { sources: Vec<File> }, Tee { @@ -151,15 +152,11 @@ impl TeeItem { impl<'a> RefinedJob<'a> { /// Returns a long description of this job: the commands and arguments - pub fn long(&self) -> String { - match self.var { - JobVariant::External { ref args, .. } - | JobVariant::Builtin { ref args, .. } - | JobVariant::Function { ref args, .. } => args.join(" ").to_owned(), - // TODO: Figure out real printing - JobVariant::Cat { .. } | JobVariant::Tee { .. } => "".into(), - } - } + pub fn long(&self) -> String { self.args.join(" ") } + + pub fn command(&self) -> &types::Str { &self.args[0] } + + pub fn args(&self) -> &types::Args { &self.args } pub fn stderr(&mut self, file: File) { if let JobVariant::Cat { .. } = self.var { @@ -169,6 +166,13 @@ impl<'a> RefinedJob<'a> { self.stderr = Some(file); } + pub fn needs_forking(&self) -> bool { + match self.var { + JobVariant::Function | JobVariant::Builtin { .. } => false, + _ => true, + } + } + pub fn stdout(&mut self, file: File) { self.stdout = Some(file); } pub fn stdin(&mut self, file: File) { self.stdin = Some(file); } @@ -178,38 +182,36 @@ impl<'a> RefinedJob<'a> { stdin: None, stdout: None, stderr: None, + args: types::Args::new(), var: JobVariant::Tee { items: (tee_out, tee_err) }, } } pub fn cat(sources: Vec<File>) -> Self { - RefinedJob { stdin: None, stdout: None, stderr: None, var: JobVariant::Cat { sources } } - } - - pub fn function(args: types::Args) -> Self { RefinedJob { stdin: None, stdout: None, stderr: None, - var: JobVariant::Function { args }, + args: types::Args::new(), + var: JobVariant::Cat { sources }, } } + pub fn function(args: types::Args) -> Self { + RefinedJob { stdin: None, stdout: None, stderr: None, args, var: JobVariant::Function } + } + pub fn builtin(main: BuiltinFunction<'a>, args: types::Args) -> Self { RefinedJob { - stdin: None, + stdin: None, stdout: None, stderr: None, - var: JobVariant::Builtin { main, args }, + args, + var: JobVariant::Builtin { main }, } } pub fn external(args: types::Args) -> Self { - RefinedJob { - stdin: None, - stdout: None, - stderr: None, - var: JobVariant::External { args }, - } + RefinedJob { stdin: None, stdout: None, stderr: None, args, var: JobVariant::External } } } diff --git a/src/lib/shell/pipe_exec/mod.rs b/src/lib/shell/pipe_exec/mod.rs index 8fc371116becd19316691c1ded9b1c5dba8884a8..b70f1f4b4577c8087b72256f40fc4e76ab14cd2e 100644 --- a/src/lib/shell/pipe_exec/mod.rs +++ b/src/lib/shell/pipe_exec/mod.rs @@ -180,40 +180,6 @@ fn prepare<'a, 'b>( } impl<'b> Shell<'b> { - fn exec_external<'a, S: AsRef<str>>( - &mut self, - name: &'a str, - args: &'a [S], - stdin: &Option<File>, - stdout: &Option<File>, - stderr: &Option<File>, - ) -> Status { - let result = sys::fork_and_exec( - name, - args, - stdin.as_ref().map(File::as_raw_fd), - stdout.as_ref().map(File::as_raw_fd), - stderr.as_ref().map(File::as_raw_fd), - false, - || prepare_child(true, 0), - ); - - match result { - Ok(pid) => { - let _ = sys::setpgid(pid, pid); - let _ = sys::tcsetpgrp(0, pid); - let _ = wait_for_interrupt(pid); - let _ = sys::kill(pid, sys::SIGCONT); - self.watch_foreground(pid) - } - Err(ref err) if err.kind() == io::ErrorKind::NotFound => { - self.command_not_found(name); - Status::NO_SUCH_COMMAND - } - Err(ref err) => Status::error(format!("ion: command exec error: {}", err)), - } - } - /// For tee jobs fn exec_multi_out( &mut self, @@ -295,11 +261,8 @@ impl<'b> Shell<'b> { if let Ok((stdin_bk, stdout_bk, stderr_bk)) = duplicate_streams() { redirect_streams(&job.stdin, &job.stdout, &job.stderr); let code = match job.var { - JobVariant::External { ref args } => { - self.exec_external(&args[0], &args[1..], &job.stdin, &job.stdout, &job.stderr) - } - JobVariant::Builtin { ref main, ref args } => self.exec_builtin(main, &**args), - JobVariant::Function { ref args } => self.exec_function(&args[0], args), + JobVariant::Builtin { ref main } => self.exec_builtin(main, job.args()), + JobVariant::Function => self.exec_function(job.command(), job.args()), _ => panic!("exec job should not be able to be called on Cat or Tee jobs"), }; redirect_streams(&stdin_bk, &Some(stdout_bk), &Some(stderr_bk)); @@ -390,7 +353,14 @@ impl<'b> Shell<'b> { }; if let Some((mut parent, mut kind)) = commands.next() { - if kind != RedirectFrom::None { + if kind == RedirectFrom::None && !parent.needs_forking() { + let status = self.exec_job(&parent); + + let _ = io::stdout().flush(); + let _ = io::stderr().flush(); + + status + } else { let (mut pgid, mut last_pid, mut current_pid) = (0, 0, 0); // Append jobs until all piped jobs are running @@ -472,13 +442,6 @@ impl<'b> Shell<'b> { let _ = io::stdout().flush(); let _ = io::stderr().flush(); } - status - } else { - let status = self.exec_job(&parent); - - let _ = io::stdout().flush(); - let _ = io::stderr().flush(); - status } } else { @@ -489,23 +452,19 @@ impl<'b> Shell<'b> { fn spawn_proc( shell: &mut Shell, - mut cmd: RefinedJob, + cmd: RefinedJob, redirection: RedirectFrom, block_child: bool, last_pid: &mut u32, current_pid: &mut u32, pgid: u32, ) { - let stdin = cmd.stdin; - let stdout = cmd.stdout; - let stderr = cmd.stderr; - match cmd.var { - JobVariant::External { ref args } => { - let name = &args[0]; - let args: Vec<&str> = args.iter().skip(1).map(|x| x as &str).collect(); + let RefinedJob { mut var, args, stdin, stdout, stderr } = cmd; + match var { + JobVariant::External => { let mut result = sys::fork_and_exec( - name, - &args, + &args[0], + &args[1..], stdin.as_ref().map(AsRawFd::as_raw_fd), stdout.as_ref().map(AsRawFd::as_raw_fd), stderr.as_ref().map(AsRawFd::as_raw_fd), @@ -519,14 +478,14 @@ fn spawn_proc( *current_pid = pid; } Err(ref mut err) if err.kind() == io::ErrorKind::NotFound => { - shell.command_not_found(name) + shell.command_not_found(&args[0]) } Err(ref mut err) => { eprintln!("ion: command exec error: {}", err); } } } - JobVariant::Builtin { main, ref mut args } => { + JobVariant::Builtin { main } => { fork_exec_internal( stdout, stderr, @@ -535,10 +494,10 @@ fn spawn_proc( last_pid, current_pid, pgid, - |_, _, _| shell.exec_builtin(main, args), + |_, _, _| main(&args, shell), ); } - JobVariant::Function { ref mut args } => { + JobVariant::Function => { fork_exec_internal( stdout, stderr,