Skip to content

Commit

Permalink
feat: implement jobs builtin command
Browse files Browse the repository at this point in the history
- added some resources
- added some more tasks
  • Loading branch information
feniljain committed Mar 26, 2023
1 parent d53f5d1 commit d2f4d91
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
2 changes: 2 additions & 0 deletions RESOURCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
- https://www.howtogeek.com/440848/how-to-run-and-control-background-processes-on-linux/
- https://wiki.bash-hackers.org/howto/redirection_tutorial
- https://stackoverflow.com/questions/8319484/regarding-background-processes-using-fork-and-child-processes-in-my-dummy-shel
- Job Control Signals: https://www.gnu.org/software/libc/manual/html_node/Job-Control-Signals.html
- Implementing a Job Control Shell: https://www.andrew.cmu.edu/course/15-310/applications/homework/homework4/lab4.pdf
6 changes: 5 additions & 1 deletion TASKS_AND_BUGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@
- [X] add support for redirect <& operator
- [X] add support for fd in redirect operations
- [ ] add support for $() in shell
- [ ] add support for & parsing for job control
- [ ] add support for background processes
- [X] add support for `jobs` command
- [ ] add support to bring commands in foreground again
- [ ] add support for proper process chains i.e. jobs
- [ ] add support for another execution mode (job control) in engine
- [ ] seperate types from engine, and into a new file

## Bonus Tasks:

Expand Down
8 changes: 8 additions & 0 deletions src/command/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ impl Command {
})
.collect()
}

pub fn as_string(&self) -> String {
self.tokens.iter().fold(String::new(), |mut acc, token| {
acc += " ";
acc += &token.lexeme;
return acc;
})
}
}

// Old Lexing + Parsing
Expand Down
57 changes: 54 additions & 3 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use nix::{
stat::Mode,
wait::{waitpid, WaitStatus},
},
unistd::{chdir, close, dup2, execve, fork, pipe, setpgid, ForkResult, Pid, getpid},
unistd::{chdir, close, dup2, execve, fork, getpid, pipe, setpgid, ForkResult, Pid},
};
use signal_hook::consts;

use std::{
collections::HashMap,
convert::Infallible,
ffi::{CStr, CString},
fmt::{Display, Formatter},
io,
os::unix::prelude::OsStrExt,
path::{Path, PathBuf},
Expand All @@ -35,7 +36,41 @@ use crate::{
frontend::{write_error_to_shell, write_to_stderr, write_to_stdout, Prompt},
};

const BUILTIN_COMMANDS: [&str; 2] = ["cd", "exec"];
const BUILTIN_COMMANDS: [&str; 3] = ["cd", "exec", "jobs"];

#[derive(Clone, Debug)]
pub enum ProcessStatus {
Running,
Suspended
}

impl Display for ProcessStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProcessStatus::Running => write!(f, "running"),
ProcessStatus::Suspended => write!(f, "suspended"),
}
}
}

#[derive(Clone, Debug)]
pub struct Process {
pid: Pid,
cmd: String,
status: ProcessStatus,
}

impl Process {
fn new(pid: Pid, cmd: String, status: ProcessStatus) -> Self {
Process { pid, cmd, status }
}
}

impl Display for Process {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {} {}", self.pid, self.status, self.cmd)
}
}

#[derive(Clone, Debug)]
pub struct Engine {
Expand All @@ -44,6 +79,7 @@ pub struct Engine {
execution_mode: ExecutionMode,
// Operations to be done on different `fd`s
fds_ops: HashMap<i32, FdOperation>,
pub job_processes: Vec<Process>,
}

#[derive(Copy, Clone, Debug)]
Expand All @@ -68,6 +104,7 @@ impl Engine {
env_paths: parse_paths(),
execution_mode: ExecutionMode::Normal,
fds_ops: HashMap::new(),
job_processes: Vec::new(),
}
}

Expand Down Expand Up @@ -341,6 +378,17 @@ impl Engine {
self.parse_and_execute(&command.tokens)?;
Ok(())
}
"jobs" => {
self.job_processes
.iter()
.enumerate()
.for_each(|(idx, process)| {
// FIXME: use panic safe write_to_stdout here
println!("{} {}", idx, process);
});

Ok(())
}
_ => Err(ShellError::CommandNotFound(cmd_str.to_string()).into()),
}
}
Expand All @@ -356,7 +404,10 @@ impl Engine {
child: child_pid, ..
}) => {
if matches!(self.execution_mode, ExecutionMode::Background) {
setpgid(child_pid, child_pid)?;
setpgid(child_pid, child_pid)?;
let command = command.expect("invalid state: should have had command in background process execution flow");
self.job_processes
.push(Process::new(child_pid, command.as_string(), ProcessStatus::Running));
}

for (fd, value) in &self.fds_ops {
Expand Down

0 comments on commit d2f4d91

Please sign in to comment.