diff --git a/Cargo.lock b/Cargo.lock index a687b991876a5570c85a19cc24776e8a154299bf..cc9f8add6d65838894bd4f9215a46e38f36fc2f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,7 +172,6 @@ dependencies = [ "ion_sys 0.1.0", "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)", "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 777eefd4643dbb6a02b6c048f36dd311cb4d359c..daf60683b4c73bfcdbc34ebe17e326f1764f75d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,8 +61,5 @@ path = "src/lib/lib.rs" lto = true panic = "abort" -[target."cfg(all(unix, not(target_os = \"redox\")))".dependencies] -libloading = "0.5" - [patch.crates-io] liner = { git = "https://gitlab.redox-os.org/redox-os/liner" } diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 4dff149b4ed2cf27f09ed03e414d4b69c5e880a5..32c7979804023706b8ee0a723f306a6a3daa5ea1 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -12,8 +12,6 @@ extern crate glob; extern crate itoa; #[macro_use] extern crate lazy_static; -#[cfg(all(unix, not(target_os = "redox")))] -extern crate libloading; extern crate liner; extern crate regex; extern crate small; diff --git a/src/lib/parser/shell_expand/mod.rs b/src/lib/parser/shell_expand/mod.rs index 97e180fb0f758057f5fa3e8597df1e5e9b2b6905..5707eefdb43acfd03dc644ee075543d34eec3a4c 100644 --- a/src/lib/parser/shell_expand/mod.rs +++ b/src/lib/parser/shell_expand/mod.rs @@ -537,7 +537,7 @@ fn expand_single_string_token<E: Expander>( } if output.as_str() != "" { - expanded_words.push(output.into()); + expanded_words.push(output); } expanded_words } diff --git a/src/lib/parser/shell_expand/words/methods/arrays.rs b/src/lib/parser/shell_expand/words/methods/arrays.rs index 4918e59b83bd2e71ddc9fd0b96be46a2eca57bab..d6ed6a0fed1725fa79da7352f920ef5c17b1f617 100644 --- a/src/lib/parser/shell_expand/words/methods/arrays.rs +++ b/src/lib/parser/shell_expand/words/methods/arrays.rs @@ -29,11 +29,7 @@ impl<'a> ArrayMethod<'a> { fn lines<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> { let variable = self.resolve_var(expand_func); - Ok(variable - .lines() - .into_iter() - .map(|line| types::Str::from(line)) - .collect()) + Ok(variable.lines().into_iter().map(types::Str::from).collect()) } fn chars<E: Expander>(&self, expand_func: &E) -> Result<Array, &'static str> { diff --git a/src/lib/parser/shell_expand/words/methods/strings.rs b/src/lib/parser/shell_expand/words/methods/strings.rs index c6acd7aa223cbbc128b6967783fefdc06789b6cd..f2e38ac9411f50732fc5326e56d91764da329155 100644 --- a/src/lib/parser/shell_expand/words/methods/strings.rs +++ b/src/lib/parser/shell_expand/words/methods/strings.rs @@ -7,16 +7,10 @@ use super::{ }; use parser::assignments::is_array; use regex::Regex; -use shell::plugins::methods::{self, MethodArguments, StringMethodPlugins}; use small; use std::path::Path; -use sys; use unicode_segmentation::UnicodeSegmentation; -lazy_static! { - static ref STRING_METHODS: StringMethodPlugins = methods::collect(); -} - pub(crate) fn unescape(input: &str) -> Result<small::String, &'static str> { let mut check = false; let mut out = small::String::with_capacity(input.len()); @@ -303,8 +297,6 @@ impl<'a> StringMethod<'a> { let second_array = pattern.array(); let first_maybe: Option<String> = if first_str != "" { Some(first_str.to_string()) - } else if first_str == "" { - None } else { None }; @@ -339,36 +331,9 @@ impl<'a> StringMethod<'a> { } }; } - method => { - if sys::is_root() { - eprintln!("ion: root is not allowed to execute plugins"); - return; - } - - let pattern = pattern.array().collect::<Vec<_>>(); - let args = if variable.starts_with('@') || is_array(variable) { - MethodArguments::Array( - expand_string(variable, expand, false).into_vec(), - pattern, - ) - } else if let Some(value) = expand.string(variable, false) { - MethodArguments::StringArg(value, pattern) - } else if is_expression(variable) { - let expanded = expand_string(variable, expand, false); - match expanded.len() { - 0 => MethodArguments::NoArgs, - 1 => MethodArguments::StringArg(expanded[0].clone(), pattern), - _ => MethodArguments::Array(expanded.into_vec(), pattern), - } - } else { - MethodArguments::NoArgs - }; - - match STRING_METHODS.execute(method, args) { - Ok(Some(string)) => output.push_str(&string), - Ok(None) => (), - Err(why) => eprintln!("ion: method plugin: {}", why), - } + _ => { + eprintln!("ion: method namespace not found"); + return; } } } diff --git a/src/lib/parser/statement/splitter.rs b/src/lib/parser/statement/splitter.rs index 5828867db0d22edea7eaad5275389536805b584f..8805481009047be1673fe62c5dc5a59b6938e023 100644 --- a/src/lib/parser/statement/splitter.rs +++ b/src/lib/parser/statement/splitter.rs @@ -313,12 +313,10 @@ impl<'a> Iterator for StatementSplitter<'a> { } b' ' if else_found => { let output = &self.data[else_pos..self.read - 1].trim(); - if !output.is_empty() { - if "if" != *output { - self.read = else_pos; - self.flags.remove(Flags::AND | Flags::OR); - return Some(Ok(StatementVariant::Default("else"))); - } + if !output.is_empty() && "if" != *output { + self.read = else_pos; + self.flags.remove(Flags::AND | Flags::OR); + return Some(Ok(StatementVariant::Default("else"))); } else_found = false; } diff --git a/src/lib/shell/assignments.rs b/src/lib/shell/assignments.rs index 64fb3a349bebe1416cb6cd0ed591e5a59e1a2015..3c98c2e88d441a7f1ca600b230205c03ea338e5e 100644 --- a/src/lib/shell/assignments.rs +++ b/src/lib/shell/assignments.rs @@ -360,7 +360,7 @@ impl VariableStore for Shell { }; let action: Box< - Fn(f64) -> f64, + dyn Fn(f64) -> f64, > = match operator { Operator::Add => Box::new(|src| src + value), Operator::Divide => Box::new(|src| src / value), @@ -447,11 +447,11 @@ impl VariableStore for Shell { match self.variables.get_mut(key.name) { Some(VariableType::HashMap(hmap)) => { hmap.entry(index.clone()) - .or_insert(VariableType::Str(value)); + .or_insert_with(|| VariableType::Str(value)); } Some(VariableType::BTreeMap(bmap)) => { bmap.entry(index.clone()) - .or_insert(VariableType::Str(value)); + .or_insert_with(|| VariableType::Str(value)); } Some(VariableType::Array(array)) => { let index_num = match index.parse::<usize>() { diff --git a/src/lib/shell/binary/readln.rs b/src/lib/shell/binary/readln.rs index 91ba2fcbfa0385b358a4f309b24a99ef57cffbbd..d3a8a443d9ae7744ac4b09a18d241c55991334c2 100644 --- a/src/lib/shell/binary/readln.rs +++ b/src/lib/shell/binary/readln.rs @@ -21,7 +21,7 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> { // Collect each result into a vector to avoid borrowing issues. .collect::<Vec<types::Str>>(); - loop { + { let prompt = handle_prompt(shell.prompt()).unwrap(); let vars = &shell.variables; let builtins = &shell.builtins; @@ -124,7 +124,7 @@ pub(crate) fn readln(shell: &mut Shell) -> Option<String> { // Handles Ctrl + C Err(ref err) if err.kind() == ErrorKind::Interrupted => return None, // Handles Ctrl + D - Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => break, + Err(ref err) if err.kind() == ErrorKind::UnexpectedEof => (), Err(err) => { eprintln!("ion: liner: {}", err); return None; diff --git a/src/lib/shell/mod.rs b/src/lib/shell/mod.rs index 08d7a44eba9e8d470d53bbc1784b390d8efe2edc..555d89625b0207738a3c6c255bb053d424d8ff9c 100644 --- a/src/lib/shell/mod.rs +++ b/src/lib/shell/mod.rs @@ -12,7 +12,6 @@ pub mod fork_function; mod history; mod job; pub(crate) mod pipe_exec; -pub(crate) mod plugins; pub(crate) mod signals; pub mod status; pub mod variables; diff --git a/src/lib/shell/plugins/library_iter/mod.rs b/src/lib/shell/plugins/library_iter/mod.rs deleted file mode 100644 index 2c5a0f74d3e884913d0250e0c67399ad9e3c0317..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/library_iter/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(target_os = "redox")] -mod redox; -// #[cfg(target_os = "redox")] -// pub(crate) use self::redox::*; - -#[cfg(all(unix, not(target_os = "redox")))] -mod unix; -#[cfg(all(unix, not(target_os = "redox")))] -pub(crate) use self::unix::*; diff --git a/src/lib/shell/plugins/library_iter/redox.rs b/src/lib/shell/plugins/library_iter/redox.rs deleted file mode 100644 index 72745aab3365f273ddbdb3b88b7ef258083507b5..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/library_iter/redox.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::fs::ReadDir; -use types; - -pub(crate) struct Library; - -/// Grabs all `Library` entries found within a given directory -pub(crate) struct LibraryIterator { - directory: ReadDir, -} - -impl LibraryIterator { - pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } } -} - -impl Iterator for LibraryIterator { - // The `Identifier` is the name of the namespace for which values may be pulled. - // The `Library` is a handle to dynamic library loaded into memory. - type Item = (types::Str, Library); - - fn next(&mut self) -> Option<(types::Str, Library)> { None } -} diff --git a/src/lib/shell/plugins/library_iter/unix.rs b/src/lib/shell/plugins/library_iter/unix.rs deleted file mode 100644 index 45b985bf29cd84b165ee2b7016eb464e5e851ded..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/library_iter/unix.rs +++ /dev/null @@ -1,52 +0,0 @@ -use libloading::Library; -use std::fs::ReadDir; -use types; - -/// Grabs all `Library` entries found within a given directory -pub(crate) struct LibraryIterator { - directory: ReadDir, -} - -impl LibraryIterator { - pub(crate) fn new(directory: ReadDir) -> LibraryIterator { LibraryIterator { directory } } -} - -impl Iterator for LibraryIterator { - // The `Identifier` is the name of the namespace for which values may be pulled. - // The `Library` is a handle to dynamic library loaded into memory. - type Item = (types::Str, Library); - - fn next(&mut self) -> Option<(types::Str, Library)> { - while let Some(entry) = self.directory.next() { - let entry = if let Ok(entry) = entry { - entry - } else { - continue; - }; - let path = entry.path(); - // An entry is a library if it is a file with a 'so' extension. - if path.is_file() && path.extension().map_or(false, |ext| ext == "so") { - // The identifier will be the file name of that file, without the extension. - let identifier = match path.file_stem().unwrap().to_str() { - Some(filename) => types::Str::from(filename), - None => { - eprintln!("ion: namespace plugin has invalid filename"); - continue; - } - }; - - // This will attempt to load the library into memory. - match Library::new(path.as_os_str()) { - Ok(library) => return Some((identifier, library)), - Err(why) => { - eprintln!("ion: failed to load library: {:?}, {:?}", path, why); - continue; - } - } - } else { - continue; - } - } - None - } -} diff --git a/src/lib/shell/plugins/methods/mod.rs b/src/lib/shell/plugins/methods/mod.rs deleted file mode 100644 index 286d5815aedba6635c57f138c25635754fa83cdc..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/methods/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(target_os = "redox")] -mod redox; -#[cfg(target_os = "redox")] -pub(crate) use self::redox::*; - -#[cfg(all(unix, not(target_os = "redox")))] -mod unix; -#[cfg(all(unix, not(target_os = "redox")))] -pub(crate) use self::unix::*; diff --git a/src/lib/shell/plugins/methods/redox.rs b/src/lib/shell/plugins/methods/redox.rs deleted file mode 100644 index 655c2d143038346d29867ddf608d12cc637904f7..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/methods/redox.rs +++ /dev/null @@ -1,28 +0,0 @@ -use super::super::StringError; -use small; - -pub(crate) enum MethodArguments { - StringArg(small::String, Vec<small::String>), - Array(Vec<small::String>, Vec<small::String>), - NoArgs, -} - -pub(crate) struct StringMethodPlugins; - -impl StringMethodPlugins { - pub(crate) fn execute( - &self, - _function: &str, - _arguments: MethodArguments, - ) -> Result<Option<small::String>, StringError> { - Ok(None) - } - - pub(crate) fn new() -> StringMethodPlugins { StringMethodPlugins } -} - -/// Collects all dynamically-loaded namespaces and their associated symbols all at once. -/// -/// This function is meant to be called with `lazy_static` to ensure that there isn't a -/// cost to collecting all this information when the shell never uses it in the first place! -pub(crate) fn collect() -> StringMethodPlugins { StringMethodPlugins::new() } diff --git a/src/lib/shell/plugins/methods/unix.rs b/src/lib/shell/plugins/methods/unix.rs deleted file mode 100644 index 65720c35f3d0ab4b5f44408813dc38bb08871ad2..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/methods/unix.rs +++ /dev/null @@ -1,246 +0,0 @@ -use super::super::{config_dir, LibraryIterator, StringError}; -use fnv::FnvHashMap; -use libloading::{os::unix::Symbol as RawSymbol, Library, Symbol}; -use small; -use std::{ffi::CString, fs::read_dir, mem::forget, os::raw::c_char, ptr, slice, str}; -use types; - -/// Either one or the other will be set. Optional status can be conveyed by setting the -/// corresponding field to `NULL`. Libraries importing this structure should check for nullness. -#[repr(C)] -pub(crate) struct RawMethodArguments { - key_ptr: *mut c_char, - key_array_ptr: *mut *mut c_char, - args_ptr: *mut *mut c_char, - key_len: usize, - args_len: usize, -} - -pub(crate) enum MethodArguments { - StringArg(small::String, Vec<small::String>), - Array(Vec<small::String>, Vec<small::String>), - NoArgs, -} - -impl From<MethodArguments> for RawMethodArguments { - fn from(arg: MethodArguments) -> RawMethodArguments { - match arg { - MethodArguments::StringArg(string, args) => { - let args_len = args.len(); - let mut args = args - .iter() - .map(|x| unsafe { - CString::from_vec_unchecked(x.as_bytes().to_owned()).into_raw() - }) - .collect::<Vec<*mut c_char>>(); - args.shrink_to_fit(); - let args_ptr = args.as_mut_ptr(); - forget(args); - - RawMethodArguments { - key_ptr: unsafe { - CString::from_vec_unchecked(string.as_bytes().to_owned()).into_raw() - }, - key_array_ptr: ptr::null_mut(), - args_ptr, - key_len: 1, - args_len, - } - } - MethodArguments::Array(array, args) => { - let key_len = array.len(); - let mut key_array = array - .iter() - .map(|x| unsafe { - CString::from_vec_unchecked(x.as_bytes().to_owned()).into_raw() - }) - .collect::<Vec<*mut c_char>>(); - let key_array_ptr = key_array.as_mut_ptr(); - forget(key_array); - - let args_len = args.len(); - let mut args = args - .iter() - .map(|x| unsafe { - CString::from_vec_unchecked(x.as_bytes().to_owned()).into_raw() - }) - .collect::<Vec<*mut c_char>>(); - args.shrink_to_fit(); - let args_ptr = args.as_mut_ptr(); - forget(args); - - RawMethodArguments { - key_ptr: ptr::null_mut(), - key_array_ptr, - args_ptr, - key_len, - args_len, - } - } - MethodArguments::NoArgs => RawMethodArguments { - key_ptr: ptr::null_mut(), - key_array_ptr: ptr::null_mut(), - args_ptr: ptr::null_mut(), - key_len: 0, - args_len: 0, - }, - } - } -} - -/// Contains all dynamically-loaded libraries and their symbols. -/// -/// The purpose of the structure is to: A) hold a `Library` handle to the dynamically-loaded -/// plugin to ensure that the plugin remains loaded in memory, and it's contained symbols -/// remain validly-executable; and B) holds a map of functions that may be executed within -/// the namespace. -pub(crate) struct StringMethodPlugins { - #[allow(dead_code)] - /// Contains all of the loaded libraries from whence the symbols were - /// obtained. - libraries: Vec<Library>, - /// A map of all the symbols that were collected from the above libraries. - pub symbols: - FnvHashMap<types::Str, RawSymbol<unsafe extern "C" fn(RawMethodArguments) -> *mut c_char>>, -} - -impl StringMethodPlugins { - /// Attempts to execute a function within a dynamically-loaded namespace. - /// - /// If the function exists, it is executed, and it's return value is then converted into a - /// proper Rusty type. - pub(crate) fn execute( - &self, - function: &str, - arguments: MethodArguments, - ) -> Result<Option<String>, StringError> { - let func = self - .symbols - .get(function) - .ok_or_else(|| StringError::FunctionMissing(function.into()))?; - unsafe { - let data = (*func)(RawMethodArguments::from(arguments)); - if data.is_null() { - Ok(None) - } else { - match CString::from_raw(data as *mut c_char).to_str() { - Ok(string) => Ok(Some(string.to_owned())), - Err(_) => Err(StringError::UTF8Result), - } - } - } - } - - pub(crate) fn load(&mut self, library: Library) -> Result<(), StringError> { - unsafe { - { - // The `index` function contains a list of functions provided by the library. - let index: Symbol<unsafe extern "C" fn() -> *const u8> = - library.get(b"index\0").map_err(StringError::SymbolErr)?; - let symbol_list = index(); - - // Yet we need to convert the raw stream of binary into a native slice if we - // want to properly reason about the contents of said aforementioned stream. - let (mut start, mut counter) = (0, 0usize); - let symbol_list: &[u8] = { - let mut byte = *symbol_list.offset(0); - while byte != b'\0' { - counter += 1; - byte = *symbol_list.offset(counter as isize); - } - slice::from_raw_parts(symbol_list, counter) - }; - counter = 0; - - // Each function symbol is delimited by spaces, so this will slice our - // newly-created byte slice on each space, and then attempt to load and - // store that symbol for future use. - for &byte in symbol_list { - if byte == b' ' { - if start == counter { - start += 1; - } else { - // Grab a slice and ensure that the name of the function is UTF-8. - let slice = &symbol_list[start..counter]; - let identifier = str::from_utf8(slice) - .map(types::Str::from) - .map_err(|_| StringError::UTF8Function)?; - - // To obtain the symbol, we need to create a new `\0`-ended byte array. - // TODO: There's no need to use a vector here. An array will do fine. - let mut symbol = Vec::new(); - symbol.reserve_exact(slice.len() + 1); - symbol.extend_from_slice(slice); - symbol.push(b'\0'); - - // Then attempt to load that symbol from the dynamic library. - let symbol: Symbol< - unsafe extern "C" fn(RawMethodArguments) -> *mut c_char, - > = library - .get(symbol.as_slice()) - .map_err(StringError::SymbolErr)?; - - // And finally add the name of the function and it's function into the - // map. - self.symbols.insert(identifier, symbol.into_raw()); - start = counter + 1; - } - } - counter += 1; - } - - // Identical to the logic in the loop above. Handles any unparsed stragglers - // that have been left over. - if counter != start { - let slice = &symbol_list[start..]; - let identifier = str::from_utf8(slice) - .map(types::Str::from) - .map_err(|_| StringError::UTF8Function)?; - let mut symbol = Vec::new(); - symbol.reserve_exact(slice.len() + 1); - symbol.extend_from_slice(slice); - symbol.push(b'\0'); - let symbol: Symbol< - unsafe extern "C" fn(RawMethodArguments) -> *mut c_char, - > = library - .get(symbol.as_slice()) - .map_err(StringError::SymbolErr)?; - self.symbols.insert(identifier, symbol.into_raw()); - } - } - - self.libraries.push(library); - Ok(()) - } - } - - pub(crate) fn new() -> StringMethodPlugins { - StringMethodPlugins { - libraries: Vec::new(), - symbols: FnvHashMap::default(), - } - } -} - -/// Collects all dynamically-loaded namespaces and their associated symbols all at once. -/// -/// This function is meant to be called with `lazy_static` to ensure that there isn't a -/// cost to collecting all this information when the shell never uses it in the first place! -pub(crate) fn collect() -> StringMethodPlugins { - let mut methods = StringMethodPlugins::new(); - if let Some(mut path) = config_dir() { - path.push("methods"); - path.push("strings"); - match read_dir(&path).map(LibraryIterator::new) { - Ok(iterator) => for (_, library) in iterator { - if let Err(why) = methods.load(library) { - eprintln!("ion: string method error: {}", why); - } - }, - Err(why) => { - eprintln!("ion: unable to read methods plugin directory: {}", why); - } - } - } - methods -} diff --git a/src/lib/shell/plugins/mod.rs b/src/lib/shell/plugins/mod.rs deleted file mode 100644 index b2d391848f1b2c948b0ba064e17fac4fd93edc8a..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -mod library_iter; -pub mod methods; -pub mod namespaces; -mod string; - -#[cfg(not(target_os = "redox"))] -pub(crate) use self::library_iter::*; -pub(crate) use self::string::StringError; - -use std::path::PathBuf; -use xdg::BaseDirectories; - -pub(crate) fn config_dir() -> Option<PathBuf> { - match BaseDirectories::with_prefix("ion") { - Ok(base_dirs) => match base_dirs.create_config_directory("plugins") { - Ok(path) => Some(path), - Err(err) => { - eprintln!("ion: unable to create config directory: {:?}", err); - None - } - }, - Err(err) => { - eprintln!("ion: unable to get config directory: {:?}", err); - None - } - } -} diff --git a/src/lib/shell/plugins/namespaces/mod.rs b/src/lib/shell/plugins/namespaces/mod.rs deleted file mode 100644 index 286d5815aedba6635c57f138c25635754fa83cdc..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/namespaces/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(target_os = "redox")] -mod redox; -#[cfg(target_os = "redox")] -pub(crate) use self::redox::*; - -#[cfg(all(unix, not(target_os = "redox")))] -mod unix; -#[cfg(all(unix, not(target_os = "redox")))] -pub(crate) use self::unix::*; diff --git a/src/lib/shell/plugins/namespaces/redox.rs b/src/lib/shell/plugins/namespaces/redox.rs deleted file mode 100644 index 787565379d67e003d15990da133565c612d30b29..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/namespaces/redox.rs +++ /dev/null @@ -1,19 +0,0 @@ -use fnv::FnvHashMap; - -use super::super::StringError; -use types; - -pub(crate) struct StringNamespace; - -impl StringNamespace { - pub(crate) fn execute(&self, _function: types::Str) -> Result<Option<types::Str>, StringError> { - Ok(None) - } - - pub(crate) fn new() -> Result<StringNamespace, StringError> { Ok(StringNamespace) } -} - -pub(crate) fn collect() -> FnvHashMap<types::Str, StringNamespace> { - eprintln!("ion: Redox doesn't support plugins yet"); - FnvHashMap::default() -} diff --git a/src/lib/shell/plugins/namespaces/unix.rs b/src/lib/shell/plugins/namespaces/unix.rs deleted file mode 100644 index 9e4d5e33853ad2bc646a595c31b00ba5777cc357..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/namespaces/unix.rs +++ /dev/null @@ -1,156 +0,0 @@ -use super::super::{config_dir, LibraryIterator, StringError}; -use fnv::FnvHashMap; -use libloading::{os::unix::Symbol as RawSymbol, Library, Symbol}; -use std::{ffi::CString, fs::read_dir, os::raw::c_char, slice, str}; -use types; - -/// A dynamically-loaded string namespace from an external library. -/// -/// The purpose of the structure is to: A) hold a `Library` handle to the dynamically-loaded -/// plugin to ensure that the plugin remains loaded in memory, and it's contained symbols -/// remain validly-executable; and B) holds a map of functions that may be executed within -/// the namespace. -pub(crate) struct StringNamespace { - /// This field, although never used directly, is required to exist in order to ensure - /// that each element in the `symbols` field remains relevant. When Rust can support - /// self-referencing lifetimes, we won't need to hold raw symbols anymore. - #[allow(dead_code)] - library: Library, - /// A hash map of symbols collected from the `Library` stored in the `library` field. - /// These are considered raw because they have their lifetimes erased. - symbols: FnvHashMap<types::Str, RawSymbol<unsafe extern "C" fn() -> *mut c_char>>, -} - -impl StringNamespace { - /// Attempts to execute a function within a dynamically-loaded namespace. - /// - /// If the function exists, it is executed, and it's return value is then converted into a - /// proper Rusty type. - pub(crate) fn execute(&self, function: types::Str) -> Result<Option<String>, StringError> { - let func = self - .symbols - .get(&function) - .ok_or_else(|| StringError::FunctionMissing(function.clone()))?; - unsafe { - let data = (*func)(); - if data.is_null() { - Ok(None) - } else { - match CString::from_raw(data as *mut c_char).to_str() { - Ok(string) => Ok(Some(string.to_owned())), - Err(_) => Err(StringError::UTF8Result), - } - } - } - } - - pub(crate) fn new(library: Library) -> Result<StringNamespace, StringError> { - unsafe { - let mut symbols = FnvHashMap::default(); - { - // The `index` function contains a list of functions provided by the library. - let index: Symbol<unsafe extern "C" fn() -> *const u8> = - library.get(b"index\0").map_err(StringError::SymbolErr)?; - let symbol_list = index(); - - // Yet we need to convert the raw stream of binary into a native slice if we - // want to properly reason about the contents of said aforementioned stream. - let (mut start, mut counter) = (0, 0usize); - let symbol_list: &[u8] = { - let mut byte = *symbol_list.offset(0); - while byte != b'\0' { - counter += 1; - byte = *symbol_list.offset(counter as isize); - } - slice::from_raw_parts(symbol_list, counter) - }; - counter = 0; - - // Each function symbol is delimited by spaces, so this will slice our - // newly-created byte slice on each space, and then attempt to load and - // store that symbol for future use. - for &byte in symbol_list { - if byte == b' ' { - if start == counter { - start += 1; - } else { - // Grab a slice and ensure that the name of the function is UTF-8. - let slice = &symbol_list[start..counter]; - let identifier = str::from_utf8(slice) - .map(types::Str::from) - .map_err(|_| StringError::UTF8Function)?; - - // To obtain the symbol, we need to create a new `\0`-ended byte array. - // TODO: There's no need to use a vector here. An array will do fine. - let mut symbol = Vec::new(); - symbol.reserve_exact(slice.len() + 1); - symbol.extend_from_slice(slice); - symbol.push(b'\0'); - - // Then attempt to load that symbol from the dynamic library. - let symbol: Symbol< - unsafe extern "C" fn() -> *mut c_char, - > = library - .get(symbol.as_slice()) - .map_err(StringError::SymbolErr)?; - - // And finally add the name of the function and it's function into the - // map. - symbols.insert(identifier, symbol.into_raw()); - start = counter + 1; - } - } - counter += 1; - } - - // Identical to the logic in the loop above. Handles any unparsed stragglers - // that have been left over. - if counter != start { - let slice = &symbol_list[start..]; - let identifier = str::from_utf8(slice) - .map(types::Str::from) - .map_err(|_| StringError::UTF8Function)?; - let mut symbol = Vec::new(); - symbol.reserve_exact(slice.len() + 1); - symbol.extend_from_slice(slice); - symbol.push(b'\0'); - let symbol: Symbol<unsafe extern "C" fn() -> *mut c_char> = library - .get(symbol.as_slice()) - .map_err(StringError::SymbolErr)?; - symbols.insert(identifier, symbol.into_raw()); - } - } - - Ok(StringNamespace { library, symbols }) - } - } -} - -/// Collects all dynamically-loaded namespaces and their associated symbols all at once. -/// -/// This function is meant to be called with `lazy_static` to ensure that there isn't a -/// cost to collecting all this information when the shell never uses it in the first place! -pub(crate) fn collect() -> FnvHashMap<types::Str, StringNamespace> { - let mut hashmap = FnvHashMap::default(); - if let Some(mut path) = config_dir() { - path.push("namespaces"); - path.push("strings"); - match read_dir(&path).map(LibraryIterator::new) { - Ok(iterator) => for (identifier, library) in iterator { - match StringNamespace::new(library) { - Ok(namespace) => { - hashmap.insert(identifier, namespace); - } - Err(why) => { - eprintln!("ion: string namespace error: {}", why); - continue; - } - } - }, - Err(why) => { - eprintln!("ion: unable to read namespaces plugin directory: {}", why); - } - } - } - hashmap -} diff --git a/src/lib/shell/plugins/string.rs b/src/lib/shell/plugins/string.rs deleted file mode 100644 index a587ec0baea11cc620b43f5f6772a81042304fe5..0000000000000000000000000000000000000000 --- a/src/lib/shell/plugins/string.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{ - fmt::{self, Display, Formatter}, - io, -}; -use types; - -#[derive(Debug)] -/// A possible error that can be caused when attempting to obtain or execute a -/// function that is supposed to return a string from across the FFI boundaries. -pub(crate) enum StringError { - /// This occurs when a symbol could not be loaded from the library in question. It is an - /// error that infers that the problem is with the plugin, not Ion itself. - SymbolErr(io::Error), - /// Function names must be valid UTF-8. If they aren't something's wrong - /// with the plugin. - UTF8Function, - /// The result from a plugin must be valid UTF-8. If it isn't, the plugin's - /// bad. - UTF8Result, - /// This infers that the user called a function that doesn't exist in the library. Bad - /// user, bad. - FunctionMissing(types::Str), -} - -impl Display for StringError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match *self { - StringError::SymbolErr(ref error) => write!(f, "symbol error: {}", error), - StringError::UTF8Function => write!(f, "function has invalid UTF-8 name"), - StringError::UTF8Result => write!(f, "result is not valid UTF-8"), - StringError::FunctionMissing(ref func) => { - write!(f, "{} doesn't exist in namespace", func) - } - } - } -} diff --git a/src/lib/shell/variables/mod.rs b/src/lib/shell/variables/mod.rs index 6a71f5095cb858b4e0a67edf7948e0ba33c6565d..818abdc7d5c364003f54d1301eb6f3bbf8bc91a7 100644 --- a/src/lib/shell/variables/mod.rs +++ b/src/lib/shell/variables/mod.rs @@ -2,7 +2,6 @@ use super::{ colors::Colors, directory_stack::DirectoryStack, flow_control::Function, - plugins::namespaces::{self, StringNamespace}, status::{FAILURE, SUCCESS}, }; use fnv::FnvHashMap; @@ -14,15 +13,11 @@ use std::{ mem, ops::{Deref, DerefMut}, }; -use sys::{self, env as sys_env, geteuid, getpid, getuid, is_root, variables as self_sys}; +use sys::{self, env as sys_env, geteuid, getpid, getuid, variables as self_sys}; use types::{self, Array}; use unicode_segmentation::UnicodeSegmentation; use xdg::BaseDirectories; -lazy_static! { - static ref STRING_NAMESPACES: FnvHashMap<types::Str, StringNamespace> = namespaces::collect(); -} - #[derive(Clone, Debug, PartialEq)] pub enum VariableType { Str(types::Str), @@ -244,7 +239,10 @@ impl Default for Variables { ); // Initialize the HOST variable - env::set_var("HOST", &self_sys::get_host_name().unwrap_or("?".to_owned())); + env::set_var( + "HOST", + &self_sys::get_host_name().unwrap_or_else(|| "?".to_owned()), + ); Variables { flags: 0, @@ -257,8 +255,6 @@ impl Default for Variables { } } -const PLUGIN: u8 = 1; - impl Variables { pub fn new_scope(&mut self, namespace: bool) { self.current += 1; @@ -497,36 +493,9 @@ impl Variables { .map(|s| T::from(VariableType::Str(s.into()))), } } - Some((_, variable)) => { - if is_root() { - eprintln!("ion: root is not allowed to execute plugins"); - return None; - } - - if !self.has_plugin_support() { - eprintln!( - "ion: plugins are disabled. Considering enabling them with `let \ - NS_PLUGINS = 1`" - ); - return None; - } - - // Attempt to obtain the given namespace from our lazily-generated map of - // namespaces. - if let Some(namespace) = STRING_NAMESPACES.get(name) { - // Attempt to execute the given function from that namespace, and map it's - // results. - match namespace.execute(variable.into()) { - Ok(value) => value.map(|s| T::from(VariableType::Str(s.into()))), - Err(why) => { - eprintln!("ion: string namespace error: {}: {}", name, why); - None - } - } - } else { - eprintln!("ion: unsupported namespace: '{}'", name); - None - } + Some((..)) => { + eprintln!("ion: unsupported namespace: '{}'", name); + None } } } else if specified_type == TypeId::of::<types::Alias>() { @@ -615,7 +584,7 @@ impl Variables { handle_type!(hashmap_action, types::HashMap, HashMap); handle_type!(function_action, Function, Function); - let mut upper_action = { + let upper_action = { let action = match self.get_mut(&name) { Some(VariableType::Str(ref mut str_)) => string_action(name, &var, str_), Some(VariableType::Alias(ref mut alias)) => alias_action(name, &var, alias), @@ -780,12 +749,6 @@ impl Variables { } SUCCESS } - - pub(crate) fn disable_plugins(&mut self) { self.flags &= !PLUGIN; } - - pub(crate) fn enable_plugins(&mut self) { self.flags |= PLUGIN; } - - pub(crate) fn has_plugin_support(&self) -> bool { self.flags & PLUGIN == PLUGIN } } #[cfg(test)] diff --git a/src/lib/types.rs b/src/lib/types.rs index 05826d50e3e66c28a48bf78af6cb628939fdf972..4cbcac3722445c97634b2d86121492c751ae78e3 100644 --- a/src/lib/types.rs +++ b/src/lib/types.rs @@ -59,6 +59,7 @@ macro_rules! array [ ( $($x:expr), *) => ({ let mut _arr = Array::new(); $(_arr.push($x.into());)* + #[allow(let_and_return)] _arr }) ];