2016-08-15 05:38:32 +02:00
|
|
|
//! # Schemes
|
|
|
|
//! A scheme is a primitive for handling filesystem syscalls in Redox.
|
|
|
|
//! Schemes accept paths from the kernel for `open`, and file descriptors that they generate
|
|
|
|
//! are then passed for operations like `close`, `read`, `write`, etc.
|
|
|
|
//!
|
|
|
|
//! The kernel validates paths and file descriptors before they are passed to schemes,
|
|
|
|
//! also stripping the scheme identifier of paths if necessary.
|
|
|
|
|
2016-08-16 19:04:14 +02:00
|
|
|
use alloc::arc::Arc;
|
|
|
|
use alloc::boxed::Box;
|
|
|
|
use collections::BTreeMap;
|
2016-09-24 01:54:39 +02:00
|
|
|
use core::sync::atomic::Ordering;
|
2016-09-20 02:29:28 +02:00
|
|
|
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};
|
2016-08-16 19:04:14 +02:00
|
|
|
|
2016-09-21 00:23:28 +02:00
|
|
|
use syscall::error::*;
|
|
|
|
use syscall::scheme::Scheme;
|
2016-08-15 05:38:32 +02:00
|
|
|
|
2016-09-24 01:54:39 +02:00
|
|
|
use self::debug::{DEBUG_SCHEME_ID, DebugScheme};
|
|
|
|
use self::event::EventScheme;
|
2016-09-19 01:55:35 +02:00
|
|
|
use self::env::EnvScheme;
|
2016-09-11 03:42:26 +02:00
|
|
|
use self::initfs::InitFsScheme;
|
Orbital (#16)
* Port previous ethernet scheme
* Add ipd
* Fix initfs rebuilds, use QEMU user networking addresses in ipd
* Add tcp/udp, netutils, dns, and network config
* Add fsync to network driver
* Add dns, router, subnet by default
* Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks
* Add orbital server, WIP
* Add futex
* Add orbutils and orbital
* Update libstd, orbutils, and orbital
Move ANSI key encoding to vesad
* Add orbital assets
* Update orbital
* Update to add login manager
* Add blocking primitives, block for most things except waitpid, update orbital
* Wait in waitpid and IRQ, improvements for other waits
* Fevent in root scheme
* WIP: Switch to using fevent
* Reorganize
* Event based e1000d driver
* Superuser-only access to some network schemes, display, and disk
* Superuser root and irq schemes
* Fix orbital
2016-10-14 01:21:42 +02:00
|
|
|
use self::irq::{IRQ_SCHEME_ID, IrqScheme};
|
2016-11-01 04:54:56 +01:00
|
|
|
use self::null::NullScheme;
|
2016-10-07 02:46:24 +02:00
|
|
|
use self::pipe::{PIPE_SCHEME_ID, PipeScheme};
|
Orbital (#16)
* Port previous ethernet scheme
* Add ipd
* Fix initfs rebuilds, use QEMU user networking addresses in ipd
* Add tcp/udp, netutils, dns, and network config
* Add fsync to network driver
* Add dns, router, subnet by default
* Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks
* Add orbital server, WIP
* Add futex
* Add orbutils and orbital
* Update libstd, orbutils, and orbital
Move ANSI key encoding to vesad
* Add orbital assets
* Update orbital
* Update to add login manager
* Add blocking primitives, block for most things except waitpid, update orbital
* Wait in waitpid and IRQ, improvements for other waits
* Fevent in root scheme
* WIP: Switch to using fevent
* Reorganize
* Event based e1000d driver
* Superuser-only access to some network schemes, display, and disk
* Superuser root and irq schemes
* Fix orbital
2016-10-14 01:21:42 +02:00
|
|
|
use self::root::{ROOT_SCHEME_ID, RootScheme};
|
2016-10-14 05:00:51 +02:00
|
|
|
use self::sys::SysScheme;
|
2016-11-01 04:54:56 +01:00
|
|
|
use self::zero::ZeroScheme;
|
2016-08-15 05:38:32 +02:00
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `debug:` - provides access to serial console
|
2016-08-15 05:38:32 +02:00
|
|
|
pub mod debug;
|
2016-09-09 04:06:33 +02:00
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `event:` - allows reading of `Event`s which are registered using `fevent`
|
2016-09-24 01:54:39 +02:00
|
|
|
pub mod event;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `env:` - access and modify environmental variables
|
2016-09-19 01:55:35 +02:00
|
|
|
pub mod env;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `initfs:` - a readonly filesystem used for initializing the system
|
2016-09-11 03:42:26 +02:00
|
|
|
pub mod initfs;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `irq:` - allows userspace handling of IRQs
|
2016-09-19 02:59:46 +02:00
|
|
|
pub mod irq;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `null:` - a scheme that will discard all writes, and read no bytes
|
2016-11-01 04:54:56 +01:00
|
|
|
pub mod null;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `pipe:` - used internally by the kernel to implement `pipe`
|
2016-10-07 02:46:24 +02:00
|
|
|
pub mod pipe;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `:` - allows the creation of userspace schemes, tightly dependent on `user`
|
2016-09-20 16:47:16 +02:00
|
|
|
pub mod root;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `sys:` - system information, such as the context list and scheme list
|
2016-10-14 05:00:51 +02:00
|
|
|
pub mod sys;
|
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// A wrapper around userspace schemes, tightly dependent on `root`
|
2016-09-20 05:24:54 +02:00
|
|
|
pub mod user;
|
2016-09-20 02:29:28 +02:00
|
|
|
|
2016-11-04 20:38:40 +01:00
|
|
|
/// `zero:` - a scheme that will discard all writes, and always fill read buffers with zero
|
2016-11-01 04:54:56 +01:00
|
|
|
pub mod zero;
|
|
|
|
|
2016-09-09 04:06:33 +02:00
|
|
|
/// Limit on number of schemes
|
|
|
|
pub const SCHEME_MAX_SCHEMES: usize = 65536;
|
2016-08-15 05:38:32 +02:00
|
|
|
|
2016-08-18 16:30:45 +02:00
|
|
|
/// Scheme list type
|
2016-09-09 04:06:33 +02:00
|
|
|
pub struct SchemeList {
|
2016-09-20 02:29:28 +02:00
|
|
|
map: BTreeMap<usize, Arc<Box<Scheme + Send + Sync>>>,
|
2016-09-09 04:06:33 +02:00
|
|
|
names: BTreeMap<Box<[u8]>, usize>,
|
|
|
|
next_id: usize
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SchemeList {
|
|
|
|
/// Create a new scheme list.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
SchemeList {
|
|
|
|
map: BTreeMap::new(),
|
|
|
|
names: BTreeMap::new(),
|
|
|
|
next_id: 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 05:13:37 +02:00
|
|
|
pub fn iter(&self) -> ::collections::btree_map::Iter<usize, Arc<Box<Scheme + Send + Sync>>> {
|
|
|
|
self.map.iter()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn iter_name(&self) -> ::collections::btree_map::Iter<Box<[u8]>, usize> {
|
|
|
|
self.names.iter()
|
|
|
|
}
|
|
|
|
|
2016-09-09 04:06:33 +02:00
|
|
|
/// Get the nth scheme.
|
2016-09-20 02:29:28 +02:00
|
|
|
pub fn get(&self, id: usize) -> Option<&Arc<Box<Scheme + Send + Sync>>> {
|
2016-09-09 04:06:33 +02:00
|
|
|
self.map.get(&id)
|
|
|
|
}
|
|
|
|
|
2016-09-20 02:29:28 +02:00
|
|
|
pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc<Box<Scheme + Send + Sync>>)> {
|
2016-09-09 04:06:33 +02:00
|
|
|
if let Some(&id) = self.names.get(name) {
|
|
|
|
self.get(id).map(|scheme| (id, scheme))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-19 01:55:35 +02:00
|
|
|
/// Create a new scheme.
|
2016-09-24 01:54:39 +02:00
|
|
|
pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<usize> {
|
2016-09-09 04:06:33 +02:00
|
|
|
if self.names.contains_key(&name) {
|
2016-09-21 00:23:28 +02:00
|
|
|
return Err(Error::new(EEXIST));
|
2016-09-09 04:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if self.next_id >= SCHEME_MAX_SCHEMES {
|
|
|
|
self.next_id = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while self.map.contains_key(&self.next_id) {
|
|
|
|
self.next_id += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.next_id >= SCHEME_MAX_SCHEMES {
|
2016-09-21 00:23:28 +02:00
|
|
|
return Err(Error::new(EAGAIN));
|
2016-09-09 04:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
let id = self.next_id;
|
|
|
|
self.next_id += 1;
|
|
|
|
|
|
|
|
assert!(self.map.insert(id, scheme).is_none());
|
|
|
|
assert!(self.names.insert(name, id).is_none());
|
|
|
|
|
2016-09-24 01:54:39 +02:00
|
|
|
Ok(id)
|
2016-09-09 04:06:33 +02:00
|
|
|
}
|
|
|
|
}
|
2016-08-18 16:10:08 +02:00
|
|
|
|
2016-08-15 05:38:32 +02:00
|
|
|
/// Schemes list
|
2016-08-18 16:10:08 +02:00
|
|
|
static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
|
|
|
|
|
2016-08-18 16:30:45 +02:00
|
|
|
/// Initialize schemes, called if needed
|
2016-08-18 16:10:08 +02:00
|
|
|
fn init_schemes() -> RwLock<SchemeList> {
|
2016-09-09 04:06:33 +02:00
|
|
|
let mut list: SchemeList = SchemeList::new();
|
Orbital (#16)
* Port previous ethernet scheme
* Add ipd
* Fix initfs rebuilds, use QEMU user networking addresses in ipd
* Add tcp/udp, netutils, dns, and network config
* Add fsync to network driver
* Add dns, router, subnet by default
* Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks
* Add orbital server, WIP
* Add futex
* Add orbutils and orbital
* Update libstd, orbutils, and orbital
Move ANSI key encoding to vesad
* Add orbital assets
* Update orbital
* Update to add login manager
* Add blocking primitives, block for most things except waitpid, update orbital
* Wait in waitpid and IRQ, improvements for other waits
* Fevent in root scheme
* WIP: Switch to using fevent
* Reorganize
* Event based e1000d driver
* Superuser-only access to some network schemes, display, and disk
* Superuser root and irq schemes
* Fix orbital
2016-10-14 01:21:42 +02:00
|
|
|
ROOT_SCHEME_ID.store(list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme"), Ordering::SeqCst);
|
2016-09-24 01:54:39 +02:00
|
|
|
DEBUG_SCHEME_ID.store(list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"), Ordering::SeqCst);
|
|
|
|
list.insert(Box::new(*b"event"), Arc::new(Box::new(EventScheme::new()))).expect("failed to insert event scheme");
|
2016-09-20 16:47:16 +02:00
|
|
|
list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme");
|
|
|
|
list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme");
|
Orbital (#16)
* Port previous ethernet scheme
* Add ipd
* Fix initfs rebuilds, use QEMU user networking addresses in ipd
* Add tcp/udp, netutils, dns, and network config
* Add fsync to network driver
* Add dns, router, subnet by default
* Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks
* Add orbital server, WIP
* Add futex
* Add orbutils and orbital
* Update libstd, orbutils, and orbital
Move ANSI key encoding to vesad
* Add orbital assets
* Update orbital
* Update to add login manager
* Add blocking primitives, block for most things except waitpid, update orbital
* Wait in waitpid and IRQ, improvements for other waits
* Fevent in root scheme
* WIP: Switch to using fevent
* Reorganize
* Event based e1000d driver
* Superuser-only access to some network schemes, display, and disk
* Superuser root and irq schemes
* Fix orbital
2016-10-14 01:21:42 +02:00
|
|
|
IRQ_SCHEME_ID.store(list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme"), Ordering::SeqCst);
|
2016-11-01 04:54:56 +01:00
|
|
|
list.insert(Box::new(*b"null"), Arc::new(Box::new(NullScheme))).expect("failed to insert null scheme");
|
2016-10-07 02:46:24 +02:00
|
|
|
PIPE_SCHEME_ID.store(list.insert(Box::new(*b"pipe"), Arc::new(Box::new(PipeScheme))).expect("failed to insert pipe scheme"), Ordering::SeqCst);
|
2016-10-14 05:00:51 +02:00
|
|
|
list.insert(Box::new(*b"sys"), Arc::new(Box::new(SysScheme::new()))).expect("failed to insert sys scheme");
|
2016-11-01 04:54:56 +01:00
|
|
|
list.insert(Box::new(*b"zero"), Arc::new(Box::new(ZeroScheme))).expect("failed to insert zero scheme");
|
2016-09-09 04:06:33 +02:00
|
|
|
RwLock::new(list)
|
2016-08-18 16:10:08 +02:00
|
|
|
}
|
|
|
|
|
2016-08-18 16:30:45 +02:00
|
|
|
/// Get the global schemes list, const
|
2016-08-18 16:10:08 +02:00
|
|
|
pub fn schemes() -> RwLockReadGuard<'static, SchemeList> {
|
|
|
|
SCHEMES.call_once(init_schemes).read()
|
|
|
|
}
|
|
|
|
|
2016-08-18 16:30:45 +02:00
|
|
|
/// Get the global schemes list, mutable
|
2016-08-18 16:10:08 +02:00
|
|
|
pub fn schemes_mut() -> RwLockWriteGuard<'static, SchemeList> {
|
|
|
|
SCHEMES.call_once(init_schemes).write()
|
2016-08-16 19:04:14 +02:00
|
|
|
}
|