use std::result; use std::error; use std::fmt; use std::str; use std::ffi::CStr; use libc; pub type Result = result::Result; #[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 for Error { fn from(kind: ErrorKind) -> Error { Error { repr: Repr::Simple(kind) } } } enum Repr { Errno(i32), Simple(ErrorKind), General(Box), } #[derive(Debug)] struct General { kind: ErrorKind, error: Box, } #[derive(Debug)] pub struct Error { repr: Repr, } impl Error { pub fn new(kind: ErrorKind, error: E) -> Error where E: Into> { Self::_new(kind, error.into()) } fn _new(kind: ErrorKind, error: Box) -> 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(), } } }