Introduce the new error handling mechanism

* Fast error diagnosing (e.g., backtrace and code location)
* First-class POSIX errno (e.g., every error has an errno)
* Zero-overhead abstraction (e.g., no heap allocation for simple errors)
* Ergonomic grammar (e.g., providing convenient macros)
This commit is contained in:
Tate, Hongliang Tian 2019-10-05 14:21:15 +00:00 committed by Tate, Hongliang Tian
parent d8d51fcfd4
commit 1a365de08f
53 changed files with 1332 additions and 1142 deletions

2
src/libos/Cargo.lock generated

@ -2,7 +2,7 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "Occlum" name = "Occlum"
version = "0.0.1" version = "0.5.0"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "derive_builder 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",

@ -1,6 +1,6 @@
[package] [package]
name = "Occlum" name = "Occlum"
version = "0.0.1" version = "0.5.0"
[lib] [lib]
name = "occlum_rs" name = "occlum_rs"

@ -1,6 +1,22 @@
include ../sgxenv.mk include ../sgxenv.mk
RELEASE ?= 0 # Build LibOS in debug or release mode
LIBOS_RELEASE ?= 0
# The log level for LibOS
#
# There are five levels:
# 1 - error
# 2 - warn
# 3 - info
# 4 - debug
# 5 - trace
#
# By setting the log level to a specific value (say warn), all log messages
# whose levels are no greater than the value (error and warn <= warn) will
# be printed.
LIBOS_LOG ?= error
ONLY_REBUILD_BUILTIN ?= 0 ONLY_REBUILD_BUILTIN ?= 0
# The final and intermediate libraries # The final and intermediate libraries

@ -1,64 +1,47 @@
use super::*; use super::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::ffi::CString; use std::ffi::CString;
use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sgxfs::SgxFile; use std::sgxfs::SgxFile;
const LIBOS_CONFIG_PATH: &str = "./.occlum/build/Occlum.json.protected";
lazy_static! { lazy_static! {
pub static ref LIBOS_CONFIG: Config = { pub static ref LIBOS_CONFIG: Config = {
fn load_config(config_path: &str) -> Result<Config> {
let mut config_file = { let mut config_file = {
let config_file = match SgxFile::open_integrity_only(LIBOS_CONFIG_PATH) { let config_file =
Err(_) => panic!( SgxFile::open_integrity_only(config_path).map_err(|e| errno!(e))?;
"Failed to find or open Occlum's config file: {}",
LIBOS_CONFIG_PATH
),
Ok(file) => file,
};
let actual_mac = match config_file.get_mac() { let actual_mac = config_file.get_mac().map_err(|e| errno!(e))?;
Err(_) => panic!(
"Failed to get the MAC of Occlum's config file: {}",
LIBOS_CONFIG_PATH
),
Ok(mac) => mac,
};
let expected_mac = conf_get_hardcoded_file_mac(); let expected_mac = conf_get_hardcoded_file_mac();
if actual_mac != expected_mac { if actual_mac != expected_mac {
panic!( return_errno!(EINVAL, "unexpected file MAC");
"The MAC of Occlum's config file is not as expected: {}",
LIBOS_CONFIG_PATH
);
} }
config_file config_file
}; };
let config_json = { let config_json = {
let mut config_json = String::new(); let mut config_json = String::new();
config_file.read_to_string(&mut config_json).map_err(|_| { config_file
panic!( .read_to_string(&mut config_json)
"Failed to read from Occlum's config file: {}", .map_err(|e| errno!(e))?;
LIBOS_CONFIG_PATH
);
});
config_json config_json
}; };
let config_input: InputConfig = match serde_json::from_str(&config_json) { let config_input: InputConfig =
Err(_) => panic!( serde_json::from_str(&config_json).map_err(|e| errno!(e))?;
"Failed to parse JSON from Occlum's config file: {}", let config = Config::from_input(&config_input)
LIBOS_CONFIG_PATH .cause_err(|e| errno!(EINVAL, "invalid config JSON"))?;
), Ok(config)
Ok(config_input) => config_input, }
};
let config = match Config::from_input(&config_input) { let config_path = "./.occlum/build/Occlum.json.protected";
Err(_) => panic!( match load_config(config_path) {
"Found invalid config in Occlum's config file: {}", Err(e) => {
LIBOS_CONFIG_PATH error!("failed to load config: {}", e.backtrace());
), panic!();
}
Ok(config) => config, Ok(config) => config,
}; }
config
}; };
} }
@ -77,18 +60,17 @@ fn conf_get_hardcoded_file_mac() -> sgx_aes_gcm_128bit_tag_t {
mac mac
} }
fn parse_mac(mac_str: &str) -> Result<sgx_aes_gcm_128bit_tag_t, Error> { fn parse_mac(mac_str: &str) -> Result<sgx_aes_gcm_128bit_tag_t> {
let bytes_str_vec = { let bytes_str_vec = {
let bytes_str_vec: Vec<&str> = mac_str.split("-").collect(); let bytes_str_vec: Vec<&str> = mac_str.split("-").collect();
if bytes_str_vec.len() != 16 { if bytes_str_vec.len() != 16 {
return errno!(EINVAL, "The length or format of MAC string is invalid"); return_errno!(EINVAL, "The length or format of MAC string is invalid");
} }
bytes_str_vec bytes_str_vec
}; };
let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default(); let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default();
for (byte_i, byte_str) in bytes_str_vec.iter().enumerate() { for (byte_i, byte_str) in bytes_str_vec.iter().enumerate() {
mac[byte_i] = u8::from_str_radix(byte_str, 16) mac[byte_i] = u8::from_str_radix(byte_str, 16).map_err(|e| errno!(e))?;
.map_err(|_| Error::new(Errno::EINVAL, "The format of MAC string is invalid"))?;
} }
Ok(mac) Ok(mac)
} }
@ -136,7 +118,7 @@ pub struct ConfigMountOptions {
} }
impl Config { impl Config {
fn from_input(input: &InputConfig) -> Result<Config, Error> { fn from_input(input: &InputConfig) -> Result<Config> {
let vm = ConfigVM::from_input(&input.vm)?; let vm = ConfigVM::from_input(&input.vm)?;
let process = ConfigProcess::from_input(&input.process)?; let process = ConfigProcess::from_input(&input.process)?;
let env = { let env = {
@ -163,14 +145,14 @@ impl Config {
} }
impl ConfigVM { impl ConfigVM {
fn from_input(input: &InputConfigVM) -> Result<ConfigVM, Error> { fn from_input(input: &InputConfigVM) -> Result<ConfigVM> {
let user_space_size = parse_memory_size(&input.user_space_size)?; let user_space_size = parse_memory_size(&input.user_space_size)?;
Ok(ConfigVM { user_space_size }) Ok(ConfigVM { user_space_size })
} }
} }
impl ConfigProcess { impl ConfigProcess {
fn from_input(input: &InputConfigProcess) -> Result<ConfigProcess, Error> { fn from_input(input: &InputConfigProcess) -> Result<ConfigProcess> {
let default_stack_size = parse_memory_size(&input.default_stack_size)?; let default_stack_size = parse_memory_size(&input.default_stack_size)?;
let default_heap_size = parse_memory_size(&input.default_heap_size)?; let default_heap_size = parse_memory_size(&input.default_heap_size)?;
let default_mmap_size = parse_memory_size(&input.default_mmap_size)?; let default_mmap_size = parse_memory_size(&input.default_mmap_size)?;
@ -183,7 +165,7 @@ impl ConfigProcess {
} }
impl ConfigMount { impl ConfigMount {
fn from_input(input: &InputConfigMount) -> Result<ConfigMount, Error> { fn from_input(input: &InputConfigMount) -> Result<ConfigMount> {
const ALL_FS_TYPES: [&str; 3] = ["sefs", "hostfs", "ramfs"]; const ALL_FS_TYPES: [&str; 3] = ["sefs", "hostfs", "ramfs"];
let type_ = match input.type_.as_str() { let type_ = match input.type_.as_str() {
@ -191,13 +173,13 @@ impl ConfigMount {
"hostfs" => ConfigMountFsType::TYPE_HOSTFS, "hostfs" => ConfigMountFsType::TYPE_HOSTFS,
"ramfs" => ConfigMountFsType::TYPE_RAMFS, "ramfs" => ConfigMountFsType::TYPE_RAMFS,
_ => { _ => {
return errno!(EINVAL, "Unsupported file system type"); return_errno!(EINVAL, "Unsupported file system type");
} }
}; };
let target = { let target = {
let target = PathBuf::from(&input.target); let target = PathBuf::from(&input.target);
if !target.starts_with("/") { if !target.starts_with("/") {
return errno!(EINVAL, "Target must be an absolute path"); return_errno!(EINVAL, "Target must be an absolute path");
} }
target target
}; };
@ -213,12 +195,12 @@ impl ConfigMount {
} }
impl ConfigMountOptions { impl ConfigMountOptions {
fn from_input(input: &InputConfigMountOptions) -> Result<ConfigMountOptions, Error> { fn from_input(input: &InputConfigMountOptions) -> Result<ConfigMountOptions> {
let (integrity_only, mac) = if !input.integrity_only { let (integrity_only, mac) = if !input.integrity_only {
(false, None) (false, None)
} else { } else {
if input.mac.is_none() { if input.mac.is_none() {
return errno!(EINVAL, "MAC is expected"); return_errno!(EINVAL, "MAC is expected");
} }
(true, Some(parse_mac(&input.mac.as_ref().unwrap())?)) (true, Some(parse_mac(&input.mac.as_ref().unwrap())?))
}; };
@ -229,7 +211,7 @@ impl ConfigMountOptions {
} }
} }
fn parse_memory_size(mem_str: &str) -> Result<usize, Error> { fn parse_memory_size(mem_str: &str) -> Result<usize> {
const UNIT2FACTOR: [(&str, usize); 5] = [ const UNIT2FACTOR: [(&str, usize); 5] = [
("KB", 1024), ("KB", 1024),
("MB", 1024 * 1024), ("MB", 1024 * 1024),
@ -242,13 +224,13 @@ fn parse_memory_size(mem_str: &str) -> Result<usize, Error> {
let (unit, factor) = UNIT2FACTOR let (unit, factor) = UNIT2FACTOR
.iter() .iter()
.position(|(unit, _)| mem_str.ends_with(unit)) .position(|(unit, _)| mem_str.ends_with(unit))
.ok_or_else(|| Error::new(Errno::EINVAL, "No unit")) .ok_or_else(|| errno!(EINVAL, "No unit"))
.map(|unit_i| &UNIT2FACTOR[unit_i])?; .map(|unit_i| &UNIT2FACTOR[unit_i])?;
let number = match mem_str[0..mem_str.len() - unit.len()] let number = match mem_str[0..mem_str.len() - unit.len()]
.trim() .trim()
.parse::<usize>() .parse::<usize>()
{ {
Err(_) => return errno!(EINVAL, "No number"), Err(_) => return_errno!(EINVAL, "No number"),
Ok(number) => number, Ok(number) => number,
}; };
Ok(number * factor) Ok(number * factor)

@ -9,10 +9,13 @@ const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum.signed.so";
#[no_mangle] #[no_mangle]
pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char) -> i32 { pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char) -> i32 {
// Init the log infrastructure first so that log messages will be printed afterwards
util::log::init(); util::log::init();
let (path, args) = match parse_arguments(path_buf, argv) { let (path, args) = match parse_arguments(path_buf, argv) {
Ok(path_and_args) => path_and_args, Ok(path_and_args) => path_and_args,
Err(_) => { Err(e) => {
error!("invalid arguments for LibOS: {}", e.backtrace());
return EXIT_STATUS_INTERNAL_ERROR; return EXIT_STATUS_INTERNAL_ERROR;
} }
}; };
@ -24,7 +27,10 @@ pub extern "C" fn libos_boot(path_buf: *const c_char, argv: *const *const c_char
panic::catch_unwind(|| { panic::catch_unwind(|| {
backtrace::__rust_begin_short_backtrace(|| match do_boot(&path, &args) { backtrace::__rust_begin_short_backtrace(|| match do_boot(&path, &args) {
Ok(()) => 0, Ok(()) => 0,
Err(err) => EXIT_STATUS_INTERNAL_ERROR, Err(e) => {
error!("failed to boot up LibOS: {}", e.backtrace());
EXIT_STATUS_INTERNAL_ERROR
}
}) })
}) })
.unwrap_or(EXIT_STATUS_INTERNAL_ERROR) .unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
@ -36,7 +42,10 @@ pub extern "C" fn libos_run(host_tid: i32) -> i32 {
panic::catch_unwind(|| { panic::catch_unwind(|| {
backtrace::__rust_begin_short_backtrace(|| match do_run(host_tid as pid_t) { backtrace::__rust_begin_short_backtrace(|| match do_run(host_tid as pid_t) {
Ok(exit_status) => exit_status, Ok(exit_status) => exit_status,
Err(err) => EXIT_STATUS_INTERNAL_ERROR, Err(e) => {
error!("failed to execute a process: {}", e.backtrace());
EXIT_STATUS_INTERNAL_ERROR
}
}) })
}) })
.unwrap_or(EXIT_STATUS_INTERNAL_ERROR) .unwrap_or(EXIT_STATUS_INTERNAL_ERROR)
@ -53,7 +62,7 @@ const EXIT_STATUS_INTERNAL_ERROR: i32 = 127;
fn parse_arguments( fn parse_arguments(
path_buf: *const c_char, path_buf: *const c_char,
argv: *const *const c_char, argv: *const *const c_char,
) -> Result<(String, Vec<CString>), Error> { ) -> Result<(String, Vec<CString>)> {
let path_string = { let path_string = {
let path_cstring = clone_cstring_safely(path_buf)?; let path_cstring = clone_cstring_safely(path_buf)?;
path_cstring.to_string_lossy().into_owned() path_cstring.to_string_lossy().into_owned()
@ -61,11 +70,11 @@ fn parse_arguments(
let program_cstring = { let program_cstring = {
let program_osstr = Path::new(&path_string) let program_osstr = Path::new(&path_string)
.file_name() .file_name()
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?; .ok_or_else(|| errno!(EINVAL, "invalid path"))?;
let program_str = program_osstr let program_str = program_osstr
.to_str() .to_str()
.ok_or_else(|| Error::new(Errno::EINVAL, "Invalid path"))?; .ok_or_else(|| errno!(EINVAL, "invalid path"))?;
CString::new(program_str).or_else(|_| errno!(EINVAL, "Invalid path"))? CString::new(program_str).map_err(|e| errno!(e))?
}; };
let mut args = clone_cstrings_safely(argv)?; let mut args = clone_cstrings_safely(argv)?;
@ -74,7 +83,7 @@ fn parse_arguments(
} }
// TODO: make sure do_boot can only be called once // TODO: make sure do_boot can only be called once
fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> { fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<()> {
// info!("boot: path: {:?}, argv: {:?}", path_str, argv); // info!("boot: path: {:?}, argv: {:?}", path_str, argv);
util::mpx_util::mpx_enable()?; util::mpx_util::mpx_enable()?;
@ -87,7 +96,7 @@ fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
} }
// TODO: make sure do_run() cannot be called after do_boot() // TODO: make sure do_run() cannot be called after do_boot()
fn do_run(host_tid: pid_t) -> Result<i32, Error> { fn do_run(host_tid: pid_t) -> Result<i32> {
let exit_status = process::run_task(host_tid)?; let exit_status = process::run_task(host_tid)?;
// sync file system // sync file system

@ -1,257 +0,0 @@
use prelude::*;
use std::{convert, error, ffi, fmt};
// TODO: remove errno.h
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Error {
pub errno: Errno,
pub desc: &'static str,
}
impl Error {
pub fn new(errno: Errno, desc: &'static str) -> Error {
let ret = Error { errno, desc };
ret
}
}
impl convert::From<(Errno, &'static str)> for Error {
fn from(info: (Errno, &'static str)) -> Error {
Error::new(info.0, info.1)
}
}
impl convert::From<std::io::Error> for Error {
fn from(info: std::io::Error) -> Error {
Error::new(
Errno::from_errno(info.raw_os_error().unwrap()),
"std::io::Error",
)
}
}
impl convert::From<std::ffi::NulError> for Error {
fn from(info: std::ffi::NulError) -> Error {
Error::new(Errno::EINVAL, "std::ffi::NulError")
}
}
impl error::Error for Error {
fn description(&self) -> &str {
self.desc
}
fn cause(&self) -> Option<&error::Error> {
None
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {} ({})", self.desc, self.errno)
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum Errno {
EUNDEF = 0,
EPERM = 1,
ENOENT = 2,
ESRCH = 3,
EINTR = 4,
EIO = 5,
ENXIO = 6,
E2BIG = 7,
ENOEXEC = 8,
EBADF = 9,
ECHILD = 10,
EAGAIN = 11,
ENOMEM = 12,
EACCES = 13,
EFAULT = 14,
ENOTBLK = 15,
EBUSY = 16,
EEXIST = 17,
EXDEV = 18,
ENODEV = 19,
ENOTDIR = 20,
EISDIR = 21,
EINVAL = 22,
ENFILE = 23,
EMFILE = 24,
ENOTTY = 25,
ETXTBSY = 26,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
EROFS = 30,
EMLINK = 31,
EPIPE = 32,
EDOM = 33,
ERANGE = 34,
EDEADLK = 35,
ENAMETOOLONG = 36,
ENOLCK = 37,
ENOSYS = 38,
ENOTEMPTY = 39,
ELOOP = 40,
EWOULDBLOCK = 41,
ENOMSG = 42,
EIDRM = 43,
ECHRNG = 44,
EL2NSYNC = 45,
EL3HLT = 46,
EL3RST = 47,
ELNRNG = 48,
EUNATCH = 49,
ENOCSI = 50,
EL2HLT = 51,
EBADE = 52,
EBADR = 53,
EXFULL = 54,
ENOANO = 55,
EBADRQC = 56,
EBADSLT = 57,
EDEADLOCK = 58,
EBFONT = 59,
ENOSTR = 60,
ENODATA = 61,
ETIME = 62,
ENOSR = 63,
ENONET = 64,
ENOPKG = 65,
EREMOTE = 66,
ENOLINK = 67,
EADV = 68,
ESRMNT = 69,
ECOMM = 70,
EPROTO = 71,
EMULTIHOP = 72,
EDOTDOT = 73,
EBADMSG = 74,
EOVERFLOW = 75,
ENOTUNIQ = 76,
EBADFD = 77,
EREMCHG = 78,
ELIBACC = 79,
ELIBBAD = 80,
ELIBSCN = 81,
ELIBMAX = 82,
ELIBEXEC = 83,
EILSEQ = 84,
ERESTART = 85,
ESTRPIPE = 86,
EUSERS = 87,
ENOTSOCK = 88,
EDESTADDRREQ = 89,
EMSGSIZE = 90,
EPROTOTYPE = 91,
ENOPROTOOPT = 92,
EPROTONOSUPPORT = 93,
ESOCKTNOSUPPORT = 94,
EOPNOTSUPP = 95,
EPFNOSUPPORT = 96,
EAFNOSUPPORT = 97,
EADDRINUSE = 98,
EADDRNOTAVAIL = 99,
ENETDOWN = 100,
ENETUNREACH = 101,
ENETRESET = 102,
ECONNABORTED = 103,
ECONNRESET = 104,
ENOBUFS = 105,
EISCONN = 106,
ENOTCONN = 107,
ESHUTDOWN = 108,
ETOOMANYREFS = 109,
ETIMEDOUT = 110,
ECONNREFUSED = 111,
EHOSTDOWN = 112,
EHOSTUNREACH = 113,
EALREADY = 114,
EINPROGRESS = 115,
ESTALE = 116,
EUCLEAN = 117,
ENOTNAM = 118,
ENAVAIL = 119,
EISNAM = 120,
EREMOTEIO = 121,
EDQUOT = 122,
ENOMEDIUM = 123,
EMEDIUMTYPE = 124,
ECANCELED = 125,
ENOKEY = 126,
EKEYEXPIRED = 127,
EKEYREVOKED = 128,
EKEYREJECTED = 129,
EOWNERDEAD = 130,
ENOTRECOVERABLE = 131,
ERFKILL = 132,
EHWPOISON = 133,
}
impl Errno {
pub fn as_retval(&self) -> i32 {
-(*self as i32)
}
pub fn from_errno(mut errno: i32) -> Self {
if errno < 0 || errno > 133 {
errno = 0;
}
unsafe { core::mem::transmute(errno as u8) }
}
}
impl fmt::Display for Errno {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"errno = {}, \"{}\"",
*self as u32,
match *self {
Errno::EPERM => "Operation not permitted",
Errno::ENOENT => "No such file or directory",
Errno::ESRCH => "No such process",
Errno::EINTR => "Interrupted system call",
Errno::EIO => "I/O error",
Errno::ENXIO => "No such device or address",
Errno::E2BIG => "Argument list too long",
Errno::ENOEXEC => "Exec format error",
Errno::EBADF => "Bad file number",
Errno::ECHILD => "No child processes",
Errno::EAGAIN => "Try again",
Errno::ENOMEM => "Out of memory",
Errno::EACCES => "Permission denied",
Errno::EFAULT => "Bad address",
Errno::ENOTBLK => "Block device required",
Errno::EBUSY => "Device or resource busy",
Errno::EEXIST => "File exists",
Errno::EXDEV => "Cross-device link",
Errno::ENODEV => "No such device",
Errno::ENOTDIR => "Not a directory",
Errno::EISDIR => "Is a directory",
Errno::EINVAL => "Invalid argument",
Errno::ENFILE => "File table overflow",
Errno::EMFILE => "Too many open files",
Errno::ENOTTY => "Not a typewriter",
Errno::ETXTBSY => "Text file busy",
Errno::EFBIG => "File too large",
Errno::ENOSPC => "No space left on device",
Errno::ESPIPE => "Illegal seek",
Errno::EROFS => "Read-only file system",
Errno::EMLINK => "Too many links",
Errno::EPIPE => "Broken pipe",
Errno::EDOM => "Math argument out of domain of func",
Errno::ERANGE => "Math result not representable",
Errno::EDEADLK => "Resource deadlock would occur",
Errno::ENAMETOOLONG => "File name too long",
Errno::ENOLCK => "No record locks available",
Errno::ENOSYS => "Function not implemented",
Errno::ENOTEMPTY => "Directory not empty",
_ => "Unknown error",
},
)
}
}

@ -0,0 +1,65 @@
use super::*;
#[derive(Debug, Clone)]
pub struct ErrorBacktrace<'a> {
next_error: Option<&'a Error>,
}
impl<'a> ErrorBacktrace<'a> {
fn new(last_error: &'a Error) -> ErrorBacktrace {
ErrorBacktrace {
next_error: Some(last_error),
}
}
}
impl<'a> fmt::Display for ErrorBacktrace<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let error_strings: Vec<String> = self.clone().map(|e| e.to_string()).collect();
let error_backtrace = error_strings.join("\n Caused by ");
write!(f, "{}", error_backtrace)
}
}
impl<'a> Iterator for ErrorBacktrace<'a> {
type Item = &'a Error;
fn next(&mut self) -> Option<&'a Error> {
if let Some(this_error) = self.next_error {
self.next_error = this_error.get_cause().as_ref().map(|e| -> &Error { &e });
return Some(this_error);
}
None
}
}
impl Error {
pub fn cause_err<F>(self, f: F) -> Error
where
F: FnOnce(&Error) -> Error,
{
let old_err = self;
let mut new_err = f(&old_err);
*new_err.get_cause_mut() = Some(Box::new(old_err));
new_err
}
pub fn backtrace(&self) -> ErrorBacktrace {
ErrorBacktrace::new(self)
}
}
pub trait ResultExt<T> {
fn cause_err<F>(self, f: F) -> Result<T>
where
F: FnOnce(&Error) -> Error;
}
impl<T> ResultExt<T> for Result<T> {
fn cause_err<F>(self, f: F) -> Result<T>
where
F: FnOnce(&Error) -> Error,
{
self.map_err(|old_e| old_e.cause_err(f))
}
}

@ -0,0 +1,207 @@
use super::*;
/// POSIX errno
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(u8)]
pub enum Errno {
// Note: we don't define EUNDEF (=0) since a syscall cannot return 0 to
// indicate the occurance of an error
EPERM = 1,
ENOENT = 2,
ESRCH = 3,
EINTR = 4,
EIO = 5,
ENXIO = 6,
E2BIG = 7,
ENOEXEC = 8,
EBADF = 9,
ECHILD = 10,
EAGAIN = 11,
ENOMEM = 12,
EACCES = 13,
EFAULT = 14,
ENOTBLK = 15,
EBUSY = 16,
EEXIST = 17,
EXDEV = 18,
ENODEV = 19,
ENOTDIR = 20,
EISDIR = 21,
EINVAL = 22,
ENFILE = 23,
EMFILE = 24,
ENOTTY = 25,
ETXTBSY = 26,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
EROFS = 30,
EMLINK = 31,
EPIPE = 32,
EDOM = 33,
ERANGE = 34,
EDEADLK = 35,
ENAMETOOLONG = 36,
ENOLCK = 37,
ENOSYS = 38,
ENOTEMPTY = 39,
ELOOP = 40,
EWOULDBLOCK = 41,
ENOMSG = 42,
EIDRM = 43,
ECHRNG = 44,
EL2NSYNC = 45,
EL3HLT = 46,
EL3RST = 47,
ELNRNG = 48,
EUNATCH = 49,
ENOCSI = 50,
EL2HLT = 51,
EBADE = 52,
EBADR = 53,
EXFULL = 54,
ENOANO = 55,
EBADRQC = 56,
EBADSLT = 57,
EDEADLOCK = 58,
EBFONT = 59,
ENOSTR = 60,
ENODATA = 61,
ETIME = 62,
ENOSR = 63,
ENONET = 64,
ENOPKG = 65,
EREMOTE = 66,
ENOLINK = 67,
EADV = 68,
ESRMNT = 69,
ECOMM = 70,
EPROTO = 71,
EMULTIHOP = 72,
EDOTDOT = 73,
EBADMSG = 74,
EOVERFLOW = 75,
ENOTUNIQ = 76,
EBADFD = 77,
EREMCHG = 78,
ELIBACC = 79,
ELIBBAD = 80,
ELIBSCN = 81,
ELIBMAX = 82,
ELIBEXEC = 83,
EILSEQ = 84,
ERESTART = 85,
ESTRPIPE = 86,
EUSERS = 87,
ENOTSOCK = 88,
EDESTADDRREQ = 89,
EMSGSIZE = 90,
EPROTOTYPE = 91,
ENOPROTOOPT = 92,
EPROTONOSUPPORT = 93,
ESOCKTNOSUPPORT = 94,
EOPNOTSUPP = 95,
EPFNOSUPPORT = 96,
EAFNOSUPPORT = 97,
EADDRINUSE = 98,
EADDRNOTAVAIL = 99,
ENETDOWN = 100,
ENETUNREACH = 101,
ENETRESET = 102,
ECONNABORTED = 103,
ECONNRESET = 104,
ENOBUFS = 105,
EISCONN = 106,
ENOTCONN = 107,
ESHUTDOWN = 108,
ETOOMANYREFS = 109,
ETIMEDOUT = 110,
ECONNREFUSED = 111,
EHOSTDOWN = 112,
EHOSTUNREACH = 113,
EALREADY = 114,
EINPROGRESS = 115,
ESTALE = 116,
EUCLEAN = 117,
ENOTNAM = 118,
ENAVAIL = 119,
EISNAM = 120,
EREMOTEIO = 121,
EDQUOT = 122,
ENOMEDIUM = 123,
EMEDIUMTYPE = 124,
ECANCELED = 125,
ENOKEY = 126,
EKEYEXPIRED = 127,
EKEYREVOKED = 128,
EKEYREJECTED = 129,
EOWNERDEAD = 130,
ENOTRECOVERABLE = 131,
ERFKILL = 132,
EHWPOISON = 133,
// Note: always keep the last item in sync with ERRNO_MAX
}
const ERRNO_MAX: u32 = Errno::EHWPOISON as u32;
impl Errno {
pub(crate) fn as_str(&self) -> &'static str {
use self::Errno::*;
match *self {
EPERM => "Operation not permitted",
ENOENT => "No such file or directory",
ESRCH => "No such process",
EINTR => "Interrupted system call",
EIO => "I/O error",
ENXIO => "No such device or address",
E2BIG => "Argument list too long",
ENOEXEC => "Exec format error",
EBADF => "Bad file number",
ECHILD => "No child processes",
EAGAIN => "Try again",
ENOMEM => "Out of memory",
EACCES => "Permission denied",
EFAULT => "Bad address",
ENOTBLK => "Block device required",
EBUSY => "Device or resource busy",
EEXIST => "File exists",
EXDEV => "Cross-device link",
ENODEV => "No such device",
ENOTDIR => "Not a directory",
EISDIR => "Is a directory",
EINVAL => "Invalid argument",
ENFILE => "File table overflow",
EMFILE => "Too many open files",
ENOTTY => "Not a typewriter",
ETXTBSY => "Text file busy",
EFBIG => "File too large",
ENOSPC => "No space left on device",
ESPIPE => "Illegal seek",
EROFS => "Read-only file system",
EMLINK => "Too many links",
EPIPE => "Broken pipe",
EDOM => "Math argument out of domain of func",
ERANGE => "Math result not representable",
EDEADLK => "Resource deadlock would occur",
ENAMETOOLONG => "File name too long",
ENOLCK => "No record locks available",
ENOSYS => "Function not implemented",
ENOTEMPTY => "Directory not empty",
_ => "Unknown error",
}
}
}
impl From<u32> for Errno {
fn from(mut raw_errno: u32) -> Self {
if raw_errno > ERRNO_MAX {
raw_errno = 0;
}
unsafe { core::mem::transmute(raw_errno as u8) }
}
}
impl fmt::Display for Errno {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?} (#{}, {})", *self, *self as u32, self.as_str())
}
}

@ -0,0 +1,107 @@
use super::*;
#[derive(Debug)]
pub struct Error {
inner: Error__,
location: Option<ErrorLocation>,
cause: Option<Box<Error>>,
}
#[derive(Debug)]
enum Error__ {
Embedded((Errno, &'static str)),
Boxed(Box<dyn ToErrno + 'static>),
}
#[derive(Debug, Clone, Copy)]
pub struct ErrorLocation {
line: u32,
file: &'static str,
}
impl Error {
pub fn embeded(inner: (Errno, &'static str), location: Option<ErrorLocation>) -> Error {
Error {
inner: Error__::Embedded(inner),
location: location,
cause: None,
}
}
pub fn boxed<T>(inner: T, location: Option<ErrorLocation>) -> Error
where
T: ToErrno + 'static,
{
Error {
inner: Error__::Boxed(Box::new(inner)),
location: location,
cause: None,
}
}
pub fn errno(&self) -> Errno {
match &self.inner {
Error__::Embedded((errno, _)) => *errno,
Error__::Boxed(inner_error) => inner_error.errno(),
}
}
pub fn get_cause_mut(&mut self) -> &mut Option<Box<Error>> {
&mut self.cause
}
pub fn get_cause(&self) -> &Option<Box<Error>> {
&self.cause
}
}
impl ErrorLocation {
pub fn new(file: &'static str, line: u32) -> ErrorLocation {
ErrorLocation {
file: file,
line: line,
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
self.errno().as_str()
}
fn cause(&self) -> Option<&dyn std::error::Error> {
self.cause.as_ref().map(|e| e as &dyn std::error::Error)
}
/*
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.cause
.as_ref()
.map(|e| e as &(dyn std::error::Error + 'static))
}
*/
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.inner)?;
if let Some(location) = self.location {
write!(f, " {}", location)?;
}
Ok(())
}
}
impl fmt::Display for Error__ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error__::Embedded((errno, msg)) => write!(f, "{}: {}", errno, msg),
Error__::Boxed(inner_error) => write!(f, "{}: {}", inner_error.errno(), inner_error),
}
}
}
impl fmt::Display for ErrorLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[line = {}, file = {}]", self.line, self.file)
}
}

@ -0,0 +1,53 @@
use super::*;
use std::fmt;
mod backtrace;
mod errno;
mod error;
mod to_errno;
pub use self::backtrace::{ErrorBacktrace, ResultExt};
pub use self::errno::Errno;
pub use self::errno::Errno::*;
pub use self::error::{Error, ErrorLocation};
pub use self::to_errno::ToErrno;
pub type Result<T> = std::result::Result<T, Error>;
macro_rules! errno {
($errno_expr: expr, $error_msg: expr) => {{
let inner_error = {
let errno: Errno = $errno_expr;
let msg: &'static str = $error_msg;
(errno, msg)
};
let error = Error::embeded(inner_error, Some(ErrorLocation::new(file!(), line!())));
error
}};
($error_expr: expr) => {{
let inner_error = $error_expr;
let error = Error::boxed(inner_error, Some(ErrorLocation::new(file!(), line!())));
error
}};
}
macro_rules! return_errno {
($errno_expr: expr, $error_msg: expr) => {{
return Err(errno!($errno_expr, $error_msg));
}};
($error_expr: expr) => {{
return Err(errno!($error_expr));
}};
}
// return Err(errno) if libc return -1
macro_rules! try_libc {
($ret: expr) => {{
let ret = unsafe { $ret };
if ret == -1 {
let errno = unsafe { libc::errno() };
return_errno!(Errno::from(errno as u32), "libc error");
}
ret
}};
}

@ -0,0 +1,100 @@
use super::*;
pub trait ToErrno: fmt::Display + fmt::Debug {
fn errno(&self) -> Errno;
}
impl ToErrno for Errno {
fn errno(&self) -> Errno {
*self
}
}
impl<T> From<T> for Error
where
T: ToErrno + 'static,
{
fn from(t: T) -> Error {
Error::boxed(t, None)
}
}
impl From<std::io::ErrorKind> for Errno {
fn from(kind: std::io::ErrorKind) -> Errno {
use std::io::ErrorKind::*;
match kind {
NotFound => ENOENT,
PermissionDenied => EPERM,
ConnectionRefused => ECONNREFUSED,
ConnectionReset => ECONNRESET,
ConnectionAborted => ECONNABORTED,
NotConnected => ENOTCONN,
AddrInUse => EADDRINUSE,
AddrNotAvailable => EADDRNOTAVAIL,
BrokenPipe => EPIPE,
AlreadyExists => EEXIST,
WouldBlock => EWOULDBLOCK,
InvalidInput => EINVAL,
InvalidData => EBADMSG, /* TODO: correct? */
TimedOut => ETIMEDOUT,
Interrupted => EINTR,
WriteZero => EINVAL,
UnexpectedEof => EIO,
Other => EIO,
_ => EIO,
}
}
}
impl ToErrno for std::io::Error {
fn errno(&self) -> Errno {
Errno::from(self.kind())
}
}
impl ToErrno for std::ffi::NulError {
fn errno(&self) -> Errno {
EINVAL
}
}
impl ToErrno for std::num::ParseIntError {
fn errno(&self) -> Errno {
EINVAL
}
}
impl ToErrno for serde_json::Error {
fn errno(&self) -> Errno {
EINVAL
}
}
impl ToErrno for rcore_fs::vfs::FsError {
fn errno(&self) -> Errno {
use rcore_fs::vfs::FsError;
match *self {
FsError::NotSupported => ENOSYS,
FsError::NotFile => EISDIR,
FsError::IsDir => EISDIR,
FsError::NotDir => ENOTDIR,
FsError::EntryNotFound => ENOENT,
FsError::EntryExist => EEXIST,
FsError::NotSameFs => EXDEV,
FsError::InvalidParam => EINVAL,
FsError::NoDeviceSpace => ENOMEM,
FsError::DirRemoved => ENOENT,
FsError::DirNotEmpty => ENOTEMPTY,
FsError::WrongFs => EINVAL,
FsError::DeviceError => EIO,
FsError::SymLoop => ELOOP,
FsError::NoDevice => ENXIO,
FsError::IOCTLError => EINVAL,
FsError::Again => EAGAIN,
FsError::Busy => EBUSY,
FsError::WrProtected => EROFS,
FsError::NoIntegrity => EIO,
FsError::PermError => EPERM,
}
}
}

@ -167,11 +167,11 @@ impl CpuId {
cpuid cpuid
} }
fn lookup_cpuid_from_cache(&self, cpuid_input: CpuIdInput) -> Result<CpuIdResult, Error> { fn lookup_cpuid_from_cache(&self, cpuid_input: CpuIdInput) -> Result<CpuIdResult> {
self.cache self.cache
.lookup(&cpuid_input) .lookup(&cpuid_input)
.map(|result| result.clone()) .map(|result| result.clone())
.ok_or_else(|| Error::new(Errno::ENOENT, "cpuid_result not found")) .ok_or_else(|| errno!(ENOENT, "cpuid_result not found"))
} }
pub fn get_max_basic_leaf(&self) -> u32 { pub fn get_max_basic_leaf(&self) -> u32 {

@ -12,8 +12,8 @@ bitflags! {
} }
impl AccessModes { impl AccessModes {
pub fn from_u32(bits: u32) -> Result<AccessModes, Error> { pub fn from_u32(bits: u32) -> Result<AccessModes> {
AccessModes::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid mode")) AccessModes::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
} }
} }
@ -25,8 +25,8 @@ bitflags! {
} }
impl AccessFlags { impl AccessFlags {
pub fn from_u32(bits: u32) -> Result<AccessFlags, Error> { pub fn from_u32(bits: u32) -> Result<AccessFlags> {
AccessFlags::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid flags")) AccessFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags"))
} }
} }
@ -37,19 +37,19 @@ pub fn do_faccessat(
path: &str, path: &str,
mode: AccessModes, mode: AccessModes,
flags: AccessFlags, flags: AccessFlags,
) -> Result<(), Error> { ) -> Result<()> {
info!( info!(
"faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", "faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}",
dirfd, path, mode, flags dirfd, path, mode, flags
); );
match dirfd { match dirfd {
// TODO: handle dirfd // TODO: handle dirfd
Some(dirfd) => errno!(ENOSYS, "cannot accept dirfd"), Some(dirfd) => return_errno!(ENOSYS, "cannot accept dirfd"),
None => do_access(path, mode), None => do_access(path, mode),
} }
} }
pub fn do_access(path: &str, mode: AccessModes) -> Result<(), Error> { pub fn do_access(path: &str, mode: AccessModes) -> Result<()> {
info!("access: path: {:?}, mode: {:?}", path, mode); info!("access: path: {:?}, mode: {:?}", path, mode);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();

@ -4,52 +4,52 @@ use super::*;
pub struct DevNull; pub struct DevNull;
impl File for DevNull { impl File for DevNull {
fn write(&self, _buf: &[u8]) -> Result<usize, Error> { fn write(&self, _buf: &[u8]) -> Result<usize> {
Ok(_buf.len()) Ok(_buf.len())
} }
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
Ok(_buf.len()) Ok(_buf.len())
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
Ok(bufs.iter().map(|buf| buf.len()).sum()) Ok(bufs.iter().map(|buf| buf.len()).sum())
} }
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, _buf: &mut [u8]) -> Result<usize> {
errno!(EINVAL, "device not support reads") return_errno!(EINVAL, "device not support reads")
} }
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
errno!(EINVAL, "device not support reads") return_errno!(EINVAL, "device not support reads")
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
errno!(EINVAL, "device not support reads") return_errno!(EINVAL, "device not support reads")
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(EINVAL, "device not support seeks") return_errno!(EINVAL, "device not support seeks")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
errno!(EINVAL, "device not support resizing") return_errno!(EINVAL, "device not support resizing")
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
errno!(ENOTDIR, "device is not a directory") return_errno!(ENOTDIR, "device is not a directory")
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {

@ -8,21 +8,21 @@ extern "C" {
} }
impl File for DevRandom { impl File for DevRandom {
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, _buf: &mut [u8]) -> Result<usize> {
let buf = _buf.as_mut_ptr(); let buf = _buf.as_mut_ptr();
let size = _buf.len(); let size = _buf.len();
let status = unsafe { sgx_read_rand(buf, size) }; let status = unsafe { sgx_read_rand(buf, size) };
if status != sgx_status_t::SGX_SUCCESS { if status != sgx_status_t::SGX_SUCCESS {
return errno!(EAGAIN, "failed to get random number from sgx"); return_errno!(EAGAIN, "failed to get random number from sgx");
} }
Ok(size) Ok(size)
} }
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
self.read(_buf) self.read(_buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut total_nbytes = 0; let mut total_nbytes = 0;
for buf in bufs { for buf in bufs {
match self.read(buf) { match self.read(buf) {
@ -41,40 +41,40 @@ impl File for DevRandom {
Ok(total_nbytes) Ok(total_nbytes)
} }
fn write(&self, _buf: &[u8]) -> Result<usize, Error> { fn write(&self, _buf: &[u8]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(EINVAL, "device not support seeks") return_errno!(EINVAL, "device not support seeks")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
errno!(EINVAL, "device not support resizing") return_errno!(EINVAL, "device not support resizing")
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
errno!(ENOTDIR, "device is not a directory") return_errno!(ENOTDIR, "device is not a directory")
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {

@ -4,18 +4,18 @@ use super::*;
pub struct DevZero; pub struct DevZero;
impl File for DevZero { impl File for DevZero {
fn read(&self, _buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, _buf: &mut [u8]) -> Result<usize> {
for b in _buf.iter_mut() { for b in _buf.iter_mut() {
*b = 0; *b = 0;
} }
Ok(_buf.len()) Ok(_buf.len())
} }
fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize> {
self.read(_buf) self.read(_buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut total_nbytes = 0; let mut total_nbytes = 0;
for buf in bufs { for buf in bufs {
total_nbytes += self.read(buf)?; total_nbytes += self.read(buf)?;
@ -23,40 +23,40 @@ impl File for DevZero {
Ok(total_nbytes) Ok(total_nbytes)
} }
fn write(&self, _buf: &[u8]) -> Result<usize, Error> { fn write(&self, _buf: &[u8]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
errno!(EINVAL, "device not support writes") return_errno!(EINVAL, "device not support writes")
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(EINVAL, "device not support seeks") return_errno!(EINVAL, "device not support seeks")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
errno!(EINVAL, "device not support resizing") return_errno!(EINVAL, "device not support resizing")
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
errno!(ENOTDIR, "device is not a directory") return_errno!(ENOTDIR, "device is not a directory")
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {

@ -5,18 +5,18 @@ use std::fmt;
use std::io::SeekFrom; use std::io::SeekFrom;
pub trait File: Debug + Sync + Send + Any { pub trait File: Debug + Sync + Send + Any {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error>; fn read(&self, buf: &mut [u8]) -> Result<usize>;
fn write(&self, buf: &[u8]) -> Result<usize, Error>; fn write(&self, buf: &[u8]) -> Result<usize>;
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize>;
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error>; fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>;
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error>; fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize>;
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error>; fn writev(&self, bufs: &[&[u8]]) -> Result<usize>;
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error>; fn seek(&self, pos: SeekFrom) -> Result<off_t>;
fn metadata(&self) -> Result<Metadata, Error>; fn metadata(&self) -> Result<Metadata>;
fn set_len(&self, len: u64) -> Result<(), Error>; fn set_len(&self, len: u64) -> Result<()>;
fn sync_all(&self) -> Result<(), Error>; fn sync_all(&self) -> Result<()>;
fn sync_data(&self) -> Result<(), Error>; fn sync_data(&self) -> Result<()>;
fn read_entry(&self) -> Result<String, Error>; fn read_entry(&self) -> Result<String>;
fn as_any(&self) -> &Any; fn as_any(&self) -> &Any;
} }
@ -34,9 +34,9 @@ impl SgxFile {
is_readable: bool, is_readable: bool,
is_writable: bool, is_writable: bool,
is_append: bool, is_append: bool,
) -> Result<SgxFile, Error> { ) -> Result<SgxFile> {
if !is_readable && !is_writable { if !is_readable && !is_writable {
return errno!(EINVAL, "Invalid permissions"); return_errno!(EINVAL, "Invalid permissions");
} }
Ok(SgxFile { Ok(SgxFile {
@ -52,67 +52,67 @@ impl SgxFile {
} }
impl File for SgxFile { impl File for SgxFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.read(buf) inner.read(buf)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.write(buf) inner.write(buf)
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.seek(SeekFrom::Start(offset as u64))?; inner.seek(SeekFrom::Start(offset as u64))?;
inner.read(buf) inner.read(buf)
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.seek(SeekFrom::Start(offset as u64))?; inner.seek(SeekFrom::Start(offset as u64))?;
inner.write(buf) inner.write(buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.readv(bufs) inner.readv(bufs)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.writev(bufs) inner.writev(bufs)
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
let mut inner_guard = self.inner.lock().unwrap(); let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut(); let inner = inner_guard.borrow_mut();
inner.seek(pos) inner.seek(pos)
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }
@ -133,9 +133,9 @@ struct SgxFileInner {
} }
impl SgxFileInner { impl SgxFileInner {
pub fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
if !self.is_writable { if !self.is_writable {
return errno!(EINVAL, "File not writable"); return_errno!(EINVAL, "File not writable");
} }
let mut file_guard = self.file.lock().unwrap(); let mut file_guard = self.file.lock().unwrap();
@ -147,13 +147,9 @@ impl SgxFileInner {
SeekFrom::End(0) SeekFrom::End(0)
}; };
// TODO: recover from error // TODO: recover from error
file.seek(seek_pos) file.seek(seek_pos).map_err(|e| errno!(e))?;
.map_err(|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let write_len = { let write_len = { file.write(buf).map_err(|e| errno!(e))? };
file.write(buf)
.map_err(|e| Error::new(Errno::EINVAL, "Failed to write"))?
};
if !self.is_append { if !self.is_append {
self.pos += write_len; self.pos += write_len;
@ -161,28 +157,24 @@ impl SgxFileInner {
Ok(write_len) Ok(write_len)
} }
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> { pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.is_readable { if !self.is_readable {
return errno!(EINVAL, "File not readable"); return_errno!(EINVAL, "File not readable");
} }
let mut file_guard = self.file.lock().unwrap(); let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut(); let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64); let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos) file.seek(seek_pos).map_err(|e| errno!(e))?;
.map_err(|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let read_len = { let read_len = { file.read(buf).map_err(|e| errno!(e))? };
file.read(buf)
.map_err(|e| Error::new(Errno::EINVAL, "Failed to write"))?
};
self.pos += read_len; self.pos += read_len;
Ok(read_len) Ok(read_len)
} }
pub fn seek(&mut self, pos: SeekFrom) -> Result<off_t, Error> { pub fn seek(&mut self, pos: SeekFrom) -> Result<off_t> {
let mut file_guard = self.file.lock().unwrap(); let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut(); let file = file_guard.borrow_mut();
@ -196,23 +188,20 @@ impl SgxFileInner {
let backward_offset = (-relative_offset) as usize; let backward_offset = (-relative_offset) as usize;
if self.pos < backward_offset { if self.pos < backward_offset {
// underflow // underflow
return errno!(EINVAL, "Invalid seek position"); return_errno!(EINVAL, "Invalid seek position");
} }
SeekFrom::Start((self.pos - backward_offset) as u64) SeekFrom::Start((self.pos - backward_offset) as u64)
} }
} }
}; };
self.pos = file self.pos = file.seek(pos).map_err(|e| errno!(e))? as usize;
.seek(pos)
.map_err(|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?
as usize;
Ok(self.pos as off_t) Ok(self.pos as off_t)
} }
pub fn writev(&mut self, bufs: &[&[u8]]) -> Result<usize, Error> { pub fn writev(&mut self, bufs: &[&[u8]]) -> Result<usize> {
if !self.is_writable { if !self.is_writable {
return errno!(EINVAL, "File not writable"); return_errno!(EINVAL, "File not writable");
} }
let mut file_guard = self.file.lock().unwrap(); let mut file_guard = self.file.lock().unwrap();
@ -223,8 +212,7 @@ impl SgxFileInner {
} else { } else {
SeekFrom::End(0) SeekFrom::End(0)
}; };
file.seek(seek_pos) file.seek(seek_pos).map_err(|e| errno!(e))?;
.map_err(|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -238,7 +226,7 @@ impl SgxFileInner {
Err(e) => { Err(e) => {
match total_bytes { match total_bytes {
// a complete failure // a complete failure
0 => return errno!(EINVAL, "Failed to write"), 0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure // a partially failure
_ => break, _ => break,
} }
@ -250,17 +238,16 @@ impl SgxFileInner {
Ok(total_bytes) Ok(total_bytes)
} }
fn readv(&mut self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&mut self, bufs: &mut [&mut [u8]]) -> Result<usize> {
if !self.is_readable { if !self.is_readable {
return errno!(EINVAL, "File not readable"); return_errno!(EINVAL, "File not readable");
} }
let mut file_guard = self.file.lock().unwrap(); let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut(); let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64); let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos) file.seek(seek_pos).map_err(|e| errno!(e))?;
.map_err(|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -274,7 +261,7 @@ impl SgxFileInner {
Err(e) => { Err(e) => {
match total_bytes { match total_bytes {
// a complete failure // a complete failure
0 => return errno!(EINVAL, "Failed to write"), 0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure // a partially failure
_ => break, _ => break,
} }
@ -309,33 +296,28 @@ impl StdoutFile {
} }
impl File for StdoutFile { impl File for StdoutFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
errno!(EBADF, "Stdout does not support read") return_errno!(EBADF, "Stdout does not support read")
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
let write_len = { let write_len = { self.inner.lock().write(buf).map_err(|e| errno!(e))? };
self.inner
.lock()
.write(buf)
.map_err(|e| (Errno::EINVAL, "Failed to write"))?
};
Ok(write_len) Ok(write_len)
} }
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read(buf) self.read(buf)
} }
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
self.write(buf) self.write(buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
errno!(EBADF, "Stdout does not support read") return_errno!(EBADF, "Stdout does not support read")
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut guard = self.inner.lock(); let mut guard = self.inner.lock();
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -349,7 +331,7 @@ impl File for StdoutFile {
Err(e) => { Err(e) => {
match total_bytes { match total_bytes {
// a complete failure // a complete failure
0 => return errno!(EINVAL, "Failed to write"), 0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure // a partially failure
_ => break, _ => break,
} }
@ -359,11 +341,11 @@ impl File for StdoutFile {
Ok(total_bytes) Ok(total_bytes)
} }
fn seek(&self, seek_pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, seek_pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Stdout does not support seek") return_errno!(ESPIPE, "Stdout does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
Ok(Metadata { Ok(Metadata {
dev: 0, dev: 0,
inode: 0, inode: 0,
@ -382,21 +364,21 @@ impl File for StdoutFile {
}) })
} }
fn set_len(&self, _len: u64) -> Result<(), Error> { fn set_len(&self, _len: u64) -> Result<()> {
errno!(EINVAL, "Stdout does not support set_len") return_errno!(EINVAL, "Stdout does not support set_len")
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
self.sync_data() self.sync_data()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
self.inner.lock().flush()?; self.inner.lock().flush()?;
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
errno!(ENOTDIR, "Stdout does not support read_entry") return_errno!(ENOTDIR, "Stdout does not support read_entry")
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {
@ -426,29 +408,24 @@ impl StdinFile {
} }
impl File for StdinFile { impl File for StdinFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
let read_len = { let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? };
self.inner
.lock()
.read(buf)
.map_err(|e| (Errno::EINVAL, "Failed to read"))?
};
Ok(read_len) Ok(read_len)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
errno!(EBADF, "Stdin does not support write") return_errno!(EBADF, "Stdin does not support write")
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut guard = self.inner.lock(); let mut guard = self.inner.lock();
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -462,7 +439,7 @@ impl File for StdinFile {
Err(e) => { Err(e) => {
match total_bytes { match total_bytes {
// a complete failure // a complete failure
0 => return errno!(EINVAL, "Failed to write"), 0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure // a partially failure
_ => break, _ => break,
} }
@ -472,15 +449,15 @@ impl File for StdinFile {
Ok(total_bytes) Ok(total_bytes)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
errno!(EBADF, "Stdin does not support write") return_errno!(EBADF, "Stdin does not support write")
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Stdin does not support seek") return_errno!(ESPIPE, "Stdin does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
Ok(Metadata { Ok(Metadata {
dev: 0, dev: 0,
inode: 0, inode: 0,
@ -499,20 +476,20 @@ impl File for StdinFile {
}) })
} }
fn set_len(&self, _len: u64) -> Result<(), Error> { fn set_len(&self, _len: u64) -> Result<()> {
errno!(EINVAL, "Stdin does not support set_len") return_errno!(EINVAL, "Stdin does not support set_len")
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
self.sync_data() self.sync_data()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
errno!(ENOTDIR, "Stdin does not support read_entry") return_errno!(ENOTDIR, "Stdin does not support read_entry")
} }
fn as_any(&self) -> &Any { fn as_any(&self) -> &Any {

@ -24,7 +24,7 @@ impl FileTable {
fd: FileDesc, fd: FileDesc,
min_fd: FileDesc, min_fd: FileDesc,
close_on_spawn: bool, close_on_spawn: bool,
) -> Result<FileDesc, Error> { ) -> Result<FileDesc> {
let file_ref = self.get(fd)?; let file_ref = self.get(fd)?;
let min_fd = min_fd as usize; let min_fd = min_fd as usize;
@ -86,38 +86,38 @@ impl FileTable {
} }
} }
pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { pub fn get(&self, fd: FileDesc) -> Result<FileRef> {
let entry = self.get_entry(fd)?; let entry = self.get_entry(fd)?;
Ok(entry.file.clone()) Ok(entry.file.clone())
} }
pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry, Error> { pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry> {
if fd as usize >= self.table.len() { if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor"); return_errno!(EBADF, "Invalid file descriptor");
} }
let table = &self.table; let table = &self.table;
match table[fd as usize].as_ref() { match table[fd as usize].as_ref() {
Some(table_entry) => Ok(table_entry), Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"), None => return_errno!(EBADF, "Invalid file descriptor"),
} }
} }
pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry, Error> { pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry> {
if fd as usize >= self.table.len() { if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor"); return_errno!(EBADF, "Invalid file descriptor");
} }
let table = &mut self.table; let table = &mut self.table;
match table[fd as usize].as_mut() { match table[fd as usize].as_mut() {
Some(table_entry) => Ok(table_entry), Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"), None => return_errno!(EBADF, "Invalid file descriptor"),
} }
} }
pub fn del(&mut self, fd: FileDesc) -> Result<FileRef, Error> { pub fn del(&mut self, fd: FileDesc) -> Result<FileRef> {
if fd as usize >= self.table.len() { if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor"); return_errno!(EBADF, "Invalid file descriptor");
} }
let mut del_table_entry = None; let mut del_table_entry = None;
@ -128,7 +128,7 @@ impl FileTable {
self.num_fds -= 1; self.num_fds -= 1;
Ok(del_table_entry.file) Ok(del_table_entry.file)
} }
None => errno!(EBADF, "Invalid file descriptor"), None => return_errno!(EBADF, "Invalid file descriptor"),
} }
} }

@ -18,19 +18,19 @@ pub struct OpenOptions {
} }
impl File for INodeFile { impl File for INodeFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
if !self.options.read { if !self.options.read {
return errno!(EBADF, "File not readable"); return_errno!(EBADF, "File not readable");
} }
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
let len = self.inode.read_at(*offset, buf)?; let len = self.inode.read_at(*offset, buf).map_err(|e| errno!(e))?;
*offset += len; *offset += len;
Ok(len) Ok(len)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
if !self.options.write { if !self.options.write {
return errno!(EBADF, "File not writable"); return_errno!(EBADF, "File not writable");
} }
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
if self.options.append { if self.options.append {
@ -42,25 +42,25 @@ impl File for INodeFile {
Ok(len) Ok(len)
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
if !self.options.read { if !self.options.read {
return errno!(EBADF, "File not readable"); return_errno!(EBADF, "File not readable");
} }
let len = self.inode.read_at(offset, buf)?; let len = self.inode.read_at(offset, buf)?;
Ok(len) Ok(len)
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
if !self.options.write { if !self.options.write {
return errno!(EBADF, "File not writable"); return_errno!(EBADF, "File not writable");
} }
let len = self.inode.write_at(offset, buf)?; let len = self.inode.write_at(offset, buf)?;
Ok(len) Ok(len)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
if !self.options.read { if !self.options.read {
return errno!(EBADF, "File not readable"); return_errno!(EBADF, "File not readable");
} }
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
let mut total_len = 0; let mut total_len = 0;
@ -77,9 +77,9 @@ impl File for INodeFile {
Ok(total_len) Ok(total_len)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
if !self.options.write { if !self.options.write {
return errno!(EBADF, "File not writable"); return_errno!(EBADF, "File not writable");
} }
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
if self.options.append { if self.options.append {
@ -100,7 +100,7 @@ impl File for INodeFile {
Ok(total_len) Ok(total_len)
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
*offset = match pos { *offset = match pos {
SeekFrom::Start(off) => off as usize, SeekFrom::Start(off) => off as usize,
@ -110,32 +110,32 @@ impl File for INodeFile {
Ok(*offset as i64) Ok(*offset as i64)
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
let metadata = self.inode.metadata()?; let metadata = self.inode.metadata()?;
Ok(metadata) Ok(metadata)
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
if !self.options.write { if !self.options.write {
return errno!(EBADF, "File not writable. Can't set len."); return_errno!(EBADF, "File not writable. Can't set len.");
} }
self.inode.resize(len as usize)?; self.inode.resize(len as usize)?;
Ok(()) Ok(())
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
self.inode.sync_all()?; self.inode.sync_all()?;
Ok(()) Ok(())
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
self.inode.sync_data()?; self.inode.sync_data()?;
Ok(()) Ok(())
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
if !self.options.read { if !self.options.read {
return errno!(EBADF, "File not readable. Can't read entry."); return_errno!(EBADF, "File not readable. Can't read entry.");
} }
let mut offset = self.offset.lock().unwrap(); let mut offset = self.offset.lock().unwrap();
let name = self.inode.get_entry(*offset)?; let name = self.inode.get_entry(*offset)?;
@ -149,12 +149,12 @@ impl File for INodeFile {
} }
impl INodeFile { impl INodeFile {
pub fn open(inode: Arc<INode>, options: OpenOptions) -> Result<Self, Error> { pub fn open(inode: Arc<INode>, options: OpenOptions) -> Result<Self> {
if (options.read && !inode.allow_read()?) { if (options.read && !inode.allow_read()?) {
return errno!(EBADF, "File not readable"); return_errno!(EBADF, "File not readable");
} }
if (options.write && !inode.allow_write()?) { if (options.write && !inode.allow_write()?) {
return errno!(EBADF, "File not writable"); return_errno!(EBADF, "File not writable");
} }
Ok(INodeFile { Ok(INodeFile {
@ -165,36 +165,6 @@ impl INodeFile {
} }
} }
/// Convert VFS Error to libc error code
impl From<FsError> for Error {
fn from(error: FsError) -> Self {
let errno = match error {
FsError::NotSupported => ENOSYS,
FsError::NotFile => EISDIR,
FsError::IsDir => EISDIR,
FsError::NotDir => ENOTDIR,
FsError::EntryNotFound => ENOENT,
FsError::EntryExist => EEXIST,
FsError::NotSameFs => EXDEV,
FsError::InvalidParam => EINVAL,
FsError::NoDeviceSpace => ENOMEM,
FsError::DirRemoved => ENOENT,
FsError::DirNotEmpty => ENOTEMPTY,
FsError::WrongFs => EINVAL,
FsError::DeviceError => EIO,
FsError::SymLoop => ELOOP,
FsError::NoDevice => ENXIO,
FsError::IOCTLError => EINVAL,
FsError::Again => EAGAIN,
FsError::Busy => EBUSY,
FsError::WrProtected => EROFS,
FsError::NoIntegrity => EROFS,
FsError::PermError => EPERM,
};
Error::new(errno, "")
}
}
impl Debug for INodeFile { impl Debug for INodeFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(
@ -207,13 +177,13 @@ impl Debug for INodeFile {
} }
pub trait INodeExt { pub trait INodeExt {
fn read_as_vec(&self) -> Result<Vec<u8>, Error>; fn read_as_vec(&self) -> Result<Vec<u8>>;
fn allow_write(&self) -> Result<bool, Error>; fn allow_write(&self) -> Result<bool>;
fn allow_read(&self) -> Result<bool, Error>; fn allow_read(&self) -> Result<bool>;
} }
impl INodeExt for INode { impl INodeExt for INode {
fn read_as_vec(&self) -> Result<Vec<u8>, Error> { fn read_as_vec(&self) -> Result<Vec<u8>> {
let size = self.metadata()?.size; let size = self.metadata()?.size;
let mut buf = Vec::with_capacity(size); let mut buf = Vec::with_capacity(size);
unsafe { unsafe {
@ -223,14 +193,14 @@ impl INodeExt for INode {
Ok(buf) Ok(buf)
} }
fn allow_write(&self) -> Result<bool, Error> { fn allow_write(&self) -> Result<bool> {
let info = self.metadata()?; let info = self.metadata()?;
let perms = info.mode as u32; let perms = info.mode as u32;
let writable = (perms & S_IWUSR) == S_IWUSR; let writable = (perms & S_IWUSR) == S_IWUSR;
Ok(writable) Ok(writable)
} }
fn allow_read(&self) -> Result<bool, Error> { fn allow_read(&self) -> Result<bool> {
let info = self.metadata()?; let info = self.metadata()?;
let perms = info.mode as u32; let perms = info.mode as u32;
let readable = (perms & S_IRUSR) == S_IRUSR; let readable = (perms & S_IRUSR) == S_IRUSR;

@ -13,7 +13,7 @@ pub fn do_select(
writefds: &mut libc::fd_set, writefds: &mut libc::fd_set,
exceptfds: &mut libc::fd_set, exceptfds: &mut libc::fd_set,
timeout: Option<libc::timeval>, timeout: Option<libc::timeval>,
) -> Result<usize, Error> { ) -> Result<usize> {
info!("select: nfds: {}", nfds); info!("select: nfds: {}", nfds);
// convert libos fd to Linux fd // convert libos fd to Linux fd
let mut host_to_libos_fd = [0; libc::FD_SETSIZE]; let mut host_to_libos_fd = [0; libc::FD_SETSIZE];
@ -108,7 +108,7 @@ pub fn do_select(
Ok(ret as usize) Ok(ret as usize)
} }
pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize, Error> { pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize> {
info!( info!(
"poll: {:?}, timeout: {}", "poll: {:?}, timeout: {}",
polls.iter().map(|p| p.fd).collect::<Vec<_>>(), polls.iter().map(|p| p.fd).collect::<Vec<_>>(),
@ -143,7 +143,7 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize, Erro
warn!("poll unix socket is unimplemented, spin for read"); warn!("poll unix socket is unimplemented, spin for read");
return Ok(1); return Ok(1);
} else { } else {
return errno!(EBADF, "not a socket"); return_errno!(EBADF, "not a socket");
} }
} }
let ret = try_libc!(libc::ocall::poll( let ret = try_libc!(libc::ocall::poll(
@ -155,7 +155,7 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result<usize, Erro
Ok(ret as usize) Ok(ret as usize)
} }
pub fn do_epoll_create1(flags: c_int) -> Result<FileDesc, Error> { pub fn do_epoll_create1(flags: c_int) -> Result<FileDesc> {
info!("epoll_create1: flags: {}", flags); info!("epoll_create1: flags: {}", flags);
let epoll = EpollFile::new()?; let epoll = EpollFile::new()?;
@ -177,7 +177,7 @@ pub fn do_epoll_ctl(
op: c_int, op: c_int,
fd: FileDesc, fd: FileDesc,
event: *const libc::epoll_event, event: *const libc::epoll_event,
) -> Result<(), Error> { ) -> Result<()> {
info!("epoll_ctl: epfd: {}, op: {:?}, fd: {}", epfd, op, fd); info!("epoll_ctl: epfd: {}, op: {:?}, fd: {}", epfd, op, fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
@ -196,7 +196,7 @@ pub fn do_epoll_wait(
epfd: FileDesc, epfd: FileDesc,
events: &mut [libc::epoll_event], events: &mut [libc::epoll_event],
timeout: c_int, timeout: c_int,
) -> Result<usize, Error> { ) -> Result<usize> {
info!( info!(
"epoll_wait: epfd: {}, len: {:?}, timeout: {}", "epoll_wait: epfd: {}, len: {:?}, timeout: {}",
epfd, epfd,
@ -245,7 +245,7 @@ pub struct EpollFile {
} }
impl EpollFile { impl EpollFile {
pub fn new() -> Result<Self, Error> { pub fn new() -> Result<Self> {
Ok(Self { Ok(Self {
inner: SgxMutex::new(EpollFileInner::new()?), inner: SgxMutex::new(EpollFileInner::new()?),
}) })
@ -259,7 +259,7 @@ struct EpollFileInner {
// FIXME: What if a Linux fd is closed but still in an epoll? // FIXME: What if a Linux fd is closed but still in an epoll?
impl EpollFileInner { impl EpollFileInner {
/// Create a new Linux epoll file descriptor /// Create a new Linux epoll file descriptor
pub fn new() -> Result<Self, Error> { pub fn new() -> Result<Self> {
let ret = try_libc!(libc::ocall::epoll_create1(0)); let ret = try_libc!(libc::ocall::epoll_create1(0));
Ok(EpollFileInner { epoll_fd: ret }) Ok(EpollFileInner { epoll_fd: ret })
} }
@ -269,7 +269,7 @@ impl EpollFileInner {
op: c_int, op: c_int,
host_fd: FileDesc, host_fd: FileDesc,
event: *const libc::epoll_event, event: *const libc::epoll_event,
) -> Result<(), Error> { ) -> Result<()> {
let ret = try_libc!(libc::ocall::epoll_ctl( let ret = try_libc!(libc::ocall::epoll_ctl(
self.epoll_fd, self.epoll_fd,
op, op,
@ -281,11 +281,7 @@ impl EpollFileInner {
/// Wait for an I/O event on the epoll. /// Wait for an I/O event on the epoll.
/// Returns the number of file descriptors ready for the requested I/O. /// Returns the number of file descriptors ready for the requested I/O.
pub fn wait( pub fn wait(&mut self, events: &mut [libc::epoll_event], timeout: c_int) -> Result<usize> {
&mut self,
events: &mut [libc::epoll_event],
timeout: c_int,
) -> Result<usize, Error> {
let ret = try_libc!(libc::ocall::epoll_wait( let ret = try_libc!(libc::ocall::epoll_wait(
self.epoll_fd, self.epoll_fd,
events.as_mut_ptr(), events.as_mut_ptr(),
@ -305,51 +301,51 @@ impl Drop for EpollFileInner {
} }
impl File for EpollFile { impl File for EpollFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Epoll does not support seek") return_errno!(ESPIPE, "Epoll does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }
@ -368,13 +364,13 @@ impl Debug for EpollFile {
} }
pub trait AsEpoll { pub trait AsEpoll {
fn as_epoll(&self) -> Result<&EpollFile, Error>; fn as_epoll(&self) -> Result<&EpollFile>;
} }
impl AsEpoll for FileRef { impl AsEpoll for FileRef {
fn as_epoll(&self) -> Result<&EpollFile, Error> { fn as_epoll(&self) -> Result<&EpollFile> {
self.as_any() self.as_any()
.downcast_ref::<EpollFile>() .downcast_ref::<EpollFile>()
.ok_or(Error::new(Errno::EBADF, "not a epoll")) .ok_or_else(|| errno!(EBADF, "not a epoll"))
} }
} }

@ -1,11 +1,11 @@
use prelude::*; use super::*;
use process::Process; use process::Process;
use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec}; use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec};
use std::io::{Read, Seek, SeekFrom, Write};
use std::sgxfs as fs_impl; use std::sgxfs as fs_impl;
use {process, std}; use {process, std};
use super::*;
pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD}; pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD};
use self::dev_null::DevNull; use self::dev_null::DevNull;
use self::dev_random::DevRandom; use self::dev_random::DevRandom;
@ -38,7 +38,7 @@ mod sgx_impl;
mod socket_file; mod socket_file;
mod unix_socket; mod unix_socket;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> { pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc> {
let flags = OpenFlags::from_bits_truncate(flags); let flags = OpenFlags::from_bits_truncate(flags);
info!( info!(
"open: path: {:?}, flags: {:?}, mode: {:#o}", "open: path: {:?}, flags: {:?}, mode: {:#o}",
@ -61,7 +61,7 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
Ok(fd) Ok(fd)
} }
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> { pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize> {
info!("write: fd: {}", fd); info!("write: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -69,7 +69,7 @@ pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
file_ref.write(buf) file_ref.write(buf)
} }
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> { pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!("read: fd: {}", fd); info!("read: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -77,7 +77,7 @@ pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
file_ref.read(buf) file_ref.read(buf)
} }
pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize, Error> { pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize> {
info!("writev: fd: {}", fd); info!("writev: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -85,7 +85,7 @@ pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize, Error> {
file_ref.writev(bufs) file_ref.writev(bufs)
} }
pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize> {
info!("readv: fd: {}", fd); info!("readv: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -93,7 +93,7 @@ pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
file_ref.readv(bufs) file_ref.readv(bufs)
} }
pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize, Error> { pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize> {
info!("pwrite: fd: {}, offset: {}", fd, offset); info!("pwrite: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -101,7 +101,7 @@ pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize, Error
file_ref.write_at(offset, buf) file_ref.write_at(offset, buf)
} }
pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize, Error> { pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize> {
info!("pread: fd: {}, offset: {}", fd, offset); info!("pread: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -109,12 +109,12 @@ pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize, Er
file_ref.read_at(offset, buf) file_ref.read_at(offset, buf)
} }
pub fn do_stat(path: &str) -> Result<Stat, Error> { pub fn do_stat(path: &str) -> Result<Stat> {
warn!("stat is partial implemented as lstat"); warn!("stat is partial implemented as lstat");
do_lstat(path) do_lstat(path)
} }
pub fn do_fstat(fd: u32) -> Result<Stat, Error> { pub fn do_fstat(fd: u32) -> Result<Stat> {
info!("fstat: fd: {}", fd); info!("fstat: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -124,7 +124,7 @@ pub fn do_fstat(fd: u32) -> Result<Stat, Error> {
Ok(stat) Ok(stat)
} }
pub fn do_lstat(path: &str) -> Result<Stat, Error> { pub fn do_lstat(path: &str) -> Result<Stat> {
info!("lstat: path: {}", path); info!("lstat: path: {}", path);
let current_ref = process::get_current(); let current_ref = process::get_current();
@ -134,14 +134,14 @@ pub fn do_lstat(path: &str) -> Result<Stat, Error> {
Ok(stat) Ok(stat)
} }
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> { pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?; let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.seek(offset) file_ref.seek(offset)
} }
pub fn do_fsync(fd: FileDesc) -> Result<(), Error> { pub fn do_fsync(fd: FileDesc) -> Result<()> {
info!("fsync: fd: {}", fd); info!("fsync: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -150,7 +150,7 @@ pub fn do_fsync(fd: FileDesc) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_fdatasync(fd: FileDesc) -> Result<(), Error> { pub fn do_fdatasync(fd: FileDesc) -> Result<()> {
info!("fdatasync: fd: {}", fd); info!("fdatasync: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -159,7 +159,7 @@ pub fn do_fdatasync(fd: FileDesc) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_truncate(path: &str, len: usize) -> Result<(), Error> { pub fn do_truncate(path: &str, len: usize) -> Result<()> {
info!("truncate: path: {:?}, len: {}", path, len); info!("truncate: path: {:?}, len: {}", path, len);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -167,7 +167,7 @@ pub fn do_truncate(path: &str, len: usize) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<(), Error> { pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<()> {
info!("ftruncate: fd: {}, len: {}", fd, len); info!("ftruncate: fd: {}, len: {}", fd, len);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -176,7 +176,7 @@ pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> { pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!( info!(
"getdents64: fd: {}, buf: {:?}, buf_size: {}", "getdents64: fd: {}, buf: {:?}, buf_size: {}",
fd, fd,
@ -188,24 +188,30 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
let file_ref = current_process.get_files().lock().unwrap().get(fd)?; let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let info = file_ref.metadata()?; let info = file_ref.metadata()?;
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
return errno!(ENOTDIR, ""); return_errno!(ENOTDIR, "");
} }
let mut writer = unsafe { DirentBufWriter::new(buf) }; let mut writer = unsafe { DirentBufWriter::new(buf) };
loop { loop {
let name = match file_ref.read_entry() { let name = match file_ref.read_entry() {
Err(e) if e.errno == ENOENT => break, Err(e) => {
r => r, let errno = e.errno();
}?; if errno == ENOENT {
break;
}
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
}
Ok(name) => name,
};
// TODO: get ino from dirent // TODO: get ino from dirent
let ok = writer.try_write(0, 0, &name); let ok = writer.try_write(0, 0, &name);
if !ok { if !ok {
break; return_errno!(EINVAL, "the given buffer is too small");
} }
} }
Ok(writer.written_size) Ok(writer.written_size)
} }
pub fn do_close(fd: FileDesc) -> Result<(), Error> { pub fn do_close(fd: FileDesc) -> Result<()> {
info!("close: fd: {}", fd); info!("close: fd: {}", fd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
@ -215,7 +221,7 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> { pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
info!("pipe2: flags: {:#x}", flags); info!("pipe2: flags: {:#x}", flags);
let flags = OpenFlags::from_bits_truncate(flags); let flags = OpenFlags::from_bits_truncate(flags);
let current_ref = process::get_current(); let current_ref = process::get_current();
@ -231,7 +237,7 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
Ok([reader_fd, writer_fd]) Ok([reader_fd, writer_fd])
} }
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> { pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current = current_ref.lock().unwrap(); let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files(); let file_table_ref = current.get_files();
@ -241,7 +247,7 @@ pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> {
Ok(new_fd) Ok(new_fd)
} }
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> { pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current = current_ref.lock().unwrap(); let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files(); let file_table_ref = current.get_files();
@ -253,7 +259,7 @@ pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> {
Ok(new_fd) Ok(new_fd)
} }
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc, Error> { pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc> {
let flags = OpenFlags::from_bits_truncate(flags); let flags = OpenFlags::from_bits_truncate(flags);
let current_ref = process::get_current(); let current_ref = process::get_current();
let current = current_ref.lock().unwrap(); let current = current_ref.lock().unwrap();
@ -261,20 +267,20 @@ pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDes
let mut file_table = file_table_ref.lock().unwrap(); let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?; let file = file_table.get(old_fd)?;
if old_fd == new_fd { if old_fd == new_fd {
return errno!(EINVAL, "old_fd must not be equal to new_fd"); return_errno!(EINVAL, "old_fd must not be equal to new_fd");
} }
let close_on_spawn = flags.contains(OpenFlags::CLOEXEC); let close_on_spawn = flags.contains(OpenFlags::CLOEXEC);
file_table.put_at(new_fd, file, close_on_spawn); file_table.put_at(new_fd, file, close_on_spawn);
Ok(new_fd) Ok(new_fd)
} }
pub fn do_sync() -> Result<(), Error> { pub fn do_sync() -> Result<()> {
info!("sync:"); info!("sync:");
ROOT_INODE.fs().sync()?; ROOT_INODE.fs().sync()?;
Ok(()) Ok(())
} }
pub fn do_chdir(path: &str) -> Result<(), Error> { pub fn do_chdir(path: &str) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap(); let mut current_process = current_ref.lock().unwrap();
info!("chdir: path: {:?}", path); info!("chdir: path: {:?}", path);
@ -282,13 +288,13 @@ pub fn do_chdir(path: &str) -> Result<(), Error> {
let inode = current_process.lookup_inode(path)?; let inode = current_process.lookup_inode(path)?;
let info = inode.metadata()?; let info = inode.metadata()?;
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
return errno!(ENOTDIR, ""); return_errno!(ENOTDIR, "");
} }
current_process.change_cwd(path); current_process.change_cwd(path);
Ok(()) Ok(())
} }
pub fn do_rename(oldpath: &str, newpath: &str) -> Result<(), Error> { pub fn do_rename(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
info!("rename: oldpath: {:?}, newpath: {:?}", oldpath, newpath); info!("rename: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
@ -301,7 +307,7 @@ pub fn do_rename(oldpath: &str, newpath: &str) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_mkdir(path: &str, mode: usize) -> Result<(), Error> { pub fn do_mkdir(path: &str, mode: usize) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
// TODO: check pathname // TODO: check pathname
@ -310,16 +316,16 @@ pub fn do_mkdir(path: &str, mode: usize) -> Result<(), Error> {
let (dir_path, file_name) = split_path(&path); let (dir_path, file_name) = split_path(&path);
let inode = current_process.lookup_inode(dir_path)?; let inode = current_process.lookup_inode(dir_path)?;
if inode.find(file_name).is_ok() { if inode.find(file_name).is_ok() {
return errno!(EEXIST, ""); return_errno!(EEXIST, "");
} }
if !inode.allow_write()? { if !inode.allow_write()? {
return errno!(EPERM, "dir cannot be written"); return_errno!(EPERM, "dir cannot be written");
} }
inode.create(file_name, FileType::Dir, mode as u32)?; inode.create(file_name, FileType::Dir, mode as u32)?;
Ok(()) Ok(())
} }
pub fn do_rmdir(path: &str) -> Result<(), Error> { pub fn do_rmdir(path: &str) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
info!("rmdir: path: {:?}", path); info!("rmdir: path: {:?}", path);
@ -328,13 +334,13 @@ pub fn do_rmdir(path: &str) -> Result<(), Error> {
let dir_inode = current_process.lookup_inode(dir_path)?; let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?; let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ != FileType::Dir { if file_inode.metadata()?.type_ != FileType::Dir {
return errno!(ENOTDIR, "rmdir on not directory"); return_errno!(ENOTDIR, "rmdir on not directory");
} }
dir_inode.unlink(file_name)?; dir_inode.unlink(file_name)?;
Ok(()) Ok(())
} }
pub fn do_link(oldpath: &str, newpath: &str) -> Result<(), Error> { pub fn do_link(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath); info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
@ -346,7 +352,7 @@ pub fn do_link(oldpath: &str, newpath: &str) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_unlink(path: &str) -> Result<(), Error> { pub fn do_unlink(path: &str) -> Result<()> {
let current_ref = process::get_current(); let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();
info!("unlink: path: {:?}", path); info!("unlink: path: {:?}", path);
@ -355,7 +361,7 @@ pub fn do_unlink(path: &str) -> Result<(), Error> {
let dir_inode = current_process.lookup_inode(dir_path)?; let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?; let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir { if file_inode.metadata()?.type_ == FileType::Dir {
return errno!(EISDIR, "unlink on directory"); return_errno!(EISDIR, "unlink on directory");
} }
dir_inode.unlink(file_name)?; dir_inode.unlink(file_name)?;
Ok(()) Ok(())
@ -366,7 +372,7 @@ pub fn do_sendfile(
in_fd: FileDesc, in_fd: FileDesc,
offset: Option<off_t>, offset: Option<off_t>,
count: usize, count: usize,
) -> Result<(usize, usize), Error> { ) -> Result<(usize, usize)> {
// (len, offset) // (len, offset)
info!( info!(
"sendfile: out: {}, in: {}, offset: {:?}, count: {}", "sendfile: out: {}, in: {}, offset: {:?}, count: {}",
@ -400,7 +406,7 @@ pub fn do_sendfile(
while bytes_written < read_len { while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..])?; let write_len = out_file.write(&buffer[bytes_written..])?;
if write_len == 0 { if write_len == 0 {
return errno!(EBADF, "sendfile write return 0"); return_errno!(EBADF, "sendfile write return 0");
} }
bytes_written += write_len; bytes_written += write_len;
} }
@ -418,7 +424,7 @@ extern "C" {
impl Process { impl Process {
/// Open a file on the process. But DO NOT add it to file table. /// Open a file on the process. But DO NOT add it to file table.
pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result<Box<File>, Error> { pub fn open_file(&self, path: &str, flags: OpenFlags, mode: u32) -> Result<Box<File>> {
if path == "/dev/null" { if path == "/dev/null" {
return Ok(Box::new(DevNull)); return Ok(Box::new(DevNull));
} }
@ -434,13 +440,13 @@ impl Process {
match dir_inode.find(file_name) { match dir_inode.find(file_name) {
Ok(file_inode) => { Ok(file_inode) => {
if flags.contains(OpenFlags::EXCLUSIVE) { if flags.contains(OpenFlags::EXCLUSIVE) {
return errno!(EEXIST, "file exists"); return_errno!(EEXIST, "file exists");
} }
file_inode file_inode
} }
Err(FsError::EntryNotFound) => { Err(FsError::EntryNotFound) => {
if !dir_inode.allow_write()? { if !dir_inode.allow_write()? {
return errno!(EPERM, "file cannot be created"); return_errno!(EPERM, "file cannot be created");
} }
dir_inode.create(file_name, FileType::File, mode)? dir_inode.create(file_name, FileType::File, mode)?
} }
@ -453,7 +459,7 @@ impl Process {
} }
/// Lookup INode from the cwd of the process /// Lookup INode from the cwd of the process
pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, Error> { pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>> {
debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path); debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path);
if path.len() > 0 && path.as_bytes()[0] == b'/' { if path.len() > 0 && path.as_bytes()[0] == b'/' {
// absolute path // absolute path
@ -727,7 +733,7 @@ pub enum FcntlCmd {
impl FcntlCmd { impl FcntlCmd {
#[deny(unreachable_patterns)] #[deny(unreachable_patterns)]
pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd, Error> { pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd> {
Ok(match cmd as c_int { Ok(match cmd as c_int {
libc::F_DUPFD => FcntlCmd::DupFd(arg as FileDesc), libc::F_DUPFD => FcntlCmd::DupFd(arg as FileDesc),
libc::F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc), libc::F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc),
@ -735,12 +741,12 @@ impl FcntlCmd {
libc::F_SETFD => FcntlCmd::SetFd(arg as u32), libc::F_SETFD => FcntlCmd::SetFd(arg as u32),
libc::F_GETFL => FcntlCmd::GetFl(), libc::F_GETFL => FcntlCmd::GetFl(),
libc::F_SETFL => FcntlCmd::SetFl(arg as u32), libc::F_SETFL => FcntlCmd::SetFl(arg as u32),
_ => return errno!(EINVAL, "invalid command"), _ => return_errno!(EINVAL, "invalid command"),
}) })
} }
} }
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> { pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd); info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();
@ -796,7 +802,7 @@ pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> {
}) })
} }
pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize, Error> { pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize> {
info!("readlink: path: {:?}", path); info!("readlink: path: {:?}", path);
match path { match path {
"/proc/self/exe" => { "/proc/self/exe" => {
@ -810,7 +816,7 @@ pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize, Error> {
} }
_ => { _ => {
// TODO: support symbolic links // TODO: support symbolic links
errno!(EINVAL, "not a symbolic link") return_errno!(EINVAL, "not a symbolic link")
} }
} }
} }

@ -12,7 +12,7 @@ pub struct Pipe {
} }
impl Pipe { impl Pipe {
pub fn new() -> Result<Pipe, Error> { pub fn new() -> Result<Pipe> {
let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE); let mut ring_buf = RingBuf::new(PIPE_BUF_SIZE);
Ok(Pipe { Ok(Pipe {
reader: PipeReader { reader: PipeReader {
@ -31,24 +31,24 @@ pub struct PipeReader {
} }
impl File for PipeReader { impl File for PipeReader {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
let ringbuf = self.inner.lock().unwrap(); let ringbuf = self.inner.lock().unwrap();
ringbuf.read(buf) ringbuf.read(buf)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
errno!(EBADF, "PipeReader does not support write") return_errno!(EBADF, "PipeReader does not support write")
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut ringbuf = self.inner.lock().unwrap(); let mut ringbuf = self.inner.lock().unwrap();
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -72,31 +72,31 @@ impl File for PipeReader {
Ok(total_bytes) Ok(total_bytes)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
errno!(EBADF, "PipeReader does not support write") return_errno!(EBADF, "PipeReader does not support write")
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Pipe does not support seek") return_errno!(ESPIPE, "Pipe does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }
@ -114,27 +114,27 @@ pub struct PipeWriter {
} }
impl File for PipeWriter { impl File for PipeWriter {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
errno!(EBADF, "PipeWriter does not support read") return_errno!(EBADF, "PipeWriter does not support read")
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
let ringbuf = self.inner.lock().unwrap(); let ringbuf = self.inner.lock().unwrap();
ringbuf.write(buf) ringbuf.write(buf)
} }
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
unimplemented!() unimplemented!()
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
errno!(EBADF, "PipeWriter does not support read") return_errno!(EBADF, "PipeWriter does not support read")
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let ringbuf = self.inner.lock().unwrap(); let ringbuf = self.inner.lock().unwrap();
let mut total_bytes = 0; let mut total_bytes = 0;
for buf in bufs { for buf in bufs {
@ -158,27 +158,27 @@ impl File for PipeWriter {
Ok(total_bytes) Ok(total_bytes)
} }
fn seek(&self, seek_pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, seek_pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Pipe does not support seek") return_errno!(ESPIPE, "Pipe does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
unimplemented!() unimplemented!()
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }

@ -13,34 +13,38 @@ use rcore_fs_sefs::SEFS;
lazy_static! { lazy_static! {
/// The root of file system /// The root of file system
pub static ref ROOT_INODE: Arc<INode> = { pub static ref ROOT_INODE: Arc<INode> = {
fn init_root_inode() -> Result<Arc<INode>> {
let mount_config = &config::LIBOS_CONFIG.mount; let mount_config = &config::LIBOS_CONFIG.mount;
let root_inode = {
let rootfs = open_root_fs_according_to(mount_config)?;
rootfs.root_inode()
};
mount_nonroot_fs_according_to(mount_config, &root_inode)?;
Ok(root_inode)
}
let rootfs = open_root_fs_according_to(mount_config) init_root_inode().unwrap_or_else(|e| {
.expect("failed to create or open SEFS for /"); error!("failed to init root inode: {}", e.backtrace());
let root = rootfs.root_inode(); panic!();
})
mount_nonroot_fs_according_to(mount_config, &root)
.expect("failed to create or open other FS");
root
}; };
} }
fn open_root_fs_according_to(mount_config: &Vec<ConfigMount>) -> Result<Arc<MountFS>, Error> { fn open_root_fs_according_to(mount_config: &Vec<ConfigMount>) -> Result<Arc<MountFS>> {
let (root_sefs_mac, root_sefs_source) = { let (root_sefs_mac, root_sefs_source) = {
let root_mount_config = mount_config let root_mount_config = mount_config
.iter() .iter()
.find(|m| m.target == Path::new("/")) .find(|m| m.target == Path::new("/"))
.ok_or_else(|| Error::new(Errno::ENOENT, "The mount point at / is not specified"))?; .ok_or_else(|| errno!(Errno::ENOENT, "the mount point at / is not specified"))?;
if root_mount_config.type_ != ConfigMountFsType::TYPE_SEFS { if root_mount_config.type_ != ConfigMountFsType::TYPE_SEFS {
return errno!(EINVAL, "The mount point at / must be SEFS"); return_errno!(EINVAL, "The mount point at / must be SEFS");
} }
if !root_mount_config.options.integrity_only { if !root_mount_config.options.integrity_only {
return errno!(EINVAL, "The root SEFS at / must be integrity-only"); return_errno!(EINVAL, "The root SEFS at / must be integrity-only");
} }
if root_mount_config.source.is_none() { if root_mount_config.source.is_none() {
return errno!( return_errno!(
EINVAL, EINVAL,
"The root SEFS must be given a source path (on host)" "The root SEFS must be given a source path (on host)"
); );
@ -60,20 +64,17 @@ fn open_root_fs_according_to(mount_config: &Vec<ConfigMount>) -> Result<Arc<Moun
Ok(root_mountable_sefs) Ok(root_mountable_sefs)
} }
fn mount_nonroot_fs_according_to( fn mount_nonroot_fs_according_to(mount_config: &Vec<ConfigMount>, root: &MNode) -> Result<()> {
mount_config: &Vec<ConfigMount>,
root: &MNode,
) -> Result<(), Error> {
for mc in mount_config { for mc in mount_config {
if mc.target == Path::new("/") { if mc.target == Path::new("/") {
continue; continue;
} }
if !mc.target.is_absolute() { if !mc.target.is_absolute() {
return errno!(EINVAL, "The target path must be absolute"); return_errno!(EINVAL, "The target path must be absolute");
} }
if mc.target.parent().unwrap() != Path::new("/") { if mc.target.parent().unwrap() != Path::new("/") {
return errno!(EINVAL, "The target mount point must be under /"); return_errno!(EINVAL, "The target mount point must be under /");
} }
let target_dirname = mc.target.file_name().unwrap().to_str().unwrap(); let target_dirname = mc.target.file_name().unwrap().to_str().unwrap();
@ -81,10 +82,10 @@ fn mount_nonroot_fs_according_to(
match mc.type_ { match mc.type_ {
TYPE_SEFS => { TYPE_SEFS => {
if mc.options.integrity_only { if mc.options.integrity_only {
return errno!(EINVAL, "Cannot mount integrity-only SEFS at non-root path"); return_errno!(EINVAL, "Cannot mount integrity-only SEFS at non-root path");
} }
if mc.source.is_none() { if mc.source.is_none() {
return errno!(EINVAL, "Source is expected for SEFS"); return_errno!(EINVAL, "Source is expected for SEFS");
} }
let source_path = mc.source.as_ref().unwrap(); let source_path = mc.source.as_ref().unwrap();
let sefs = { let sefs = {
@ -105,7 +106,7 @@ fn mount_nonroot_fs_according_to(
} }
TYPE_HOSTFS => { TYPE_HOSTFS => {
if mc.source.is_none() { if mc.source.is_none() {
return errno!(EINVAL, "Source is expected for HostFS"); return_errno!(EINVAL, "Source is expected for HostFS");
} }
let source_path = mc.source.as_ref().unwrap(); let source_path = mc.source.as_ref().unwrap();
@ -121,15 +122,15 @@ fn mount_nonroot_fs_according_to(
Ok(()) Ok(())
} }
fn mount_fs_at(fs: Arc<dyn FileSystem>, parent_inode: &MNode, dirname: &str) -> Result<(), Error> { fn mount_fs_at(fs: Arc<dyn FileSystem>, parent_inode: &MNode, dirname: &str) -> Result<()> {
let mount_dir = match parent_inode.find(false, dirname) { let mount_dir = match parent_inode.find(false, dirname) {
Ok(existing_dir) => { Ok(existing_dir) => {
if existing_dir.metadata()?.type_ != FileType::Dir { if existing_dir.metadata()?.type_ != FileType::Dir {
return errno!(EIO, "not a directory"); return_errno!(EIO, "not a directory");
} }
existing_dir existing_dir
} }
Err(_) => return errno!(ENOENT, "Mount point does not exist"), Err(_) => return_errno!(ENOENT, "Mount point does not exist"),
}; };
mount_dir.mount(fs); mount_dir.mount(fs);
Ok(()) Ok(())

@ -129,8 +129,8 @@ impl Storage for SgxStorage {
if file_id == "metadata" && self.root_mac.is_some() { if file_id == "metadata" && self.root_mac.is_some() {
let root_file_mac = file.get_mac().expect("Failed to get mac"); let root_file_mac = file.get_mac().expect("Failed to get mac");
if root_file_mac != self.root_mac.unwrap() { if root_file_mac != self.root_mac.unwrap() {
println!( error!(
"Expected MAC = {:#?}, actual MAC = {:?}", "MAC validation for metadata file failed: expected = {:#?}, found = {:?}",
self.root_mac.unwrap(), self.root_mac.unwrap(),
root_file_mac root_file_mac
); );

@ -8,7 +8,7 @@ pub struct SocketFile {
} }
impl SocketFile { impl SocketFile {
pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<Self, Error> { pub fn new(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<Self> {
let ret = try_libc!(libc::ocall::socket(domain, socket_type, protocol)); let ret = try_libc!(libc::ocall::socket(domain, socket_type, protocol));
Ok(SocketFile { fd: ret }) Ok(SocketFile { fd: ret })
} }
@ -18,7 +18,7 @@ impl SocketFile {
addr: *mut libc::sockaddr, addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t, addr_len: *mut libc::socklen_t,
flags: c_int, flags: c_int,
) -> Result<Self, Error> { ) -> Result<Self> {
let ret = try_libc!(libc::ocall::accept4(self.fd, addr, addr_len, flags)); let ret = try_libc!(libc::ocall::accept4(self.fd, addr, addr_len, flags));
Ok(SocketFile { fd: ret }) Ok(SocketFile { fd: ret })
} }
@ -42,7 +42,7 @@ impl Drop for SocketFile {
} }
impl File for SocketFile { impl File for SocketFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
let ret = try_libc!(libc::ocall::read( let ret = try_libc!(libc::ocall::read(
self.fd, self.fd,
buf.as_mut_ptr() as *mut c_void, buf.as_mut_ptr() as *mut c_void,
@ -51,7 +51,7 @@ impl File for SocketFile {
Ok(ret as usize) Ok(ret as usize)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
let ret = try_libc!(libc::ocall::write( let ret = try_libc!(libc::ocall::write(
self.fd, self.fd,
buf.as_ptr() as *const c_void, buf.as_ptr() as *const c_void,
@ -60,15 +60,15 @@ impl File for SocketFile {
Ok(ret as usize) Ok(ret as usize)
} }
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read(buf) self.read(buf)
} }
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
self.write(buf) self.write(buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut total_len = 0; let mut total_len = 0;
for buf in bufs { for buf in bufs {
match self.read(buf) { match self.read(buf) {
@ -82,7 +82,7 @@ impl File for SocketFile {
Ok(total_len) Ok(total_len)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut total_len = 0; let mut total_len = 0;
for buf in bufs { for buf in bufs {
match self.write(buf) { match self.write(buf) {
@ -96,11 +96,11 @@ impl File for SocketFile {
Ok(total_len) Ok(total_len)
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "Socket does not support seek") return_errno!(ESPIPE, "Socket does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
Ok(Metadata { Ok(Metadata {
dev: 0, dev: 0,
inode: 0, inode: 0,
@ -119,19 +119,19 @@ impl File for SocketFile {
}) })
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }
@ -141,13 +141,13 @@ impl File for SocketFile {
} }
pub trait AsSocket { pub trait AsSocket {
fn as_socket(&self) -> Result<&SocketFile, Error>; fn as_socket(&self) -> Result<&SocketFile>;
} }
impl AsSocket for FileRef { impl AsSocket for FileRef {
fn as_socket(&self) -> Result<&SocketFile, Error> { fn as_socket(&self) -> Result<&SocketFile> {
self.as_any() self.as_any()
.downcast_ref::<SocketFile>() .downcast_ref::<SocketFile>()
.ok_or(Error::new(Errno::EBADF, "not a socket")) .ok_or_else(|| errno!(EBADF, "not a socket"))
} }
} }

@ -11,25 +11,25 @@ pub struct UnixSocketFile {
} }
impl File for UnixSocketFile { impl File for UnixSocketFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { fn read(&self, buf: &mut [u8]) -> Result<usize> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.read(buf) inner.read(buf)
} }
fn write(&self, buf: &[u8]) -> Result<usize, Error> { fn write(&self, buf: &[u8]) -> Result<usize> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.write(buf) inner.write(buf)
} }
fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize, Error> { fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result<usize> {
self.read(buf) self.read(buf)
} }
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize, Error> { fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
self.write(buf) self.write(buf)
} }
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize, Error> { fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
let mut total_len = 0; let mut total_len = 0;
for buf in bufs { for buf in bufs {
@ -44,7 +44,7 @@ impl File for UnixSocketFile {
Ok(total_len) Ok(total_len)
} }
fn writev(&self, bufs: &[&[u8]]) -> Result<usize, Error> { fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
let mut total_len = 0; let mut total_len = 0;
for buf in bufs { for buf in bufs {
@ -59,11 +59,11 @@ impl File for UnixSocketFile {
Ok(total_len) Ok(total_len)
} }
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> { fn seek(&self, pos: SeekFrom) -> Result<off_t> {
errno!(ESPIPE, "UnixSocket does not support seek") return_errno!(ESPIPE, "UnixSocket does not support seek")
} }
fn metadata(&self) -> Result<Metadata, Error> { fn metadata(&self) -> Result<Metadata> {
Ok(Metadata { Ok(Metadata {
dev: 0, dev: 0,
inode: 0, inode: 0,
@ -82,19 +82,19 @@ impl File for UnixSocketFile {
}) })
} }
fn set_len(&self, len: u64) -> Result<(), Error> { fn set_len(&self, len: u64) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_all(&self) -> Result<(), Error> { fn sync_all(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn sync_data(&self) -> Result<(), Error> { fn sync_data(&self) -> Result<()> {
unimplemented!() unimplemented!()
} }
fn read_entry(&self) -> Result<String, Error> { fn read_entry(&self) -> Result<String> {
unimplemented!() unimplemented!()
} }
@ -104,24 +104,24 @@ impl File for UnixSocketFile {
} }
impl UnixSocketFile { impl UnixSocketFile {
pub fn new(socket_type: c_int, protocol: c_int) -> Result<Self, Error> { pub fn new(socket_type: c_int, protocol: c_int) -> Result<Self> {
let inner = UnixSocket::new(socket_type, protocol)?; let inner = UnixSocket::new(socket_type, protocol)?;
Ok(UnixSocketFile { Ok(UnixSocketFile {
inner: Mutex::new(inner), inner: Mutex::new(inner),
}) })
} }
pub fn bind(&self, path: impl AsRef<str>) -> Result<(), Error> { pub fn bind(&self, path: impl AsRef<str>) -> Result<()> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.bind(path) inner.bind(path)
} }
pub fn listen(&self) -> Result<(), Error> { pub fn listen(&self) -> Result<()> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.listen() inner.listen()
} }
pub fn accept(&self) -> Result<UnixSocketFile, Error> { pub fn accept(&self) -> Result<UnixSocketFile> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
let new_socket = inner.accept()?; let new_socket = inner.accept()?;
Ok(UnixSocketFile { Ok(UnixSocketFile {
@ -129,17 +129,17 @@ impl UnixSocketFile {
}) })
} }
pub fn connect(&self, path: impl AsRef<str>) -> Result<(), Error> { pub fn connect(&self, path: impl AsRef<str>) -> Result<()> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.connect(path) inner.connect(path)
} }
pub fn poll(&self) -> Result<(bool, bool, bool), Error> { pub fn poll(&self) -> Result<(bool, bool, bool)> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.poll() inner.poll()
} }
pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> { pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<()> {
let mut inner = self.inner.lock().unwrap(); let mut inner = self.inner.lock().unwrap();
inner.ioctl(cmd, argp) inner.ioctl(cmd, argp)
} }
@ -152,14 +152,14 @@ impl Debug for UnixSocketFile {
} }
pub trait AsUnixSocket { pub trait AsUnixSocket {
fn as_unix_socket(&self) -> Result<&UnixSocketFile, Error>; fn as_unix_socket(&self) -> Result<&UnixSocketFile>;
} }
impl AsUnixSocket for FileRef { impl AsUnixSocket for FileRef {
fn as_unix_socket(&self) -> Result<&UnixSocketFile, Error> { fn as_unix_socket(&self) -> Result<&UnixSocketFile> {
self.as_any() self.as_any()
.downcast_ref::<UnixSocketFile>() .downcast_ref::<UnixSocketFile>()
.ok_or(Error::new(Errno::EBADF, "not a unix socket")) .ok_or_else(|| errno!(EBADF, "not a unix socket"))
} }
} }
@ -176,38 +176,38 @@ enum Status {
impl UnixSocket { impl UnixSocket {
/// C/S 1: Create a new unix socket /// C/S 1: Create a new unix socket
pub fn new(socket_type: c_int, protocol: c_int) -> Result<Self, Error> { pub fn new(socket_type: c_int, protocol: c_int) -> Result<Self> {
if socket_type == libc::SOCK_STREAM && protocol == 0 { if socket_type == libc::SOCK_STREAM && protocol == 0 {
Ok(UnixSocket { Ok(UnixSocket {
obj: None, obj: None,
status: Status::None, status: Status::None,
}) })
} else { } else {
errno!(ENOSYS, "unimplemented unix socket type") return_errno!(ENOSYS, "unimplemented unix socket type")
} }
} }
/// Server 2: Bind the socket to a file system path /// Server 2: Bind the socket to a file system path
pub fn bind(&mut self, path: impl AsRef<str>) -> Result<(), Error> { pub fn bind(&mut self, path: impl AsRef<str>) -> Result<()> {
// TODO: check permission // TODO: check permission
if self.obj.is_some() { if self.obj.is_some() {
return errno!(EINVAL, "The socket is already bound to an address."); return_errno!(EINVAL, "The socket is already bound to an address.");
} }
self.obj = Some(UnixSocketObject::create(path)?); self.obj = Some(UnixSocketObject::create(path)?);
Ok(()) Ok(())
} }
/// Server 3: Listen to a socket /// Server 3: Listen to a socket
pub fn listen(&mut self) -> Result<(), Error> { pub fn listen(&mut self) -> Result<()> {
self.status = Status::Listening; self.status = Status::Listening;
Ok(()) Ok(())
} }
/// Server 4: Accept a connection on listening. /// Server 4: Accept a connection on listening.
pub fn accept(&mut self) -> Result<UnixSocket, Error> { pub fn accept(&mut self) -> Result<UnixSocket> {
match self.status { match self.status {
Status::Listening => {} Status::Listening => {}
_ => return errno!(EINVAL, "unix socket is not listening"), _ => return_errno!(EINVAL, "unix socket is not listening"),
}; };
// FIXME: Block. Now spin loop. // FIXME: Block. Now spin loop.
let socket = loop { let socket = loop {
@ -220,12 +220,12 @@ impl UnixSocket {
} }
/// Client 2: Connect to a path /// Client 2: Connect to a path
pub fn connect(&mut self, path: impl AsRef<str>) -> Result<(), Error> { pub fn connect(&mut self, path: impl AsRef<str>) -> Result<()> {
if let Status::Listening = self.status { if let Status::Listening = self.status {
return errno!(EINVAL, "unix socket is listening?"); return_errno!(EINVAL, "unix socket is listening?");
} }
let obj = let obj = UnixSocketObject::get(path)
UnixSocketObject::get(path).ok_or(Error::new(EINVAL, "unix socket path not found"))?; .ok_or_else(|| errno!(EINVAL, "unix socket path not found"))?;
let (channel1, channel2) = Channel::new_pair(); let (channel1, channel2) = Channel::new_pair();
self.status = Status::Connected(channel1); self.status = Status::Connected(channel1);
obj.push(UnixSocket { obj.push(UnixSocket {
@ -235,15 +235,15 @@ impl UnixSocket {
Ok(()) Ok(())
} }
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
self.channel()?.reader.read(buf) self.channel()?.reader.read(buf)
} }
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> { pub fn write(&self, buf: &[u8]) -> Result<usize> {
self.channel()?.writer.write(buf) self.channel()?.writer.write(buf)
} }
pub fn poll(&self) -> Result<(bool, bool, bool), Error> { pub fn poll(&self) -> Result<(bool, bool, bool)> {
// (read, write, error) // (read, write, error)
let channel = self.channel()?; let channel = self.channel()?;
let r = channel.reader.can_read(); let r = channel.reader.can_read();
@ -251,7 +251,7 @@ impl UnixSocket {
Ok((r, w, false)) Ok((r, w, false))
} }
pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<(), Error> { pub fn ioctl(&self, cmd: c_int, argp: *mut c_int) -> Result<()> {
const FIONREAD: c_int = 0x541B; // Get the number of bytes to read const FIONREAD: c_int = 0x541B; // Get the number of bytes to read
if cmd == FIONREAD { if cmd == FIONREAD {
let bytes_to_read = self.channel()?.reader.bytes_to_read(); let bytes_to_read = self.channel()?.reader.bytes_to_read();
@ -261,15 +261,15 @@ impl UnixSocket {
Ok(()) Ok(())
} else { } else {
warn!("ioctl for unix socket is unimplemented"); warn!("ioctl for unix socket is unimplemented");
errno!(ENOSYS, "ioctl for unix socket is unimplemented") return_errno!(ENOSYS, "ioctl for unix socket is unimplemented")
} }
} }
fn channel(&self) -> Result<&Channel, Error> { fn channel(&self) -> Result<&Channel> {
if let Status::Connected(channel) = &self.status { if let Status::Connected(channel) = &self.status {
Ok(channel) Ok(channel)
} else { } else {
errno!(EBADF, "UnixSocket is not connected") return_errno!(EBADF, "UnixSocket is not connected")
} }
} }
} }
@ -301,10 +301,10 @@ impl UnixSocketObject {
let mut paths = UNIX_SOCKET_OBJS.lock().unwrap(); let mut paths = UNIX_SOCKET_OBJS.lock().unwrap();
paths.get(path.as_ref()).map(|obj| obj.clone()) paths.get(path.as_ref()).map(|obj| obj.clone())
} }
fn create(path: impl AsRef<str>) -> Result<Arc<Self>, Error> { fn create(path: impl AsRef<str>) -> Result<Arc<Self>> {
let mut paths = UNIX_SOCKET_OBJS.lock().unwrap(); let mut paths = UNIX_SOCKET_OBJS.lock().unwrap();
if paths.contains_key(path.as_ref()) { if paths.contains_key(path.as_ref()) {
return errno!(EADDRINUSE, "unix socket path already exists"); return_errno!(EADDRINUSE, "unix socket path already exists");
} }
let obj = Arc::new(UnixSocketObject { let obj = Arc::new(UnixSocketObject {
path: path.as_ref().to_string(), path: path.as_ref().to_string(),

@ -37,11 +37,18 @@ use std::backtrace::{self, PrintFormat};
use std::ffi::CStr; // a borrowed C string use std::ffi::CStr; // a borrowed C string
use std::panic; use std::panic;
use error::*;
use prelude::*;
// Override prelude::Result with error::Result
use error::Result;
#[macro_use] #[macro_use]
mod prelude; mod prelude;
#[macro_use]
mod error;
mod config; mod config;
mod entry; mod entry;
mod errno;
mod exception; mod exception;
mod fs; mod fs;
mod misc; mod misc;
@ -51,8 +58,6 @@ mod time;
mod util; mod util;
mod vm; mod vm;
use prelude::*;
// Export system calls // Export system calls
pub use syscall::*; pub use syscall::*;
// Export ECalls // Export ECalls

@ -65,7 +65,7 @@ pub enum resource_t {
const RLIMIT_COUNT: usize = 15; const RLIMIT_COUNT: usize = 15;
impl resource_t { impl resource_t {
pub fn from_u32(bits: u32) -> Result<resource_t, Error> { pub fn from_u32(bits: u32) -> Result<resource_t> {
match bits { match bits {
0 => Ok(resource_t::RLIMIT_CPU), 0 => Ok(resource_t::RLIMIT_CPU),
1 => Ok(resource_t::RLIMIT_FSIZE), 1 => Ok(resource_t::RLIMIT_FSIZE),
@ -82,7 +82,7 @@ impl resource_t {
12 => Ok(resource_t::RLIMIT_MSGQUEUE), 12 => Ok(resource_t::RLIMIT_MSGQUEUE),
13 => Ok(resource_t::RLIMIT_NICE), 13 => Ok(resource_t::RLIMIT_NICE),
14 => Ok(resource_t::RLIMIT_RTPRIO), 14 => Ok(resource_t::RLIMIT_RTPRIO),
_ => errno!(EINVAL, "invalid resource"), _ => return_errno!(EINVAL, "invalid resource"),
} }
} }
} }
@ -92,11 +92,11 @@ pub fn do_prlimit(
resource: resource_t, resource: resource_t,
new_limit: Option<&rlimit_t>, new_limit: Option<&rlimit_t>,
old_limit: Option<&mut rlimit_t>, old_limit: Option<&mut rlimit_t>,
) -> Result<(), Error> { ) -> Result<()> {
let process_ref = if pid == 0 { let process_ref = if pid == 0 {
process::get_current() process::get_current()
} else { } else {
process::get(pid)? process::get(pid).cause_err(|_| errno!(ESRCH, "invalid pid"))?
}; };
let mut process = process_ref.lock().unwrap(); let mut process = process_ref.lock().unwrap();
let rlimits_ref = process.get_rlimits(); let rlimits_ref = process.get_rlimits();
@ -110,10 +110,10 @@ pub fn do_prlimit(
Ok(()) Ok(())
} }
pub fn do_getrlimit(resource: resource_t, old_limit: &mut rlimit_t) -> Result<(), Error> { pub fn do_getrlimit(resource: resource_t, old_limit: &mut rlimit_t) -> Result<()> {
do_prlimit(0 as pid_t, resource, None, Some(old_limit)) do_prlimit(0 as pid_t, resource, None, Some(old_limit))
} }
pub fn do_setrlimit(resource: resource_t, new_limit: &rlimit_t) -> Result<(), Error> { pub fn do_setrlimit(resource: resource_t, new_limit: &rlimit_t) -> Result<()> {
do_prlimit(0 as pid_t, resource, Some(new_limit), None) do_prlimit(0 as pid_t, resource, Some(new_limit), None)
} }

@ -23,7 +23,7 @@ pub struct utsname_t {
domainname: [u8; 65], domainname: [u8; 65],
} }
pub fn do_uname(name: &mut utsname_t) -> Result<(), Error> { pub fn do_uname(name: &mut utsname_t) -> Result<()> {
copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname); copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname);
copy_from_cstr_to_u8_array(&NODENAME, &mut name.nodename); copy_from_cstr_to_u8_array(&NODENAME, &mut name.nodename);
copy_from_cstr_to_u8_array(&RELEASE, &mut name.release); copy_from_cstr_to_u8_array(&RELEASE, &mut name.release);

@ -1,32 +1,16 @@
pub use sgx_trts::libc; pub use sgx_trts::libc;
pub use sgx_trts::libc::off_t; pub use sgx_trts::libc::off_t;
pub use sgx_types::*; pub use sgx_types::*;
use std; use std;
//pub use {elf_helper, errno, file, file_table, fs, mm, process, syscall, vma, };
pub use std::cell::{Cell, RefCell}; pub use std::cell::{Cell, RefCell};
pub use std::marker::{Send, Sync}; pub use std::cmp::{max, min};
pub use std::result::Result; pub use std::collections::{HashMap, VecDeque};
pub use std::fmt::{Debug, Display};
pub use std::prelude::v1::*;
pub use std::sync::{ pub use std::sync::{
Arc, SgxMutex, SgxMutexGuard, SgxRwLock, SgxRwLockReadGuard, SgxRwLockWriteGuard, Arc, SgxMutex, SgxMutexGuard, SgxRwLock, SgxRwLockReadGuard, SgxRwLockWriteGuard,
}; };
//pub use std::borrow::BorrowMut;
pub use std::borrow::ToOwned;
pub use std::boxed::Box;
pub use std::cmp::{max, min};
pub use std::cmp::{Ordering, PartialOrd};
pub use std::collections::{HashMap, VecDeque};
pub use std::fmt::{Debug, Display};
pub use std::io::{Read, Seek, SeekFrom, Write};
pub use std::iter::Iterator;
pub use std::rc::Rc;
pub use std::string::{String, ToString};
pub use std::vec::Vec;
pub use errno::Errno;
pub use errno::Errno::*;
pub use errno::Error;
macro_rules! debug_trace { macro_rules! debug_trace {
() => { () => {
@ -34,38 +18,6 @@ macro_rules! debug_trace {
}; };
} }
macro_rules! errno {
($errno: ident, $msg: expr) => {{
error!(
"ERROR: {} ({}, line {} in file {})",
$errno,
$msg,
line!(),
file!()
);
Err(Error::new($errno, $msg))
}};
}
// return Err(errno) if libc return -1
macro_rules! try_libc {
($ret: expr) => {{
let ret = unsafe { $ret };
if ret == -1 {
let errno = unsafe { libc::errno() };
// println will cause libc ocall and overwrite errno
error!(
"ERROR from libc: {} (line {} in file {})",
errno,
line!(),
file!()
);
return Err(Error::new(Errno::from_errno(errno), "libc error"));
}
ret
}};
}
pub fn align_up(addr: usize, align: usize) -> usize { pub fn align_up(addr: usize, align: usize) -> usize {
debug_assert!(align != 0 && align.is_power_of_two()); debug_assert!(align != 0 && align.is_power_of_two());
align_down(addr + (align - 1), align) align_down(addr + (align - 1), align)

@ -10,18 +10,18 @@ pub enum ArchPrctlCode {
} }
impl ArchPrctlCode { impl ArchPrctlCode {
pub fn from_u32(bits: u32) -> Result<ArchPrctlCode, Error> { pub fn from_u32(bits: u32) -> Result<ArchPrctlCode> {
match bits { match bits {
0x1001 => Ok(ArchPrctlCode::ARCH_SET_GS), 0x1001 => Ok(ArchPrctlCode::ARCH_SET_GS),
0x1002 => Ok(ArchPrctlCode::ARCH_SET_FS), 0x1002 => Ok(ArchPrctlCode::ARCH_SET_FS),
0x1003 => Ok(ArchPrctlCode::ARCH_GET_FS), 0x1003 => Ok(ArchPrctlCode::ARCH_GET_FS),
0x1004 => Ok(ArchPrctlCode::ARCH_GET_GS), 0x1004 => Ok(ArchPrctlCode::ARCH_GET_GS),
_ => errno!(EINVAL, "Unknown code for arch_prctl"), _ => return_errno!(EINVAL, "Unknown code for arch_prctl"),
} }
} }
} }
pub fn do_arch_prctl(code: ArchPrctlCode, addr: *mut usize) -> Result<(), Error> { pub fn do_arch_prctl(code: ArchPrctlCode, addr: *mut usize) -> Result<()> {
info!( info!(
"do_arch_prctl: code: {:?}, addr: {:#o}", "do_arch_prctl: code: {:?}, addr: {:#o}",
code, addr as usize code, addr as usize
@ -42,7 +42,7 @@ pub fn do_arch_prctl(code: ArchPrctlCode, addr: *mut usize) -> Result<(), Error>
} }
} }
ArchPrctlCode::ARCH_SET_GS | ArchPrctlCode::ARCH_GET_GS => { ArchPrctlCode::ARCH_SET_GS | ArchPrctlCode::ARCH_GET_GS => {
return errno!(EINVAL, "GS cannot be accessed from the user space"); return_errno!(EINVAL, "GS cannot be accessed from the user space");
} }
} }
Ok(()) Ok(())

@ -64,7 +64,7 @@ pub fn do_exit(exit_status: i32) {
}); });
} }
pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Result<pid_t, Error> { pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Result<pid_t> {
let current_ref = get_current(); let current_ref = get_current();
let waiter = { let waiter = {
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();
@ -91,7 +91,7 @@ pub fn do_wait4(child_filter: &ChildProcessFilter, exit_status: &mut i32) -> Res
any_child_to_wait_for = true; any_child_to_wait_for = true;
} }
if !any_child_to_wait_for { if !any_child_to_wait_for {
return errno!(ECHILD, "No such child"); return_errno!(ECHILD, "No such child");
} }
let waiter = Waiter::new(child_filter); let waiter = Waiter::new(child_filter);

@ -21,7 +21,7 @@ pub enum FutexOp {
const FUTEX_OP_MASK: u32 = 0x0000_000F; const FUTEX_OP_MASK: u32 = 0x0000_000F;
impl FutexOp { impl FutexOp {
pub fn from_u32(bits: u32) -> Result<FutexOp, Error> { pub fn from_u32(bits: u32) -> Result<FutexOp> {
match bits { match bits {
0 => Ok(FutexOp::FUTEX_WAIT), 0 => Ok(FutexOp::FUTEX_WAIT),
1 => Ok(FutexOp::FUTEX_WAKE), 1 => Ok(FutexOp::FUTEX_WAKE),
@ -33,7 +33,7 @@ impl FutexOp {
7 => Ok(FutexOp::FUTEX_UNLOCK_PI), 7 => Ok(FutexOp::FUTEX_UNLOCK_PI),
8 => Ok(FutexOp::FUTEX_TRYLOCK_PI), 8 => Ok(FutexOp::FUTEX_TRYLOCK_PI),
9 => Ok(FutexOp::FUTEX_WAIT_BITSET), 9 => Ok(FutexOp::FUTEX_WAIT_BITSET),
_ => errno!(EINVAL, "Unknown futex op"), _ => return_errno!(EINVAL, "Unknown futex op"),
} }
} }
} }
@ -47,12 +47,12 @@ bitflags! {
const FUTEX_FLAGS_MASK: u32 = 0xFFFF_FFF0; const FUTEX_FLAGS_MASK: u32 = 0xFFFF_FFF0;
impl FutexFlags { impl FutexFlags {
pub fn from_u32(bits: u32) -> Result<FutexFlags, Error> { pub fn from_u32(bits: u32) -> Result<FutexFlags> {
FutexFlags::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "Unknown futex flags")) FutexFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "unknown futex flags"))
} }
} }
pub fn futex_op_and_flags_from_u32(bits: u32) -> Result<(FutexOp, FutexFlags), Error> { pub fn futex_op_and_flags_from_u32(bits: u32) -> Result<(FutexOp, FutexFlags)> {
let op = { let op = {
let op_bits = bits & FUTEX_OP_MASK; let op_bits = bits & FUTEX_OP_MASK;
FutexOp::from_u32(op_bits)? FutexOp::from_u32(op_bits)?
@ -65,7 +65,7 @@ pub fn futex_op_and_flags_from_u32(bits: u32) -> Result<(FutexOp, FutexFlags), E
} }
/// Do futex wait /// Do futex wait
pub fn futex_wait(futex_addr: *const i32, futex_val: i32) -> Result<(), Error> { pub fn futex_wait(futex_addr: *const i32, futex_val: i32) -> Result<()> {
let futex_key = FutexKey::new(futex_addr); let futex_key = FutexKey::new(futex_addr);
let futex_item = FUTEX_TABLE.lock().unwrap().get_or_new_item(futex_key); let futex_item = FUTEX_TABLE.lock().unwrap().get_or_new_item(futex_key);
@ -76,7 +76,7 @@ pub fn futex_wait(futex_addr: *const i32, futex_val: i32) -> Result<(), Error> {
} }
/// Do futex wake /// Do futex wake
pub fn futex_wake(futex_addr: *const i32, max_count: usize) -> Result<usize, Error> { pub fn futex_wake(futex_addr: *const i32, max_count: usize) -> Result<usize> {
let futex_key = FutexKey::new(futex_addr); let futex_key = FutexKey::new(futex_addr);
let futex_item = FUTEX_TABLE.lock().unwrap().get_item(futex_key)?; let futex_item = FUTEX_TABLE.lock().unwrap().get_item(futex_key)?;
let count = futex_item.wake(max_count); let count = futex_item.wake(max_count);
@ -167,12 +167,12 @@ impl FutexTable {
item.clone() item.clone()
} }
pub fn get_item(&mut self, key: FutexKey) -> Result<FutexItemRef, Error> { pub fn get_item(&mut self, key: FutexKey) -> Result<FutexItemRef> {
let table = &mut self.table; let table = &mut self.table;
table table
.get_mut(&key) .get_mut(&key)
.map(|item| item.clone()) .map(|item| item.clone())
.ok_or_else(|| Error::new(Errno::ENOENT, "futex key cannot be found")) .ok_or_else(|| errno!(ENOENT, "futex key cannot be found"))
} }
pub fn put_item(&mut self, item: FutexItemRef) { pub fn put_item(&mut self, item: FutexItemRef) {

@ -33,7 +33,7 @@ impl Process {
vm_ref: ProcessVMRef, vm_ref: ProcessVMRef,
file_table_ref: FileTableRef, file_table_ref: FileTableRef,
rlimits_ref: ResourceLimitsRef, rlimits_ref: ResourceLimitsRef,
) -> Result<(pid_t, ProcessRef), Error> { ) -> Result<(pid_t, ProcessRef)> {
let new_pid = process_table::alloc_pid(); let new_pid = process_table::alloc_pid();
let new_process_ref = Arc::new(SgxMutex::new(Process { let new_process_ref = Arc::new(SgxMutex::new(Process {
task: task, task: task,

@ -14,13 +14,13 @@ pub fn remove(pid: pid_t) {
PROCESS_TABLE.lock().unwrap().remove(&pid); PROCESS_TABLE.lock().unwrap().remove(&pid);
} }
pub fn get(pid: pid_t) -> Result<ProcessRef, Error> { pub fn get(pid: pid_t) -> Result<ProcessRef> {
PROCESS_TABLE PROCESS_TABLE
.lock() .lock()
.unwrap() .unwrap()
.get(&pid) .get(&pid)
.map(|pr| pr.clone()) .map(|pr| pr.clone())
.ok_or_else(|| Error::new(Errno::ENOENT, "process not found")) .ok_or_else(|| errno!(ENOENT, "process not found"))
} }
static NEXT_PID: AtomicU32 = AtomicU32::new(1); static NEXT_PID: AtomicU32 = AtomicU32::new(1);

@ -61,7 +61,7 @@ impl CpuSet {
} }
impl std::fmt::LowerHex for CpuSet { impl std::fmt::LowerHex for CpuSet {
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
for byte in &(self.vec) { for byte in &(self.vec) {
try!(fmtr.write_fmt(format_args!("{:02x}", byte))); try!(fmtr.write_fmt(format_args!("{:02x}", byte)));
} }
@ -70,7 +70,7 @@ impl std::fmt::LowerHex for CpuSet {
} }
impl std::fmt::UpperHex for CpuSet { impl std::fmt::UpperHex for CpuSet {
fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { fn fmt(&self, fmtr: &mut std::fmt::Formatter) -> std::fmt::Result {
for byte in &(self.vec) { for byte in &(self.vec) {
try!(fmtr.write_fmt(format_args!("{:02X}", byte))); try!(fmtr.write_fmt(format_args!("{:02X}", byte)));
} }
@ -78,14 +78,14 @@ impl std::fmt::UpperHex for CpuSet {
} }
} }
fn find_host_tid(pid: pid_t) -> Result<pid_t, Error> { fn find_host_tid(pid: pid_t) -> Result<pid_t> {
let process_ref = if pid == 0 { get_current() } else { get(pid)? }; let process_ref = if pid == 0 { get_current() } else { get(pid)? };
let mut process = process_ref.lock().unwrap(); let mut process = process_ref.lock().unwrap();
let host_tid = process.get_host_tid(); let host_tid = process.get_host_tid();
Ok(host_tid) Ok(host_tid)
} }
pub fn do_sched_getaffinity(pid: pid_t, cpu_set: &mut CpuSet) -> Result<i32, Error> { pub fn do_sched_getaffinity(pid: pid_t, cpu_set: &mut CpuSet) -> Result<i32> {
let host_tid = match pid { let host_tid = match pid {
0 => 0, 0 => 0,
_ => find_host_tid(pid)?, _ => find_host_tid(pid)?,
@ -98,13 +98,13 @@ pub fn do_sched_getaffinity(pid: pid_t, cpu_set: &mut CpuSet) -> Result<i32, Err
ocall_sched_getaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf); ocall_sched_getaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
} }
if (ret < 0) { if (ret < 0) {
let errno = Errno::from_errno(error); let errno = Errno::from(error as u32);
return errno!(errno, "ocall_sched_getaffinity failed"); return_errno!(errno, "ocall_sched_getaffinity failed");
} }
Ok(ret) Ok(ret)
} }
pub fn do_sched_setaffinity(pid: pid_t, cpu_set: &CpuSet) -> Result<i32, Error> { pub fn do_sched_setaffinity(pid: pid_t, cpu_set: &CpuSet) -> Result<i32> {
let host_tid = match pid { let host_tid = match pid {
0 => 0, 0 => 0,
_ => find_host_tid(pid)?, _ => find_host_tid(pid)?,
@ -117,8 +117,8 @@ pub fn do_sched_setaffinity(pid: pid_t, cpu_set: &CpuSet) -> Result<i32, Error>
ocall_sched_setaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf); ocall_sched_setaffinity(&mut ret, &mut error, host_tid as i32, cpusize, buf);
} }
if (ret < 0) { if (ret < 0) {
let errno = Errno::from_errno(error); let errno = Errno::from(error as u32);
return errno!(errno, "ocall_sched_setaffinity failed"); return_errno!(errno, "ocall_sched_setaffinity failed");
} }
Ok(ret) Ok(ret)
} }

@ -13,7 +13,7 @@ pub struct ProgramHeaderInfo {
pub entry_num: usize, pub entry_num: usize,
} }
pub fn get_program_header_info(elf_file: &ElfFile) -> Result<ProgramHeaderInfo, Error> { pub fn get_program_header_info(elf_file: &ElfFile) -> Result<ProgramHeaderInfo> {
let elf_header = &elf_file.header.pt2; let elf_header = &elf_file.header.pt2;
Ok(ProgramHeaderInfo { Ok(ProgramHeaderInfo {
addr: elf_header.ph_offset() as usize, addr: elf_header.ph_offset() as usize,
@ -22,37 +22,37 @@ pub fn get_program_header_info(elf_file: &ElfFile) -> Result<ProgramHeaderInfo,
}) })
} }
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), Error> { pub fn print_program_headers(elf_file: &ElfFile) -> Result<()> {
println!("Program headers:"); println!("Program headers:");
let ph_iter = elf_file.program_iter(); let ph_iter = elf_file.program_iter();
for sect in ph_iter { for sect in ph_iter {
program::sanity_check(sect, &elf_file) program::sanity_check(sect, &elf_file)
.map_err(|e| (Errno::ENOEXEC, "Sanity check for program header failed"))?; .map_err(|e| errno!(ENOEXEC, "sanity check for program header failed"))?;
println!("\t{:?}", sect.get_type()); println!("\t{:?}", sect.get_type());
} }
Ok(()) Ok(())
} }
pub fn print_sections(elf_file: &ElfFile) -> Result<(), Error> { pub fn print_sections(elf_file: &ElfFile) -> Result<()> {
println!("Sections:"); println!("Sections:");
let mut sect_iter = elf_file.section_iter(); let mut sect_iter = elf_file.section_iter();
sect_iter.next(); // Skip the first, dummy section sect_iter.next(); // Skip the first, dummy section
for sect in sect_iter { for sect in sect_iter {
sections::sanity_check(sect, &elf_file) sections::sanity_check(sect, &elf_file)
.map_err(|e| (Errno::ENOEXEC, "Sanity check for program header failed"))?; .map_err(|e| errno!(ENOEXEC, "sanity check for program header failed"))?;
let sec_name = sect let sec_name = sect
.get_name(&elf_file) .get_name(&elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get section name"))?; .map_err(|e| errno!(ENOEXEC, "failed to get section name"))?;
println!("\t{}\n{:?}", sec_name, sect); println!("\t{}\n{:?}", sec_name, sect);
} }
Ok(()) Ok(())
} }
pub fn print_rela_plt_section(elf_file: &ElfFile) -> Result<(), Error> { pub fn print_rela_plt_section(elf_file: &ElfFile) -> Result<()> {
let rela_entries = get_rela_entries(elf_file, ".rela.plt") let rela_entries = get_rela_entries(elf_file, ".rela.plt")
.map_err(|e| (Errno::ENOEXEC, "Failed to get .pltrel entries"))?; .map_err(|e| errno!(ENOEXEC, "failed to get .pltrel entries"))?;
let dynsym_entries = get_dynsym_entries(elf_file) let dynsym_entries = get_dynsym_entries(elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get .dynsym entries"))?; .map_err(|e| errno!(ENOEXEC, "failed to get .dynsym entries"))?;
println!(".rela.plt section:"); println!(".rela.plt section:");
for entry in rela_entries { for entry in rela_entries {
@ -68,15 +68,13 @@ pub fn print_rela_plt_section(elf_file: &ElfFile) -> Result<(), Error> {
let dynsym_entry = &dynsym_entries[symidx]; let dynsym_entry = &dynsym_entries[symidx];
let dynsym_name = dynsym_entry let dynsym_name = dynsym_entry
.get_name(&elf_file) .get_name(&elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get the name of a dynamic symbol"))?; .map_err(|e| errno!(ENOEXEC, "failed to get the name of a dynamic symbol"))?;
println!("\t\t{} = {:?}", dynsym_name, dynsym_entry); println!("\t\t{} = {:?}", dynsym_name, dynsym_entry);
} }
Ok(()) Ok(())
} }
pub fn get_data_program_header<'b, 'a: 'b>( pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<ProgramHeader<'a>> {
elf_file: &'b ElfFile<'a>,
) -> Result<ProgramHeader<'a>, Error> {
let mut ph_iter = elf_file.program_iter(); let mut ph_iter = elf_file.program_iter();
ph_iter ph_iter
.find(|&ph| { .find(|&ph| {
@ -85,12 +83,10 @@ pub fn get_data_program_header<'b, 'a: 'b>(
&& ph.flags().is_write() && ph.flags().is_write()
&& ph.flags().is_read() && ph.flags().is_read()
}) })
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get the data segment").into()) .ok_or_else(|| errno!(ENOEXEC, "failed to get the data segment"))
} }
pub fn get_code_program_header<'b, 'a: 'b>( pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<ProgramHeader<'a>> {
elf_file: &'b ElfFile<'a>,
) -> Result<ProgramHeader<'a>, Error> {
let mut ph_iter = elf_file.program_iter(); let mut ph_iter = elf_file.program_iter();
ph_iter ph_iter
.find(|&ph| { .find(|&ph| {
@ -99,15 +95,15 @@ pub fn get_code_program_header<'b, 'a: 'b>(
&& !ph.flags().is_write() && !ph.flags().is_write()
&& ph.flags().is_read() && ph.flags().is_read()
}) })
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get the code segment").into()) .ok_or_else(|| errno!(ENOEXEC, "failed to get the code segment"))
} }
pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<usize, Error> { pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<usize> {
let elf_header = &elf_file.header.pt2; let elf_header = &elf_file.header.pt2;
Ok(elf_header.entry_point() as usize) Ok(elf_header.entry_point() as usize)
} }
pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Entry64], Error> { pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Entry64]> {
elf_file elf_file
.find_section_by_name(".symtab") .find_section_by_name(".symtab")
.and_then(|symtab_section| symtab_section.get_data(&elf_file).ok()) .and_then(|symtab_section| symtab_section.get_data(&elf_file).ok())
@ -115,13 +111,13 @@ pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Ent
sections::SectionData::SymbolTable64(entries) => Some(entries), sections::SectionData::SymbolTable64(entries) => Some(entries),
_ => None, _ => None,
}) })
.ok_or_else(|| (Errno::ENOEXEC, "Failed get the symbol entries").into()) .ok_or_else(|| errno!(ENOEXEC, "failed get the symbol entries"))
} }
pub fn get_rela_entries<'b, 'a: 'b>( pub fn get_rela_entries<'b, 'a: 'b>(
elf_file: &'b ElfFile<'a>, elf_file: &'b ElfFile<'a>,
sec_name: &'b str, sec_name: &'b str,
) -> Result<&'a [Rela<P64>], Error> { ) -> Result<&'a [Rela<P64>]> {
elf_file elf_file
.find_section_by_name(sec_name) .find_section_by_name(sec_name)
.and_then(|plt_rela_section| plt_rela_section.get_data(&elf_file).ok()) .and_then(|plt_rela_section| plt_rela_section.get_data(&elf_file).ok())
@ -129,12 +125,10 @@ pub fn get_rela_entries<'b, 'a: 'b>(
sections::SectionData::Rela64(entries) => Some(entries), sections::SectionData::Rela64(entries) => Some(entries),
_ => None, _ => None,
}) })
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get .rela.plt entries").into()) .ok_or_else(|| errno!(ENOEXEC, "failed to get .rela.plt entries"))
} }
pub fn get_dynsym_entries<'b, 'a: 'b>( pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [DynEntry64]> {
elf_file: &'b ElfFile<'a>,
) -> Result<&'a [DynEntry64], Error> {
elf_file elf_file
.find_section_by_name(".dynsym") .find_section_by_name(".dynsym")
.and_then(|dynamic_section| dynamic_section.get_data(&elf_file).ok()) .and_then(|dynamic_section| dynamic_section.get_data(&elf_file).ok())
@ -142,5 +136,5 @@ pub fn get_dynsym_entries<'b, 'a: 'b>(
sections::SectionData::DynSymbolTable64(entries) => Some(entries), sections::SectionData::DynSymbolTable64(entries) => Some(entries),
_ => None, _ => None,
}) })
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get .dynsym entries").into()) .ok_or_else(|| errno!(ENOEXEC, "failed to get .dynsym entries"))
} }

@ -53,7 +53,7 @@ pub fn do_init(
argv: &[CString], argv: &[CString],
envp: &[CString], envp: &[CString],
auxtbl: &AuxTable, auxtbl: &AuxTable,
) -> Result<usize, Error> { ) -> Result<usize> {
let stack_buf = unsafe { StackBuf::new(stack_top, init_area_size)? }; let stack_buf = unsafe { StackBuf::new(stack_top, init_area_size)? };
let envp_cloned = clone_cstrings_on_stack(&stack_buf, envp)?; let envp_cloned = clone_cstrings_on_stack(&stack_buf, envp)?;
let argv_cloned = clone_cstrings_on_stack(&stack_buf, argv)?; let argv_cloned = clone_cstrings_on_stack(&stack_buf, argv)?;
@ -75,9 +75,9 @@ pub struct StackBuf {
} }
impl StackBuf { impl StackBuf {
pub unsafe fn new(stack_top: usize, stack_size: usize) -> Result<StackBuf, Error> { pub unsafe fn new(stack_top: usize, stack_size: usize) -> Result<StackBuf> {
if stack_top % 16 != 0 || stack_size == 0 || stack_top < stack_size { if stack_top % 16 != 0 || stack_size == 0 || stack_top < stack_size {
return errno!(EINVAL, "Invalid stack range"); return_errno!(EINVAL, "Invalid stack range");
}; };
Ok(StackBuf { Ok(StackBuf {
stack_top: stack_top, stack_top: stack_top,
@ -86,7 +86,7 @@ impl StackBuf {
}) })
} }
pub fn put(&self, val: u64) -> Result<*const u64, Error> { pub fn put(&self, val: u64) -> Result<*const u64> {
let val_ptr = self.alloc(8, 8)? as *mut u64; let val_ptr = self.alloc(8, 8)? as *mut u64;
unsafe { unsafe {
ptr::write(val_ptr, val); ptr::write(val_ptr, val);
@ -94,7 +94,7 @@ impl StackBuf {
Ok(val_ptr as *const u64) Ok(val_ptr as *const u64)
} }
pub fn put_slice<T>(&self, vals: &[T]) -> Result<*const T, Error> pub fn put_slice<T>(&self, vals: &[T]) -> Result<*const T>
where where
T: Copy, T: Copy,
{ {
@ -120,7 +120,7 @@ impl StackBuf {
Ok(base_ptr as *const T) Ok(base_ptr as *const T)
} }
pub fn put_cstr(&self, cstr: &CStr) -> Result<*const u8, Error> { pub fn put_cstr(&self, cstr: &CStr) -> Result<*const u8> {
let bytes = cstr.to_bytes_with_nul(); let bytes = cstr.to_bytes_with_nul();
self.put_slice(bytes) self.put_slice(bytes)
} }
@ -129,12 +129,12 @@ impl StackBuf {
self.stack_pos.get() self.stack_pos.get()
} }
fn alloc(&self, size: usize, align: usize) -> Result<*mut u8, Error> { fn alloc(&self, size: usize, align: usize) -> Result<*mut u8> {
let new_pos = { let new_pos = {
let old_pos = self.stack_pos.get(); let old_pos = self.stack_pos.get();
let new_pos = align_down(old_pos - size, align); let new_pos = align_down(old_pos - size, align);
if new_pos < self.stack_bottom { if new_pos < self.stack_bottom {
return errno!(ENOMEM, "No enough space in buffer"); return_errno!(ENOMEM, "No enough space in buffer");
} }
new_pos new_pos
}; };
@ -147,7 +147,7 @@ impl StackBuf {
fn clone_cstrings_on_stack<'a, 'b>( fn clone_cstrings_on_stack<'a, 'b>(
stack: &'a StackBuf, stack: &'a StackBuf,
cstrings: &'b [CString], cstrings: &'b [CString],
) -> Result<Vec<&'a CStr>, Error> { ) -> Result<Vec<&'a CStr>> {
let mut cstrs_cloned = Vec::new(); let mut cstrs_cloned = Vec::new();
for cs in cstrings.iter().rev() { for cs in cstrings.iter().rev() {
let cstrp_cloned = stack.put_cstr(cs)?; let cstrp_cloned = stack.put_cstr(cs)?;
@ -158,7 +158,7 @@ fn clone_cstrings_on_stack<'a, 'b>(
Ok(cstrs_cloned) Ok(cstrs_cloned)
} }
fn dump_auxtbl_on_stack<'a, 'b>(stack: &'a StackBuf, auxtbl: &'b AuxTable) -> Result<(), Error> { fn dump_auxtbl_on_stack<'a, 'b>(stack: &'a StackBuf, auxtbl: &'b AuxTable) -> Result<()> {
// For every key-value pair, dump the value first, then the key // For every key-value pair, dump the value first, then the key
stack.put(0 as u64); stack.put(0 as u64);
stack.put(AuxKey::AT_NULL as u64); stack.put(AuxKey::AT_NULL as u64);
@ -169,10 +169,7 @@ fn dump_auxtbl_on_stack<'a, 'b>(stack: &'a StackBuf, auxtbl: &'b AuxTable) -> Re
Ok(()) Ok(())
} }
fn dump_cstrptrs_on_stack<'a, 'b>( fn dump_cstrptrs_on_stack<'a, 'b>(stack: &'a StackBuf, strptrs: &'b [&'a CStr]) -> Result<()> {
stack: &'a StackBuf,
strptrs: &'b [&'a CStr],
) -> Result<(), Error> {
stack.put(0 as u64); // End with a NULL pointer stack.put(0 as u64); // End with a NULL pointer
for sp in strptrs.iter().rev() { for sp in strptrs.iter().rev() {
stack.put(sp.as_ptr() as u64); stack.put(sp.as_ptr() as u64);
@ -233,9 +230,9 @@ impl AuxTable {
} }
impl AuxTable { impl AuxTable {
pub fn set(&mut self, key: AuxKey, val: u64) -> Result<(), Error> { pub fn set(&mut self, key: AuxKey, val: u64) -> Result<()> {
if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE { if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE {
return errno!(EINVAL, "Illegal key"); return_errno!(EINVAL, "Illegal key");
} }
self.table self.table
.entry(key) .entry(key)

@ -8,7 +8,7 @@ pub fn do_init(
elf_buf: &[u8], elf_buf: &[u8],
ldso_elf_file: &ElfFile, ldso_elf_file: &ElfFile,
ldso_elf_buf: &[u8], ldso_elf_buf: &[u8],
) -> Result<ProcessVM, Error> { ) -> Result<ProcessVM> {
// Alloc all virtual memory areas // Alloc all virtual memory areas
let mut code_seg = get_code_segment(elf_file)?; let mut code_seg = get_code_segment(elf_file)?;
let mut data_seg = get_data_segment(elf_file)?; let mut data_seg = get_data_segment(elf_file)?;
@ -34,7 +34,8 @@ pub fn do_init(
let mut process_vm = ProcessVMBuilder::new(code_size, data_size) let mut process_vm = ProcessVMBuilder::new(code_size, data_size)
.ldso_code_size(ldso_code_size) .ldso_code_size(ldso_code_size)
.ldso_data_size(ldso_data_size) .ldso_data_size(ldso_data_size)
.build()?; .build()
.cause_err(|e| errno!(e.errno(), "failed to create process VM"))?;
// Load code and data // Load code and data
let process_base_addr = process_vm.get_code_range().start(); let process_base_addr = process_vm.get_code_range().start();
@ -57,7 +58,7 @@ pub fn do_init(
Ok(process_vm) Ok(process_vm)
} }
fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Error> { fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> {
let rela_entries = elf_helper::get_rela_entries(elf_file, ".rela.dyn")?; let rela_entries = elf_helper::get_rela_entries(elf_file, ".rela.dyn")?;
for rela_entry in rela_entries { for rela_entry in rela_entries {
/* /*
@ -84,7 +85,7 @@ fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err
Ok(()) Ok(())
} }
/* /*
fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Error> { fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<()> {
let syscall_addr = __occlum_syscall as *const () as usize; let syscall_addr = __occlum_syscall as *const () as usize;
let rela_entries = elf_helper::get_rela_entries(elf_file, ".rela.plt")?; let rela_entries = elf_helper::get_rela_entries(elf_file, ".rela.plt")?;

@ -38,17 +38,23 @@ pub fn do_spawn<P: AsRef<Path>>(
envp: &[CString], envp: &[CString],
file_actions: &[FileAction], file_actions: &[FileAction],
parent_ref: &ProcessRef, parent_ref: &ProcessRef,
) -> Result<u32, Error> { ) -> Result<u32> {
let mut elf_buf = { let mut elf_buf = {
let path = elf_path.as_ref().to_str().unwrap(); let path = elf_path.as_ref().to_str().unwrap();
let inode = parent_ref.lock().unwrap().lookup_inode(path)?; let inode = parent_ref
inode.read_as_vec()? .lock()
.unwrap()
.lookup_inode(path)
.map_err(|e| errno!(e.errno(), "cannot find the executable"))?;
inode
.read_as_vec()
.map_err(|e| errno!(e.errno(), "failed to read the executable ELF"))?
}; };
let elf_file = { let elf_file = {
let elf_file = let elf_file = ElfFile::new(&elf_buf)
ElfFile::new(&elf_buf).map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?; .map_err(|e| errno!(ENOEXEC, "failed to parse the executable ELF"))?;
header::sanity_check(&elf_file) header::sanity_check(&elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?; .map_err(|e| errno!(ENOEXEC, "failed to parse the executable ELF"))?;
/* /*
elf_helper::print_program_headers(&elf_file)?; elf_helper::print_program_headers(&elf_file)?;
elf_helper::print_sections(&elf_file)?; elf_helper::print_sections(&elf_file)?;
@ -59,15 +65,22 @@ pub fn do_spawn<P: AsRef<Path>>(
let mut ldso_elf_buf = { let mut ldso_elf_buf = {
let ldso_path = "/lib/ld-musl-x86_64.so.1"; let ldso_path = "/lib/ld-musl-x86_64.so.1";
let ldso_inode = ROOT_INODE.lookup(ldso_path)?; let ldso_inode = ROOT_INODE.lookup(ldso_path).map_err(|e| {
ldso_inode.read_as_vec()? errno!(
e.errno(),
"cannot find the loader at /lib/ld-musl-x86_64.so.1"
)
})?;
ldso_inode
.read_as_vec()
.map_err(|e| errno!(e.errno(), "failed to read the ld.so ELF"))?
}; };
let ldso_elf_file = { let ldso_elf_file = {
let ldso_elf_file = ElfFile::new(&ldso_elf_buf) let ldso_elf_file = ElfFile::new(&ldso_elf_buf)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?; .map_err(|e| errno!(ENOEXEC, "failed to parse the ld.so ELF"))?;
header::sanity_check(&ldso_elf_file) header::sanity_check(&ldso_elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?; .map_err(|e| errno!(ENOEXEC, "failed to parse the ld.so ELF"))?;
/* /*
elf_helper::print_program_headers(&elf_file)?; elf_helper::print_program_headers(&elf_file)?;
elf_helper::print_sections(&elf_file)?; elf_helper::print_sections(&elf_file)?;
@ -86,7 +99,7 @@ pub fn do_spawn<P: AsRef<Path>>(
let ldso_base_addr = vm.get_ldso_code_range().start(); let ldso_base_addr = vm.get_ldso_code_range().start();
let ldso_entry = ldso_base_addr + elf_helper::get_start_address(&ldso_elf_file)?; let ldso_entry = ldso_base_addr + elf_helper::get_start_address(&ldso_elf_file)?;
if !vm.get_ldso_code_range().contains(ldso_entry) { if !vm.get_ldso_code_range().contains(ldso_entry) {
return errno!(EINVAL, "Invalid program entry"); return_errno!(EINVAL, "Invalid program entry");
} }
ldso_entry ldso_entry
}; };
@ -117,7 +130,7 @@ pub fn do_spawn<P: AsRef<Path>>(
Ok(new_pid) Ok(new_pid)
} }
fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<FileTable, Error> { fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<FileTable> {
// Usually, we just inherit the file table from the parent // Usually, we just inherit the file table from the parent
let parent = parent_ref.lock().unwrap(); let parent = parent_ref.lock().unwrap();
let should_inherit_file_table = parent.get_pid() > 0; let should_inherit_file_table = parent.get_pid() > 0;
@ -170,7 +183,7 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<Fi
Ok(file_table) Ok(file_table)
} }
fn init_auxtbl(process_vm: &ProcessVM, elf_file: &ElfFile) -> Result<AuxTable, Error> { fn init_auxtbl(process_vm: &ProcessVM, elf_file: &ElfFile) -> Result<AuxTable> {
let mut auxtbl = AuxTable::new(); let mut auxtbl = AuxTable::new();
auxtbl.set(AuxKey::AT_PAGESZ, 4096)?; auxtbl.set(AuxKey::AT_PAGESZ, 4096)?;
auxtbl.set(AuxKey::AT_UID, 0)?; auxtbl.set(AuxKey::AT_UID, 0)?;

@ -29,25 +29,24 @@ impl Segment {
self.mem_size self.mem_size
} }
pub fn from_program_header(ph: &ProgramHeader) -> Result<Segment, Error> { pub fn from_program_header(ph: &ProgramHeader) -> Result<Segment> {
let ph64 = match ph { let ph64 = match ph {
ProgramHeader::Ph32(ph) => { ProgramHeader::Ph32(ph) => {
return Err((Errno::ENOEXEC, "Not support 32-bit ELF").into()); return_errno!(ENOEXEC, "not support 32-bit ELF");
} }
ProgramHeader::Ph64(ph64) => ph64, ProgramHeader::Ph64(ph64) => ph64,
}; };
if ph64.align > 1 && ((ph64.offset % ph64.align) != (ph64.virtual_addr % ph64.align)) { if ph64.align > 1 && ((ph64.offset % ph64.align) != (ph64.virtual_addr % ph64.align)) {
return Err(( return_errno!(
Errno::EINVAL, EINVAL,
"Memory address and file offset is not equal, per modulo", "memory address and file offset is not equal, per modulo"
) );
.into());
} }
if ph64.mem_size < ph64.file_size { if ph64.mem_size < ph64.file_size {
return Err((Errno::EINVAL, "Memory size must be greater than file size").into()); return_errno!(EINVAL, "memory size must be greater than file size");
} }
if !ph64.align.is_power_of_two() { if !ph64.align.is_power_of_two() {
return Err((Errno::EINVAL, "Memory alignment must be a power of two").into()); return_errno!(EINVAL, "memory alignment must be a power of two");
} }
Ok(Segment { Ok(Segment {
@ -90,15 +89,15 @@ impl Segment {
} }
} }
pub fn get_code_segment(elf_file: &ElfFile) -> Result<Segment, Error> { pub fn get_code_segment(elf_file: &ElfFile) -> Result<Segment> {
let code_ph = elf_helper::get_code_program_header(elf_file) let code_ph = elf_helper::get_code_program_header(elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?; .map_err(|e| errno!(ENOEXEC, "failed to get the program header of code"))?;
Segment::from_program_header(&code_ph) Segment::from_program_header(&code_ph)
} }
pub fn get_data_segment(elf_file: &ElfFile) -> Result<Segment, Error> { pub fn get_data_segment(elf_file: &ElfFile) -> Result<Segment> {
let data_ph = elf_helper::get_data_program_header(elf_file) let data_ph = elf_helper::get_data_program_header(elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?; .map_err(|e| errno!(ENOEXEC, "failed to get the program header of code"))?;
Segment::from_program_header(&data_ph) Segment::from_program_header(&data_ph)
} }

@ -23,9 +23,9 @@ impl Task {
user_stack_base: usize, user_stack_base: usize,
user_stack_limit: usize, user_stack_limit: usize,
user_fs: Option<usize>, user_fs: Option<usize>,
) -> Result<Task, Error> { ) -> Result<Task> {
if !(user_stack_base >= user_rsp && user_rsp > user_stack_limit) { if !(user_stack_base >= user_rsp && user_rsp > user_stack_limit) {
return errno!(EINVAL, "Invalid user stack"); return_errno!(EINVAL, "Invalid user stack");
} }
// Set the default user fsbase to an address on user stack, which is // Set the default user fsbase to an address on user stack, which is
@ -71,9 +71,9 @@ fn dequeue_task() -> Option<ProcessRef> {
NEW_PROCESS_QUEUE.lock().unwrap().pop_front() NEW_PROCESS_QUEUE.lock().unwrap().pop_front()
} }
pub fn run_task(host_tid: pid_t) -> Result<i32, Error> { pub fn run_task(host_tid: pid_t) -> Result<i32> {
let new_process: ProcessRef = let new_process: ProcessRef =
dequeue_task().ok_or_else(|| (Errno::EAGAIN, "No new processes to run"))?; dequeue_task().ok_or_else(|| errno!(EAGAIN, "no new processes to run"))?;
set_current(&new_process); set_current(&new_process);
let (pid, task) = { let (pid, task) = {

@ -39,7 +39,7 @@ pub fn do_clone(
ptid: Option<*mut pid_t>, ptid: Option<*mut pid_t>,
ctid: Option<*mut pid_t>, ctid: Option<*mut pid_t>,
new_tls: Option<usize>, new_tls: Option<usize>,
) -> Result<pid_t, Error> { ) -> Result<pid_t> {
info!( info!(
"clone: flags: {:?}, stack_addr: {:?}, ptid: {:?}, ctid: {:?}, new_tls: {:?}", "clone: flags: {:?}, stack_addr: {:?}, ptid: {:?}, ctid: {:?}, new_tls: {:?}",
flags, user_rsp, ptid, ctid, new_tls flags, user_rsp, ptid, ctid, new_tls
@ -107,7 +107,7 @@ pub fn do_clone(
Ok(new_thread_pid) Ok(new_thread_pid)
} }
pub fn do_set_tid_address(tidptr: *mut pid_t) -> Result<pid_t, Error> { pub fn do_set_tid_address(tidptr: *mut pid_t) -> Result<pid_t> {
info!("set_tid_address: tidptr: {:#x}", tidptr as usize); info!("set_tid_address: tidptr: {:#x}", tidptr as usize);
let current_ref = get_current(); let current_ref = get_current();
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();
@ -115,7 +115,7 @@ pub fn do_set_tid_address(tidptr: *mut pid_t) -> Result<pid_t, Error> {
Ok(current.get_tid()) Ok(current.get_tid())
} }
fn guess_user_stack_bound(vm: &ProcessVM, user_rsp: usize) -> Result<&VMRange, Error> { fn guess_user_stack_bound(vm: &ProcessVM, user_rsp: usize) -> Result<&VMRange> {
// The first case is most likely // The first case is most likely
if let Ok(stack_range) = vm.find_mmap_region(user_rsp) { if let Ok(stack_range) = vm.find_mmap_region(user_rsp) {
Ok(stack_range) Ok(stack_range)
@ -130,6 +130,6 @@ fn guess_user_stack_bound(vm: &ProcessVM, user_rsp: usize) -> Result<&VMRange, E
} }
// Invalid // Invalid
else { else {
errno!(ESRCH, "invalid rsp") return_errno!(ESRCH, "invalid rsp")
} }
} }

@ -9,7 +9,6 @@
use fs::*; use fs::*;
use misc::{resource_t, rlimit_t, utsname_t}; use misc::{resource_t, rlimit_t, utsname_t};
use prelude::*;
use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp}; use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::ptr; use std::ptr;
@ -22,6 +21,7 @@ use super::*;
use self::consts::*; use self::consts::*;
use std::any::Any; use std::any::Any;
use std::io::{Read, Seek, SeekFrom, Write};
// Use the internal syscall wrappers from sgx_tstd // Use the internal syscall wrappers from sgx_tstd
//use std::libc_fs as fs; //use std::libc_fs as fs;
@ -302,9 +302,14 @@ pub extern "C" fn dispatch_syscall(
info!("=> {:?}", ret); info!("=> {:?}", ret);
match ret { match ret {
Ok(code) => code as isize, Ok(retval) => retval as isize,
Err(e) if e.errno.as_retval() == 0 => panic!("undefined errno"), Err(e) => {
Err(e) => e.errno.as_retval() as isize, warn!("{}", e.backtrace());
let retval = -(e.errno() as isize);
debug_assert!(retval == 0);
retval
}
} }
} }
@ -350,7 +355,7 @@ pub struct FdOp {
path: *const i8, path: *const i8,
} }
fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result<Vec<FileAction>, Error> { fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result<Vec<FileAction>> {
let mut file_actions = Vec::new(); let mut file_actions = Vec::new();
let mut fdop_ptr = fdop_ptr; let mut fdop_ptr = fdop_ptr;
@ -370,7 +375,7 @@ fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result<Vec<FileAction>, E
fd: fdop.fd, fd: fdop.fd,
}, },
_ => { _ => {
return errno!(EINVAL, "Unknown file action command"); return_errno!(EINVAL, "Unknown file action command");
} }
}; };
file_actions.push(file_action); file_actions.push(file_action);
@ -387,7 +392,7 @@ fn do_spawn(
argv: *const *const i8, argv: *const *const i8,
envp: *const *const i8, envp: *const *const i8,
fdop_list: *const FdOp, fdop_list: *const FdOp,
) -> Result<isize, Error> { ) -> Result<isize> {
check_mut_ptr(child_pid_ptr)?; check_mut_ptr(child_pid_ptr)?;
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let argv = clone_cstrings_safely(argv)?; let argv = clone_cstrings_safely(argv)?;
@ -411,7 +416,7 @@ pub fn do_clone(
ptid: *mut pid_t, ptid: *mut pid_t,
ctid: *mut pid_t, ctid: *mut pid_t,
new_tls: usize, new_tls: usize,
) -> Result<isize, Error> { ) -> Result<isize> {
let flags = CloneFlags::from_bits_truncate(flags); let flags = CloneFlags::from_bits_truncate(flags);
check_mut_ptr(stack_addr as *mut u64)?; check_mut_ptr(stack_addr as *mut u64)?;
let ptid = { let ptid = {
@ -444,7 +449,7 @@ pub fn do_clone(
Ok(child_pid as isize) Ok(child_pid as isize)
} }
pub fn do_futex(futex_addr: *const i32, futex_op: u32, futex_val: i32) -> Result<isize, Error> { pub fn do_futex(futex_addr: *const i32, futex_op: u32, futex_val: i32) -> Result<isize> {
check_ptr(futex_addr)?; check_ptr(futex_addr)?;
let (futex_op, futex_flags) = process::futex_op_and_flags_from_u32(futex_op)?; let (futex_op, futex_flags) = process::futex_op_and_flags_from_u32(futex_op)?;
match futex_op { match futex_op {
@ -452,28 +457,28 @@ pub fn do_futex(futex_addr: *const i32, futex_op: u32, futex_val: i32) -> Result
FutexOp::FUTEX_WAKE => { FutexOp::FUTEX_WAKE => {
let max_count = { let max_count = {
if futex_val < 0 { if futex_val < 0 {
return errno!(EINVAL, "the count must not be negative"); return_errno!(EINVAL, "the count must not be negative");
} }
futex_val as usize futex_val as usize
}; };
process::futex_wake(futex_addr, max_count).map(|count| count as isize) process::futex_wake(futex_addr, max_count).map(|count| count as isize)
} }
_ => errno!(ENOSYS, "the futex operation is not supported"), _ => return_errno!(ENOSYS, "the futex operation is not supported"),
} }
} }
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize, Error> { fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let fd = fs::do_open(&path, flags, mode)?; let fd = fs::do_open(&path, flags, mode)?;
Ok(fd as isize) Ok(fd as isize)
} }
fn do_close(fd: FileDesc) -> Result<isize, Error> { fn do_close(fd: FileDesc) -> Result<isize> {
fs::do_close(fd)?; fs::do_close(fd)?;
Ok(0) Ok(0)
} }
fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize, Error> { fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_mut_array(buf, size)?; check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) } unsafe { std::slice::from_raw_parts_mut(buf, size) }
@ -482,7 +487,7 @@ fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize, Error> {
Ok(len as isize) Ok(len as isize)
} }
fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize, Error> { fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_array(buf, size)?; check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) } unsafe { std::slice::from_raw_parts(buf, size) }
@ -491,10 +496,10 @@ fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize, Error> {
Ok(len as isize) Ok(len as isize)
} }
fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize, Error> { fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize> {
let count = { let count = {
if count < 0 { if count < 0 {
return errno!(EINVAL, "Invalid count of iovec"); return_errno!(EINVAL, "Invalid count of iovec");
} }
count as usize count as usize
}; };
@ -516,10 +521,10 @@ fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize, Err
Ok(len as isize) Ok(len as isize)
} }
fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize, Error> { fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize> {
let count = { let count = {
if count < 0 { if count < 0 {
return errno!(EINVAL, "Invalid count of iovec"); return_errno!(EINVAL, "Invalid count of iovec");
} }
count as usize count as usize
}; };
@ -541,7 +546,7 @@ fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize, Error>
Ok(len as isize) Ok(len as isize)
} }
fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<isize, Error> { fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_mut_array(buf, size)?; check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) } unsafe { std::slice::from_raw_parts_mut(buf, size) }
@ -550,7 +555,7 @@ fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<is
Ok(len as isize) Ok(len as isize)
} }
fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result<isize, Error> { fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_array(buf, size)?; check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) } unsafe { std::slice::from_raw_parts(buf, size) }
@ -559,7 +564,7 @@ fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result
Ok(len as isize) Ok(len as isize)
} }
fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> { fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?; check_mut_ptr(stat_buf)?;
@ -570,7 +575,7 @@ fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize, Error> { fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize> {
check_mut_ptr(stat_buf)?; check_mut_ptr(stat_buf)?;
let stat = fs::do_fstat(fd)?; let stat = fs::do_fstat(fd)?;
@ -580,7 +585,7 @@ fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> { fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?; check_mut_ptr(stat_buf)?;
@ -591,12 +596,12 @@ fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize, Error> { fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize> {
let seek_from = match whence { let seek_from = match whence {
0 => { 0 => {
// SEEK_SET // SEEK_SET
if offset < 0 { if offset < 0 {
return errno!(EINVAL, "Invalid offset"); return_errno!(EINVAL, "Invalid offset");
} }
SeekFrom::Start(offset as u64) SeekFrom::Start(offset as u64)
} }
@ -609,7 +614,7 @@ fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize, Error> {
SeekFrom::End(offset) SeekFrom::End(offset)
} }
_ => { _ => {
return errno!(EINVAL, "Invalid whence"); return_errno!(EINVAL, "Invalid whence");
} }
}; };
@ -617,28 +622,28 @@ fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize, Error> {
Ok(offset as isize) Ok(offset as isize)
} }
fn do_fsync(fd: FileDesc) -> Result<isize, Error> { fn do_fsync(fd: FileDesc) -> Result<isize> {
fs::do_fsync(fd)?; fs::do_fsync(fd)?;
Ok(0) Ok(0)
} }
fn do_fdatasync(fd: FileDesc) -> Result<isize, Error> { fn do_fdatasync(fd: FileDesc) -> Result<isize> {
fs::do_fdatasync(fd)?; fs::do_fdatasync(fd)?;
Ok(0) Ok(0)
} }
fn do_truncate(path: *const i8, len: usize) -> Result<isize, Error> { fn do_truncate(path: *const i8, len: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_truncate(&path, len)?; fs::do_truncate(&path, len)?;
Ok(0) Ok(0)
} }
fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize, Error> { fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize> {
fs::do_ftruncate(fd, len)?; fs::do_ftruncate(fd, len)?;
Ok(0) Ok(0)
} }
fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize, Error> { fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_mut_array(buf, buf_size)?; check_mut_array(buf, buf_size)?;
unsafe { std::slice::from_raw_parts_mut(buf, buf_size) } unsafe { std::slice::from_raw_parts_mut(buf, buf_size) }
@ -647,7 +652,7 @@ fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize, E
Ok(len as isize) Ok(len as isize)
} }
fn do_sync() -> Result<isize, Error> { fn do_sync() -> Result<isize> {
fs::do_sync()?; fs::do_sync()?;
Ok(0) Ok(0)
} }
@ -659,14 +664,14 @@ fn do_mmap(
flags: i32, flags: i32,
fd: FileDesc, fd: FileDesc,
offset: off_t, offset: off_t,
) -> Result<isize, Error> { ) -> Result<isize> {
let perms = VMPerms::from_u32(perms as u32)?; let perms = VMPerms::from_u32(perms as u32)?;
let flags = MMapFlags::from_u32(flags as u32)?; let flags = MMapFlags::from_u32(flags as u32)?;
let addr = vm::do_mmap(addr, size, perms, flags, fd, offset as usize)?; let addr = vm::do_mmap(addr, size, perms, flags, fd, offset as usize)?;
Ok(addr as isize) Ok(addr as isize)
} }
fn do_munmap(addr: usize, size: usize) -> Result<isize, Error> { fn do_munmap(addr: usize, size: usize) -> Result<isize> {
vm::do_munmap(addr, size)?; vm::do_munmap(addr, size)?;
Ok(0) Ok(0)
} }
@ -677,22 +682,22 @@ fn do_mremap(
new_size: usize, new_size: usize,
flags: i32, flags: i32,
new_addr: usize, new_addr: usize,
) -> Result<isize, Error> { ) -> Result<isize> {
warn!("mremap: not implemented!"); warn!("mremap: not implemented!");
errno!(ENOSYS, "not supported yet") return_errno!(ENOSYS, "not supported yet")
} }
fn do_mprotect(addr: usize, len: usize, prot: u32) -> Result<isize, Error> { fn do_mprotect(addr: usize, len: usize, prot: u32) -> Result<isize> {
// TODO: implement it // TODO: implement it
Ok(0) Ok(0)
} }
fn do_brk(new_brk_addr: usize) -> Result<isize, Error> { fn do_brk(new_brk_addr: usize) -> Result<isize> {
let ret_brk_addr = vm::do_brk(new_brk_addr)?; let ret_brk_addr = vm::do_brk(new_brk_addr)?;
Ok(ret_brk_addr as isize) Ok(ret_brk_addr as isize)
} }
fn do_wait4(pid: i32, _exit_status: *mut i32) -> Result<isize, Error> { fn do_wait4(pid: i32, _exit_status: *mut i32) -> Result<isize> {
if !_exit_status.is_null() { if !_exit_status.is_null() {
check_mut_ptr(_exit_status)?; check_mut_ptr(_exit_status)?;
} }
@ -723,45 +728,45 @@ fn do_wait4(pid: i32, _exit_status: *mut i32) -> Result<isize, Error> {
} }
} }
fn do_getpid() -> Result<isize, Error> { fn do_getpid() -> Result<isize> {
let pid = process::do_getpid(); let pid = process::do_getpid();
Ok(pid as isize) Ok(pid as isize)
} }
fn do_gettid() -> Result<isize, Error> { fn do_gettid() -> Result<isize> {
let tid = process::do_gettid(); let tid = process::do_gettid();
Ok(tid as isize) Ok(tid as isize)
} }
fn do_getppid() -> Result<isize, Error> { fn do_getppid() -> Result<isize> {
let ppid = process::do_getppid(); let ppid = process::do_getppid();
Ok(ppid as isize) Ok(ppid as isize)
} }
fn do_getpgid() -> Result<isize, Error> { fn do_getpgid() -> Result<isize> {
let pgid = process::do_getpgid(); let pgid = process::do_getpgid();
Ok(pgid as isize) Ok(pgid as isize)
} }
// TODO: implement uid, gid, euid, egid // TODO: implement uid, gid, euid, egid
fn do_getuid() -> Result<isize, Error> { fn do_getuid() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_getgid() -> Result<isize, Error> { fn do_getgid() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_geteuid() -> Result<isize, Error> { fn do_geteuid() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_getegid() -> Result<isize, Error> { fn do_getegid() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> { fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize> {
check_mut_array(fds_u, 2)?; check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags??? // TODO: how to deal with open flags???
let fds = fs::do_pipe2(flags as u32)?; let fds = fs::do_pipe2(flags as u32)?;
@ -772,23 +777,23 @@ fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_dup(old_fd: FileDesc) -> Result<isize, Error> { fn do_dup(old_fd: FileDesc) -> Result<isize> {
let new_fd = fs::do_dup(old_fd)?; let new_fd = fs::do_dup(old_fd)?;
Ok(new_fd as isize) Ok(new_fd as isize)
} }
fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<isize, Error> { fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<isize> {
let new_fd = fs::do_dup2(old_fd, new_fd)?; let new_fd = fs::do_dup2(old_fd, new_fd)?;
Ok(new_fd as isize) Ok(new_fd as isize)
} }
fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<isize, Error> { fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<isize> {
let new_fd = fs::do_dup3(old_fd, new_fd, flags)?; let new_fd = fs::do_dup3(old_fd, new_fd, flags)?;
Ok(new_fd as isize) Ok(new_fd as isize)
} }
// TODO: handle tz: timezone_t // TODO: handle tz: timezone_t
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize, Error> { fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
check_mut_ptr(tv_u)?; check_mut_ptr(tv_u)?;
let tv = time::do_gettimeofday(); let tv = time::do_gettimeofday();
unsafe { unsafe {
@ -797,7 +802,7 @@ fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result<isize, Error> { fn do_clock_gettime(clockid: clockid_t, ts_u: *mut timespec_t) -> Result<isize> {
check_mut_ptr(ts_u)?; check_mut_ptr(ts_u)?;
let clockid = time::ClockID::from_raw(clockid)?; let clockid = time::ClockID::from_raw(clockid)?;
let ts = time::do_clock_gettime(clockid)?; let ts = time::do_clock_gettime(clockid)?;
@ -829,15 +834,15 @@ fn do_unknown(
arg3: isize, arg3: isize,
arg4: isize, arg4: isize,
arg5: isize, arg5: isize,
) -> Result<isize, Error> { ) -> Result<isize> {
warn!( warn!(
"unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", "unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
num, arg0, arg1, arg2, arg3, arg4, arg5 num, arg0, arg1, arg2, arg3, arg4, arg5
); );
errno!(ENOSYS, "Unknown syscall") return_errno!(ENOSYS, "Unknown syscall")
} }
fn do_getcwd(buf: *mut u8, size: usize) -> Result<isize, Error> { fn do_getcwd(buf: *mut u8, size: usize) -> Result<isize> {
let safe_buf = { let safe_buf = {
check_mut_array(buf, size)?; check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) } unsafe { std::slice::from_raw_parts_mut(buf, size) }
@ -846,20 +851,20 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result<isize, Error> {
let mut proc = proc_ref.lock().unwrap(); let mut proc = proc_ref.lock().unwrap();
let cwd = proc.get_cwd(); let cwd = proc.get_cwd();
if cwd.len() + 1 > safe_buf.len() { if cwd.len() + 1 > safe_buf.len() {
return errno!(ERANGE, "buf is not long enough"); return_errno!(ERANGE, "buf is not long enough");
} }
safe_buf[..cwd.len()].copy_from_slice(cwd.as_bytes()); safe_buf[..cwd.len()].copy_from_slice(cwd.as_bytes());
safe_buf[cwd.len()] = 0; safe_buf[cwd.len()] = 0;
Ok(buf as isize) Ok(buf as isize)
} }
fn do_chdir(path: *const i8) -> Result<isize, Error> { fn do_chdir(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_chdir(&path)?; fs::do_chdir(&path)?;
Ok(0) Ok(0)
} }
fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize, Error> { fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = clone_cstring_safely(oldpath)? let oldpath = clone_cstring_safely(oldpath)?
.to_string_lossy() .to_string_lossy()
.into_owned(); .into_owned();
@ -870,19 +875,19 @@ fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_mkdir(path: *const i8, mode: usize) -> Result<isize, Error> { fn do_mkdir(path: *const i8, mode: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_mkdir(&path, mode)?; fs::do_mkdir(&path, mode)?;
Ok(0) Ok(0)
} }
fn do_rmdir(path: *const i8) -> Result<isize, Error> { fn do_rmdir(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_rmdir(&path)?; fs::do_rmdir(&path)?;
Ok(0) Ok(0)
} }
fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize, Error> { fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = clone_cstring_safely(oldpath)? let oldpath = clone_cstring_safely(oldpath)?
.to_string_lossy() .to_string_lossy()
.into_owned(); .into_owned();
@ -893,13 +898,13 @@ fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_unlink(path: *const i8) -> Result<isize, Error> { fn do_unlink(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_unlink(&path)?; fs::do_unlink(&path)?;
Ok(0) Ok(0)
} }
fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize, Error> { fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let buf = { let buf = {
check_array(buf, size)?; check_array(buf, size)?;
@ -914,7 +919,7 @@ fn do_sendfile(
in_fd: FileDesc, in_fd: FileDesc,
offset_ptr: *mut off_t, offset_ptr: *mut off_t,
count: usize, count: usize,
) -> Result<isize, Error> { ) -> Result<isize> {
let offset = if offset_ptr.is_null() { let offset = if offset_ptr.is_null() {
None None
} else { } else {
@ -931,12 +936,12 @@ fn do_sendfile(
Ok(len as isize) Ok(len as isize)
} }
fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> { fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
let cmd = FcntlCmd::from_raw(cmd, arg)?; let cmd = FcntlCmd::from_raw(cmd, arg)?;
fs::do_fcntl(fd, &cmd) fs::do_fcntl(fd, &cmd)
} }
fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result<isize, Error> { fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result<isize> {
info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp); info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap(); let mut proc = current_ref.lock().unwrap();
@ -950,30 +955,30 @@ fn do_ioctl(fd: FileDesc, cmd: c_int, argp: *mut c_int) -> Result<isize, Error>
Ok(0) Ok(0)
} else { } else {
warn!("ioctl is unimplemented"); warn!("ioctl is unimplemented");
errno!(ENOSYS, "ioctl is unimplemented") return_errno!(ENOSYS, "ioctl is unimplemented")
} }
} }
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> {
let code = process::ArchPrctlCode::from_u32(code)?; let code = process::ArchPrctlCode::from_u32(code)?;
check_mut_ptr(addr)?; check_mut_ptr(addr)?;
process::do_arch_prctl(code, addr).map(|_| 0) process::do_arch_prctl(code, addr).map(|_| 0)
} }
fn do_set_tid_address(tidptr: *mut pid_t) -> Result<isize, Error> { fn do_set_tid_address(tidptr: *mut pid_t) -> Result<isize> {
check_mut_ptr(tidptr)?; check_mut_ptr(tidptr)?;
process::do_set_tid_address(tidptr).map(|tid| tid as isize) process::do_set_tid_address(tidptr).map(|tid| tid as isize)
} }
fn do_sched_getaffinity(pid: pid_t, cpusize: size_t, buf: *mut c_uchar) -> Result<isize, Error> { fn do_sched_getaffinity(pid: pid_t, cpusize: size_t, buf: *mut c_uchar) -> Result<isize> {
// Construct safe Rust types // Construct safe Rust types
let mut buf_slice = { let mut buf_slice = {
check_mut_array(buf, cpusize)?; check_mut_array(buf, cpusize)?;
if cpusize == 0 { if cpusize == 0 {
return errno!(EINVAL, "cpuset size must be greater than zero"); return_errno!(EINVAL, "cpuset size must be greater than zero");
} }
if buf as *const _ == std::ptr::null() { if buf as *const _ == std::ptr::null() {
return errno!(EFAULT, "cpuset mask must NOT be null"); return_errno!(EFAULT, "cpuset mask must NOT be null");
} }
unsafe { std::slice::from_raw_parts_mut(buf, cpusize) } unsafe { std::slice::from_raw_parts_mut(buf, cpusize) }
}; };
@ -986,15 +991,15 @@ fn do_sched_getaffinity(pid: pid_t, cpusize: size_t, buf: *mut c_uchar) -> Resul
Ok(ret as isize) Ok(ret as isize)
} }
fn do_sched_setaffinity(pid: pid_t, cpusize: size_t, buf: *const c_uchar) -> Result<isize, Error> { fn do_sched_setaffinity(pid: pid_t, cpusize: size_t, buf: *const c_uchar) -> Result<isize> {
// Convert unsafe C types into safe Rust types // Convert unsafe C types into safe Rust types
let cpuset = { let cpuset = {
check_array(buf, cpusize)?; check_array(buf, cpusize)?;
if cpusize == 0 { if cpusize == 0 {
return errno!(EINVAL, "cpuset size must be greater than zero"); return_errno!(EINVAL, "cpuset size must be greater than zero");
} }
if buf as *const _ == std::ptr::null() { if buf as *const _ == std::ptr::null() {
return errno!(EFAULT, "cpuset mask must NOT be null"); return_errno!(EFAULT, "cpuset mask must NOT be null");
} }
CpuSet::from_raw_buf(buf, cpusize) CpuSet::from_raw_buf(buf, cpusize)
}; };
@ -1004,7 +1009,7 @@ fn do_sched_setaffinity(pid: pid_t, cpusize: size_t, buf: *const c_uchar) -> Res
Ok(ret as isize) Ok(ret as isize)
} }
fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize, Error> { fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize> {
info!( info!(
"socket: domain: {}, socket_type: {}, protocol: {}", "socket: domain: {}, socket_type: {}, protocol: {}",
domain, socket_type, protocol domain, socket_type, protocol
@ -1028,11 +1033,7 @@ fn do_socket(domain: c_int, socket_type: c_int, protocol: c_int) -> Result<isize
Ok(fd as isize) Ok(fd as isize)
} }
fn do_connect( fn do_connect(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
fd: c_int,
addr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Result<isize, Error> {
info!( info!(
"connect: fd: {}, addr: {:?}, addr_len: {}", "connect: fd: {}, addr: {:?}, addr_len: {}",
fd, addr, addr_len fd, addr, addr_len
@ -1052,7 +1053,7 @@ fn do_connect(
unix_socket.connect(path)?; unix_socket.connect(path)?;
Ok(0) Ok(0)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
@ -1061,7 +1062,7 @@ fn do_accept4(
addr: *mut libc::sockaddr, addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t, addr_len: *mut libc::socklen_t,
flags: c_int, flags: c_int,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}", "accept4: fd: {}, addr: {:?}, addr_len: {:?}, flags: {:#x}",
fd, addr, addr_len, flags fd, addr, addr_len, flags
@ -1087,11 +1088,11 @@ fn do_accept4(
Ok(new_fd as isize) Ok(new_fd as isize)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
fn do_shutdown(fd: c_int, how: c_int) -> Result<isize, Error> { fn do_shutdown(fd: c_int, how: c_int) -> Result<isize> {
info!("shutdown: fd: {}, how: {}", fd, how); info!("shutdown: fd: {}, how: {}", fd, how);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap(); let mut proc = current_ref.lock().unwrap();
@ -1100,15 +1101,11 @@ fn do_shutdown(fd: c_int, how: c_int) -> Result<isize, Error> {
let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how)); let ret = try_libc!(libc::ocall::shutdown(socket.fd(), how));
Ok(ret as isize) Ok(ret as isize)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
fn do_bind( fn do_bind(fd: c_int, addr: *const libc::sockaddr, addr_len: libc::socklen_t) -> Result<isize> {
fd: c_int,
addr: *const libc::sockaddr,
addr_len: libc::socklen_t,
) -> Result<isize, Error> {
info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len); info!("bind: fd: {}, addr: {:?}, addr_len: {}", fd, addr, addr_len);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap(); let mut proc = current_ref.lock().unwrap();
@ -1126,11 +1123,11 @@ fn do_bind(
unix_socket.bind(path)?; unix_socket.bind(path)?;
Ok(0) Ok(0)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
fn do_listen(fd: c_int, backlog: c_int) -> Result<isize, Error> { fn do_listen(fd: c_int, backlog: c_int) -> Result<isize> {
info!("listen: fd: {}, backlog: {}", fd, backlog); info!("listen: fd: {}, backlog: {}", fd, backlog);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap(); let mut proc = current_ref.lock().unwrap();
@ -1142,7 +1139,7 @@ fn do_listen(fd: c_int, backlog: c_int) -> Result<isize, Error> {
unix_socket.listen()?; unix_socket.listen()?;
Ok(0) Ok(0)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
@ -1152,7 +1149,7 @@ fn do_setsockopt(
optname: c_int, optname: c_int,
optval: *const c_void, optval: *const c_void,
optlen: libc::socklen_t, optlen: libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", "setsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen fd, level, optname, optval, optlen
@ -1173,7 +1170,7 @@ fn do_setsockopt(
warn!("setsockopt for unix socket is unimplemented"); warn!("setsockopt for unix socket is unimplemented");
Ok(0) Ok(0)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
@ -1183,7 +1180,7 @@ fn do_getsockopt(
optname: c_int, optname: c_int,
optval: *mut c_void, optval: *mut c_void,
optlen: *mut libc::socklen_t, optlen: *mut libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}", "getsockopt: fd: {}, level: {}, optname: {}, optval: {:?}, optlen: {:?}",
fd, level, optname, optval, optlen fd, level, optname, optval, optlen
@ -1207,7 +1204,7 @@ fn do_getpeername(
fd: c_int, fd: c_int,
addr: *mut libc::sockaddr, addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t, addr_len: *mut libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"getpeername: fd: {}, addr: {:?}, addr_len: {:?}", "getpeername: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len fd, addr, addr_len
@ -1220,12 +1217,12 @@ fn do_getpeername(
Ok(ret as isize) Ok(ret as isize)
} else if let Ok(unix_socket) = file_ref.as_unix_socket() { } else if let Ok(unix_socket) = file_ref.as_unix_socket() {
warn!("getpeername for unix socket is unimplemented"); warn!("getpeername for unix socket is unimplemented");
errno!( return_errno!(
ENOTCONN, ENOTCONN,
"hack for php: Transport endpoint is not connected" "hack for php: Transport endpoint is not connected"
) )
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
@ -1233,7 +1230,7 @@ fn do_getsockname(
fd: c_int, fd: c_int,
addr: *mut libc::sockaddr, addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t, addr_len: *mut libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"getsockname: fd: {}, addr: {:?}, addr_len: {:?}", "getsockname: fd: {}, addr: {:?}, addr_len: {:?}",
fd, addr, addr_len fd, addr, addr_len
@ -1248,7 +1245,7 @@ fn do_getsockname(
warn!("getsockname for unix socket is unimplemented"); warn!("getsockname for unix socket is unimplemented");
Ok(0) Ok(0)
} else { } else {
errno!(EBADF, "not a socket") return_errno!(EBADF, "not a socket")
} }
} }
@ -1259,7 +1256,7 @@ fn do_sendto(
flags: c_int, flags: c_int,
addr: *const libc::sockaddr, addr: *const libc::sockaddr,
addr_len: libc::socklen_t, addr_len: libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}", "sendto: fd: {}, base: {:?}, len: {}, addr: {:?}, addr_len: {}",
fd, base, len, addr, addr_len fd, base, len, addr, addr_len
@ -1287,7 +1284,7 @@ fn do_recvfrom(
flags: c_int, flags: c_int,
addr: *mut libc::sockaddr, addr: *mut libc::sockaddr,
addr_len: *mut libc::socklen_t, addr_len: *mut libc::socklen_t,
) -> Result<isize, Error> { ) -> Result<isize> {
info!( info!(
"recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}", "recvfrom: fd: {}, base: {:?}, len: {}, flags: {}, addr: {:?}, addr_len: {:?}",
fd, base, len, flags, addr, addr_len fd, base, len, flags, addr, addr_len
@ -1314,10 +1311,10 @@ fn do_select(
writefds: *mut libc::fd_set, writefds: *mut libc::fd_set,
exceptfds: *mut libc::fd_set, exceptfds: *mut libc::fd_set,
timeout: *const libc::timeval, timeout: *const libc::timeval,
) -> Result<isize, Error> { ) -> Result<isize> {
// check arguments // check arguments
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int { if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
return errno!(EINVAL, "nfds is negative or exceeds the resource limit"); return_errno!(EINVAL, "nfds is negative or exceeds the resource limit");
} }
let nfds = nfds as usize; let nfds = nfds as usize;
@ -1354,7 +1351,7 @@ fn do_select(
Ok(n as isize) Ok(n as isize)
} }
fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize, Error> { fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize> {
check_mut_array(fds, nfds as usize)?; check_mut_array(fds, nfds as usize)?;
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) }; let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
@ -1362,14 +1359,14 @@ fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result
Ok(n as isize) Ok(n as isize)
} }
fn do_epoll_create(size: c_int) -> Result<isize, Error> { fn do_epoll_create(size: c_int) -> Result<isize> {
if size <= 0 { if size <= 0 {
return errno!(EINVAL, "size is not positive"); return_errno!(EINVAL, "size is not positive");
} }
do_epoll_create1(0) do_epoll_create1(0)
} }
fn do_epoll_create1(flags: c_int) -> Result<isize, Error> { fn do_epoll_create1(flags: c_int) -> Result<isize> {
let fd = fs::do_epoll_create1(flags)?; let fd = fs::do_epoll_create1(flags)?;
Ok(fd as isize) Ok(fd as isize)
} }
@ -1379,7 +1376,7 @@ fn do_epoll_ctl(
op: c_int, op: c_int,
fd: c_int, fd: c_int,
event: *const libc::epoll_event, event: *const libc::epoll_event,
) -> Result<isize, Error> { ) -> Result<isize> {
if !event.is_null() { if !event.is_null() {
check_ptr(event)?; check_ptr(event)?;
} }
@ -1392,10 +1389,10 @@ fn do_epoll_wait(
events: *mut libc::epoll_event, events: *mut libc::epoll_event,
maxevents: c_int, maxevents: c_int,
timeout: c_int, timeout: c_int,
) -> Result<isize, Error> { ) -> Result<isize> {
let maxevents = { let maxevents = {
if maxevents <= 0 { if maxevents <= 0 {
return errno!(EINVAL, "maxevents <= 0"); return_errno!(EINVAL, "maxevents <= 0");
} }
maxevents as usize maxevents as usize
}; };
@ -1407,7 +1404,7 @@ fn do_epoll_wait(
Ok(count as isize) Ok(count as isize)
} }
fn do_uname(name: *mut utsname_t) -> Result<isize, Error> { fn do_uname(name: *mut utsname_t) -> Result<isize> {
check_mut_ptr(name)?; check_mut_ptr(name)?;
let name = unsafe { &mut *name }; let name = unsafe { &mut *name };
misc::do_uname(name).map(|_| 0) misc::do_uname(name).map(|_| 0)
@ -1418,7 +1415,7 @@ fn do_prlimit(
resource: u32, resource: u32,
new_limit: *const rlimit_t, new_limit: *const rlimit_t,
old_limit: *mut rlimit_t, old_limit: *mut rlimit_t,
) -> Result<isize, Error> { ) -> Result<isize> {
let resource = resource_t::from_u32(resource)?; let resource = resource_t::from_u32(resource)?;
let new_limit = { let new_limit = {
if new_limit != ptr::null() { if new_limit != ptr::null() {
@ -1439,19 +1436,19 @@ fn do_prlimit(
misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0) misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0)
} }
fn do_access(path: *const i8, mode: u32) -> Result<isize, Error> { fn do_access(path: *const i8, mode: u32) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?; let mode = AccessModes::from_u32(mode)?;
fs::do_access(&path, mode).map(|_| 0) fs::do_access(&path, mode).map(|_| 0)
} }
fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize, Error> { fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize> {
let dirfd = if dirfd >= 0 { let dirfd = if dirfd >= 0 {
Some(dirfd as FileDesc) Some(dirfd as FileDesc)
} else if dirfd == AT_FDCWD { } else if dirfd == AT_FDCWD {
None None
} else { } else {
return errno!(EINVAL, "invalid dirfd"); return_errno!(EINVAL, "invalid dirfd");
}; };
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?; let mode = AccessModes::from_u32(mode)?;
@ -1461,10 +1458,10 @@ fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<is
// TODO: implement signals // TODO: implement signals
fn do_rt_sigaction() -> Result<isize, Error> { fn do_rt_sigaction() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_rt_sigprocmask() -> Result<isize, Error> { fn do_rt_sigprocmask() -> Result<isize> {
Ok(0) Ok(0)
} }

@ -61,7 +61,7 @@ pub enum ClockID {
impl ClockID { impl ClockID {
#[deny(unreachable_patterns)] #[deny(unreachable_patterns)]
pub fn from_raw(clockid: clockid_t) -> Result<ClockID, Error> { pub fn from_raw(clockid: clockid_t) -> Result<ClockID> {
Ok(match clockid as i32 { Ok(match clockid as i32 {
0 => ClockID::CLOCK_REALTIME, 0 => ClockID::CLOCK_REALTIME,
1 => ClockID::CLOCK_MONOTONIC, 1 => ClockID::CLOCK_MONOTONIC,
@ -71,12 +71,12 @@ impl ClockID {
5 => ClockID::CLOCK_REALTIME_COARSE, 5 => ClockID::CLOCK_REALTIME_COARSE,
6 => ClockID::CLOCK_MONOTONIC_COARSE, 6 => ClockID::CLOCK_MONOTONIC_COARSE,
7 => ClockID::CLOCK_BOOTTIME, 7 => ClockID::CLOCK_BOOTTIME,
_ => return errno!(EINVAL, "invalid command"), _ => return_errno!(EINVAL, "invalid command"),
}) })
} }
} }
pub fn do_clock_gettime(clockid: ClockID) -> Result<timespec_t, Error> { pub fn do_clock_gettime(clockid: ClockID) -> Result<timespec_t> {
let mut sec = 0; let mut sec = 0;
let mut nsec = 0; let mut nsec = 0;
unsafe { unsafe {

@ -2,14 +2,14 @@ use log::*;
pub fn init() { pub fn init() {
static LOGGER: SimpleLogger = SimpleLogger; static LOGGER: SimpleLogger = SimpleLogger;
log::set_logger(&LOGGER).unwrap(); log::set_logger(&LOGGER).expect("logger cannot be set twice");
log::set_max_level(match option_env!("LOG") { log::set_max_level(match option_env!("LIBOS_LOG") {
Some("error") => LevelFilter::Error, Some("error") => LevelFilter::Error,
Some("warn") => LevelFilter::Warn, Some("warn") => LevelFilter::Warn,
Some("info") => LevelFilter::Info, Some("info") => LevelFilter::Info,
Some("debug") => LevelFilter::Debug, Some("debug") => LevelFilter::Debug,
Some("trace") => LevelFilter::Trace, Some("trace") => LevelFilter::Trace,
_ => LevelFilter::Off, _ => LevelFilter::Error, // errors are printed be default
}); });
} }
@ -22,11 +22,13 @@ impl Log for SimpleLogger {
fn log(&self, record: &Record) { fn log(&self, record: &Record) {
if self.enabled(record.metadata()) { if self.enabled(record.metadata()) {
let color = Color::from(record.level()); let color = Color::from(record.level());
// TODO: add process info
println!( println!(
"\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m", //"\u{1B}[{}m[{:>5}][{}] {}\u{1B}[0m",
"\u{1B}[{}m[{:>5}] {}\u{1B}[0m",
color as u8, color as u8,
record.level(), record.level(),
crate::process::current_pid(), //crate::process::current_pid(),
record.args() record.args()
); );
} }

@ -8,27 +8,27 @@ pub mod from_user {
use super::*; use super::*;
/// Check the user pointer is within the readable memory range of the user process /// Check the user pointer is within the readable memory range of the user process
pub fn check_ptr<T>(user_ptr: *const T) -> Result<(), Error> { pub fn check_ptr<T>(user_ptr: *const T) -> Result<()> {
Ok(()) Ok(())
} }
/// Check the mutable user pointer is within the writable memory of the user process /// Check the mutable user pointer is within the writable memory of the user process
pub fn check_mut_ptr<T>(user_ptr: *mut T) -> Result<(), Error> { pub fn check_mut_ptr<T>(user_ptr: *mut T) -> Result<()> {
Ok(()) Ok(())
} }
/// Check the readonly array is within the readable memory of the user process /// Check the readonly array is within the readable memory of the user process
pub fn check_array<T>(user_buf: *const T, count: usize) -> Result<(), Error> { pub fn check_array<T>(user_buf: *const T, count: usize) -> Result<()> {
Ok(()) Ok(())
} }
/// Check the mutable array is within the writable memory of the user process /// Check the mutable array is within the writable memory of the user process
pub fn check_mut_array<T>(user_buf: *mut T, count: usize) -> Result<(), Error> { pub fn check_mut_array<T>(user_buf: *mut T, count: usize) -> Result<()> {
Ok(()) Ok(())
} }
/// Clone a C-string from the user process safely /// Clone a C-string from the user process safely
pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString, Error> { pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString> {
check_ptr(out_ptr)?; check_ptr(out_ptr)?;
// TODO: using from_ptr directly is not safe // TODO: using from_ptr directly is not safe
let cstr = unsafe { CStr::from_ptr(out_ptr) }; let cstr = unsafe { CStr::from_ptr(out_ptr) };
@ -39,7 +39,7 @@ pub mod from_user {
/// Clone a C-string array (const char*[]) from the user process safely /// Clone a C-string array (const char*[]) from the user process safely
/// ///
/// This array must be ended with a NULL pointer. /// This array must be ended with a NULL pointer.
pub fn clone_cstrings_safely(user_ptr: *const *const c_char) -> Result<Vec<CString>, Error> { pub fn clone_cstrings_safely(user_ptr: *const *const c_char) -> Result<Vec<CString>> {
let mut cstrings = Vec::new(); let mut cstrings = Vec::new();
if user_ptr == ptr::null() { if user_ptr == ptr::null() {
return Ok(cstrings); return Ok(cstrings);
@ -70,17 +70,20 @@ pub mod from_untrusted {
use super::*; use super::*;
/// Check the untrusted pointer is outside the enclave /// Check the untrusted pointer is outside the enclave
pub fn check_ptr<T>(out_ptr: *const T) -> Result<(), Error> { // TODO: implement this!
pub fn check_ptr<T>(out_ptr: *const T) -> Result<()> {
Ok(()) Ok(())
} }
/// Check the untrusted array is outside the enclave /// Check the untrusted array is outside the enclave
pub fn check_array<T>(out_ptr: *const T, count: usize) -> Result<(), Error> { // TODO: implement this!
pub fn check_array<T>(out_ptr: *const T, count: usize) -> Result<()> {
Ok(()) Ok(())
} }
/// Clone a C-string from outside the enclave /// Clone a C-string from outside the enclave
pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString, Error> { // TODO: strict check!
pub fn clone_cstring_safely(out_ptr: *const c_char) -> Result<CString> {
check_ptr(out_ptr)?; check_ptr(out_ptr)?;
// TODO: using from_ptr directly is not safe // TODO: using from_ptr directly is not safe
let cstr = unsafe { CStr::from_ptr(out_ptr) }; let cstr = unsafe { CStr::from_ptr(out_ptr) };
@ -91,7 +94,8 @@ pub mod from_untrusted {
/// Clone a C-string array (const char*[]) from outside the enclave /// Clone a C-string array (const char*[]) from outside the enclave
/// ///
/// This array must be ended with a NULL pointer. /// This array must be ended with a NULL pointer.
pub fn clone_cstrings_safely(out_ptr: *const *const c_char) -> Result<Vec<CString>, Error> { // TODO: strict check!
pub fn clone_cstrings_safely(out_ptr: *const *const c_char) -> Result<Vec<CString>> {
let mut cstrings = Vec::new(); let mut cstrings = Vec::new();
if out_ptr == ptr::null() { if out_ptr == ptr::null() {
return Ok(cstrings); return Ok(cstrings);

@ -1,9 +1,9 @@
use super::*; use super::*;
pub fn mpx_enable() -> Result<(), Error> { pub fn mpx_enable() -> Result<()> {
match unsafe { __mpx_enable() } { match unsafe { __mpx_enable() } {
0 => Ok(()), 0 => Ok(()),
_ => errno!(EPERM, "MPX cannot be enabled"), _ => Err(errno!(EPERM, "MPX cannot be enabled")),
} }
} }
@ -14,10 +14,10 @@ pub enum MpxReg {
BND3, BND3,
} }
pub fn mpx_bndmk(bndreg: MpxReg, base: usize, size: usize) -> Result<(), Error> { pub fn mpx_bndmk(bndreg: MpxReg, base: usize, size: usize) -> Result<()> {
/* Check whether the upper bound overflows the max of 64-bit */ /* Check whether the upper bound overflows the max of 64-bit */
if base.checked_add(size).is_none() { if base.checked_add(size).is_none() {
return errno!(ERANGE, "Upper bound overflows"); return_errno!(ERANGE, "Upper bound overflows");
} }
match bndreg { match bndreg {

@ -122,7 +122,7 @@ impl Drop for RingBufInner {
} }
impl RingBufReader { impl RingBufReader {
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> { pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
let mut tail = self.inner.get_tail(); let mut tail = self.inner.get_tail();
let mut buf_remain = buf.len(); let mut buf_remain = buf.len();
let mut buf_pos = 0; let mut buf_pos = 0;
@ -179,9 +179,9 @@ impl Drop for RingBufReader {
} }
impl RingBufWriter { impl RingBufWriter {
pub fn write(&self, buf: &[u8]) -> Result<usize, Error> { pub fn write(&self, buf: &[u8]) -> Result<usize> {
if self.inner.is_closed() { if self.inner.is_closed() {
return errno!(EPIPE, "Reader has been closed"); return_errno!(EPIPE, "Reader has been closed");
} }
let mut head = self.inner.get_head(); let mut head = self.inner.get_head();

@ -1,5 +1,5 @@
use super::*;
use fs::{File, FileDesc, FileRef}; use fs::{File, FileDesc, FileRef};
use prelude::*;
use process::{get_current, Process, ProcessRef}; use process::{get_current, Process, ProcessRef};
use std::fmt; use std::fmt;
@ -17,7 +17,7 @@ pub fn do_mmap(
flags: MMapFlags, flags: MMapFlags,
fd: FileDesc, fd: FileDesc,
offset: usize, offset: usize,
) -> Result<usize, Error> { ) -> Result<usize> {
if flags.contains(MMapFlags::MAP_ANONYMOUS) { if flags.contains(MMapFlags::MAP_ANONYMOUS) {
info!( info!(
"mmap: addr: {:#x}, size: {:#x}, perms: {:?}, flags: {:?}", "mmap: addr: {:#x}, size: {:#x}, perms: {:?}, flags: {:?}",
@ -39,7 +39,7 @@ pub fn do_mmap(
current_vm.mmap(addr, size, perms, flags, fd, offset) current_vm.mmap(addr, size, perms, flags, fd, offset)
} }
pub fn do_munmap(addr: usize, size: usize) -> Result<(), Error> { pub fn do_munmap(addr: usize, size: usize) -> Result<()> {
info!("munmap: addr: {:#x}, size: {:#x}", addr, size); info!("munmap: addr: {:#x}, size: {:#x}", addr, size);
let mut current_vm_ref = { let mut current_vm_ref = {
let current_ref = get_current(); let current_ref = get_current();
@ -50,7 +50,7 @@ pub fn do_munmap(addr: usize, size: usize) -> Result<(), Error> {
current_vm.munmap(addr, size) current_vm.munmap(addr, size)
} }
pub fn do_brk(addr: usize) -> Result<usize, Error> { pub fn do_brk(addr: usize) -> Result<usize> {
info!("brk: addr: {:#x}", addr); info!("brk: addr: {:#x}", addr);
let current_ref = get_current(); let current_ref = get_current();
let current_process = current_ref.lock().unwrap(); let current_process = current_ref.lock().unwrap();

@ -41,7 +41,7 @@ impl ProcessVMBuilder {
impl_setter_for_process_vm_builder!(stack_size); impl_setter_for_process_vm_builder!(stack_size);
impl_setter_for_process_vm_builder!(mmap_size); impl_setter_for_process_vm_builder!(mmap_size);
pub fn build(self) -> Result<ProcessVM, Error> { pub fn build(self) -> Result<ProcessVM> {
self.validate()?; self.validate()?;
let code_size = self.code_size; let code_size = self.code_size;
@ -111,7 +111,7 @@ impl ProcessVMBuilder {
} }
// TODO: implement this! // TODO: implement this!
fn validate(&self) -> Result<(), Error> { fn validate(&self) -> Result<()> {
Ok(()) Ok(())
} }
} }
@ -191,16 +191,16 @@ impl ProcessVM {
self.brk self.brk
} }
pub fn brk(&mut self, new_brk: usize) -> Result<usize, Error> { pub fn brk(&mut self, new_brk: usize) -> Result<usize> {
let heap_start = self.heap_range.start(); let heap_start = self.heap_range.start();
let heap_end = self.heap_range.end(); let heap_end = self.heap_range.end();
if new_brk == 0 { if new_brk == 0 {
return Ok(self.get_brk()); return Ok(self.get_brk());
} else if new_brk < heap_start { } else if new_brk < heap_start {
return errno!(EINVAL, "New brk address is too low"); return_errno!(EINVAL, "New brk address is too low");
} else if new_brk > heap_end { } else if new_brk > heap_end {
return errno!(EINVAL, "New brk address is too high"); return_errno!(EINVAL, "New brk address is too high");
} }
if self.brk < new_brk { if self.brk < new_brk {
@ -219,11 +219,11 @@ impl ProcessVM {
flags: MMapFlags, flags: MMapFlags,
fd: FileDesc, fd: FileDesc,
offset: usize, offset: usize,
) -> Result<usize, Error> { ) -> Result<usize> {
let addr_option = { let addr_option = {
if flags.contains(MMapFlags::MAP_FIXED) { if flags.contains(MMapFlags::MAP_FIXED) {
if !self.process_range.range().contains(addr) { if !self.process_range.range().contains(addr) {
return errno!(EINVAL, "Beyond valid memory range"); return_errno!(EINVAL, "Beyond valid memory range");
} }
VMMapAddr::Fixed(addr) VMMapAddr::Fixed(addr)
} else { } else {
@ -256,11 +256,11 @@ impl ProcessVM {
Ok(mmap_addr) Ok(mmap_addr)
} }
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> { pub fn munmap(&mut self, addr: usize, size: usize) -> Result<()> {
self.mmap_manager.munmap(addr, size) self.mmap_manager.munmap(addr, size)
} }
pub fn find_mmap_region(&self, addr: usize) -> Result<&VMRange, Error> { pub fn find_mmap_region(&self, addr: usize) -> Result<&VMRange> {
self.mmap_manager.find_mmap_region(addr) self.mmap_manager.find_mmap_region(addr)
} }
} }
@ -289,9 +289,9 @@ bitflags! {
} }
impl MMapFlags { impl MMapFlags {
pub fn from_u32(bits: u32) -> Result<MMapFlags, Error> { pub fn from_u32(bits: u32) -> Result<MMapFlags> {
// TODO: detect non-supporting flags // TODO: detect non-supporting flags
MMapFlags::from_bits(bits).ok_or_else(|| (Errno::EINVAL, "Unknown mmap flags").into()) MMapFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "unknown mmap flags"))
} }
} }
@ -316,8 +316,8 @@ impl VMPerms {
self.contains(VMPerms::EXEC) self.contains(VMPerms::EXEC)
} }
pub fn from_u32(bits: u32) -> Result<VMPerms, Error> { pub fn from_u32(bits: u32) -> Result<VMPerms> {
VMPerms::from_bits(bits).ok_or_else(|| (Errno::EINVAL, "Unknown permission bits").into()) VMPerms::from_bits(bits).ok_or_else(|| errno!(EINVAL, "unknown permission bits"))
} }
} }

@ -8,12 +8,12 @@ pub struct UserSpaceVMManager {
} }
impl UserSpaceVMManager { impl UserSpaceVMManager {
pub unsafe fn from(addr: usize, size: usize) -> Result<UserSpaceVMManager, Error> { pub unsafe fn from(addr: usize, size: usize) -> Result<UserSpaceVMManager> {
let vm_manager = Arc::new(SgxMutex::new(VMManager::from(addr, size)?)); let vm_manager = Arc::new(SgxMutex::new(VMManager::from(addr, size)?));
Ok(UserSpaceVMManager { vm_manager }) Ok(UserSpaceVMManager { vm_manager })
} }
pub fn alloc(&self, size: usize) -> Result<UserSpaceVMRange, Error> { pub fn alloc(&self, size: usize) -> Result<UserSpaceVMRange> {
let user_vm_range = unsafe { let user_vm_range = unsafe {
let mmap_options = VMMapOptionsBuilder::default().size(size).build()?; let mmap_options = VMMapOptionsBuilder::default().size(size).build()?;

@ -1,5 +1,4 @@
use super::*; use super::*;
use std::slice;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum VMInitializer { pub enum VMInitializer {
@ -15,7 +14,7 @@ impl Default for VMInitializer {
} }
impl VMInitializer { impl VMInitializer {
pub fn initialize(&self, buf: &mut [u8]) -> Result<(), Error> { pub fn initialize(&self, buf: &mut [u8]) -> Result<()> {
match self { match self {
VMInitializer::DoNothing() => { VMInitializer::DoNothing() => {
// Do nothing // Do nothing
@ -27,7 +26,9 @@ impl VMInitializer {
} }
VMInitializer::LoadFromFile { file, offset } => { VMInitializer::LoadFromFile { file, offset } => {
// TODO: make sure that read_at does not move file cursor // TODO: make sure that read_at does not move file cursor
let len = file.read_at(*offset, buf)?; let len = file
.read_at(*offset, buf)
.cause_err(|_| errno!(EIO, "failed to init memory from file"))?;
for b in &mut buf[len..] { for b in &mut buf[len..] {
*b = 0; *b = 0;
} }
@ -61,20 +62,20 @@ pub struct VMMapOptions {
// VMMapOptionsBuilder is generated automatically, except the build function // VMMapOptionsBuilder is generated automatically, except the build function
impl VMMapOptionsBuilder { impl VMMapOptionsBuilder {
pub fn build(&self) -> Result<VMMapOptions, Error> { pub fn build(&self) -> Result<VMMapOptions> {
let size = { let size = {
let size = self let size = self
.size .size
.ok_or_else(|| (Errno::EINVAL, "Invalid size for mmap"))?; .ok_or_else(|| errno!(EINVAL, "invalid size for mmap"))?;
if size == 0 { if size == 0 {
return errno!(EINVAL, "Invalid size for mmap"); return_errno!(EINVAL, "invalid size for mmap");
} }
align_up(size, PAGE_SIZE) align_up(size, PAGE_SIZE)
}; };
let align = { let align = {
let align = self.align.unwrap_or(PAGE_SIZE); let align = self.align.unwrap_or(PAGE_SIZE);
if align == 0 || align % PAGE_SIZE != 0 { if align == 0 || align % PAGE_SIZE != 0 {
return errno!(EINVAL, "Invalid size for mmap"); return_errno!(EINVAL, "invalid size for mmap");
} }
align align
}; };
@ -89,7 +90,7 @@ impl VMMapOptionsBuilder {
} }
VMMapAddr::Fixed(addr) => { VMMapAddr::Fixed(addr) => {
if addr % align != 0 { if addr % align != 0 {
return errno!(EINVAL, "Unaligned addr for fixed mmap"); return_errno!(EINVAL, "unaligned addr for fixed mmap");
} }
VMMapAddr::Fixed(addr) VMMapAddr::Fixed(addr)
} }
@ -129,7 +130,7 @@ pub struct VMManager {
} }
impl VMManager { impl VMManager {
pub fn from(addr: usize, size: usize) -> Result<VMManager, Error> { pub fn from(addr: usize, size: usize) -> Result<VMManager> {
let range = VMRange::from(addr, addr + size)?; let range = VMRange::from(addr, addr + size)?;
let sub_ranges = { let sub_ranges = {
let start = range.start(); let start = range.start();
@ -145,7 +146,7 @@ impl VMManager {
&self.range &self.range
} }
pub fn mmap(&mut self, options: &VMMapOptions) -> Result<usize, Error> { pub fn mmap(&mut self, options: &VMMapOptions) -> Result<usize> {
// TODO: respect options.align when mmap // TODO: respect options.align when mmap
let addr = *options.addr(); let addr = *options.addr();
let size = *options.size(); let size = *options.size();
@ -163,7 +164,7 @@ impl VMManager {
unsafe { unsafe {
let buf_ptr = new_subrange.start() as *mut u8; let buf_ptr = new_subrange.start() as *mut u8;
let buf_size = new_subrange.size() as usize; let buf_size = new_subrange.size() as usize;
let buf = slice::from_raw_parts_mut(buf_ptr, buf_size); let buf = std::slice::from_raw_parts_mut(buf_ptr, buf_size);
options.initializer.initialize(buf)?; options.initializer.initialize(buf)?;
} }
@ -173,10 +174,10 @@ impl VMManager {
Ok(new_subrange_addr) Ok(new_subrange_addr)
} }
pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> { pub fn munmap(&mut self, addr: usize, size: usize) -> Result<()> {
let size = { let size = {
if size == 0 { if size == 0 {
return errno!(EINVAL, "size of munmap must not be zero"); return_errno!(EINVAL, "size of munmap must not be zero");
} }
align_up(size, PAGE_SIZE) align_up(size, PAGE_SIZE)
}; };
@ -211,22 +212,15 @@ impl VMManager {
Ok(()) Ok(())
} }
pub fn find_mmap_region(&self, addr: usize) -> Result<&VMRange, Error> { pub fn find_mmap_region(&self, addr: usize) -> Result<&VMRange> {
self.sub_ranges self.sub_ranges
.iter() .iter()
.find(|subrange| subrange.contains(addr)) .find(|subrange| subrange.contains(addr))
.ok_or(Error::new( .ok_or_else(|| errno!(ESRCH, "no mmap regions that contains the address"))
Errno::ESRCH,
"no mmap regions that contains the address",
))
} }
// Find the free subrange that satisfies the constraints of size and address // Find the free subrange that satisfies the constraints of size and address
fn find_free_subrange( fn find_free_subrange(&mut self, size: usize, addr: VMMapAddr) -> Result<(usize, VMRange)> {
&mut self,
size: usize,
addr: VMMapAddr,
) -> Result<(usize, VMRange), Error> {
// TODO: reduce the complexity from O(N) to O(log(N)), where N is // TODO: reduce the complexity from O(N) to O(log(N)), where N is
// the number of existing subranges. // the number of existing subranges.
@ -268,13 +262,13 @@ impl VMManager {
// Must have free_range.start == addr // Must have free_range.start == addr
VMMapAddr::Fixed(addr) => { VMMapAddr::Fixed(addr) => {
if free_range.start() > addr { if free_range.start() > addr {
return errno!(ENOMEM, "Not enough memory for fixed mmap"); return_errno!(ENOMEM, "not enough memory for fixed mmap");
} }
if !free_range.contains(addr) { if !free_range.contains(addr) {
continue; continue;
} }
if free_range.end() - addr < size { if free_range.end() - addr < size {
return errno!(ENOMEM, "Not enough memory for fixed mmap"); return_errno!(ENOMEM, "not enough memory for fixed mmap");
} }
free_range.start = addr; free_range.start = addr;
let insert_idx = idx + 1; let insert_idx = idx + 1;
@ -291,7 +285,7 @@ impl VMManager {
} }
if result_free_range.is_none() { if result_free_range.is_none() {
return errno!(ENOMEM, "Cannot find enough memory"); return_errno!(ENOMEM, "not enough memory");
} }
let free_range = result_free_range.unwrap(); let free_range = result_free_range.unwrap();
@ -324,9 +318,9 @@ pub struct VMRange {
} }
impl VMRange { impl VMRange {
pub fn from(start: usize, end: usize) -> Result<VMRange, Error> { pub fn from(start: usize, end: usize) -> Result<VMRange> {
if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 || start > end { if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 || start > end {
return errno!(EINVAL, "invalid start or end"); return_errno!(EINVAL, "invalid start or end");
} }
Ok(VMRange { Ok(VMRange {
start: start, start: start,