[crates] Seperate error module into errno crate
This commit is contained in:
		
							parent
							
								
									f9b53dc410
								
							
						
					
					
						commit
						9404da7cf8
					
				| @ -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