diff --git a/scheme/debug.rs b/scheme/debug.rs index 0623b8b69322c59a63114e7fab292aca55c75c31..8f63bf654f6f832206032332014f2a14f09db3fa 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 0000000000000000000000000000000000000000..a04142f11e4ba4cff89fd675a0808560c98d11be --- /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 82e5f3581c23807d50a8f6746de5a7268dd14b7a..0b15bd239589060d272f3bd1999123c83b01fafa 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 a2a800975abe9e0bb956ff8c1531205635468473..af9f0a9a71e8c04fc25c3e078f1760aff71c71a0 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 e4a7e9263788639abf42a776310aef39a601e953..3bcefd4830cb0f681b1231b7bacc4bab3fb8a632 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 c992bbaac7858fea7ca17ef1447680d23ec77dc7..d68727d500740d3b9218a8e222b4ec18780415fa 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 c6ab11dfadef97cbd2299faea5f385118e2d29c6..396f366ac94daf343c2d0faeeb702a040b314763 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)?)