moros 0.6.0

MOROS: Obscure Rust Operating System
Documentation
diff --git a/Cargo.lock b/Cargo.lock
index c01bab3..00a939d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -127,6 +127,18 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "enum_dispatch"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8"
+dependencies = [
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "float-cmp"
 version = "0.9.0"
@@ -220,6 +232,7 @@ dependencies = [
  "base64",
  "bit_field 0.10.1",
  "bootloader",
+ "enum_dispatch",
  "float-cmp",
  "hmac",
  "lazy_static",
@@ -250,6 +263,12 @@ dependencies = [
  "autocfg",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
+
 [[package]]
 name = "opaque-debug"
 version = "0.3.0"
diff --git a/Cargo.toml b/Cargo.toml
index f339e54..6758aad 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -41,6 +41,7 @@ time = { version = "0.2.27", default-features = false }
 uart_16550 = "0.2.15"
 vte = "0.10.1"
 x86_64 = "0.14.4"
+enum_dispatch = "0.3.7"
 
 [package.metadata.bootimage]
 test-success-exit-code = 33 # (0x10 << 1) | 1
diff --git a/src/api/fs.rs b/src/api/fs.rs
index 22dec6f..32b80ba 100644
--- a/src/api/fs.rs
+++ b/src/api/fs.rs
@@ -1,5 +1,7 @@
 use crate::sys;
 use alloc::string::{String, ToString};
+use alloc::vec;
+use alloc::vec::Vec;
 
 pub fn canonicalize(path: &str) -> Result<String, ()> {
     match sys::process::env("HOME") {
@@ -31,6 +33,23 @@ pub fn read_to_string(path: &str) -> Result<String, ()> {
     }
 }
 
+pub fn read(path: &str) -> Result<Vec<u8>, ()> {
+    let path = match canonicalize(path) {
+        Ok(path) => path,
+        Err(_) => return Err(()),
+    };
+    match sys::fs::File::open(&path) {
+        Some(mut file) => {
+            let mut buf = vec![0; file.size()];
+            file.read(&mut buf);
+            Ok(buf)
+        },
+        None => {
+            Err(())
+        }
+    }
+}
+
 pub fn write(path: &str, buf: &[u8]) -> Result<(), ()> {
     let path = match canonicalize(path) {
         Ok(path) => path,
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 196423c..56ea98d 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -19,6 +19,7 @@ macro_rules! println {
 pub mod console;
 pub mod font;
 pub mod fs;
+pub mod process;
 pub mod prompt;
 pub mod regex;
 pub mod syscall;
diff --git a/src/main.rs b/src/main.rs
index 83da2ba..4dc2668 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,11 +11,6 @@ entry_point!(main);
 
 fn main(boot_info: &'static BootInfo) -> ! {
     moros::init(boot_info);
-
-    let bin = include_bytes!("../dsk/bin/sleep");
-    let process = sys::process::Process::create(bin);
-    process.switch();
-
     loop {
         let bootrc = "/ini/boot.sh";
         if sys::fs::File::open(bootrc).is_some() {
@@ -27,7 +22,6 @@ fn main(boot_info: &'static BootInfo) -> ! {
                 println!("MFS is not mounted to '/'");
             }
             println!("Running console in diskless mode");
-
             usr::shell::main(&["shell"]);
         }
     }
diff --git a/src/sys/net/mod.rs b/src/sys/net/mod.rs
index e4dfe11..597e268 100644
--- a/src/sys/net/mod.rs
+++ b/src/sys/net/mod.rs
@@ -1,34 +1,37 @@
+pub mod rtl8139;
+pub mod pcnet;
+
+use rtl8139::RTL8139;
+use pcnet::PCNET;
+
 use alloc::sync::Arc;
 use core::sync::atomic::{AtomicU64, Ordering};
 use lazy_static::lazy_static;
 use spin::Mutex;
 
-// TODO: Support dyn EthernetInterface
-pub type EthernetInterface<T> = smoltcp::iface::EthernetInterface<'static, T>;
-
-#[cfg(feature = "rtl8139")]
-pub mod rtl8139;
+use smoltcp::socket::SocketSet;
+use smoltcp::time::Instant;
+use core::time::Duration;
+use smoltcp::Result;
 
-#[cfg(feature = "rtl8139")]
 lazy_static! {
-    pub static ref IFACE: Mutex<Option<EthernetInterface<rtl8139::RTL8139>>> = Mutex::new(None);
+    pub static ref IFACE: Mutex<Option<EthernetInterface>> = Mutex::new(None);
 }
 
-#[cfg(feature = "rtl8139")]
-pub fn init() {
-    rtl8139::init();
+#[enum_dispatch]
+pub enum EthernetInterface {
+    RTL8139,
+    PCNET,
 }
 
-#[cfg(feature = "pcnet")]
-pub mod pcnet;
-
-#[cfg(feature = "pcnet")]
-lazy_static! {
-    pub static ref IFACE: Mutex<Option<EthernetInterface<pcnet::PCNET>>> = Mutex::new(None);
+#[enum_dispatch(EthernetInterface)]
+trait EthernetInterface {
+    pub fn poll(&mut self, sockets: &mut SocketSet<'_>,timestamp: Instant) -> Result<bool>;
+    pub fn poll_delay(&self, sockets: &SocketSet<'_>, timestamp: Instant) -> Option<Duration>;
 }
 
-#[cfg(feature = "pcnet")]
 pub fn init() {
+    rtl8139::init();
     pcnet::init();
 }
 
diff --git a/src/sys/net/pcnet.rs b/src/sys/net/pcnet.rs
index 587128a..0e5104d 100644
--- a/src/sys/net/pcnet.rs
+++ b/src/sys/net/pcnet.rs
@@ -1,6 +1,7 @@
 use crate::{sys, usr};
 use crate::sys::allocator::PhysBuf;
 use crate::sys::net::Stats;
+use crate::sys::net::EthernetInterface;
 
 use alloc::collections::BTreeMap;
 use alloc::sync::Arc;
@@ -456,7 +457,7 @@ pub fn init() {
                 routes(routes).
                 finalize();
 
-            *sys::net::IFACE.lock() = Some(iface);
+            *sys::net::IFACE.lock() = Some(EthernetInterface::PCNET(iface));
         }
     }
 }
diff --git a/src/sys/net/rtl8139.rs b/src/sys/net/rtl8139.rs
index 174e329..4eed684 100644
--- a/src/sys/net/rtl8139.rs
+++ b/src/sys/net/rtl8139.rs
@@ -1,6 +1,8 @@
 use crate::{sys, usr};
 use crate::sys::allocator::PhysBuf;
 use crate::sys::net::Stats;
+use crate::sys::net::EthernetInterface;
+
 use alloc::collections::BTreeMap;
 use alloc::vec::Vec;
 use array_macro::array;
@@ -382,7 +384,7 @@ pub fn init() {
                 routes(routes).
                 finalize();
 
-            *sys::net::IFACE.lock() = Some(iface);
+            *sys::net::IFACE.lock() = Some(EthernetInterface::RTL8139(iface));
         }
 
         //let irq = pci_device.interrupt_line;
diff --git a/src/sys/process.rs b/src/sys/process.rs
index bc9c201..d1eda01 100644
--- a/src/sys/process.rs
+++ b/src/sys/process.rs
@@ -135,4 +135,3 @@ impl Process {
         }
     }
 }
-
diff --git a/src/usr/install.rs b/src/usr/install.rs
index a67fc4f..6690aab 100644
--- a/src/usr/install.rs
+++ b/src/usr/install.rs
@@ -38,6 +38,7 @@ pub fn main(_args: &[&str]) -> usr::shell::ExitCode {
         create_dir("/usr"); // User directories
         create_dir("/var"); // Variables
 
+        copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"));
         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"));
diff --git a/src/usr/shell.rs b/src/usr/shell.rs
index d261438..8a480a6 100644
--- a/src/usr/shell.rs
+++ b/src/usr/shell.rs
@@ -1,5 +1,5 @@
 use crate::api::prompt::Prompt;
-use crate::{sys, usr};
+use crate::{api, sys, usr};
 use crate::api::console::Style;
 use alloc::format;
 use alloc::vec::Vec;
@@ -178,7 +178,14 @@ pub fn exec(cmd: &str) -> ExitCode {
         "mem" | "memory"       => usr::mem::main(&args),
         "kb" | "keyboard"      => usr::keyboard::main(&args),
         "lisp"                 => usr::lisp::main(&args),
-        _                      => ExitCode::CommandUnknown,
+        cmd                    => {
+            if let Ok(process) = api::process::create(cmd) {
+                process.switch();
+                ExitCode::CommandSuccessful
+            } else {
+                ExitCode::CommandUnknown
+            }
+        }
     }
 }