storefd/storefd-listen/src/error.rs

175 lines
6.8 KiB
Rust

//! Contains the error types used by the [`listen`](super) module.
#![allow(clippy::module_name_repetitions)]
use core::fmt::Display;
use core::num::ParseIntError;
use std::error::Error;
use std::ffi::OsString;
use rustix::io::Errno;
use super::{FD_NAMES_VAR, FD_NUMBER_VAR, PID_VAR};
/// Errors that might happens when receiving file descriptors using [`FileDescriptor::receive()`](super::FileDescriptor::receive())
#[derive(Debug)]
pub enum ReceiveError {
/// The environement variable `LISTEN_PID` didn't exists (probably meaning that no file descriptor was passed to us).
NoListenPID,
/// The environement variable `LISTEN_PID` (which should be a decimal number) isn't unicode.
NotUnicodeListenPID(OsString),
/// The environement variable `LISTEN_PID` couldn't be parsed as a [`u32`] (real [`pid_t`](libc::pid_t) due to [`std::process::id`])
ListenPIDParse(ParseIntError),
/// The environement variable `LISTEN_FDS` didn't exists (probably meaning that no file descriptor was passed to us)
NoListenFD,
/// The environement variable `LISTEN_FDS` (which should be a decimal number) isn't unicode.
NotUnicodeListenFD(OsString),
/// The environement variable `LISTEN_FDS` couldn't be parsed as a [`usize`].
ListenFDParse(ParseIntError),
/// Our PID isn't the one expected as per `LISTEN_PID`.
PidMismatch { expected: u32, found: u32 },
/// We couldn't get the file descriptors (see [`GetFdsError`])
GetFds(GetFdsError),
}
impl Display for ReceiveError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Couldn't receive file descriptors :")?;
match self {
ReceiveError::NoListenPID => write!(f, "The variable {PID_VAR} doesn't exists."),
ReceiveError::NotUnicodeListenPID(var) => write!(f, "The variable {PID_VAR} isn't unicode (this should never happen): it is {var:?}"),
ReceiveError::ListenPIDParse(error) => write!(f, "Couldn't parse {PID_VAR} as a `u32`: {error}"),
ReceiveError::NoListenFD => write!(f, "The variable {FD_NUMBER_VAR} doesn't exists."),
ReceiveError::NotUnicodeListenFD(var) => write!(f, "The variable {FD_NUMBER_VAR} isn't unicode (this should never happen): it is {var:?}"),
ReceiveError::ListenFDParse(error) => write!(f, "Couldn't parse {FD_NUMBER_VAR} as a `u32`: {error}"),
ReceiveError::PidMismatch{expected, found} => write!(f, "PID mismatch! Was {found} but should have been {expected}."),
ReceiveError::GetFds(error) => Display::fmt(error, f),
}
}
}
impl Error for ReceiveError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ReceiveError::NoListenPID
| ReceiveError::NotUnicodeListenPID(_)
| ReceiveError::NoListenFD
| ReceiveError::NotUnicodeListenFD(_)
| ReceiveError::PidMismatch {
expected: _,
found: _,
} => None,
ReceiveError::ListenPIDParse(error) | ReceiveError::ListenFDParse(error) => Some(error),
ReceiveError::GetFds(error) => Some(error),
}
}
}
/// Errors that might happens when receiving file descriptors along with their names using [`FileDescriptor::receive_with_names()`](super::FileDescriptor::receive_with_names()).
#[derive(Debug)]
pub enum ReceiveNameError {
/// The variable `LISTEN_FDNAMES` didn't exists.
NoListenFDName,
/// No file descriptors could be received.
Receive(ReceiveError),
}
impl From<ReceiveError> for ReceiveNameError {
fn from(value: ReceiveError) -> Self {
Self::Receive(value)
}
}
impl Display for ReceiveNameError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ReceiveNameError::NoListenFDName => write!(
f,
"Couldn't find FDs name : the variable {FD_NAMES_VAR} doesn't exists."
),
ReceiveNameError::Receive(error) => Display::fmt(error, f),
}
}
}
impl Error for ReceiveNameError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
ReceiveNameError::NoListenFDName => None,
ReceiveNameError::Receive(error) => Some(error),
}
}
}
/// Errors that might be obtained when producing the iterator in [`FileDescriptor::receive()`](super::FileDescriptor::receive())
#[derive(Debug)]
pub enum GetFdsError {
/// Too many file descriptors were passed so we overflowed when adding `SD_LISTEN_FDS_START` (3)
TooManyFDs(usize),
}
impl Display for GetFdsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GetFdsError::TooManyFDs(size) => write!(f, "Too many file descriptors ({size})"),
}
}
}
impl Error for GetFdsError {}
/// Errors when trying to duplicate the received file descriptors using [`rustix::fs::fcntl_dupfd_cloexec`].
#[derive(Debug)]
pub enum DupError {
/// The file descriptor we are attempting to duplicate isn't open.
InvalidFd(Errno),
/// Some other problem in the arguments passed to [`fcntl`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html).
InvalidArgument(Errno),
/// No file descriptor was available to us.
NoAvailableFd(Errno),
/// Some other error (see [`Errno`] and [`fcntl`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html) for details).
///
/// Please fill a bug if you see this variant so that we might add a more precise variant.
Other(Errno),
}
impl From<Errno> for DupError {
fn from(value: Errno) -> Self {
if value == Errno::INVAL {
Self::InvalidArgument(value)
} else if value == Errno::MFILE {
Self::NoAvailableFd(value)
} else if value == Errno::BADF {
Self::InvalidFd(value)
} else {
Self::Other(value)
}
}
}
impl Display for DupError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Couldn't duplicate FD : ")?;
match self {
DupError::InvalidFd(_) => {
f.write_str("The file descriptor isn't valid (probably closed in the meantime).")
}
DupError::InvalidArgument(_) => f.write_str("Invalid argument."),
DupError::NoAvailableFd(_) => {
f.write_str("Too many file descriptors are already open.")
}
DupError::Other(err) => Display::fmt(err, f),
}
}
}
impl Error for DupError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
DupError::InvalidArgument(error)
| DupError::InvalidFd(error)
| DupError::NoAvailableFd(error)
| DupError::Other(error) => Some(error),
}
}
}