From 5003532e937381129d5e23a51d1b116d97ea210c Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 31 Oct 2021 10:03:53 +0100 Subject: [PATCH 01/10] Reorder syscalls --- dsk/src/bin/hello.s | 2 +- dsk/src/bin/sleep.s | 2 +- src/sys/syscall/number.rs | 21 ++++++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/dsk/src/bin/hello.s b/dsk/src/bin/hello.s index bbcc4b4f1..cc8c7d1b0 100644 --- a/dsk/src/bin/hello.s +++ b/dsk/src/bin/hello.s @@ -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 diff --git a/dsk/src/bin/sleep.s b/dsk/src/bin/sleep.s index 81b2b4025..b91a880d7 100644 --- a/dsk/src/bin/sleep.s +++ b/dsk/src/bin/sleep.s @@ -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 diff --git a/src/sys/syscall/number.rs b/src/sys/syscall/number.rs index c8d1b3498..1d58d8554 100644 --- a/src/sys/syscall/number.rs +++ b/src/sys/syscall/number.rs @@ -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; From 066e65087368bf439d7de8321e428f0ae1611126 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 31 Oct 2021 10:04:30 +0100 Subject: [PATCH 02/10] Add DUP syscall --- src/api/syscall.rs | 9 +++++++++ src/sys/syscall/mod.rs | 5 +++++ src/sys/syscall/service.rs | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/src/api/syscall.rs b/src/api/syscall.rs index 1d503e946..60974b4fe 100644 --- a/src/api/syscall.rs +++ b/src/api/syscall.rs @@ -40,6 +40,15 @@ pub fn open(path: &str, flags: usize) -> Option { } } +pub fn dup(old_handle: usize, new_handle: usize) -> Option { + 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 { let ptr = buf.as_ptr() as usize; let len = buf.len() as usize; diff --git a/src/sys/syscall/mod.rs b/src/sys/syscall/mod.rs index e05d3018a..ae1dc8dd5 100644 --- a/src/sys/syscall/mod.rs +++ b/src/sys/syscall/mod.rs @@ -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; diff --git a/src/sys/syscall/service.rs b/src/sys/syscall/service.rs index 9e0a8bedc..dc850b478 100644 --- a/src/sys/syscall/service.rs +++ b/src/sys/syscall/service.rs @@ -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) { From 28f340b28859b8ddafa825616f11e9d387e65c57 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 31 Oct 2021 10:04:44 +0100 Subject: [PATCH 03/10] Add api::fs::reopen --- src/api/fs.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/api/fs.rs b/src/api/fs.rs index 9f2a3284c..2974026bb 100644 --- a/src/api/fs.rs +++ b/src/api/fs.rs @@ -112,7 +112,7 @@ pub fn read(path: &str) -> Result, ()> { if let Some(bytes) = syscall::read(handle, &mut buf) { buf.resize(bytes, 0); syscall::close(handle); - return Ok(buf) + return Ok(buf); } } } @@ -127,12 +127,33 @@ pub fn write(path: &str, buf: &[u8]) -> Result { 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 { + 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}; From e9652559f5098bafb956647e6c44475a96aeb9b6 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 31 Oct 2021 10:05:14 +0100 Subject: [PATCH 04/10] Add shell redirections --- src/usr/shell.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 1a723a84f..a1c1a3838 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -124,9 +124,43 @@ fn change_dir(args: &[&str]) -> ExitCode { } pub fn exec(cmd: &str) -> ExitCode { - let args = split_args(cmd); + let mut args = split_args(cmd); - match args[0] { + // Redirections + let mut n = args.len(); + let mut i = 0; + loop { + if i == n { + break; + } + let mut chars = args[i].chars(); + let mut handle = match chars.next_back() { + Some('<') => 0, + Some('>') => 1, + _ => { + i += 1; + continue; + } + }; + let s = chars.as_str(); + if let Ok(h) = s.parse() { + handle = h; + } + if i == n - 1 { + println!("Could not parse path for redirection"); + return ExitCode::CommandError; + } + let path = args[i + 1]; + if api::fs::reopen(path, handle).is_err() { + println!("Could not open path for redirection"); + return ExitCode::CommandError; + } + args.remove(i); // Remove redirection from args + args.remove(i); // Remove path from args + n -= 2; + } + + let res = match args[0] { "" => ExitCode::CommandError, "a" | "alias" => ExitCode::CommandUnknown, "b" => ExitCode::CommandUnknown, @@ -189,7 +223,14 @@ pub fn exec(cmd: &str) -> ExitCode { ExitCode::CommandUnknown } } + }; + + // TODO: Remove this when redirections are done in spawned process + for i in 0..3 { + api::fs::reopen("/dev/console", i).ok(); } + + return res; } pub fn run() -> usr::shell::ExitCode { From 8e70eff7fffc951e2215ad0483e2f0131651eef2 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Sun, 31 Oct 2021 16:11:13 +0100 Subject: [PATCH 05/10] Use regex to parse arrow --- doc/shell.md | 27 ++++++++++++++++++--- src/usr/chess.rs | 2 +- src/usr/shell.rs | 63 +++++++++++++++++++++++++++++++----------------- 3 files changed, 65 insertions(+), 27 deletions(-) diff --git a/doc/shell.md b/doc/shell.md index f97a8058d..71827771d 100644 --- a/doc/shell.md +++ b/doc/shell.md @@ -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: @@ -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 + diff --git a/src/usr/chess.rs b/src/usr/chess.rs index 64196651c..b9a314e25 100644 --- a/src/usr/chess.rs +++ b/src/usr/chess.rs @@ -119,7 +119,7 @@ impl Chess { ("m", "ove ", "Play on the board\n"), ("u", "ndo", "Undo the last move\n"), ("s", "how ", "Show \n"), - ("p", "erf []", "Count the nodes at each depth\n"), + ("p", "erf []", "Count the nodes at each depth\n"), ]; for (alias, command, usage) in &cmds { let csi_col1 = Style::color("LightGreen"); diff --git a/src/usr/shell.rs b/src/usr/shell.rs index a1c1a3838..cd59523b4 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -1,5 +1,6 @@ use crate::{api, sys, usr}; use crate::api::fs; +use crate::api::regex::Regex; use crate::api::prompt::Prompt; use crate::api::console::Style; use alloc::format; @@ -126,38 +127,56 @@ fn change_dir(args: &[&str]) -> ExitCode { pub fn exec(cmd: &str) -> ExitCode { let mut args = split_args(cmd); - // Redirections + // Redirections like `print hello => /tmp/hello` + // Pipes like `print hello -> write /tmp/hello` or `p hello > w /tmp/hello` let mut n = args.len(); let mut i = 0; loop { if i == n { break; } - let mut chars = args[i].chars(); - let mut handle = match chars.next_back() { - Some('<') => 0, - Some('>') => 1, - _ => { - i += 1; - continue; - } - }; - let s = chars.as_str(); - if let Ok(h) = s.parse() { - handle = h; + + let mut is_fat_arrow = false; + let mut is_thin_arrow = false; + let mut left_handle; + + if Regex::new("<=+").is_match(args[i]) { // Redirect input stream + is_fat_arrow = true; + left_handle = 0; + } else if Regex::new("\\d*=+>").is_match(args[i]) { // Redirect output stream(s) + is_fat_arrow = true; + left_handle = 1; + } else if Regex::new("\\d*-*>\\d*").is_match(args[i]) { // Pipe output stream(s) + is_thin_arrow = true; + left_handle = 1; + // TODO: right_handle? + } else { + i += 1; + continue; } - if i == n - 1 { - println!("Could not parse path for redirection"); - return ExitCode::CommandError; + + let s = args[i].chars().take_while(|c| c.is_numeric()).collect::(); + if let Ok(h) = s.parse() { + left_handle = h; } - let path = args[i + 1]; - if api::fs::reopen(path, handle).is_err() { - println!("Could not open path for redirection"); + + if is_fat_arrow { // Redirections + if i == n - 1 { + println!("Could not parse path for redirection"); + return ExitCode::CommandError; + } + let path = args[i + 1]; + if api::fs::reopen(path, left_handle).is_err() { + println!("Could not open path for redirection"); + return ExitCode::CommandError; + } + args.remove(i); // Remove redirection from args + args.remove(i); // Remove path from args + n -= 2; + } else if is_thin_arrow { // TODO: Implement pipes + println!("Could not parse arrow"); return ExitCode::CommandError; } - args.remove(i); // Remove redirection from args - args.remove(i); // Remove path from args - n -= 2; } let res = match args[0] { From 0da026095b057616ee9f4d3443573cce620f1b27 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 1 Nov 2021 23:16:13 +0100 Subject: [PATCH 06/10] Add tests --- src/usr/calc.rs | 2 +- src/usr/install.rs | 107 +++++++++++++++++++++++++-------------------- src/usr/lisp.rs | 2 +- src/usr/shell.rs | 14 ++++++ 4 files changed, 75 insertions(+), 50 deletions(-) diff --git a/src/usr/calc.rs b/src/usr/calc.rs index 60c04a0c2..1a07c65bd 100644 --- a/src/usr/calc.rs +++ b/src/usr/calc.rs @@ -155,7 +155,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } #[test_case] -pub fn test_calc() { +fn test_calc() { macro_rules! eval { ($e:expr) => { format!("{}", parse_eval($e).unwrap()) diff --git a/src/usr/install.rs b/src/usr/install.rs index 6298f5cde..4ce496fca 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -5,6 +5,57 @@ use crate::api::io; use crate::api::syscall; use alloc::string::String; +pub fn copy_files(verbose: bool) { + create_dir("/bin", verbose); // Binaries + create_dir("/dev", verbose); // Devices + create_dir("/ini", verbose); // Initializers + create_dir("/lib", verbose); // Libraries + create_dir("/net", verbose); // Network + create_dir("/src", verbose); // Sources + create_dir("/tmp", verbose); // Temporaries + create_dir("/usr", verbose); // User directories + create_dir("/var", verbose); // Variables + + copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello"), verbose); + copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"), verbose); + + create_dir("/dev/clk", verbose); // Clocks + let pathname = "/dev/console"; + if syscall::stat(pathname).is_none() { + if fs::create_device(pathname, sys::fs::DeviceType::Console).is_some() { + if verbose { + println!("Created '{}'", pathname); + } + } + } + let pathname = "/dev/random"; + if syscall::stat(pathname).is_none() { + if fs::create_device(pathname, sys::fs::DeviceType::Random).is_some() { + if verbose { + println!("Created '{}'", pathname); + } + } + } + + copy_file("/ini/boot.sh", include_bytes!("../../dsk/ini/boot.sh"), verbose); + copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt"), verbose); + copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt"), verbose); + copy_file("/ini/palette.csv", include_bytes!("../../dsk/ini/palette.csv"), verbose); + + create_dir("/ini/fonts", verbose); + copy_file("/ini/fonts/lat15-terminus-8x16.psf", include_bytes!("../../dsk/ini/fonts/lat15-terminus-8x16.psf"), verbose); + copy_file("/ini/fonts/zap-light-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-light-8x16.psf"), verbose); + copy_file("/ini/fonts/zap-vga-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-vga-8x16.psf"), verbose); + + copy_file("/tmp/alice.txt", include_bytes!("../../dsk/tmp/alice.txt"), verbose); + copy_file("/tmp/fibonacci.lisp", include_bytes!("../../dsk/tmp/fibonacci.lisp"), verbose); + + create_dir("/tmp/beep", verbose); + copy_file("/tmp/beep/tetris.sh", include_bytes!("../../dsk/tmp/beep/tetris.sh"), verbose); + copy_file("/tmp/beep/starwars.sh", include_bytes!("../../dsk/tmp/beep/starwars.sh"), verbose); + copy_file("/tmp/beep/mario.sh", include_bytes!("../../dsk/tmp/beep/mario.sh"), verbose); +} + pub fn main(_args: &[&str]) -> usr::shell::ExitCode { let csi_color = Style::color("Yellow"); let csi_reset = Style::reset(); @@ -31,50 +82,8 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { } println!("{}Populating filesystem...{}", csi_color, csi_reset); - create_dir("/bin"); // Binaries - create_dir("/dev"); // Devices - create_dir("/ini"); // Initializers - create_dir("/lib"); // Libraries - create_dir("/net"); // Network - create_dir("/src"); // Sources - create_dir("/tmp"); // Temporaries - create_dir("/usr"); // User directories - create_dir("/var"); // Variables - - copy_file("/bin/hello", include_bytes!("../../dsk/bin/hello")); - copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep")); - - create_dir("/dev/clk"); // Clocks - let pathname = "/dev/console"; - if syscall::stat(pathname).is_none() { - if fs::create_device(pathname, sys::fs::DeviceType::Console).is_some() { - println!("Created '{}'", pathname); - } - } - let pathname = "/dev/random"; - if syscall::stat(pathname).is_none() { - if fs::create_device(pathname, sys::fs::DeviceType::Random).is_some() { - println!("Created '{}'", pathname); - } - } - - copy_file("/ini/boot.sh", include_bytes!("../../dsk/ini/boot.sh")); - copy_file("/ini/banner.txt", include_bytes!("../../dsk/ini/banner.txt")); - copy_file("/ini/version.txt", include_bytes!("../../dsk/ini/version.txt")); - copy_file("/ini/palette.csv", include_bytes!("../../dsk/ini/palette.csv")); - - create_dir("/ini/fonts"); - copy_file("/ini/fonts/lat15-terminus-8x16.psf", include_bytes!("../../dsk/ini/fonts/lat15-terminus-8x16.psf")); - copy_file("/ini/fonts/zap-light-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-light-8x16.psf")); - copy_file("/ini/fonts/zap-vga-8x16.psf", include_bytes!("../../dsk/ini/fonts/zap-vga-8x16.psf")); - - copy_file("/tmp/alice.txt", include_bytes!("../../dsk/tmp/alice.txt")); - copy_file("/tmp/fibonacci.lisp", include_bytes!("../../dsk/tmp/fibonacci.lisp")); - - create_dir("/tmp/beep"); - copy_file("/tmp/beep/tetris.sh", include_bytes!("../../dsk/tmp/beep/tetris.sh")); - copy_file("/tmp/beep/starwars.sh", include_bytes!("../../dsk/tmp/beep/starwars.sh")); - copy_file("/tmp/beep/mario.sh", include_bytes!("../../dsk/tmp/beep/mario.sh")); + let verbose = true; + copy_files(verbose); if sys::process::user().is_none() { println!(); @@ -94,13 +103,13 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { usr::shell::ExitCode::CommandSuccessful } -fn create_dir(pathname: &str) { - if sys::fs::Dir::create(pathname).is_some() { +fn create_dir(pathname: &str, verbose: bool) { + if sys::fs::Dir::create(pathname).is_some() && verbose { println!("Created '{}'", pathname); } } -fn copy_file(pathname: &str, buf: &[u8]) { +fn copy_file(pathname: &str, buf: &[u8], verbose: bool) { if fs::exists(pathname) { return; } @@ -115,5 +124,7 @@ fn copy_file(pathname: &str, buf: &[u8]) { fs::write(pathname, buf).ok(); } // TODO: add File::write_all to split buf if needed - println!("Copied '{}'", pathname); + if verbose { + println!("Copied '{}'", pathname); + } } diff --git a/src/usr/lisp.rs b/src/usr/lisp.rs index a6219ce43..bb8f7b467 100644 --- a/src/usr/lisp.rs +++ b/src/usr/lisp.rs @@ -586,7 +586,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } #[test_case] -pub fn test_lisp() { +fn test_lisp() { let env = &mut default_env(); macro_rules! eval { diff --git a/src/usr/shell.rs b/src/usr/shell.rs index e961c3276..a2a90f781 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -307,3 +307,17 @@ pub fn main(args: &[&str]) -> ExitCode { }, } } + +#[test_case] +fn test_shell() { + use alloc::string::ToString; + + sys::fs::mount_mem(); + sys::fs::format_mem(); + usr::install::copy_files(false); + + exec("print test => /test"); + assert_eq!(api::fs::read_to_string("/test"), Ok("test\n".to_string())); + + sys::fs::dismount(); +} From 020ba0052a062956f9dfcf73237003e6bda36fa4 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Mon, 1 Nov 2021 23:18:09 +0100 Subject: [PATCH 07/10] Refactor install --- src/usr/install.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/usr/install.rs b/src/usr/install.rs index 4ce496fca..fe28a5001 100644 --- a/src/usr/install.rs +++ b/src/usr/install.rs @@ -22,18 +22,14 @@ pub fn copy_files(verbose: bool) { create_dir("/dev/clk", verbose); // Clocks let pathname = "/dev/console"; if syscall::stat(pathname).is_none() { - if fs::create_device(pathname, sys::fs::DeviceType::Console).is_some() { - if verbose { - println!("Created '{}'", pathname); - } + if fs::create_device(pathname, sys::fs::DeviceType::Console).is_some() && verbose { + println!("Created '{}'", pathname); } } let pathname = "/dev/random"; if syscall::stat(pathname).is_none() { - if fs::create_device(pathname, sys::fs::DeviceType::Random).is_some() { - if verbose { - println!("Created '{}'", pathname); - } + if fs::create_device(pathname, sys::fs::DeviceType::Random).is_some() && verbose { + println!("Created '{}'", pathname); } } From d93ba2ba44f6d565123c15eed3a6ccc62d48a4b8 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 2 Nov 2021 18:29:43 +0100 Subject: [PATCH 08/10] Add eprint macro --- src/api/io.rs | 19 +++++++++++++++++-- src/api/mod.rs | 19 +++++++++++++++++++ src/usr/beep.rs | 8 ++++---- src/usr/calc.rs | 2 +- src/usr/copy.rs | 8 ++++---- src/usr/date.rs | 2 +- src/usr/delete.rs | 10 +++++----- src/usr/dhcp.rs | 4 ++-- src/usr/disk.rs | 4 ++-- src/usr/env.rs | 2 +- src/usr/find.rs | 4 ++-- src/usr/geotime.rs | 2 +- src/usr/help.rs | 2 +- src/usr/hex.rs | 2 +- src/usr/host.rs | 4 ++-- src/usr/http.rs | 16 ++++++++-------- src/usr/httpd.rs | 6 +++--- src/usr/ip.rs | 2 +- src/usr/keyboard.rs | 5 +++-- src/usr/lisp.rs | 4 ++-- src/usr/list.rs | 6 +++--- src/usr/net.rs | 10 +++++----- src/usr/read.rs | 10 +++++----- src/usr/route.rs | 2 +- src/usr/shell.rs | 18 ++++++++++++++++-- src/usr/tcp.rs | 14 +++++++------- src/usr/user.rs | 8 ++++---- src/usr/vga.rs | 10 +++++----- src/usr/write.rs | 4 ++-- 29 files changed, 128 insertions(+), 79 deletions(-) diff --git a/src/api/io.rs b/src/api/io.rs index 8563dd27a..8db3f7542 100644 --- a/src/api/io.rs +++ b/src/api/io.rs @@ -5,6 +5,7 @@ use alloc::string::{String, ToString}; pub struct Stdin; pub struct Stdout; +pub struct Stderr; impl Stdin { fn new() -> Self { @@ -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() +} diff --git a/src/api/mod.rs b/src/api/mod.rs index f169462d0..17ab76cda 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -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; diff --git a/src/usr/beep.rs b/src/usr/beep.rs index 65a3e1a7e..b62795765 100644 --- a/src/usr/beep.rs +++ b/src/usr/beep.rs @@ -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; } }, @@ -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; } }, diff --git a/src/usr/calc.rs b/src/usr/calc.rs index 1a07c65bd..0ee58a56d 100644 --- a/src/usr/calc.rs +++ b/src/usr/calc.rs @@ -147,7 +147,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { usr::shell::ExitCode::CommandSuccessful } Err(msg) => { - println!("{}", msg); + eprintln!("{}", msg); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/copy.rs b/src/usr/copy.rs index f519aab80..97da85d11 100644 --- a/src/usr/copy.rs +++ b/src/usr/copy.rs @@ -3,7 +3,7 @@ use crate::api::fs; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() != 3 { - println!("Usage: copy "); + eprintln!("Usage: copy "); return usr::shell::ExitCode::CommandError; } @@ -11,7 +11,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { 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; } @@ -19,11 +19,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { 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 } } diff --git a/src/usr/date.rs b/src/usr/date.rs index 06c09665d..942710535 100644 --- a/src/usr/date.rs +++ b/src/usr/date.rs @@ -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 } } diff --git a/src/usr/delete.rs b/src/usr/delete.rs index 3f68b54c0..b43b6cf56 100644 --- a/src/usr/delete.rs +++ b/src/usr/delete.rs @@ -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; } @@ -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 } } diff --git a/src/usr/dhcp.rs b/src/usr/dhcp.rs index da75ddbcb..96c805527 100644 --- a/src/usr/dhcp.rs +++ b/src/usr/dhcp.rs @@ -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); diff --git a/src/usr/disk.rs b/src/usr/disk.rs index ed2603460..32c79953c 100644 --- a/src/usr/disk.rs +++ b/src/usr/disk.rs @@ -35,13 +35,13 @@ fn help() -> usr::shell::ExitCode { println!(" list"); println!(" usage"); - usr::shell::ExitCode::CommandError + usr::shell::ExitCode::CommandSuccessful } fn format(pathname: &str) -> usr::shell::ExitCode { let path: Vec<_> = pathname.split('/').collect(); if !pathname.starts_with("/dev/ata/") || path.len() != 5 { - println!("Could not find disk at '{}'", pathname); + eprintln!("Could not find disk at '{}'", pathname); return usr::shell::ExitCode::CommandError; } diff --git a/src/usr/env.rs b/src/usr/env.rs index 474163f89..034fb79e3 100644 --- a/src/usr/env.rs +++ b/src/usr/env.rs @@ -13,7 +13,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { sys::process::set_env(key, val); println!("{}={}", key, val); } else { - println!("Error: could not parse '{}'", arg); + eprintln!("Error: could not parse '{}'", arg); return usr::shell::ExitCode::CommandError; } } diff --git a/src/usr/find.rs b/src/usr/find.rs index a7ff48d54..a8784ab2b 100644 --- a/src/usr/find.rs +++ b/src/usr/find.rs @@ -36,7 +36,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { name = Some(args[i + 1]); i += 1; } else { - println!("Missing name"); + eprintln!("Missing name"); return usr::shell::ExitCode::CommandError; } }, @@ -45,7 +45,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { line = Some(args[i + 1]); i += 1; } else { - println!("Missing line"); + eprintln!("Missing line"); return usr::shell::ExitCode::CommandError; } }, diff --git a/src/usr/geotime.rs b/src/usr/geotime.rs index 20d895e47..f051ef6d7 100644 --- a/src/usr/geotime.rs +++ b/src/usr/geotime.rs @@ -5,7 +5,7 @@ use core::f64::consts::PI; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() < 2 { - println!("Usage: []"); + eprintln!("Usage: []"); return usr::shell::ExitCode::CommandError; } diff --git a/src/usr/help.rs b/src/usr/help.rs index 1717cd0a4..9d540e632 100644 --- a/src/usr/help.rs +++ b/src/usr/help.rs @@ -18,7 +18,7 @@ fn help_command(cmd: &str) -> usr::shell::ExitCode { } fn help_unknown(cmd: &str) -> usr::shell::ExitCode { - println!("Help not found for command '{}'", cmd); + eprintln!("Help not found for command '{}'", cmd); usr::shell::ExitCode::CommandError } diff --git a/src/usr/hex.rs b/src/usr/hex.rs index 150b20a5b..bc60b8e03 100644 --- a/src/usr/hex.rs +++ b/src/usr/hex.rs @@ -13,7 +13,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { print_hex(&buf); usr::shell::ExitCode::CommandSuccessful } else { - println!("File not found '{}'", pathname); + eprintln!("File not found '{}'", pathname); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/host.rs b/src/usr/host.rs index 621adc9f8..28fb6e95e 100644 --- a/src/usr/host.rs +++ b/src/usr/host.rs @@ -218,7 +218,7 @@ pub fn resolve(name: &str) -> Result { pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() != 2 { - println!("Usage: host "); + eprintln!("Usage: host "); return usr::shell::ExitCode::CommandError; } let name = args[1]; @@ -228,7 +228,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { usr::shell::ExitCode::CommandSuccessful } Err(e) => { - println!("Could not resolve host: {:?}", e); + eprintln!("Could not resolve host: {:?}", e); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/http.rs b/src/usr/http.rs index 4671bfcff..de191770f 100644 --- a/src/usr/http.rs +++ b/src/usr/http.rs @@ -64,7 +64,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } if args.len() != 3 { - println!("Usage: http "); + eprintln!("Usage: http "); return usr::shell::ExitCode::CommandError; } @@ -79,7 +79,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { ip_addr } Err(e) => { - println!("Could not resolve host: {:?}", e); + eprintln!("Could not resolve host: {:?}", e); return usr::shell::ExitCode::CommandError; } } @@ -98,11 +98,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if let Some(ref mut iface) = *sys::net::IFACE.lock() { match iface.ipv4_addr() { None => { - println!("Error: Interface not ready"); + eprintln!("Error: Interface not ready"); return usr::shell::ExitCode::CommandError; } Some(ip_addr) if ip_addr.is_unspecified() => { - println!("Error: Interface not ready"); + eprintln!("Error: Interface not ready"); return usr::shell::ExitCode::CommandError; } _ => {} @@ -113,18 +113,18 @@ 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); match iface.poll(&mut sockets, timestamp) { Err(smoltcp::Error::Unrecognized) => {} Err(e) => { - println!("Network Error: {}", e); + eprintln!("Network Error: {}", e); } Ok(_) => {} } @@ -139,7 +139,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { println!("* Connecting to {}:{}", address, url.port); } if socket.connect((address, url.port), local_port).is_err() { - println!("Could not connect to {}:{}", address, url.port); + eprintln!("Could not connect to {}:{}", address, url.port); return usr::shell::ExitCode::CommandError; } State::Request diff --git a/src/usr/httpd.rs b/src/usr/httpd.rs index 60c7b2087..49f17f779 100644 --- a/src/usr/httpd.rs +++ b/src/usr/httpd.rs @@ -21,11 +21,11 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { if let Some(ref mut iface) = *sys::net::IFACE.lock() { match iface.ipv4_addr() { None => { - println!("Error: Interface not ready"); + eprintln!("Error: Interface not ready"); return usr::shell::ExitCode::CommandError; } Some(ip_addr) if ip_addr.is_unspecified() => { - println!("Error: Interface not ready"); + eprintln!("Error: Interface not ready"); return usr::shell::ExitCode::CommandError; } _ => {} @@ -195,7 +195,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { } } } else { - println!("Error: Could not find network interface"); + eprintln!("Error: Could not find network interface"); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/ip.rs b/src/usr/ip.rs index 95db35e89..2e012d6a9 100644 --- a/src/usr/ip.rs +++ b/src/usr/ip.rs @@ -44,6 +44,6 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } fn error(message: &str) -> usr::shell::ExitCode { - println!("Error: {}", message); + eprintln!("Error: {}", message); usr::shell::ExitCode::CommandError } diff --git a/src/usr/keyboard.rs b/src/usr/keyboard.rs index a05c7cdb4..6e70f1d15 100644 --- a/src/usr/keyboard.rs +++ b/src/usr/keyboard.rs @@ -2,7 +2,7 @@ use crate::{sys, usr}; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() == 1 { - println!("Usage: keyboard "); + eprintln!("Usage: keyboard "); return usr::shell::ExitCode::CommandError; } match args[1] { @@ -23,7 +23,8 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { usr::shell::ExitCode::CommandSuccessful } +// TODO: Move that to API fn error(message: &str) -> usr::shell::ExitCode { - println!("Error: {}", message); + eprintln!("Error: {}", message); usr::shell::ExitCode::CommandError } diff --git a/src/usr/lisp.rs b/src/usr/lisp.rs index bb8f7b467..450ab7117 100644 --- a/src/usr/lisp.rs +++ b/src/usr/lisp.rs @@ -562,7 +562,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if let Err(e) = parse_eval(&block, env) { match e { Err::Reason(msg) => { - println!("{}", msg); + eprintln!("{}", msg); return usr::shell::ExitCode::CommandError; } } @@ -575,7 +575,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } usr::shell::ExitCode::CommandSuccessful } else { - println!("File not found '{}'", pathname); + eprintln!("File not found '{}'", pathname); usr::shell::ExitCode::CommandError } }, diff --git a/src/usr/list.rs b/src/usr/list.rs index 00cfa11c5..c88ea9235 100644 --- a/src/usr/list.rs +++ b/src/usr/list.rs @@ -17,7 +17,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { sort = args[i + 1]; i += 1; } else { - println!("Missing sort key"); + eprintln!("Missing sort key"); return usr::shell::ExitCode::CommandError; } }, @@ -43,7 +43,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { "size" => files.sort_by_key(|f| f.size()), "time" => files.sort_by_key(|f| f.time()), _ => { - println!("Invalid sort key '{}'", sort); + eprintln!("Invalid sort key '{}'", sort); return usr::shell::ExitCode::CommandError; } } @@ -71,7 +71,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } usr::shell::ExitCode::CommandSuccessful } else { - println!("Dir not found '{}'", path); + eprintln!("Dir not found '{}'", path); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/net.rs b/src/usr/net.rs index 21d433c92..58f6a8f23 100644 --- a/src/usr/net.rs +++ b/src/usr/net.rs @@ -6,7 +6,7 @@ use smoltcp::time::Instant; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() == 1 { - println!("Usage: net "); + eprintln!("Usage: net "); return usr::shell::ExitCode::CommandError; } @@ -14,7 +14,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { match args[1] { "config" => { if args.len() < 4 { - println!("Usage: net config "); + eprintln!("Usage: net config "); return usr::shell::ExitCode::CommandError; } match args[2] { @@ -23,13 +23,13 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { "1" | "on" | "enable" => true, "0" | "off" | "disable" => false, _ => { - println!("Invalid config value"); + eprintln!("Invalid config value"); return usr::shell::ExitCode::CommandError; } } } _ => { - println!("Invalid config key"); + eprintln!("Invalid config key"); return usr::shell::ExitCode::CommandError; } } @@ -73,7 +73,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } } _ => { - println!("Invalid command"); + eprintln!("Invalid command"); return usr::shell::ExitCode::CommandError; } } diff --git a/src/usr/read.rs b/src/usr/read.rs index 31e4aa471..4b0b38b7b 100644 --- a/src/usr/read.rs +++ b/src/usr/read.rs @@ -39,7 +39,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { // > read /net/tcp/time.nist.gov:13 let parts: Vec<_> = pathname.split('/').collect(); if parts.len() < 4 { - println!("Usage: read /net/http//"); + eprintln!("Usage: read /net/http//"); usr::shell::ExitCode::CommandError } else { match parts[2] { @@ -58,7 +58,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { usr::http::main(&["http", host, &path]) } _ => { - println!("Error: unknown protocol '{}'", parts[2]); + eprintln!("Error: unknown protocol '{}'", parts[2]); usr::shell::ExitCode::CommandError } } @@ -69,7 +69,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { print!("{}", contents); usr::shell::ExitCode::CommandSuccessful } else { - println!("Could not read '{}'", pathname); + eprintln!("Could not read '{}'", pathname); usr::shell::ExitCode::CommandError } } else if stat.is_dir() { @@ -85,11 +85,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } } } else { - println!("Could not read type of '{}'", pathname); + eprintln!("Could not read type of '{}'", pathname); usr::shell::ExitCode::CommandError } } else { - println!("File not found '{}'", pathname); + eprintln!("File not found '{}'", pathname); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/route.rs b/src/usr/route.rs index 48d2f337d..e8d6c289f 100644 --- a/src/usr/route.rs +++ b/src/usr/route.rs @@ -11,7 +11,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode { }); usr::shell::ExitCode::CommandSuccessful } else { - println!("Could not find network interface"); + eprintln!("Could not find network interface"); usr::shell::ExitCode::CommandError } } diff --git a/src/usr/shell.rs b/src/usr/shell.rs index a2a90f781..25b05d932 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -316,8 +316,22 @@ fn test_shell() { sys::fs::format_mem(); usr::install::copy_files(false); - exec("print test => /test"); - assert_eq!(api::fs::read_to_string("/test"), Ok("test\n".to_string())); + + // Redirect standard output + exec("print test1 => /test"); + assert_eq!(api::fs::read_to_string("/test"), Ok("test1\n".to_string())); + + // Overwrite content of existing file + exec("print test2 => /test"); + assert_eq!(api::fs::read_to_string("/test"), Ok("test2\n".to_string())); + + // Redirect standard output explicitely + exec("print test3 1=> /test"); + assert_eq!(api::fs::read_to_string("/test"), Ok("test3\n".to_string())); + + // Redirect standard error explicitely + exec("http 2=> /test"); + assert_eq!(api::fs::read_to_string("/test"), Ok("Usage: http \n".to_string())); sys::fs::dismount(); } diff --git a/src/usr/tcp.rs b/src/usr/tcp.rs index 85b2e85d8..6dac6bcf1 100644 --- a/src/usr/tcp.rs +++ b/src/usr/tcp.rs @@ -25,7 +25,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } if args.len() != 3 { - println!("Usage: tcp "); + eprintln!("Usage: tcp "); return usr::shell::ExitCode::CommandError; } @@ -41,7 +41,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { ip_addr } Err(e) => { - println!("Could not resolve host: {:?}", e); + eprintln!("Could not resolve host: {:?}", e); return usr::shell::ExitCode::CommandError; } } @@ -60,11 +60,11 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if let Some(ref mut iface) = *sys::net::IFACE.lock() { match iface.ipv4_addr() { None => { - println!("Interface not ready"); + eprintln!("Interface not ready"); return usr::shell::ExitCode::CommandError; } Some(ip_addr) if ip_addr.is_unspecified() => { - println!("Interface not ready"); + eprintln!("Interface not ready"); return usr::shell::ExitCode::CommandError; } _ => {} @@ -74,11 +74,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); @@ -98,7 +98,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let local_port = 49152 + random::get_u16() % 16384; println!("Connecting to {}:{}", address, port); if socket.connect((address, port), local_port).is_err() { - println!("Could not connect to {}:{}", address, port); + eprintln!("Could not connect to {}:{}", address, port); return usr::shell::ExitCode::CommandError; } State::Request diff --git a/src/usr/user.rs b/src/usr/user.rs index b23b9e68e..bfed62f91 100644 --- a/src/usr/user.rs +++ b/src/usr/user.rs @@ -35,7 +35,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { } fn usage() -> usr::shell::ExitCode { - println!("Usage: user [{}] ", COMMANDS.join("|")); + eprintln!("Usage: user [{}] ", COMMANDS.join("|")); usr::shell::ExitCode::CommandError } @@ -82,7 +82,7 @@ pub fn create(username: &str) -> usr::shell::ExitCode { } if hashed_password(username).is_some() { - println!("Username exists"); + eprintln!("Username exists"); return usr::shell::ExitCode::CommandError; } @@ -103,12 +103,12 @@ pub fn create(username: &str) -> usr::shell::ExitCode { println!(); if password != confirm { - println!("Password confirmation failed"); + eprintln!("Password confirmation failed"); return usr::shell::ExitCode::CommandError; } if save_hashed_password(username, &hash(&password)).is_err() { - println!("Could not save user"); + eprintln!("Could not save user"); return usr::shell::ExitCode::CommandError; } diff --git a/src/usr/vga.rs b/src/usr/vga.rs index 36fbd4bce..a0a69519d 100644 --- a/src/usr/vga.rs +++ b/src/usr/vga.rs @@ -4,7 +4,7 @@ use crate::api::fs; pub fn main(args: &[&str]) -> usr::shell::ExitCode { if args.len() == 1 { - println!("Usage: vga "); + eprintln!("Usage: vga "); return usr::shell::ExitCode::CommandError; } match args[1] { @@ -14,7 +14,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if let Ok(font) = api::font::from_bytes(&buf) { sys::vga::set_font(&font); } else { - println!("Could not parse font file"); + eprintln!("Could not parse font file"); return usr::shell::ExitCode::CommandError; } } @@ -29,17 +29,17 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { // } // And "ESC]R" to reset a palette. } else { - println!("Could not parse palette file"); + eprintln!("Could not parse palette file"); return usr::shell::ExitCode::CommandError; } } } else { - println!("Invalid command"); + eprintln!("Invalid command"); return usr::shell::ExitCode::CommandError; } }, _ => { - println!("Invalid command"); + eprintln!("Invalid command"); return usr::shell::ExitCode::CommandError; } } diff --git a/src/usr/write.rs b/src/usr/write.rs index fdee7cd1f..7b849d1f5 100644 --- a/src/usr/write.rs +++ b/src/usr/write.rs @@ -8,7 +8,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { let pathname = args[1]; if pathname.starts_with("/dev") || pathname.starts_with("/sys") { - println!("Permission denied to write to '{}'", pathname); + eprintln!("Permission denied to write to '{}'", pathname); return usr::shell::ExitCode::CommandError; } @@ -25,7 +25,7 @@ pub fn main(args: &[&str]) -> usr::shell::ExitCode { if success { usr::shell::ExitCode::CommandSuccessful } else { - println!("Could not write to '{}'", pathname); + eprintln!("Could not write to '{}'", pathname); usr::shell::ExitCode::CommandError } } From e93e7372cc42792c1271efce42093e2ff28eef4b Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Tue, 2 Nov 2021 19:03:59 +0100 Subject: [PATCH 09/10] Change exit code of empty command in shell --- src/usr/shell.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usr/shell.rs b/src/usr/shell.rs index 25b05d932..7c521309e 100644 --- a/src/usr/shell.rs +++ b/src/usr/shell.rs @@ -180,7 +180,7 @@ pub fn exec(cmd: &str) -> ExitCode { } let res = match args[0] { - "" => ExitCode::CommandError, + "" => ExitCode::CommandSuccessful, "a" | "alias" => ExitCode::CommandUnknown, "b" => ExitCode::CommandUnknown, "c" | "copy" => usr::copy::main(&args), From a1b39633ce1dca56a8f13576f85ba93d8cabf4a8 Mon Sep 17 00:00:00 2001 From: Vincent Ollivier Date: Fri, 5 Nov 2021 08:55:35 +0100 Subject: [PATCH 10/10] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e60aa8193..a7ee79c9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)