From ecfef2274fa8c9c1c1f37843658d99124b773f58 Mon Sep 17 00:00:00 2001 From: pagedmov Date: Sat, 15 Mar 2025 17:54:08 -0400 Subject: [PATCH] Adapted old code to fit new codebase --- src/builtin/echo.rs | 13 ++++++-- src/jobs.rs | 10 ++++++ src/parse/execute.rs | 75 +++++++++++++++++++++++++++++--------------- src/parse/lex.rs | 4 ++- src/state.rs | 8 ++++- 5 files changed, 81 insertions(+), 29 deletions(-) diff --git a/src/builtin/echo.rs b/src/builtin/echo.rs index 6baa2e0..2511f3b 100644 --- a/src/builtin/echo.rs +++ b/src/builtin/echo.rs @@ -1,11 +1,20 @@ -use crate::{libsh::error::ShResult, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}}; +use crate::{jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}}; -pub fn echo(node: Node, io_stack: &mut IoStack) -> ShResult<()> { +pub fn echo(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> { let NdRule::Command { assignments: _, argv } = node.class else { unreachable!() }; assert!(!argv.is_empty()); + let child_pgid = if let Some(pgid) = job.pgid() { + pgid + } else { + job.set_pgid(Pid::this()); + Pid::this() + }; + let child = ChildProc::new(Pid::this(), Some("echo"), Some(child_pgid))?; + job.push_child(child); + for redir in node.redirs { io_stack.push_to_frame(redir); } diff --git a/src/jobs.rs b/src/jobs.rs index f792664..8ded499 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -76,6 +76,7 @@ impl<'a> ChildProc { if let Some(pgid) = pgid { child.set_pgid(pgid).ok(); } + flog!(TRACE, "new child: {:?}", child); Ok(child) } pub fn pid(&self) -> Pid { @@ -149,6 +150,12 @@ impl JobBldr { children: self.children } } + pub fn set_pgid(&mut self, pgid: Pid) { + self.pgid = Some(pgid); + } + pub fn pgid(&self) -> Option { + self.pgid + } pub fn with_children(self, children: Vec) -> Self { Self { table_id: self.table_id, @@ -156,6 +163,9 @@ impl JobBldr { children } } + pub fn push_child(&mut self, child: ChildProc) { + self.children.push(child); + } pub fn build(self) -> Job { Job { table_id: self.table_id, diff --git a/src/parse/execute.rs b/src/parse/execute.rs index 50a97bb..22b1f31 100644 --- a/src/parse/execute.rs +++ b/src/parse/execute.rs @@ -1,9 +1,9 @@ use std::collections::VecDeque; -use crate::{builtin::echo::echo, libsh::error::ShResult, prelude::*, procio::{IoFrame, IoPipe, IoStack}, state::{self, write_vars}}; +use crate::{builtin::echo::echo, jobs::{dispatch_job, ChildProc, Job, JobBldr}, libsh::error::ShResult, prelude::*, procio::{IoFrame, IoPipe, IoStack}, state::{self, write_vars}}; -use super::{lex::{Tk, TkFlags}, AssignKind, ConjunctNode, ConjunctOp, NdRule, Node, Redir, RedirType}; +use super::{lex::{Tk, TkFlags}, AssignKind, ConjunctNode, ConjunctOp, NdFlags, NdRule, Node, Redir, RedirType}; pub enum AssignBehavior { Export, @@ -39,13 +39,14 @@ impl ExecArgs { pub struct Dispatcher<'t> { nodes: VecDeque>, - pub io_stack: IoStack + pub io_stack: IoStack, + pub curr_job: Option } impl<'t> Dispatcher<'t> { pub fn new(nodes: Vec>) -> Self { let nodes = VecDeque::from(nodes); - Self { nodes, io_stack: IoStack::new() } + Self { nodes, io_stack: IoStack::new(), curr_job: None } } pub fn begin_dispatch(&mut self) -> ShResult<()> { flog!(TRACE, "beginning dispatch"); @@ -96,6 +97,7 @@ impl<'t> Dispatcher<'t> { let NdRule::Pipeline { cmds, pipe_err } = pipeline.class else { unreachable!() }; + self.curr_job = Some(JobBldr::new()); // Zip the commands and their respective pipes into an iterator let pipes_and_cmds = get_pipe_stack(cmds.len()) .into_iter() @@ -110,8 +112,14 @@ impl<'t> Dispatcher<'t> { } self.dispatch_node(cmd)?; } + let job = self.finalize_job(); + let is_bg = pipeline.flags.contains(NdFlags::BACKGROUND); + dispatch_job(job, is_bg)?; Ok(()) } + pub fn finalize_job(&mut self) -> Job { + self.curr_job.take().unwrap().build() + } pub fn exec_builtin(&mut self, mut cmd: Node<'t>) -> ShResult<()> { let NdRule::Command { ref mut assignments, argv } = &mut cmd.class else { unreachable!() @@ -119,8 +127,9 @@ impl<'t> Dispatcher<'t> { let env_vars_to_unset = self.set_assignments(mem::take(assignments), AssignBehavior::Export); let cmd_raw = cmd.get_command().unwrap(); flog!(TRACE, "doing builtin"); + let curr_job_mut = self.curr_job.as_mut().unwrap(); let result = match cmd_raw.span.as_str() { - "echo" => echo(cmd, &mut self.io_stack), + "echo" => echo(cmd, &mut self.io_stack, curr_job_mut), _ => unimplemented!("Have not yet added support for builtin '{}'", cmd_raw.span.as_str()) }; @@ -154,7 +163,8 @@ impl<'t> Dispatcher<'t> { let io_frame = self.io_stack.pop_frame(); run_fork( io_frame, - exec_args, + Some(exec_args), + self.curr_job.as_mut().unwrap(), def_child_action, def_parent_action )?; @@ -220,46 +230,61 @@ pub fn prepare_argv(argv: Vec) -> Vec { pub fn run_fork<'t,C,P>( io_frame: IoFrame, - exec_args: ExecArgs, + exec_args: Option, + job: &mut JobBldr, child_action: C, parent_action: P, ) -> ShResult<()> where - C: Fn(IoFrame,ExecArgs) -> Errno, - P: Fn(IoFrame,Pid) -> ShResult<()> + C: Fn(IoFrame,Option), + P: Fn(IoFrame,&mut JobBldr,Option<&str>,Pid) -> ShResult<()> { match unsafe { fork()? } { ForkResult::Child => { - let cmd = &exec_args.cmd.to_str().unwrap().to_string(); - let errno = child_action(io_frame,exec_args); - match errno { - Errno::ENOENT => eprintln!("Command not found: {}", cmd), - _ => eprintln!("{errno}") - } - exit(errno as i32); + child_action(io_frame,exec_args); + exit(0); // Just in case } ForkResult::Parent { child } => { - parent_action(io_frame,child) + let cmd = if let Some(args) = exec_args { + Some(args.cmd.to_str().unwrap().to_string()) + } else { + None + }; + parent_action(io_frame,job,cmd.as_deref(),child) } } } /// The default behavior for the child process after forking -pub fn def_child_action<'t>(mut io_frame: IoFrame, exec_args: ExecArgs) -> Errno { +pub fn def_child_action<'t>(mut io_frame: IoFrame, exec_args: Option) { if let Err(e) = io_frame.redirect() { eprintln!("{e}"); } + let exec_args = exec_args.unwrap(); + let cmd = &exec_args.cmd.to_str().unwrap().to_string(); let Err(e) = execvpe(&exec_args.cmd, &exec_args.argv, &exec_args.envp); - e + match e { + Errno::ENOENT => eprintln!("Command not found: {}", cmd), + _ => eprintln!("{e}") + } + exit(e as i32) } /// The default behavior for the parent process after forking -pub fn def_parent_action<'t>(io_frame: IoFrame, child: Pid) -> ShResult<()> { - let status = waitpid(child, Some(WtFlag::WSTOPPED))?; - match status { - WtStat::Exited(_, status) => state::set_status(status), - _ => unimplemented!() - } +pub fn def_parent_action<'t>( + io_frame: IoFrame, + job: &mut JobBldr, + cmd: Option<&str>, + child_pid: Pid +) -> ShResult<()> { + let child_pgid = if let Some(pgid) = job.pgid() { + pgid + } else { + job.set_pgid(child_pid); + child_pid + }; + let child = ChildProc::new(child_pid, cmd, Some(child_pgid))?; + job.push_child(child); Ok(()) } diff --git a/src/parse/lex.rs b/src/parse/lex.rs index c834ff1..66df6cd 100644 --- a/src/parse/lex.rs +++ b/src/parse/lex.rs @@ -299,7 +299,9 @@ impl<'t> LexStream<'t> { } } - assert!(tk != Tk::default()); + if tk == Tk::default() { + return None + } self.cursor = pos; Some(tk) diff --git a/src/state.rs b/src/state.rs index 9a7eeca..22337dc 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard}}; -use crate::{jobs::{wait_fg, attach_tty, take_term, Job, JobCmdFlags, JobID}, libsh::error::ShResult, prelude::*, procio::borrow_fd}; +use crate::{jobs::{attach_tty, take_term, wait_fg, Job, JobCmdFlags, JobID}, libsh::error::ShResult, parse::lex::get_char, prelude::*, procio::borrow_fd}; pub static JOB_TABLE: LazyLock> = LazyLock::new(|| RwLock::new(JobTab::new())); @@ -237,6 +237,12 @@ impl VarTab { &mut self.params } pub fn get_var(&self, var: &str) -> String { + if var.chars().count() == 1 { + let param = self.get_param(get_char(var, 0).unwrap()); + if !param.is_empty() { + return param + } + } if let Some(var) = self.vars.get(var).map(|s| s.to_string()) { var } else {