add usr apps: pipe_shell and getchars for PIPE demo

ch7-signal-pipe
Yu Chen 3 years ago
parent ad28f5f627
commit 44710585ce

@ -0,0 +1,26 @@
#![no_std]
#![no_main]
#[macro_use]
extern crate user_lib;
use user_lib::console::getchar;
const N: usize = 10;
#[no_mangle]
pub fn main() -> i32 {
println!("I will receive {} letters.", N);
let mut line = [0u8; N];
for idx in 0..N {
let c = getchar();
line[idx] = c;
}
println!("{} letters entered", N);
for idx in 0..N {
print!("{}", line[idx] as char);
}
println!("");
println!("You got it!");
0
}

@ -0,0 +1,201 @@
// https://www.joshmcguigan.com/blog/build-your-own-shell-rust/
// https://github.com/JoshMcguigan/bubble-shell
// https://github.com/psinghal20/rush
#![no_std]
#![no_main]
extern crate alloc;
#[macro_use]
extern crate user_lib;
const LF: u8 = 0x0au8;
const CR: u8 = 0x0du8;
const DL: u8 = 0x7fu8;
const BS: u8 = 0x08u8;
use alloc::string::String;
use alloc::vec::Vec;
use user_lib::console::{getchar};
use user_lib::{close, dup, exec, fork, open, pipe, waitpid, OpenFlags};
const STDIN: usize = 0;
const STDOUT: usize = 1;
#[derive(Debug, Clone)]
enum IOType {
File(String),
// [read end, write end]
Pipe([usize; 2]),
Inherit,
}
impl IOType {
pub fn new_pipe() -> Self {
let mut pipe_fd: [usize; 2] = [0; 2];
pipe(&mut pipe_fd);
Self::Pipe(pipe_fd)
}
}
#[derive(Debug, Clone)]
struct Process {
pub pid: isize,
pub output: IOType,
}
#[no_mangle]
pub fn main() -> i32 {
println!("Rust user shell (with pipe)");
let mut line: String = String::new();
print!(">) ");
//flush();
loop {
let c = getchar();
match c {
LF | CR => {
println!("");
if !line.is_empty() {
let mut commands = line.trim().split(" | ").peekable();
let mut previous_process: Option<Process> = None;
while let Some(command) = commands.next() {
let args: Vec<_> = command.trim().split(' ').collect();
let mut args_copy: Vec<String> = args
.iter()
.map(|&arg| {
let mut string = String::new();
string.push_str(arg);
string.push('\0');
string
})
.collect();
// redirect input
let input = if previous_process.is_some() {
previous_process.clone().unwrap().output
} else if let Some((idx, _)) = args_copy
.iter()
.enumerate()
.find(|(_, arg)| arg.as_str() == "<\0")
{
let tmp = IOType::File(args_copy[idx + 1].clone());
args_copy.drain(idx..=idx + 1);
tmp
} else {
IOType::Inherit
};
// redirect output
let output = if commands.peek().is_some() {
IOType::new_pipe()
} else if let Some((idx, _)) = args_copy
.iter()
.enumerate()
.find(|(_, arg)| arg.as_str() == ">\0")
{
let tmp = IOType::File(args_copy[idx + 1].clone());
args_copy.drain(idx..=idx + 1);
tmp
} else {
IOType::Inherit
};
let mut args_addr: Vec<*const u8> =
args_copy.iter().map(|arg| arg.as_ptr()).collect();
args_addr.push(0 as *const u8);
let pid = fork();
if pid == 0 {
// input redirection
match input.clone() {
IOType::File(filename) => {
let input_fd = open(filename.as_str(), OpenFlags::RDONLY);
if input_fd == -1 {
println!("Error when opening file {}", filename);
return -4;
}
let input_fd = input_fd as usize;
close(STDIN);
assert_eq!(dup(input_fd) as usize, STDIN);
close(input_fd);
}
IOType::Pipe(pipes) => {
close(pipes[1]); // close write end
close(STDIN);
assert_eq!(dup(pipes[0]) as usize, STDIN);
close(pipes[0]);
}
_ => {}
}
// output redirection
match output.clone() {
IOType::File(filename) => {
let output_fd = open(
filename.as_str(),
OpenFlags::CREATE | OpenFlags::WRONLY,
);
if output_fd == -1 {
println!("Error when opening file {}", filename);
return -4;
}
let output_fd = output_fd as usize;
close(STDOUT);
assert_eq!(dup(output_fd) as usize, STDOUT);
close(output_fd);
}
IOType::Pipe(pipes) => {
close(pipes[0]); // close read end
close(STDOUT);
assert_eq!(dup(pipes[1]) as usize, STDOUT);
close(pipes[1]);
}
_ => {}
}
// run child process
if exec(args_copy[0].as_str(), args_addr.as_slice()) == -1 {
println!("Error when executing!");
return -4;
}
unreachable!("Should not happen!");
}
// old pipe was done, close it.
if let Some(p) = previous_process {
match p.output {
IOType::Pipe(pipes) => {
close(pipes[0]);
close(pipes[1]);
}
_ => {}
}
}
previous_process = Some(Process { pid, output });
}
line.clear();
if let Some(process) = previous_process {
let mut exit_code: i32 = 0;
let pid = process.pid;
let exit_pid = waitpid(pid as usize, &mut exit_code);
assert_eq!(pid, exit_pid);
println!("Shell: Process {} exited with code {}", pid, exit_code);
}
}
print!(">) ");
//flush();
}
BS | DL => {
if !line.is_empty() {
print!("{}", BS as char);
print!(" ");
print!("{}", BS as char);
//flush();
line.pop();
}
}
_ => {
print!("{}", c as char);
//flush();
line.push(c as char);
}
}
}
}
Loading…
Cancel
Save