[crates] Seperate error module into errno crate
This commit is contained in:
parent
4027258ec5
commit
5b704984e3
@ -25,6 +25,7 @@ rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" }
|
||||
resolv-conf = { path = "../../deps/resolv-conf" }
|
||||
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
|
||||
serde_json = { path = "../../deps/serde-json-sgx" }
|
||||
errno = { path = "./crates/errno", features = ["occlum"] }
|
||||
memoffset = "0.6.1"
|
||||
scroll = { version = "0.11.0", default-features = false }
|
||||
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
|
||||
|
265
src/libos/crates/errno/Cargo.lock
generated
Normal file
265
src/libos/crates/errno/Cargo.lock
generated
Normal file
@ -0,0 +1,265 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"rcore-fs",
|
||||
"serde_json",
|
||||
"sgx_tstd 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown_tstd"
|
||||
version = "0.12.0"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.5"
|
||||
dependencies = [
|
||||
"sgx_tstd 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "rcore-fs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.104"
|
||||
dependencies = [
|
||||
"sgx_tstd 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.40"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"sgx_tstd 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_alloc"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_alloc"
|
||||
version = "1.1.6"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_backtrace_sys"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"sgx_build_helper 0.1.0",
|
||||
"sgx_libc 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_backtrace_sys"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"sgx_build_helper 1.1.6",
|
||||
"sgx_libc 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_build_helper"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_build_helper"
|
||||
version = "1.1.6"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_demangle"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_demangle"
|
||||
version = "1.1.6"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_libc"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_libc"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"sgx_types 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tcrypto"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tprotected_fs"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_trts 1.1.0",
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tprotected_fs"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"sgx_trts 1.1.6",
|
||||
"sgx_types 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_trts"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_libc 1.1.0",
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_trts"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"sgx_libc 1.1.6",
|
||||
"sgx_types 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tse"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tseal"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_tcrypto",
|
||||
"sgx_trts 1.1.0",
|
||||
"sgx_tse",
|
||||
"sgx_types 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tstd"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_alloc 1.1.0",
|
||||
"sgx_backtrace_sys 1.1.0",
|
||||
"sgx_demangle 1.1.0",
|
||||
"sgx_libc 1.1.0",
|
||||
"sgx_tprotected_fs 1.1.0",
|
||||
"sgx_trts 1.1.0",
|
||||
"sgx_tseal",
|
||||
"sgx_types 1.1.0",
|
||||
"sgx_unwind 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_tstd"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"hashbrown_tstd",
|
||||
"sgx_alloc 1.1.6",
|
||||
"sgx_backtrace_sys 1.1.6",
|
||||
"sgx_demangle 1.1.6",
|
||||
"sgx_libc 1.1.6",
|
||||
"sgx_tprotected_fs 1.1.6",
|
||||
"sgx_trts 1.1.6",
|
||||
"sgx_types 1.1.6",
|
||||
"sgx_unwind 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_types"
|
||||
version = "1.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_types"
|
||||
version = "1.1.6"
|
||||
|
||||
[[package]]
|
||||
name = "sgx_unwind"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/apache/teaclave-sgx-sdk.git?rev=v1.1.0#71a88b647bb76a16cbc5c3e29403e2afb67f82fd"
|
||||
dependencies = [
|
||||
"sgx_build_helper 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_unwind"
|
||||
version = "1.1.6"
|
||||
dependencies = [
|
||||
"sgx_build_helper 1.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
19
src/libos/crates/errno/Cargo.toml
Normal file
19
src/libos/crates/errno/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "errno"
|
||||
version = "0.1.0"
|
||||
authors = ["Tate, Hongliang Tian <tate.thl@antgroup.com>"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = []
|
||||
std = []
|
||||
occlum = ["sgx", "serde_json", "rcore-fs"]
|
||||
sgx = ["sgx_tstd"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
serde_json = { path = "../../../../deps/serde-json-sgx", optional = true }
|
||||
sgx_tstd = { path = "../../../../deps/rust-sgx-sdk/sgx_tstd", optional = true }
|
||||
rcore-fs = { path = "../../../../deps/sefs/rcore-fs", optional = true }
|
@ -1,4 +1,9 @@
|
||||
use super::*;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt;
|
||||
|
||||
use super::Error;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ErrorBacktrace<'a> {
|
||||
@ -15,7 +20,7 @@ impl<'a> ErrorBacktrace<'a> {
|
||||
|
||||
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_strings: Vec<String> = self.clone().map(|e| alloc::format!("{}", e)).collect();
|
||||
let error_backtrace = error_strings.join("\n Caused by ");
|
||||
write!(f, "{}", error_backtrace)
|
||||
}
|
||||
@ -48,18 +53,3 @@ impl Error {
|
||||
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))
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
use super::*;
|
||||
use core::fmt;
|
||||
|
||||
/// POSIX errno
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@ -46,7 +46,6 @@ pub enum Errno {
|
||||
ENOSYS = 38,
|
||||
ENOTEMPTY = 39,
|
||||
ELOOP = 40,
|
||||
EWOULDBLOCK = 41,
|
||||
ENOMSG = 42,
|
||||
EIDRM = 43,
|
||||
ECHRNG = 44,
|
||||
@ -145,6 +144,9 @@ const ERRNO_MIN: u32 = Errno::EPERM as u32;
|
||||
const ERRNO_MAX: u32 = Errno::EHWPOISON as u32;
|
||||
|
||||
impl Errno {
|
||||
// EWOULDBLOCK was used on BSD/Sun variants of Unix, and EAGAIN was the AT&T System V error code.
|
||||
// Here we keep same with linux, define EWOULDBLOCK with EAGAIN.
|
||||
pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
|
||||
pub(crate) fn as_str(&self) -> &'static str {
|
||||
use self::Errno::*;
|
||||
match *self {
|
@ -1,4 +1,7 @@
|
||||
use super::*;
|
||||
use alloc::boxed::Box;
|
||||
use core::fmt;
|
||||
|
||||
use super::{Errno, ToErrno};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
@ -10,7 +13,7 @@ pub struct Error {
|
||||
#[derive(Debug)]
|
||||
enum Error__ {
|
||||
Embedded((Errno, &'static str)),
|
||||
Boxed(Box<dyn ToErrno + 'static>),
|
||||
Boxed(Box<dyn ToErrno + Send + 'static>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@ -30,7 +33,7 @@ impl Error {
|
||||
|
||||
pub fn boxed<T>(inner: T, location: Option<ErrorLocation>) -> Error
|
||||
where
|
||||
T: ToErrno + 'static,
|
||||
T: ToErrno + Send + 'static,
|
||||
{
|
||||
Error {
|
||||
inner: Error__::Boxed(Box::new(inner)),
|
||||
@ -64,23 +67,6 @@ impl ErrorLocation {
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
@ -105,3 +91,25 @@ impl fmt::Display for ErrorLocation {
|
||||
write!(f, "[line = {}, file = {}]", self.line, self.file)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "sgx", test, doctest))]
|
||||
mod if_std {
|
||||
use super::*;
|
||||
|
||||
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))
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
204
src/libos/crates/errno/src/lib.rs
Normal file
204
src/libos/crates/errno/src/lib.rs
Normal file
@ -0,0 +1,204 @@
|
||||
//! User-friendly error handling with build-in support for POSIX errno.
|
||||
//!
|
||||
//! This crate extends Rust's standard error handling with the abilities of
|
||||
//! reporting error locations, providing backtrace information, and unifying
|
||||
//! all types of errors with POSIX errno.
|
||||
//!
|
||||
//! # Motivation
|
||||
//!
|
||||
//! While the built-in error handling mechanism of Rust is undoubtedly superior
|
||||
//! than that of a traditional system programming language (e.g., C/C++), it
|
||||
//! is _not perfect_.
|
||||
//!
|
||||
//! First, trait `std::error::Error` does not provide any means to
|
||||
//! record the location of the source code that triggers an error, leading to
|
||||
//! a slow process of diagnosing errors or bugs.
|
||||
//!
|
||||
//! Second, while the `Error` trait (which has a `cause` method)
|
||||
//! supports backtrace in theory, it is inconvenient---in practice---to implement
|
||||
//! backtrace. This is because the users still need to manually write the concrete
|
||||
//! implementation that stores the cause for every error struct.
|
||||
//!
|
||||
//! Third, one challenging aspect of error handling in Rust is
|
||||
//! dealing with the various types of errors. The standard library
|
||||
//! defines errors like `std::io::Error`, `std::fmt::Error`, `std::str::Utf8Error`, etc.
|
||||
//! Not to mention the error types defined by third-party libraries.
|
||||
//! To make it even worse, we, as OS writers, have to convert all these errors
|
||||
//! into POSIX errno eventually.
|
||||
//!
|
||||
//! To cope with the issues above, this crate extends Rust's standard error
|
||||
//! handling mechanism. Specifically, it aims at the following design goals:
|
||||
//!
|
||||
//! * **Fast diagnose** (e.g., reporting the backtrace and the code location of an error).
|
||||
//! * **First-class POSIX errno** (e.g., every error has an errno).
|
||||
//! * **Zero-overhead abstraction** (e.g., no heap allocation unless absolutely necesary).
|
||||
//! * **Ergonomic grammar** (e.g., use macros to avoid writing code manually).
|
||||
//! * **Compatibility with `no_std`**.
|
||||
//!
|
||||
//! # How to Use
|
||||
//!
|
||||
//! ## Basic Usage
|
||||
//!
|
||||
//! The simplest usage involves just one macro---`errno!`.
|
||||
//! See the sample code below:
|
||||
//! ```rust
|
||||
//! use errno::prelude::*;
|
||||
//!
|
||||
//! fn return_err() -> Result<()> {
|
||||
//! Err(errno!(EINVAL, "the root error"))
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! if let Err(e) = return_err() {
|
||||
//! println!("{}", e);
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//! which prints something like
|
||||
//! ```text
|
||||
//! EINVAL (#22, Invalid argument): the root error [line = 45, file = src/lib.rs]
|
||||
//! ```
|
||||
//! Note that the specific line and file of source code that generates the error
|
||||
//! is printed. This facilitates diagnosing errors.
|
||||
//!
|
||||
//! ## Backtrace
|
||||
//!
|
||||
//! A more interesting usage is to print the backtrace of an error. To create
|
||||
//! the chains of errors, `std::result::Result` is extended with a new method
|
||||
//! named `cause_err`. If the result is `Ok`, the method does nothing; otherwise,
|
||||
//! this method executes a user-given closure to output a new error whose cause
|
||||
//! is the error contained in the result. The method consumes the current result
|
||||
//! and generates a new result that contains the new error. The two errors are
|
||||
//! chained. More calls to `cause_err` form deeper backtraces.
|
||||
//!
|
||||
//! See the sample code below:
|
||||
//! ```rust
|
||||
//! use errno::prelude::*;
|
||||
//!
|
||||
//! fn return_err() -> Result<()> {
|
||||
//! Err(errno!(EINVAL, "the root error"))
|
||||
//! }
|
||||
//!
|
||||
//! fn cause_err() -> Result<()> {
|
||||
//! return_err()
|
||||
//! .cause_err(|_e| errno!(EIO, "another error"))
|
||||
//! }
|
||||
//!
|
||||
//! # fn main() {
|
||||
//! if let Err(e) = cause_err() {
|
||||
//! println!("{}", e.backtrace());
|
||||
//! }
|
||||
//! # }
|
||||
//! ```
|
||||
//! which prints something like
|
||||
//! ```text
|
||||
//! EIO (#5, I/O error): another error [line = 71, file = src/lib.rs]
|
||||
//! Caused by EINVAL (#22, Invalid argument): the root error [line = 68, file = src/lib.rs]
|
||||
//! ```
|
||||
//!
|
||||
|
||||
#![feature(allocator_api)]
|
||||
// Use no_std and alloc crate except when given std feature or during test.
|
||||
#![cfg_attr(not(any(feature = "std", test, doctest)), no_std)]
|
||||
extern crate alloc;
|
||||
// Use Rust SGX SDK's std when given SGX feature.
|
||||
#[cfg(feature = "sgx")]
|
||||
extern crate sgx_tstd as std;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod backtrace;
|
||||
mod errno;
|
||||
mod error;
|
||||
pub mod prelude;
|
||||
mod result;
|
||||
mod to_errno;
|
||||
|
||||
pub use self::backtrace::ErrorBacktrace;
|
||||
pub use self::errno::*;
|
||||
pub use self::errno::Errno::*;
|
||||
pub use self::error::{Error, ErrorLocation};
|
||||
pub use self::result::{Result, ResultExt};
|
||||
pub use self::to_errno::ToErrno;
|
||||
|
||||
#[macro_export]
|
||||
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 =
|
||||
$crate::Error::embedded(inner_error, Some($crate::ErrorLocation::new(file!(), line!())));
|
||||
error
|
||||
}};
|
||||
($error_expr: expr) => {{
|
||||
let inner_error = $error_expr;
|
||||
let error = $crate::Error::boxed(inner_error, Some($crate::ErrorLocation::new(file!(), line!())));
|
||||
error
|
||||
}};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
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_export]
|
||||
macro_rules! try_libc {
|
||||
($ret: expr) => {{
|
||||
let ret = unsafe { $ret };
|
||||
if ret < 0 {
|
||||
let errno = unsafe { libc::errno() };
|
||||
return_errno!(Errno::from(errno as u32), "libc error");
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
// return Err(errno) if libc return -1
|
||||
// raise SIGPIPE if errno == EPIPE
|
||||
#[macro_export]
|
||||
macro_rules! try_libc_may_epipe {
|
||||
($ret: expr) => {{
|
||||
let ret = unsafe { $ret };
|
||||
if ret < 0 {
|
||||
let errno = unsafe { libc::errno() };
|
||||
if errno == Errno::EPIPE as i32 {
|
||||
crate::signal::do_tkill(current!().tid(), crate::signal::SIGPIPE.as_u8() as i32);
|
||||
}
|
||||
return_errno!(Errno::from(errno as u32), "libc error");
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn convert_std_io_error() -> Result<()> {
|
||||
use std::io::{BufWriter, Write};
|
||||
let mut buf_writer = BufWriter::new(Vec::<u8>::new());
|
||||
// std::io::Error can be converted crate::Error implicitly
|
||||
buf_writer.write("foo".as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convert_std_ffi_nul_error() -> Result<()> {
|
||||
use std::ffi::CString;
|
||||
// std::ffi::NulError can be converted crate::Error implicitly
|
||||
let _ = CString::new(b"foo".to_vec())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
3
src/libos/crates/errno/src/prelude.rs
Normal file
3
src/libos/crates/errno/src/prelude.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub use crate::{
|
||||
errno, return_errno, Errno, Errno::*, Error, ErrorLocation, Result, ResultExt, ToErrno,
|
||||
};
|
34
src/libos/crates/errno/src/result.rs
Normal file
34
src/libos/crates/errno/src/result.rs
Normal file
@ -0,0 +1,34 @@
|
||||
use super::{Errno, Error};
|
||||
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
/// Extending `Result` with extra functionalities.
|
||||
pub trait ResultExt<T> {
|
||||
fn cause_err<F>(self, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&Error) -> Error;
|
||||
|
||||
fn errno(&self) -> Option<Errno>;
|
||||
|
||||
fn has_errno(&self, errno: Errno) -> bool;
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
fn errno(&self) -> Option<Errno> {
|
||||
match self {
|
||||
Ok(_) => None,
|
||||
Err(e) => Some(e.errno()),
|
||||
}
|
||||
}
|
||||
|
||||
fn has_errno(&self, errno: Errno) -> bool {
|
||||
self.errno() == Some(errno)
|
||||
}
|
||||
}
|
138
src/libos/crates/errno/src/to_errno.rs
Normal file
138
src/libos/crates/errno/src/to_errno.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use core::fmt;
|
||||
|
||||
use super::{Errno, Error};
|
||||
|
||||
pub trait ToErrno: fmt::Display + fmt::Debug {
|
||||
fn errno(&self) -> Errno;
|
||||
}
|
||||
|
||||
impl<T> From<T> for Error
|
||||
where
|
||||
T: ToErrno + Send + 'static,
|
||||
{
|
||||
fn from(t: T) -> Error {
|
||||
Error::boxed(t, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for Errno {
|
||||
fn errno(&self) -> Errno {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for core::alloc::AllocError {
|
||||
fn errno(&self) -> Errno {
|
||||
Errno::ENOMEM
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for core::alloc::LayoutError {
|
||||
fn errno(&self) -> Errno {
|
||||
Errno::EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for core::num::ParseIntError {
|
||||
fn errno(&self) -> Errno {
|
||||
Errno::EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "sgx", test, doctest))]
|
||||
mod if_std {
|
||||
use super::*;
|
||||
|
||||
impl From<std::io::ErrorKind> for Errno {
|
||||
fn from(kind: std::io::ErrorKind) -> Errno {
|
||||
use std::io::ErrorKind::*;
|
||||
use Errno::*;
|
||||
match kind {
|
||||
NotFound => ENOENT,
|
||||
PermissionDenied => EPERM,
|
||||
ConnectionRefused => ECONNREFUSED,
|
||||
ConnectionReset => ECONNRESET,
|
||||
ConnectionAborted => ECONNABORTED,
|
||||
NotConnected => ENOTCONN,
|
||||
AddrInUse => EADDRINUSE,
|
||||
AddrNotAvailable => EADDRNOTAVAIL,
|
||||
BrokenPipe => EPIPE,
|
||||
AlreadyExists => EEXIST,
|
||||
WouldBlock => Errno::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 {
|
||||
Errno::EINVAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "occlum")]
|
||||
mod if_occlum {
|
||||
use rcore_fs::dev::DevError;
|
||||
use rcore_fs::vfs::FsError;
|
||||
|
||||
use super::*;
|
||||
|
||||
impl ToErrno for serde_json::Error {
|
||||
fn errno(&self) -> Errno {
|
||||
Errno::EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for FsError {
|
||||
fn errno(&self) -> Errno {
|
||||
use Errno::*;
|
||||
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(_err) => 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,
|
||||
FsError::NameTooLong => ENAMETOOLONG,
|
||||
FsError::FileTooBig => EFBIG,
|
||||
FsError::OpNotSupported => EOPNOTSUPP,
|
||||
FsError::NotMountPoint => EINVAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for DevError {
|
||||
fn from(e: Error) -> Self {
|
||||
DevError(e.errno() as i32)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +1,3 @@
|
||||
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::embedded(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 < 0 {
|
||||
let errno = unsafe { libc::errno() };
|
||||
return_errno!(Errno::from(errno as u32), "libc error");
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
|
||||
// return Err(errno) if libc return -1
|
||||
// raise SIGPIPE if errno == EPIPE
|
||||
macro_rules! try_libc_may_epipe {
|
||||
($ret: expr) => {{
|
||||
let ret = unsafe { $ret };
|
||||
if ret < 0 {
|
||||
let errno = unsafe { libc::errno() };
|
||||
if errno == Errno::EPIPE as i32 {
|
||||
crate::signal::do_tkill(current!().tid(), crate::signal::SIGPIPE.as_u8() as i32);
|
||||
}
|
||||
return_errno!(Errno::from(errno as u32), "libc error");
|
||||
}
|
||||
ret
|
||||
}};
|
||||
}
|
||||
pub use errno::{Errno::*, *};
|
||||
|
@ -1,116 +0,0 @@
|
||||
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(err) => 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,
|
||||
FsError::NameTooLong => ENAMETOOLONG,
|
||||
FsError::FileTooBig => EFBIG,
|
||||
FsError::OpNotSupported => EOPNOTSUPP,
|
||||
FsError::NotMountPoint => EINVAL,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for std::alloc::AllocError {
|
||||
fn errno(&self) -> Errno {
|
||||
ENOMEM
|
||||
}
|
||||
}
|
||||
|
||||
impl ToErrno for std::alloc::LayoutError {
|
||||
fn errno(&self) -> Errno {
|
||||
EINVAL
|
||||
}
|
||||
}
|
@ -321,10 +321,3 @@ impl File for LockedFile {
|
||||
Ok(SefsMac(file.get_mac().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for DevError {
|
||||
fn from(e: Error) -> Self {
|
||||
error!("SGX protected file I/O error: {}", e.backtrace());
|
||||
DevError(e.errno() as i32)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user