Skip to main content

coreshift_core/
error.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/
4
5//! Shared low-level error types.
6//!
7//! [`CoreError`] is the crate-wide error for Linux and Android primitive
8//! operations. It intentionally stays small: low-level modules surface the
9//! syscall that failed and the raw OS error code, while callers decide how
10//! much policy or recovery to layer on top.
11
12use std::fmt;
13
14/// Error type for low-level system operations.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum CoreError {
17    /// A syscall or libc-style operation failed with the specified OS error.
18    Syscall {
19        /// The raw OS error code.
20        code: i32,
21        /// The name of the failed operation.
22        op: &'static str,
23    },
24    /// An NDK binder operation failed with the specified status code.
25    Binder {
26        /// The NDK binder status code (`binder_status_t`).
27        code: i32,
28        /// The name of the failed operation.
29        op: &'static str,
30    },
31}
32
33impl CoreError {
34    /// Construct a new syscall error.
35    pub fn sys(code: i32, op: &'static str) -> Self {
36        Self::Syscall { code, op }
37    }
38
39    /// Construct a new binder error.
40    pub fn binder(code: i32, op: &'static str) -> Self {
41        Self::Binder { code, op }
42    }
43
44    /// Return the raw OS error code if applicable.
45    pub fn raw_os_error(&self) -> Option<i32> {
46        match self {
47            Self::Syscall { code, .. } => Some(*code),
48            Self::Binder { .. } => None,
49        }
50    }
51
52    /// Convert this low-level error into a standard I/O error.
53    pub fn to_io_error(&self) -> std::io::Error {
54        std::io::Error::from_raw_os_error(self.raw_os_error().unwrap_or(libc::EIO))
55    }
56}
57
58impl fmt::Display for CoreError {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        match self {
61            Self::Syscall { code, op } => write!(f, "{op} failed (code={code})"),
62            Self::Binder { code, op } => write!(f, "binder {op} failed (status={code})"),
63        }
64    }
65}
66
67impl std::error::Error for CoreError {}
68
69#[inline(always)]
70pub(crate) fn syscall_ret(ret: i32, op: &'static str) -> Result<(), CoreError> {
71    if ret == -1 {
72        let code = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
73        Err(CoreError::sys(code, op))
74    } else {
75        Ok(())
76    }
77}
78
79#[inline(always)]
80pub(crate) fn posix_ret(ret: i32, op: &'static str) -> Result<(), CoreError> {
81    if ret != 0 {
82        Err(CoreError::sys(ret, op))
83    } else {
84        Ok(())
85    }
86}