Files
latchd/crates/latchd-core/src/error.rs

84 lines
2.3 KiB
Rust

use std::io;
use thiserror::Error;
/// The application-wide error type.
#[derive(Debug, Error)]
pub enum Error {
/// A command-line or configuration value was invalid.
#[error("configuration: {0}")]
Config(String),
/// A filesystem operation failed.
#[error("{context}: {source}")]
Io {
/// The operation being performed.
context: String,
/// The underlying error.
#[source]
source: io::Error,
},
/// TOML could not be decoded.
#[error("parse {path}: {source}")]
Toml {
/// The file being parsed.
path: String,
/// The parser error.
#[source]
source: toml::de::Error,
},
/// PAM rejected or could not complete an operation.
#[error("PAM {operation} failed with status {status}: {message}")]
Pam {
/// The PAM operation.
operation: &'static str,
/// The numeric PAM status.
status: i32,
/// The human-readable PAM message.
message: String,
},
/// A session process failed.
#[error("session: {0}")]
Session(String),
/// The terminal could not be initialized or restored.
#[error("terminal: {0}")]
Terminal(String),
/// An authentication worker request was cancelled or disconnected.
#[error("authentication worker: {0}")]
Worker(String),
}
impl Error {
/// Returns a PAM status when this error came directly from PAM.
pub fn pam_status(&self) -> Option<i32> {
match self {
Self::Pam { status, .. } => Some(*status),
_ => None,
}
}
/// Returns whether PAM requires a password change before login can finish.
pub fn requires_password_change(&self) -> bool {
matches!(self.pam_status(), Some(12 | 27))
}
}
/// Adds a stable operation label to an I/O error.
pub fn io_error(context: impl Into<String>, source: io::Error) -> Error {
Error::Io {
context: context.into(),
source,
}
}
/// Converts a failed result into an application error with context.
pub trait ResultExt<T> {
/// Adds context to an I/O operation.
fn io_context(self, context: impl Into<String>) -> Result<T, Error>;
}
impl<T> ResultExt<T> for io::Result<T> {
fn io_context(self, context: impl Into<String>) -> Result<T, Error> {
self.map_err(|source| io_error(context, source))
}
}