use core::num::TryFromIntError;
use core::str::Utf8Error;
use std::io;
use std::path::PathBuf;
use selinux_sys::pid_t;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("path is invalid: '{}'", .0.display())]
PathIsInvalid(PathBuf),
#[error("input security contexts have different formats")]
SecurityContextFormatMismatch,
#[error("security context has an expected format")]
UnexpectedSecurityContextFormat,
#[error("{operation} failed due to poisoned lock")]
LockPoisoned {
operation: &'static str,
},
#[error("{operation} failed")]
IO {
source: io::Error,
operation: &'static str,
},
#[error("{operation} failed on process with ID '{process_id}'")]
IO1Process {
source: io::Error,
operation: &'static str,
process_id: pid_t,
},
#[error("{operation} failed with '{name}'")]
IO1Name {
source: io::Error,
operation: &'static str,
name: String,
},
#[error("{operation} failed on path '{path}'")]
IO1Path {
source: io::Error,
operation: &'static str,
path: PathBuf,
},
#[error(transparent)]
NotUTF8(#[from] Utf8Error),
#[error(transparent)]
IntegerOutOfRange(#[from] TryFromIntError),
}
impl Error {
pub(crate) fn from_io(operation: &'static str, source: io::Error) -> Self {
Error::IO { source, operation }
}
pub(crate) fn last_io_error(operation: &'static str) -> Self {
Error::IO {
source: io::Error::last_os_error(),
operation,
}
}
pub(crate) fn from_io_pid(
operation: &'static str,
process_id: pid_t,
source: io::Error,
) -> Self {
Error::IO1Process {
source,
operation,
process_id,
}
}
pub(crate) fn from_io_path(
operation: &'static str,
path: impl Into<PathBuf>,
source: io::Error,
) -> Self {
Error::IO1Path {
source,
operation,
path: path.into(),
}
}
pub(crate) fn from_io_name(
operation: &'static str,
name: impl Into<String>,
source: io::Error,
) -> Self {
Error::IO1Name {
source,
operation,
name: name.into(),
}
}
pub(crate) fn clear_errno() {
errno::set_errno(errno::Errno(0));
}
#[cfg_attr(not(test), expect(dead_code, reason = "used by unit tests"))]
pub(crate) fn io_source(&self) -> Option<&io::Error> {
match self {
Self::IO { source, .. }
| Self::IO1Process { source, .. }
| Self::IO1Name { source, .. }
| Self::IO1Path { source, .. } => Some(source),
Self::PathIsInvalid(_)
| Self::SecurityContextFormatMismatch
| Self::UnexpectedSecurityContextFormat
| Self::LockPoisoned { .. }
| Self::NotUTF8(_)
| Self::IntegerOutOfRange(_) => None,
}
}
}