Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shell redirections #262

Merged
merged 11 commits into from
Nov 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Changelog

## Unreleased
- Add calc command #263
- Add shell redirections (#262)
- Add calc command (#263)
- Add website (#261)
- Fix VGA issues with real hardware (#258)
- Add rust binaries support (#255)
Expand Down
27 changes: 23 additions & 4 deletions doc/shell.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,22 @@ double them.

## Pipes (TODO)

The pipe symbol `|` from UNIX is replaced by `-->`, shortened to `>`, and `>`
is replaced by `--> write` or `> w` in short. An additional standard stream
stdnil(3) is added to simplify writing to `/dev/null`.
The pipe symbol `|` from UNIX is replaced by a thin arrow `->`, shortened to
`>`, and the redirection symbol `>` from UNIX is replaced by a fat arrow `=>`
(see below).

Piping the standard output of a program to the `write` command to emulate a
redirection for example would be `-> write` or `> w` in short.

An additional standard stream stdnull(3) is added to simplify writing to `/dev/null`.

Examples:

Read file A and redirect stdout(1) to stdin(0) of write file B:

> r a.txt > w b.txt
> r a.txt 1>0 w b.txt # with explicit streams
> r a.txt --> w b.txt # with arrow
> r a.txt -> w b.txt # with thin arrow

Read file A and redirect stderr(2) to stdin(0) of write file B:

Expand All @@ -102,3 +109,15 @@ Redirect stdout(1) to stdin(0) and stderr(2) to stdnil(3):

> r a.txt > 2>3 w b.txt
> r a.txt 1>0 2>3 w b.txt

## Redirections

Redirecting standard IO streams can be done with a fat arrow, for example the
output of the print command can be written to a file like so:

> print hello => /tmp/hello

Which is more efficient than doing:

> print hello -> write /tmp/hello

2 changes: 1 addition & 1 deletion dsk/src/bin/hello.s
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ msg: db "Hello, World!", 10
global _start
section .text
_start:
mov rax, 5 ; syscall number for WRITE
mov rax, 4 ; syscall number for WRITE
mov rdi, 1 ; standard output
mov rsi, msg ; addr of string
mov rdx, 14 ; size of string
Expand Down
2 changes: 1 addition & 1 deletion dsk/src/bin/sleep.s
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[bits 64]
_start:
mov rax, 0 ; syscall number for SLEEP
mov rax, 9 ; syscall number for SLEEP
mov rdi, __float64__(1.0) ; time to sleep in seconds
mov rsi, 0
mov rdx, 0
Expand Down
25 changes: 23 additions & 2 deletions src/api/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ pub fn read(path: &str) -> Result<Vec<u8>, ()> {
if let Some(bytes) = syscall::read(handle, &mut buf) {
buf.resize(bytes, 0);
syscall::close(handle);
return Ok(buf)
return Ok(buf);
}
}
}
Expand All @@ -127,12 +127,33 @@ pub fn write(path: &str, buf: &[u8]) -> Result<usize, ()> {
if let Some(handle) = create_file(&path) {
if let Some(bytes) = syscall::write(handle, buf) {
syscall::close(handle);
return Ok(bytes)
return Ok(bytes);
}
}
Err(())
}

pub fn reopen(path: &str, handle: usize) -> Result<usize, ()> {
let path = match canonicalize(path) {
Ok(path) => path,
Err(_) => return Err(()),
};
let res = if let Some(stat) = syscall::stat(&path) {
if stat.is_device() {
open_device(&path)
} else {
open_file(&path)
}
} else {
create_file(&path)
};
if let Some(old_handle) = res {
syscall::dup(old_handle, handle);
return Ok(old_handle);
}
Err(())
}

#[test_case]
fn test_file() {
use crate::sys::fs::{mount_mem, format_mem, dismount};
Expand Down
19 changes: 17 additions & 2 deletions src/api/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use alloc::string::{String, ToString};

pub struct Stdin;
pub struct Stdout;
pub struct Stderr;

impl Stdin {
fn new() -> Self {
Expand Down Expand Up @@ -42,10 +43,24 @@ impl Stdout {
}
}

pub fn stdout() -> Stdout {
Stdout::new()
impl Stderr {
fn new() -> Self {
Self {}
}

pub fn write(&self, s: &str) {
syscall::write(2, s.as_bytes());
}
}

pub fn stdin() -> Stdin {
Stdin::new()
}

pub fn stdout() -> Stdout {
Stdout::new()
}

pub fn stderr() -> Stderr {
Stderr::new()
}
19 changes: 19 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ macro_rules! println {
});
}

#[macro_export]
macro_rules! eprint {
($($arg:tt)*) => ({
use alloc::format;
let s = format!("{}", format_args!($($arg)*));
$crate::api::io::stderr().write(&s);
});
}

#[macro_export]
macro_rules! eprintln {
() => ({
eprint!("\n");
});
($($arg:tt)*) => ({
eprint!("{}\n", format_args!($($arg)*));
});
}

pub mod console;
pub mod font;
pub mod fs;
Expand Down
9 changes: 9 additions & 0 deletions src/api/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,15 @@ pub fn open(path: &str, flags: usize) -> Option<usize> {
}
}

pub fn dup(old_handle: usize, new_handle: usize) -> Option<usize> {
let res = unsafe { syscall!(DUP, old_handle, new_handle) } as isize;
if res.is_negative() {
None
} else {
Some(res as usize)
}
}

pub fn read(handle: usize, buf: &mut [u8]) -> Option<usize> {
let ptr = buf.as_ptr() as usize;
let len = buf.len() as usize;
Expand Down
5 changes: 5 additions & 0 deletions src/sys/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ pub fn dispatcher(n: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
service::close(handle);
0
}
number::DUP => {
let old_handle = arg1;
let new_handle = arg2;
service::dup(old_handle, new_handle) as usize
}
number::SPAWN => {
let ptr = sys::process::ptr_from_addr(arg1 as u64);
let len = arg2;
Expand Down
21 changes: 12 additions & 9 deletions src/sys/syscall/number.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
pub const SLEEP: usize = 0;
pub const UPTIME: usize = 1;
pub const REALTIME: usize = 2;
pub const OPEN: usize = 3;
pub const READ: usize = 4;
pub const WRITE: usize = 5;
pub const CLOSE: usize = 6;
pub const STAT: usize = 7;
pub const SPAWN: usize = 8;
pub const NULL: usize = 0x0;
pub const EXIT: usize = 0x1;
pub const SPAWN: usize = 0x2;
pub const READ: usize = 0x3;
pub const WRITE: usize = 0x4;
pub const OPEN: usize = 0x5;
pub const CLOSE: usize = 0x6;
pub const STAT: usize = 0x7;
pub const DUP: usize = 0x8;
pub const SLEEP: usize = 0x9;
pub const UPTIME: usize = 0xA;
pub const REALTIME: usize = 0xB;
8 changes: 8 additions & 0 deletions src/sys/syscall/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ pub fn open(path: &str, flags: usize) -> isize {
-1
}

pub fn dup(old_handle: usize, new_handle: usize) -> isize {
if let Some(file) = sys::process::file_handle(old_handle) {
sys::process::update_file_handle(new_handle, file);
return new_handle as isize;
}
-1
}

pub fn read(handle: usize, buf: &mut [u8]) -> isize {
if let Some(mut file) = sys::process::file_handle(handle) {
if let Ok(bytes) = file.read(buf) {
Expand Down
8 changes: 4 additions & 4 deletions src/usr/beep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if let Ok(value) = args[i + 1].parse() {
freq = value;
} else {
println!("Could not parse freq");
eprintln!("Could not parse freq");
return usr::shell::ExitCode::CommandError;
}
i += 1;
} else {
println!("Missing freq");
eprintln!("Missing freq");
return usr::shell::ExitCode::CommandError;
}
},
Expand All @@ -56,12 +56,12 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if let Ok(value) = args[i + 1].parse() {
len = value;
} else {
println!("Could not parse len");
eprintln!("Could not parse len");
return usr::shell::ExitCode::CommandError;
}
i += 1;
} else {
println!("Missing len");
eprintln!("Missing len");
return usr::shell::ExitCode::CommandError;
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/usr/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
usr::shell::ExitCode::CommandSuccessful
}
Err(msg) => {
println!("{}", msg);
eprintln!("{}", msg);
usr::shell::ExitCode::CommandError
}
}
}
}

#[test_case]
pub fn test_calc() {
fn test_calc() {
macro_rules! eval {
($e:expr) => {
format!("{}", parse_eval($e).unwrap())
Expand Down
2 changes: 1 addition & 1 deletion src/usr/chess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl Chess {
("m", "ove <move>", "Play <move> on the board\n"),
("u", "ndo", "Undo the last move\n"),
("s", "how <attr>", "Show <attr>\n"),
("p", "erf [<dept>]", "Count the nodes at each depth\n"),
("p", "erf [<depth>]", "Count the nodes at each depth\n"),
];
for (alias, command, usage) in &cmds {
let csi_col1 = Style::color("LightGreen");
Expand Down
8 changes: 4 additions & 4 deletions src/usr/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ use crate::api::fs;

pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if args.len() != 3 {
println!("Usage: copy <source> <dest>");
eprintln!("Usage: copy <source> <dest>");
return usr::shell::ExitCode::CommandError;
}

let source = args[1];
let dest = args[2];

if dest.starts_with("/dev") || dest.starts_with("/sys") {
println!("Permission denied to write to '{}'", dest);
eprintln!("Permission denied to write to '{}'", dest);
return usr::shell::ExitCode::CommandError;
}

if let Ok(contents) = fs::read(source) {
if fs::write(dest, &contents).is_ok() {
usr::shell::ExitCode::CommandSuccessful
} else {
println!("Could not write to '{}'", dest);
eprintln!("Could not write to '{}'", dest);
usr::shell::ExitCode::CommandError
}
} else {
println!("File not found '{}'", source);
eprintln!("File not found '{}'", source);
usr::shell::ExitCode::CommandError
}
}
2 changes: 1 addition & 1 deletion src/usr/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
usr::shell::ExitCode::CommandSuccessful
}
Err(e) => {
println!("Error: {}", e);
eprintln!("Error: {}", e);
usr::shell::ExitCode::CommandError
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/usr/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
let mut pathname = args[1];

if pathname.starts_with("/dev") || pathname.starts_with("/sys") {
println!("Permission denied to delete '{}'", pathname);
eprintln!("Permission denied to delete '{}'", pathname);
return usr::shell::ExitCode::CommandError;
}

Expand All @@ -24,22 +24,22 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode {
if sys::fs::Dir::delete(pathname).is_ok() {
usr::shell::ExitCode::CommandSuccessful
} else {
println!("Could not delete directory '{}'", pathname);
eprintln!("Could not delete directory '{}'", pathname);
usr::shell::ExitCode::CommandError
}
} else {
println!("Directory '{}' not empty", pathname);
eprintln!("Directory '{}' not empty", pathname);
usr::shell::ExitCode::CommandError
}
} else if fs::exists(pathname) {
if sys::fs::File::delete(pathname).is_ok() {
usr::shell::ExitCode::CommandSuccessful
} else {
println!("Could not delete file '{}'", pathname);
eprintln!("Could not delete file '{}'", pathname);
usr::shell::ExitCode::CommandError
}
} else {
println!("File not found '{}'", pathname);
eprintln!("File not found '{}'", pathname);
usr::shell::ExitCode::CommandError
}
}
4 changes: 2 additions & 2 deletions src/usr/dhcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode {
let started = syscall::realtime();
loop {
if syscall::realtime() - started > timeout {
println!("Timeout reached");
eprintln!("Timeout reached");
return usr::shell::ExitCode::CommandError;
}
if sys::console::end_of_text() {
println!();
eprintln!();
return usr::shell::ExitCode::CommandError;
}
let timestamp = Instant::from_millis((syscall::realtime() * 1000.0) as i64);
Expand Down
Loading