Skip to content

Commit

Permalink
Pass the test
Browse files Browse the repository at this point in the history
  • Loading branch information
ryuichiueda committed Jan 18, 2025
1 parent b05ed5b commit 1228cf4
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 36 deletions.
15 changes: 8 additions & 7 deletions src/elements/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,16 +30,15 @@ impl Debug for dyn Command {
}

pub trait Command {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option<Pid> {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result<Option<Pid>, 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<Pid> {
fn fork_exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result<Option<Pid>, ExecError> {
match unsafe{unistd::fork()} {
Ok(ForkResult::Child) => {
core.initialize_as_subshell(Pid::from_raw(0), pipe.pgid);
Expand All @@ -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<Option<Pid>, 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<Redirect>;
fn set_force_fork(&mut self);
Expand Down
3 changes: 2 additions & 1 deletion src/elements/command/brace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)"),
Expand Down
10 changes: 6 additions & 4 deletions src/elements/command/if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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() }
Expand Down
8 changes: 5 additions & 3 deletions src/elements/command/paren.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,19 +16,20 @@ pub struct ParenCommand {
}

impl Command for ParenCommand {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option<Pid> {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result<Option<Pid>, 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() }
Expand Down
12 changes: 6 additions & 6 deletions src/elements/command/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,7 +29,7 @@ pub struct SimpleCommand {
}

impl Command for SimpleCommand {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Option<Pid> {
fn exec(&mut self, core: &mut ShellCore, pipe: &mut Pipe) -> Result<Option<Pid>, ExecError> {
self.args.clear();
let mut words = self.words.to_vec();

Expand All @@ -37,23 +38,22 @@ impl Command for SimpleCommand {
}

if self.args.is_empty() {
return None;
return Ok(None);
}

if self.force_fork
|| pipe.is_connected()
|| ! 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) {
Expand Down
4 changes: 3 additions & 1 deletion src/elements/command/while.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)")
Expand All @@ -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() }
Expand Down
17 changes: 12 additions & 5 deletions src/elements/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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),
Expand All @@ -29,35 +30,41 @@ 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;

let pids = if self.pipelines.len() == 1 {
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)]
};
eprintln!("{}", &pids[0].unwrap().as_raw());
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<Pid> {
Expand Down
22 changes: 14 additions & 8 deletions src/elements/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -17,29 +18,34 @@ pub struct Pipeline {
}

impl Pipeline {
pub fn exec(&mut self, core: &mut ShellCore, pgid: Pid) -> Vec<Option<Pid>> {
pub fn exec(&mut self, core: &mut ShellCore, pgid: Pid) -> (Vec<Option<Pid>>, Option<ExecError>) {
if core.sigint.load(Relaxed) { //以下4行追加
core.db.set_param("?", "130").unwrap();
return vec![];
return (vec![], Some(ExecError::Interrupted));
}

let mut prev = -1;
let mut pids = vec![];
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)
Expand Down
4 changes: 3 additions & 1 deletion src/elements/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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() }
Expand Down
2 changes: 2 additions & 0 deletions src/error/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub enum ExecError {
InvalidBase(String),
InvalidName(String),
InvalidOption(String),
Interrupted,
ValidOnlyInFunction(String),
VariableReadOnly(String),
VariableInvalid(String),
Expand All @@ -36,6 +37,7 @@ impl From<ExecError> 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),
Expand Down

0 comments on commit 1228cf4

Please sign in to comment.