pH/src/vm/error.rs
2017-10-16 02:36:00 +00:00

171 lines
4.8 KiB
Rust

use std::result;
use std::error;
use std::fmt;
use std::str;
use std::ffi::CStr;
use libc;
pub type Result<T> = result::Result<T, Error>;
#[derive(Debug)]
pub enum ErrorKind {
InvalidAddress(u64),
InvalidMappingOffset(usize),
RegisterMemoryFailed,
ReadKernelFailed,
Interrupted,
InvalidVring,
IoctlFailed(&'static str),
MissingRequiredExtension(u32),
OpenDeviceFailed,
CreateVmFailed,
BadVersion,
EventFdError,
}
impl ErrorKind {
fn as_str(&self) -> &'static str {
match *self {
ErrorKind::InvalidAddress(..) => "Invalid guest memory address",
ErrorKind::InvalidMappingOffset(..) => "Invalid memory mapping offset",
ErrorKind::RegisterMemoryFailed => "Failed to register memory region",
ErrorKind::ReadKernelFailed => "Failed to load kernel from disk",
ErrorKind::Interrupted => "System call interrupted",
ErrorKind::InvalidVring => "Invalid Vring",
ErrorKind::IoctlFailed(..) => "Ioctl failed",
ErrorKind::MissingRequiredExtension(..) => "kernel does not support requred kvm extension",
ErrorKind::OpenDeviceFailed => "could not open /dev/kvm",
ErrorKind::CreateVmFailed => "call to create vm failed",
ErrorKind::BadVersion => "unexpected kvm api version",
ErrorKind::EventFdError => "eventfd error",
}
}
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorKind::InvalidAddress(addr) => write!(f, "{}: 0x{:x}", self.as_str(), addr),
ErrorKind::InvalidMappingOffset(offset) => write!(f, "{}: 0x{:x}", self.as_str(), offset),
ErrorKind::IoctlFailed(name) => write!(f, "Ioctl {} failed", name),
_ => write!(f, "{}", self.as_str()),
}
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error { repr: Repr::Simple(kind) }
}
}
enum Repr {
Errno(i32),
Simple(ErrorKind),
General(Box<General>),
}
#[derive(Debug)]
struct General {
kind: ErrorKind,
error: Box<error::Error+Send+Sync>,
}
#[derive(Debug)]
pub struct Error {
repr: Repr,
}
impl Error {
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where E: Into<Box<error::Error+Send+Sync>> {
Self::_new(kind, error.into())
}
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::General(Box::new(General{
kind, error
}))
}
}
pub fn from_last_errno() -> Error {
let errno = unsafe { *libc::__errno_location() };
Error::from_errno(errno)
}
pub fn from_errno(errno: i32) -> Error {
if errno == libc::EINTR {
Error { repr: Repr::Simple(ErrorKind::Interrupted) }
} else {
Error { repr: Repr::Errno(errno) }
}
}
pub fn is_interrupted(&self) -> bool {
match self.repr {
Repr::Simple(ErrorKind::Interrupted) => true,
_ => false,
}
}
}
fn error_string(errno: i32) -> String {
let mut buf = [0 as libc::c_char; 256];
let p = buf.as_mut_ptr();
unsafe {
if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 {
panic!("strerror_r failed in error_string");
}
let p = p as *const _;
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
}
}
impl fmt::Debug for Repr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Repr::Errno(ref errno) =>
f.debug_struct("Errno").field("errno", errno)
.field("message", &error_string(*errno)).finish(),
Repr::General(ref c) => f.debug_tuple("General").field(c).finish(),
Repr::Simple(ref kind) => f.debug_tuple("Kind").field(kind).finish(),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.repr {
Repr::Errno(errno) => {
let detail = error_string(errno);
write!(f, "{} (errno: {})", detail, errno)
}
Repr::General(ref c) => {
write!(f, "{}: {}", c.kind, c.error)
},
Repr::Simple(ref kind) => kind.fmt(f),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match self.repr {
Repr::Errno(..) => "Errno Error",
Repr::Simple(ref kind) => kind.as_str(),
Repr::General(ref c) => c.error.description(),
}
}
fn cause(&self) -> Option<&error::Error> {
match self.repr {
Repr::Errno(..) => None,
Repr::Simple(..) => None,
Repr::General(ref c) => c.error.cause(),
}
}
}