From af2f6fc6dfc95ef1ce2d8f0d97f37e8d5370ec44 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sun, 18 Sep 2016 17:55:35 -0600
Subject: [PATCH] Add fsync. Add env scheme, currently hardcoded to get ion to
 launch. Make serial IRQ send data to debug scheme

---
 scheme/debug.rs  | 40 ++++++++++++++++++++--
 scheme/env.rs    | 88 ++++++++++++++++++++++++++++++++++++++++++++++++
 scheme/initfs.rs |  4 +++
 scheme/mod.rs    | 10 +++++-
 syscall/call.rs  |  3 ++
 syscall/fs.rs    | 15 +++++++++
 syscall/mod.rs   |  1 +
 7 files changed, 158 insertions(+), 3 deletions(-)
 create mode 100644 scheme/env.rs

diff --git a/scheme/debug.rs b/scheme/debug.rs
index 0623b8b6..8f63bf65 100644
--- a/scheme/debug.rs
+++ b/scheme/debug.rs
@@ -1,8 +1,25 @@
+use collections::VecDeque;
 use core::str;
+use spin::{Mutex, MutexGuard, Once};
 
+use context;
 use syscall::Result;
 use super::Scheme;
 
+/// Input
+static INPUT: Once<Mutex<VecDeque<u8>>> = Once::new();
+
+/// Initialize contexts, called if needed
+fn init_input() -> Mutex<VecDeque<u8>> {
+    Mutex::new(VecDeque::new())
+}
+
+/// Get the global schemes list, const
+#[no_mangle]
+pub extern fn debug_input(b: u8) {
+    INPUT.call_once(init_input).lock().push_back(b)
+}
+
 pub struct DebugScheme;
 
 impl Scheme for DebugScheme {
@@ -17,8 +34,23 @@ impl Scheme for DebugScheme {
     /// Read the file `number` into the `buffer`
     ///
     /// Returns the number of bytes read
-    fn read(&mut self, _file: usize, _buffer: &mut [u8]) -> Result<usize> {
-        Ok(0)
+    fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result<usize> {
+        loop {
+            let mut i = 0;
+            {
+                let mut input = INPUT.call_once(init_input).lock();
+                while i < buf.len() && ! input.is_empty() {
+                    buf[i] = input.pop_front().expect("debug_input lost byte");
+                    i += 1;
+                }
+            }
+
+            if i > 0 {
+                return Ok(i);
+            } else {
+                unsafe { context::switch(); }
+            }
+        }
     }
 
     /// Write the `buffer` to the `file`
@@ -30,6 +62,10 @@ impl Scheme for DebugScheme {
         Ok(buffer.len())
     }
 
+    fn fsync(&mut self, file: usize) -> Result<()> {
+        Ok(())
+    }
+
     /// Close the file `number`
     fn close(&mut self, _file: usize) -> Result<()> {
         Ok(())
diff --git a/scheme/env.rs b/scheme/env.rs
new file mode 100644
index 00000000..a04142f1
--- /dev/null
+++ b/scheme/env.rs
@@ -0,0 +1,88 @@
+use collections::BTreeMap;
+
+use syscall::{Error, Result};
+use super::Scheme;
+
+struct Handle {
+    data: &'static [u8],
+    seek: usize
+}
+
+pub struct EnvScheme {
+    next_id: usize,
+    files: BTreeMap<&'static [u8], &'static [u8]>,
+    handles: BTreeMap<usize, Handle>
+}
+
+impl EnvScheme {
+    pub fn new() -> EnvScheme {
+        let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new();
+
+        files.insert(b"HOME", b"initfs:");
+        files.insert(b"PWD", b"initfs:");
+        files.insert(b"COLUMNS", b"80");
+        files.insert(b"LINES", b"30");
+
+        EnvScheme {
+            next_id: 0,
+            files: files,
+            handles: BTreeMap::new()
+        }
+    }
+}
+
+impl Scheme for EnvScheme {
+    fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> {
+        let data = self.files.get(path).ok_or(Error::NoEntry)?;
+
+        let id = self.next_id;
+        self.next_id += 1;
+        self.handles.insert(id, Handle {
+            data: data,
+            seek: 0
+        });
+
+        Ok(id)
+    }
+
+    fn dup(&mut self, file: usize) -> Result<usize> {
+        let (data, seek) = {
+            let handle = self.handles.get(&file).ok_or(Error::BadFile)?;
+            (handle.data, handle.seek)
+        };
+
+        let id = self.next_id;
+        self.next_id += 1;
+        self.handles.insert(id, Handle {
+            data: data,
+            seek: seek
+        });
+
+        Ok(id)
+    }
+
+    fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> {
+        let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?;
+
+        let mut i = 0;
+        while i < buffer.len() && handle.seek < handle.data.len() {
+            buffer[i] = handle.data[handle.seek];
+            i += 1;
+            handle.seek += 1;
+        }
+
+        Ok(i)
+    }
+
+    fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> {
+        Err(Error::NotPermitted)
+    }
+
+    fn fsync(&mut self, file: usize) -> Result<()> {
+        Ok(())
+    }
+
+    fn close(&mut self, file: usize) -> Result<()> {
+        self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(()))
+    }
+}
diff --git a/scheme/initfs.rs b/scheme/initfs.rs
index 82e5f358..0b15bd23 100644
--- a/scheme/initfs.rs
+++ b/scheme/initfs.rs
@@ -78,6 +78,10 @@ impl Scheme for InitFsScheme {
         Err(Error::NotPermitted)
     }
 
+    fn fsync(&mut self, file: usize) -> Result<()> {
+        Ok(())
+    }
+
     fn close(&mut self, file: usize) -> Result<()> {
         self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(()))
     }
diff --git a/scheme/mod.rs b/scheme/mod.rs
index a2a80097..af9f0a9a 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -16,11 +16,15 @@ use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
 use syscall::{Error, Result};
 
 use self::debug::DebugScheme;
+use self::env::EnvScheme;
 use self::initfs::InitFsScheme;
 
 /// Debug scheme
 pub mod debug;
 
+/// Environmental variables
+pub mod env;
+
 /// InitFS scheme
 pub mod initfs;
 
@@ -57,7 +61,7 @@ impl SchemeList {
         }
     }
 
-    /// Create a new context.
+    /// Create a new scheme.
     pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Mutex<Box<Scheme + Send>>>) -> Result<&Arc<Mutex<Box<Scheme + Send>>>> {
         if self.names.contains_key(&name) {
             return Err(Error::FileExists);
@@ -92,6 +96,7 @@ static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
 fn init_schemes() -> RwLock<SchemeList> {
     let mut list: SchemeList = SchemeList::new();
     list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme");
+    list.insert(Box::new(*b"env"), Arc::new(Mutex::new(Box::new(EnvScheme::new())))).expect("failed to insert env: scheme");
     list.insert(Box::new(*b"initfs"), Arc::new(Mutex::new(Box::new(InitFsScheme::new())))).expect("failed to insert initfs: scheme");
     RwLock::new(list)
 }
@@ -128,6 +133,9 @@ pub trait Scheme {
     /// Returns the number of bytes written
     fn write(&mut self, file: usize, buffer: &[u8]) -> Result<usize>;
 
+    /// Sync the file descriptor
+    fn fsync(&mut self, file: usize) -> Result<()>;
+
     /// Close the file descriptor
     fn close(&mut self, file: usize) -> Result<()>;
 }
diff --git a/syscall/call.rs b/syscall/call.rs
index e4a7e926..3bcefd48 100644
--- a/syscall/call.rs
+++ b/syscall/call.rs
@@ -29,6 +29,8 @@ pub enum Call {
     Brk = 45,
     /// Set process I/O privilege level
     Iopl = 110,
+    /// Sync file descriptor
+    FSync = 118,
     /// Clone process
     Clone = 120,
     /// Yield to scheduler
@@ -55,6 +57,7 @@ impl Call {
             41 => Ok(Call::Dup),
             45 => Ok(Call::Brk),
             110 => Ok(Call::Iopl),
+            118 => Ok(Call::FSync),
             120 => Ok(Call::Clone),
             158 => Ok(Call::SchedYield),
             183 => Ok(Call::GetCwd),
diff --git a/syscall/fs.rs b/syscall/fs.rs
index c992bbaa..d68727d5 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -120,3 +120,18 @@ pub fn dup(fd: usize) -> Result<usize> {
     let result = scheme_mutex.lock().dup(file.number);
     result
 }
+
+pub fn fsync(fd: usize) -> Result<usize> {
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context = context_lock.read();
+        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        file
+    };
+
+    let schemes = scheme::schemes();
+    let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+    let result = scheme_mutex.lock().fsync(file.number).and(Ok(0));
+    result
+}
diff --git a/syscall/mod.rs b/syscall/mod.rs
index c6ab11df..396f366a 100644
--- a/syscall/mod.rs
+++ b/syscall/mod.rs
@@ -39,6 +39,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
                 Call::Dup => dup(b),
                 Call::Brk => brk(b),
                 Call::Iopl => iopl(b),
+                Call::FSync => fsync(b),
                 Call::Clone => clone(b, stack),
                 Call::SchedYield => sched_yield(),
                 Call::GetCwd => getcwd(validate_slice_mut(b as *mut u8, c)?)
-- 
GitLab