//! 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 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 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), } } }