diff --git a/src/elements/command.rs b/src/elements/command.rs index c3628c1b..b8e8318f 100644 --- a/src/elements/command.rs +++ b/src/elements/command.rs @@ -8,6 +8,7 @@ pub mod r#while; pub mod r#if; use crate::{ShellCore, Feeder, Script}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use crate::utils::exit; use self::simple::SimpleCommand; @@ -29,16 +30,15 @@ impl Debug for dyn Command { } pub trait Command { - fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option { + fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result, ExecError> { if self.force_fork() || pipe.is_connected() { self.fork_exec(core, pipe) }else{ - self.nofork_exec(core); - None + self.nofork_exec(core) } } - fn fork_exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option { + fn fork_exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result, ExecError> { match unsafe{unistd::fork()} { Ok(ForkResult::Child) => { core.initialize_as_subshell(Pid::from_raw(0), pipe.pgid); @@ -49,22 +49,23 @@ pub trait Command { Ok(ForkResult::Parent { child } ) => { core.set_pgid(child, pipe.pgid); pipe.parent_close(); - Some(child) + Ok(Some(child)) }, Err(err) => panic!("sush(fatal): Failed to fork. {}", err), } } - fn nofork_exec(&mut self, core: &mut ShellCore) { + fn nofork_exec(&mut self, core: &mut ShellCore) -> Result, ExecError> { if self.get_redirects().iter_mut().all(|r| r.connect(true, core)){ self.run(core, false); }else{ core.db.set_param("?", "1").unwrap(); } self.get_redirects().iter_mut().rev().for_each(|r| r.restore()); + Ok(None) } - fn run(&mut self, _: &mut ShellCore, fork: bool); + fn run(&mut self, _: &mut ShellCore, fork: bool) -> Result<(), ExecError>; fn get_text(&self) -> String; fn get_redirects(&mut self) -> &mut Vec; fn set_force_fork(&mut self); diff --git a/src/elements/command/brace.rs b/src/elements/command/brace.rs index 822cdd81..4ccff7e0 100644 --- a/src/elements/command/brace.rs +++ b/src/elements/command/brace.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{ShellCore, Feeder, Script}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use super::{Command, Redirect}; use crate::elements::command; @@ -15,7 +16,7 @@ pub struct BraceCommand { } impl Command for BraceCommand { - fn run(&mut self, core: &mut ShellCore, _: bool) { + fn run(&mut self, core: &mut ShellCore, _: bool) -> Result<(), ExecError> { match self.script { Some(ref mut s) => s.exec(core), _ => panic!("SUSH INTERNAL ERROR (ParenCommand::exec)"), diff --git a/src/elements/command/if.rs b/src/elements/command/if.rs index 31762582..b5e4d428 100644 --- a/src/elements/command/if.rs +++ b/src/elements/command/if.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{ShellCore, Feeder, Script}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use crate::elements::command; use super::{Command, Redirect}; @@ -17,18 +18,19 @@ pub struct IfCommand { } impl Command for IfCommand { - fn run(&mut self, core: &mut ShellCore, _: bool) { + fn run(&mut self, core: &mut ShellCore, _: bool) -> Result<(), ExecError> { for i in 0..self.if_elif_scripts.len() { self.if_elif_scripts[i].exec(core); if core.db.get_param("?").unwrap() == "0" { - self.then_scripts[i].exec(core); - return; + self.then_scripts[i].exec(core)?; + return Ok(()); } } if let Some(s) = self.else_script.as_mut() { - s.exec(core); + s.exec(core)?; } + Ok(()) } fn get_text(&self) -> String { self.text.clone() } diff --git a/src/elements/command/paren.rs b/src/elements/command/paren.rs index 55b5410b..20604704 100644 --- a/src/elements/command/paren.rs +++ b/src/elements/command/paren.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{ShellCore, Feeder, Script}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use super::{Command, Pipe, Redirect}; use crate::elements::command; @@ -15,19 +16,20 @@ pub struct ParenCommand { } impl Command for ParenCommand { - fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option { + fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result, ExecError> { self.fork_exec(core, pipe) } - fn run(&mut self, core: &mut ShellCore, fork: bool) { + fn run(&mut self, core: &mut ShellCore, fork: bool) -> Result<(), ExecError> { if ! fork { panic!("SUSH INTERNAL ERROR (no fork for subshell)"); } match self.script { - Some(ref mut s) => s.exec(core), + Some(ref mut s) => s.exec(core)?, _ => panic!("SUSH INTERNAL ERROR (ParenCommand::exec)"), } + Ok(()) } fn get_text(&self) -> String { self.text.clone() } diff --git a/src/elements/command/simple.rs b/src/elements/command/simple.rs index 2d228d03..6e49f921 100644 --- a/src/elements/command/simple.rs +++ b/src/elements/command/simple.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{ShellCore, Feeder}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use super::{Command, Pipe, Redirect}; use crate::elements::command; @@ -28,7 +29,7 @@ pub struct SimpleCommand { } impl Command for SimpleCommand { - fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option { + fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result, ExecError> { self.args.clear(); let mut words = self.words.to_vec(); @@ -37,7 +38,7 @@ impl Command for SimpleCommand { } if self.args.is_empty() { - return None; + return Ok(None); } if self.force_fork @@ -45,15 +46,14 @@ impl Command for SimpleCommand { || ! core.builtins.contains_key(&self.args[0]) { self.fork_exec(core, pipe) }else{ - self.nofork_exec(core); - None + self.nofork_exec(core) } } - fn run(&mut self, core: &mut ShellCore, fork: bool) { + fn run(&mut self, core: &mut ShellCore, fork: bool) -> Result<(), ExecError> { if ! fork { core.run_builtin(&mut self.args); - return; + return Ok(()); } if core.run_builtin(&mut self.args) { diff --git a/src/elements/command/while.rs b/src/elements/command/while.rs index 833e95c8..3256f4e4 100644 --- a/src/elements/command/while.rs +++ b/src/elements/command/while.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{ShellCore, Feeder, Script}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use super::{Command, Redirect}; use crate::elements::command; @@ -16,7 +17,7 @@ pub struct WhileCommand { } impl Command for WhileCommand { - fn run(&mut self, core: &mut ShellCore, _: bool) { + fn run(&mut self, core: &mut ShellCore, _: bool) -> Result<(), ExecError> { loop { self.while_script.as_mut() .expect("SUSH INTERNAL ERROR (no script)") @@ -30,6 +31,7 @@ impl Command for WhileCommand { .expect("SUSH INTERNAL ERROR (no script)") .exec(core); } + Ok(()) } fn get_text(&self) -> String { self.text.clone() } diff --git a/src/elements/job.rs b/src/elements/job.rs index fab725f4..4a4dea3f 100644 --- a/src/elements/job.rs +++ b/src/elements/job.rs @@ -4,6 +4,7 @@ use super::pipeline::Pipeline; use crate::{Feeder, ShellCore}; use crate::core::jobtable::JobEntry; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use crate::utils::exit; use nix::unistd; @@ -17,7 +18,7 @@ pub struct Job { } impl Job { - pub fn exec(&mut self, core: &mut ShellCore, bg: bool) { + pub fn exec(&mut self, core: &mut ShellCore, bg: bool) -> Result<(), ExecError> { let pgid = match core.is_subshell { true => unistd::getpgrp(), false => Pid::from_raw(0), @@ -29,20 +30,25 @@ impl Job { } } - fn exec_fg(&mut self, core: &mut ShellCore, pgid: Pid) { + fn exec_fg(&mut self, core: &mut ShellCore, pgid: Pid) -> Result<(), ExecError> { let mut do_next = true; for (pipeline, end) in self.pipelines.iter_mut() .zip(self.pipeline_ends.iter()) { if do_next { core.jobtable_check_status(); - let pids = pipeline.exec(core, pgid); + let (pids, err) = pipeline.exec(core, pgid); core.wait_pipeline(pids); + + if err.is_some() { + return Err(err.unwrap()); + } } do_next = (core.db.get_param("?").unwrap() == "0") == (end == "&&"); } + Ok(()) } - fn exec_bg(&mut self, core: &mut ShellCore, pgid: Pid) { + fn exec_bg(&mut self, core: &mut ShellCore, pgid: Pid) -> Result<(), ExecError> { let backup = core.tty_fd.as_ref().map(|fd| fd.try_clone().unwrap()); core.tty_fd = None; @@ -50,7 +56,7 @@ impl Job { if self.pipelines[0].commands.len() == 1 { self.pipelines[0].commands[0].set_force_fork(); } - self.pipelines[0].exec(core, pgid) + self.pipelines[0].exec(core, pgid).0 }else{ vec![self.exec_fork_bg(core, pgid)] }; @@ -58,6 +64,7 @@ impl Job { core.job_table.push(JobEntry::new(pids, &self.text)); core.tty_fd = backup; + Ok(()) } fn exec_fork_bg(&mut self, core: &mut ShellCore, pgid: Pid) -> Option { diff --git a/src/elements/pipeline.rs b/src/elements/pipeline.rs index 0423d98e..f0f20760 100644 --- a/src/elements/pipeline.rs +++ b/src/elements/pipeline.rs @@ -2,6 +2,7 @@ //SPDX-License-Identifier: BSD-3-Clause use crate::{Feeder, ShellCore}; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; use super::command; use super::command::Command; @@ -17,10 +18,10 @@ pub struct Pipeline { } impl Pipeline { - pub fn exec(&mut self, core: &mut ShellCore, pgid: Pid) -> Vec> { + pub fn exec(&mut self, core: &mut ShellCore, pgid: Pid) -> (Vec>, Option) { if core.sigint.load(Relaxed) { //以下4行追加 core.db.set_param("?", "130").unwrap(); - return vec![]; + return (vec![], Some(ExecError::Interrupted)); } let mut prev = -1; @@ -28,18 +29,23 @@ impl Pipeline { let mut pgid = pgid; for (i, p) in self.pipes.iter_mut().enumerate() { p.set(prev, pgid); - pids.push(self.commands[i].exec(core, p)); + match self.commands[i].exec(core, p) { + Ok(pid) => pids.push(pid), + Err(e) => return (pids, Some(e)), + } + if i == 0 && pgid.as_raw() == 0 { // 最初のexecが終わったら、pgidにコマンドのPIDを記録 - pgid = pids[0].expect("SUSHI INTERNAL ERROR (unforked in pipeline)"); + pgid = pids[0].unwrap(); } prev = p.recv; } - pids.push( - self.commands[self.pipes.len()].exec(core, &mut Pipe::end(prev, pgid)) - ); + match self.commands[self.pipes.len()].exec(core, &mut Pipe::end(prev, pgid)) { + Ok(pid) => pids.push(pid), + Err(e) => return (pids, Some(e)), + } - pids + (pids, None) } fn eat_command(feeder: &mut Feeder, ans: &mut Pipeline, core: &mut ShellCore) diff --git a/src/elements/script.rs b/src/elements/script.rs index dcfe3689..1d316ca7 100644 --- a/src/elements/script.rs +++ b/src/elements/script.rs @@ -4,6 +4,7 @@ use super::job::Job; use crate::{Feeder, ShellCore}; use crate::error::parse; +use crate::error::exec::ExecError; use crate::error::parse::ParseError; enum Status{ @@ -20,10 +21,11 @@ pub struct Script { } impl Script { - pub fn exec(&mut self, core: &mut ShellCore) { + pub fn exec(&mut self, core: &mut ShellCore) -> Result<(), ExecError> { for (job, end) in self.jobs.iter_mut().zip(self.job_ends.iter()) { job.exec(core, end == "&"); } + Ok(()) } pub fn get_text(&self) -> String { self.text.clone() } diff --git a/src/error/exec.rs b/src/error/exec.rs index 78816ace..fdae5fa5 100644 --- a/src/error/exec.rs +++ b/src/error/exec.rs @@ -15,6 +15,7 @@ pub enum ExecError { InvalidBase(String), InvalidName(String), InvalidOption(String), + Interrupted, ValidOnlyInFunction(String), VariableReadOnly(String), VariableInvalid(String), @@ -36,6 +37,7 @@ impl From for String { ExecError::InvalidName(name) => format!("`{}': invalid name", name), ExecError::InvalidBase(b) => format!("sush: {0}: invalid arithmetic base (error token is \"{0}\")", b), ExecError::InvalidOption(opt) => format!("sush: {}: invalid option", opt), + ExecError::Interrupted => "interrupted".to_string(), ExecError::AssignmentToNonVariable(right) => format!("attempted assignment to non-variable (error token is \"{}\")", right), ExecError::ValidOnlyInFunction(com) => format!("{}: can only be used in a function", &com), ExecError::VariableReadOnly(name) => format!("{}: readonly variable", name),