blob: 1ed53e74001ad588ea9a81462788825bc7e3b5c0 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![allow(dead_code)]
use crate::types::uapi;
pub struct Errno {
value: u32,
anyhow: Option<anyhow::Error>,
}
impl Errno {
pub fn new(value: u32, name: &'static str, context: Option<String>) -> Errno {
Errno {
value,
anyhow: Some(anyhow::format_err!(
"{} ({}), context: {}",
name,
value,
context.as_ref().unwrap_or(&"None".to_string())
)),
}
}
pub fn value(&self) -> u32 {
self.value
}
pub fn return_value(&self) -> u64 {
-(self.value as i32) as u64
}
}
impl PartialEq for Errno {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl Eq for Errno {}
impl From<Errno> for anyhow::Error {
fn from(e: Errno) -> anyhow::Error {
let value = e.value;
e.anyhow.unwrap_or_else(|| anyhow::format_err!("errno {} from unknown location", value))
}
}
impl std::fmt::Debug for Errno {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
if let Some(err) = self.anyhow.as_ref() {
std::fmt::Debug::fmt(&err, f)
} else {
write!(f, "error {} from unknown location", self.value)
}
}
}
pub const EPERM: Errno = Errno { value: uapi::EPERM, anyhow: None };
pub const ENOENT: Errno = Errno { value: uapi::ENOENT, anyhow: None };
pub const ESRCH: Errno = Errno { value: uapi::ESRCH, anyhow: None };
pub const EINTR: Errno = Errno { value: uapi::EINTR, anyhow: None };
pub const EIO: Errno = Errno { value: uapi::EIO, anyhow: None };
pub const ENXIO: Errno = Errno { value: uapi::ENXIO, anyhow: None };
pub const E2BIG: Errno = Errno { value: uapi::E2BIG, anyhow: None };
pub const ENOEXEC: Errno = Errno { value: uapi::ENOEXEC, anyhow: None };
pub const EBADF: Errno = Errno { value: uapi::EBADF, anyhow: None };
pub const ECHILD: Errno = Errno { value: uapi::ECHILD, anyhow: None };
pub const EAGAIN: Errno = Errno { value: uapi::EAGAIN, anyhow: None };
pub const ENOMEM: Errno = Errno { value: uapi::ENOMEM, anyhow: None };
pub const EACCES: Errno = Errno { value: uapi::EACCES, anyhow: None };
pub const EFAULT: Errno = Errno { value: uapi::EFAULT, anyhow: None };
pub const ENOTBLK: Errno = Errno { value: uapi::ENOTBLK, anyhow: None };
pub const EBUSY: Errno = Errno { value: uapi::EBUSY, anyhow: None };
pub const EEXIST: Errno = Errno { value: uapi::EEXIST, anyhow: None };
pub const EXDEV: Errno = Errno { value: uapi::EXDEV, anyhow: None };
pub const ENODEV: Errno = Errno { value: uapi::ENODEV, anyhow: None };
pub const ENOTDIR: Errno = Errno { value: uapi::ENOTDIR, anyhow: None };
pub const EISDIR: Errno = Errno { value: uapi::EISDIR, anyhow: None };
pub const EINVAL: Errno = Errno { value: uapi::EINVAL, anyhow: None };
pub const ENFILE: Errno = Errno { value: uapi::ENFILE, anyhow: None };
pub const EMFILE: Errno = Errno { value: uapi::EMFILE, anyhow: None };
pub const ENOTTY: Errno = Errno { value: uapi::ENOTTY, anyhow: None };
pub const ETXTBSY: Errno = Errno { value: uapi::ETXTBSY, anyhow: None };
pub const EFBIG: Errno = Errno { value: uapi::EFBIG, anyhow: None };
pub const ENOSPC: Errno = Errno { value: uapi::ENOSPC, anyhow: None };
pub const ESPIPE: Errno = Errno { value: uapi::ESPIPE, anyhow: None };
pub const EROFS: Errno = Errno { value: uapi::EROFS, anyhow: None };
pub const EMLINK: Errno = Errno { value: uapi::EMLINK, anyhow: None };
pub const EPIPE: Errno = Errno { value: uapi::EPIPE, anyhow: None };
pub const EDOM: Errno = Errno { value: uapi::EDOM, anyhow: None };
pub const ERANGE: Errno = Errno { value: uapi::ERANGE, anyhow: None };
pub const EDEADLK: Errno = Errno { value: uapi::EDEADLK, anyhow: None };
pub const ENAMETOOLONG: Errno = Errno { value: uapi::ENAMETOOLONG, anyhow: None };
pub const ENOLCK: Errno = Errno { value: uapi::ENOLCK, anyhow: None };
pub const ENOSYS: Errno = Errno { value: uapi::ENOSYS, anyhow: None };
pub const ENOTEMPTY: Errno = Errno { value: uapi::ENOTEMPTY, anyhow: None };
pub const ELOOP: Errno = Errno { value: uapi::ELOOP, anyhow: None };
pub const EWOULDBLOCK: Errno = Errno { value: uapi::EWOULDBLOCK, anyhow: None };
pub const ENOMSG: Errno = Errno { value: uapi::ENOMSG, anyhow: None };
pub const EIDRM: Errno = Errno { value: uapi::EIDRM, anyhow: None };
pub const ECHRNG: Errno = Errno { value: uapi::ECHRNG, anyhow: None };
pub const EL2NSYNC: Errno = Errno { value: uapi::EL2NSYNC, anyhow: None };
pub const EL3HLT: Errno = Errno { value: uapi::EL3HLT, anyhow: None };
pub const EL3RST: Errno = Errno { value: uapi::EL3RST, anyhow: None };
pub const ELNRNG: Errno = Errno { value: uapi::ELNRNG, anyhow: None };
pub const EUNATCH: Errno = Errno { value: uapi::EUNATCH, anyhow: None };
pub const ENOCSI: Errno = Errno { value: uapi::ENOCSI, anyhow: None };
pub const EL2HLT: Errno = Errno { value: uapi::EL2HLT, anyhow: None };
pub const EBADE: Errno = Errno { value: uapi::EBADE, anyhow: None };
pub const EBADR: Errno = Errno { value: uapi::EBADR, anyhow: None };
pub const EXFULL: Errno = Errno { value: uapi::EXFULL, anyhow: None };
pub const ENOANO: Errno = Errno { value: uapi::ENOANO, anyhow: None };
pub const EBADRQC: Errno = Errno { value: uapi::EBADRQC, anyhow: None };
pub const EBADSLT: Errno = Errno { value: uapi::EBADSLT, anyhow: None };
pub const EDEADLOCK: Errno = Errno { value: uapi::EDEADLOCK, anyhow: None };
pub const EBFONT: Errno = Errno { value: uapi::EBFONT, anyhow: None };
pub const ENOSTR: Errno = Errno { value: uapi::ENOSTR, anyhow: None };
pub const ENODATA: Errno = Errno { value: uapi::ENODATA, anyhow: None };
pub const ETIME: Errno = Errno { value: uapi::ETIME, anyhow: None };
pub const ENOSR: Errno = Errno { value: uapi::ENOSR, anyhow: None };
pub const ENONET: Errno = Errno { value: uapi::ENONET, anyhow: None };
pub const ENOPKG: Errno = Errno { value: uapi::ENOPKG, anyhow: None };
pub const EREMOTE: Errno = Errno { value: uapi::EREMOTE, anyhow: None };
pub const ENOLINK: Errno = Errno { value: uapi::ENOLINK, anyhow: None };
pub const EADV: Errno = Errno { value: uapi::EADV, anyhow: None };
pub const ESRMNT: Errno = Errno { value: uapi::ESRMNT, anyhow: None };
pub const ECOMM: Errno = Errno { value: uapi::ECOMM, anyhow: None };
pub const EPROTO: Errno = Errno { value: uapi::EPROTO, anyhow: None };
pub const EMULTIHOP: Errno = Errno { value: uapi::EMULTIHOP, anyhow: None };
pub const EDOTDOT: Errno = Errno { value: uapi::EDOTDOT, anyhow: None };
pub const EBADMSG: Errno = Errno { value: uapi::EBADMSG, anyhow: None };
pub const EOVERFLOW: Errno = Errno { value: uapi::EOVERFLOW, anyhow: None };
pub const ENOTUNIQ: Errno = Errno { value: uapi::ENOTUNIQ, anyhow: None };
pub const EBADFD: Errno = Errno { value: uapi::EBADFD, anyhow: None };
pub const EREMCHG: Errno = Errno { value: uapi::EREMCHG, anyhow: None };
pub const ELIBACC: Errno = Errno { value: uapi::ELIBACC, anyhow: None };
pub const ELIBBAD: Errno = Errno { value: uapi::ELIBBAD, anyhow: None };
pub const ELIBSCN: Errno = Errno { value: uapi::ELIBSCN, anyhow: None };
pub const ELIBMAX: Errno = Errno { value: uapi::ELIBMAX, anyhow: None };
pub const ELIBEXEC: Errno = Errno { value: uapi::ELIBEXEC, anyhow: None };
pub const EILSEQ: Errno = Errno { value: uapi::EILSEQ, anyhow: None };
pub const ERESTART: Errno = Errno { value: uapi::ERESTART, anyhow: None };
pub const ESTRPIPE: Errno = Errno { value: uapi::ESTRPIPE, anyhow: None };
pub const EUSERS: Errno = Errno { value: uapi::EUSERS, anyhow: None };
pub const ENOTSOCK: Errno = Errno { value: uapi::ENOTSOCK, anyhow: None };
pub const EDESTADDRREQ: Errno = Errno { value: uapi::EDESTADDRREQ, anyhow: None };
pub const EMSGSIZE: Errno = Errno { value: uapi::EMSGSIZE, anyhow: None };
pub const EPROTOTYPE: Errno = Errno { value: uapi::EPROTOTYPE, anyhow: None };
pub const ENOPROTOOPT: Errno = Errno { value: uapi::ENOPROTOOPT, anyhow: None };
pub const EPROTONOSUPPORT: Errno = Errno { value: uapi::EPROTONOSUPPORT, anyhow: None };
pub const ESOCKTNOSUPPORT: Errno = Errno { value: uapi::ESOCKTNOSUPPORT, anyhow: None };
pub const EOPNOTSUPP: Errno = Errno { value: uapi::EOPNOTSUPP, anyhow: None };
pub const EPFNOSUPPORT: Errno = Errno { value: uapi::EPFNOSUPPORT, anyhow: None };
pub const EAFNOSUPPORT: Errno = Errno { value: uapi::EAFNOSUPPORT, anyhow: None };
pub const EADDRINUSE: Errno = Errno { value: uapi::EADDRINUSE, anyhow: None };
pub const EADDRNOTAVAIL: Errno = Errno { value: uapi::EADDRNOTAVAIL, anyhow: None };
pub const ENETDOWN: Errno = Errno { value: uapi::ENETDOWN, anyhow: None };
pub const ENETUNREACH: Errno = Errno { value: uapi::ENETUNREACH, anyhow: None };
pub const ENETRESET: Errno = Errno { value: uapi::ENETRESET, anyhow: None };
pub const ECONNABORTED: Errno = Errno { value: uapi::ECONNABORTED, anyhow: None };
pub const ECONNRESET: Errno = Errno { value: uapi::ECONNRESET, anyhow: None };
pub const ENOBUFS: Errno = Errno { value: uapi::ENOBUFS, anyhow: None };
pub const EISCONN: Errno = Errno { value: uapi::EISCONN, anyhow: None };
pub const ENOTCONN: Errno = Errno { value: uapi::ENOTCONN, anyhow: None };
pub const ESHUTDOWN: Errno = Errno { value: uapi::ESHUTDOWN, anyhow: None };
pub const ETOOMANYREFS: Errno = Errno { value: uapi::ETOOMANYREFS, anyhow: None };
pub const ETIMEDOUT: Errno = Errno { value: uapi::ETIMEDOUT, anyhow: None };
pub const ECONNREFUSED: Errno = Errno { value: uapi::ECONNREFUSED, anyhow: None };
pub const EHOSTDOWN: Errno = Errno { value: uapi::EHOSTDOWN, anyhow: None };
pub const EHOSTUNREACH: Errno = Errno { value: uapi::EHOSTUNREACH, anyhow: None };
pub const EALREADY: Errno = Errno { value: uapi::EALREADY, anyhow: None };
pub const EINPROGRESS: Errno = Errno { value: uapi::EINPROGRESS, anyhow: None };
pub const ESTALE: Errno = Errno { value: uapi::ESTALE, anyhow: None };
pub const EUCLEAN: Errno = Errno { value: uapi::EUCLEAN, anyhow: None };
pub const ENOTNAM: Errno = Errno { value: uapi::ENOTNAM, anyhow: None };
pub const ENAVAIL: Errno = Errno { value: uapi::ENAVAIL, anyhow: None };
pub const EISNAM: Errno = Errno { value: uapi::EISNAM, anyhow: None };
pub const EREMOTEIO: Errno = Errno { value: uapi::EREMOTEIO, anyhow: None };
pub const EDQUOT: Errno = Errno { value: uapi::EDQUOT, anyhow: None };
pub const ENOMEDIUM: Errno = Errno { value: uapi::ENOMEDIUM, anyhow: None };
pub const EMEDIUMTYPE: Errno = Errno { value: uapi::EMEDIUMTYPE, anyhow: None };
pub const ECANCELED: Errno = Errno { value: uapi::ECANCELED, anyhow: None };
pub const ENOKEY: Errno = Errno { value: uapi::ENOKEY, anyhow: None };
pub const EKEYEXPIRED: Errno = Errno { value: uapi::EKEYEXPIRED, anyhow: None };
pub const EKEYREVOKED: Errno = Errno { value: uapi::EKEYREVOKED, anyhow: None };
pub const EKEYREJECTED: Errno = Errno { value: uapi::EKEYREJECTED, anyhow: None };
pub const EOWNERDEAD: Errno = Errno { value: uapi::EOWNERDEAD, anyhow: None };
pub const ENOTRECOVERABLE: Errno = Errno { value: uapi::ENOTRECOVERABLE, anyhow: None };
pub const ERFKILL: Errno = Errno { value: uapi::ERFKILL, anyhow: None };
pub const EHWPOISON: Errno = Errno { value: uapi::EHWPOISON, anyhow: None };
// ENOTSUP is a different error in posix, but has the same value as EOPNOTSUPP in linux.
pub const ENOTSUP: Errno = EOPNOTSUPP;
/// A special error that represents an interrupted syscall that should be restarted if possible.
// This is not defined in uapi as it is never exposed to userspace.
pub const ERESTARTSYS: Errno = Errno { value: 512, anyhow: None };
/// `errno` returns an `Errno` struct tagged with the current file name and line number.
///
/// Use `error!` instead if you want the `Errno` to be wrapped in an `Err`.
macro_rules! errno {
($err:ident) => {
Errno::new(crate::types::errno::$err.value(), stringify!($err), None)
};
($err:ident, $context:expr) => {
Errno::new(crate::types::errno::$err.value(), stringify!($err), Some($context.to_string()))
};
}
/// `error` returns a `Err` containing an `Errno` struct tagged with the current file name and line
/// number.
///
/// Use `errno!` instead if you want an unwrapped, but still tagged, `Errno`.
macro_rules! error {
($($args:tt)*) => { Err(errno!($($args)*)) };
}
// There isn't really a mapping from zx::Status to Errno. The correct mapping is context-speific
// but this converter is a reasonable first-approximation. The translation matches
// fdio_status_to_errno. See fxbug.dev/30921 for more context.
// TODO: Replace clients with more context-specific mappings.
macro_rules! from_status_like_fdio {
($status:ident) => {{
from_status_like_fdio!($status, "")
}};
($status:ident, $context:expr) => {{
match $status {
zx::Status::NOT_FOUND => errno!(ENOENT, $context),
zx::Status::NO_MEMORY => errno!(ENOMEM, $context),
zx::Status::INVALID_ARGS => errno!(EINVAL, $context),
zx::Status::BUFFER_TOO_SMALL => errno!(EINVAL, $context),
zx::Status::TIMED_OUT => errno!(ETIMEDOUT, $context),
zx::Status::UNAVAILABLE => errno!(EBUSY, $context),
zx::Status::ALREADY_EXISTS => errno!(EEXIST, $context),
zx::Status::PEER_CLOSED => errno!(EPIPE, $context),
zx::Status::BAD_STATE => errno!(EPIPE, $context),
zx::Status::BAD_PATH => errno!(ENAMETOOLONG, $context),
zx::Status::IO => errno!(EIO, $context),
zx::Status::NOT_FILE => errno!(EISDIR, $context),
zx::Status::NOT_DIR => errno!(ENOTDIR, $context),
zx::Status::NOT_SUPPORTED => errno!(EOPNOTSUPP, $context),
zx::Status::WRONG_TYPE => errno!(EOPNOTSUPP, $context),
zx::Status::OUT_OF_RANGE => errno!(EINVAL, $context),
zx::Status::NO_RESOURCES => errno!(ENOMEM, $context),
zx::Status::BAD_HANDLE => errno!(EBADF, $context),
zx::Status::ACCESS_DENIED => errno!(EACCES, $context),
zx::Status::SHOULD_WAIT => errno!(EAGAIN, $context),
zx::Status::FILE_BIG => errno!(EFBIG, $context),
zx::Status::NO_SPACE => errno!(ENOSPC, $context),
zx::Status::NOT_EMPTY => errno!(ENOTEMPTY, $context),
zx::Status::IO_REFUSED => errno!(ECONNREFUSED, $context),
zx::Status::IO_INVALID => errno!(EIO, $context),
zx::Status::CANCELED => errno!(EBADF, $context),
zx::Status::PROTOCOL_NOT_SUPPORTED => errno!(EPROTONOSUPPORT, $context),
zx::Status::ADDRESS_UNREACHABLE => errno!(ENETUNREACH, $context),
zx::Status::ADDRESS_IN_USE => errno!(EADDRINUSE, $context),
zx::Status::NOT_CONNECTED => errno!(ENOTCONN, $context),
zx::Status::CONNECTION_REFUSED => errno!(ECONNREFUSED, $context),
zx::Status::CONNECTION_RESET => errno!(ECONNRESET, $context),
zx::Status::CONNECTION_ABORTED => errno!(ECONNABORTED, $context),
_ => errno!(EIO, $context),
}
}};
}
// Public re-export of macros allows them to be used like regular rust items.
pub(crate) use errno;
pub(crate) use error;
pub(crate) use from_status_like_fdio;
/// An extension trait for `Result<T, Errno>`.
pub trait ErrnoResultExt<T> {
/// Maps `Err(EINTR)` to `Err(ERESTARTSYS)`, which tells the kernel to restart the syscall if
/// the dispatched signal action that interrupted the syscall has the `SA_RESTART` flag.
fn restartable(self) -> Result<T, Errno>;
}
impl<T> ErrnoResultExt<T> for Result<T, Errno> {
fn restartable(self) -> Result<T, Errno> {
self.map_err(|err| if err == EINTR { errno!(ERESTARTSYS) } else { err })
}
}