3d8ee62087
Change-Id: Iab7e00cc26a4f9727d3ab98691ef379921a33052 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5240 Tested-by: BuildkiteCI Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: grfn <grfn@gws.fyi> Reviewed-by: tazjin <tazjin@tvl.su>
122 lines
5 KiB
Rust
122 lines
5 KiB
Rust
use nix;
|
|
use std::{error, fmt, io, num};
|
|
|
|
/// This module implements a simple error type to match the errors that can be thrown from the C
|
|
/// functions as well as some extra errors resulting from internal validations.
|
|
///
|
|
/// As this crate exposes an opinionated API to the POSIX queues certain errors have been
|
|
/// ignored:
|
|
///
|
|
/// * ETIMEDOUT: The low-level timed functions are not exported and this error can not occur.
|
|
/// * EAGAIN: Non-blocking queue calls are not supported.
|
|
/// * EINVAL: Same reason as ETIMEDOUT
|
|
/// * EMSGSIZE: The message size is immutable after queue creation and this crate checks it.
|
|
/// * ENAMETOOLONG: This crate performs name validation
|
|
///
|
|
/// If an unexpected error is encountered it will be wrapped appropriately and should be reported
|
|
/// as a bug on https://b.tvl.fyi
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
// These errors are raised inside of the library
|
|
InvalidQueueName(&'static str),
|
|
ValueReadingError(io::Error),
|
|
MessageSizeExceeded(),
|
|
MaximumMessageSizeExceeded(),
|
|
MaximumMessageCountExceeded(),
|
|
|
|
// These errors match what is described in the man pages (from mq_overview(7) onwards).
|
|
PermissionDenied(),
|
|
InvalidQueueDescriptor(),
|
|
QueueCallInterrupted(),
|
|
QueueAlreadyExists(),
|
|
QueueNotFound(),
|
|
InsufficientMemory(),
|
|
InsufficientSpace(),
|
|
|
|
// These two are (hopefully) unlikely in modern systems
|
|
ProcessFileDescriptorLimitReached(),
|
|
SystemFileDescriptorLimitReached(),
|
|
|
|
// If an unhandled / unknown / unexpected error occurs this error will be used.
|
|
// In those cases bug reports would be welcome!
|
|
UnknownForeignError(nix::errno::Errno),
|
|
|
|
// Some other unexpected / unknown error occured. This is probably an error from
|
|
// the nix crate. Bug reports also welcome for this!
|
|
UnknownInternalError(),
|
|
}
|
|
|
|
impl fmt::Display for Error {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
use Error::*;
|
|
f.write_str(match *self {
|
|
// This error contains more sensible description strings already
|
|
InvalidQueueName(e) => e,
|
|
ValueReadingError(_) => "error reading system configuration for message queues",
|
|
MessageSizeExceeded() => "message is larger than maximum size for specified queue",
|
|
MaximumMessageSizeExceeded() => "specified queue message size exceeds system maximum",
|
|
MaximumMessageCountExceeded() => "specified queue message count exceeds system maximum",
|
|
PermissionDenied() => "permission to the specified queue was denied",
|
|
InvalidQueueDescriptor() => "the internal queue descriptor was invalid",
|
|
QueueCallInterrupted() => "queue method interrupted by signal",
|
|
QueueAlreadyExists() => "the specified queue already exists",
|
|
QueueNotFound() => "the specified queue could not be found",
|
|
InsufficientMemory() => "insufficient memory to call queue method",
|
|
InsufficientSpace() => "insufficient space to call queue method",
|
|
ProcessFileDescriptorLimitReached() => {
|
|
"maximum number of process file descriptors reached"
|
|
}
|
|
SystemFileDescriptorLimitReached() => {
|
|
"maximum number of system file descriptors reached"
|
|
}
|
|
UnknownForeignError(_) => "unknown foreign error occured: please report a bug!",
|
|
UnknownInternalError() => "unknown internal error occured: please report a bug!",
|
|
})
|
|
}
|
|
}
|
|
|
|
impl error::Error for Error {
|
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
|
match self {
|
|
Error::ValueReadingError(e) => Some(e),
|
|
Error::UnknownForeignError(e) => Some(e),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This from implementation is used to translate errors from the lower-level
|
|
/// C-calls into sensible Rust errors.
|
|
impl From<nix::errno::Errno> for Error {
|
|
fn from(err: nix::Error) -> Self {
|
|
use nix::errno::Errno::*;
|
|
match err {
|
|
EACCES => Error::PermissionDenied(),
|
|
EBADF => Error::InvalidQueueDescriptor(),
|
|
EINTR => Error::QueueCallInterrupted(),
|
|
EEXIST => Error::QueueAlreadyExists(),
|
|
EMFILE => Error::ProcessFileDescriptorLimitReached(),
|
|
ENFILE => Error::SystemFileDescriptorLimitReached(),
|
|
ENOENT => Error::QueueNotFound(),
|
|
ENOMEM => Error::InsufficientMemory(),
|
|
ENOSPC => Error::InsufficientSpace(),
|
|
_ => Error::UnknownForeignError(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
// This implementation is used when reading system queue settings.
|
|
impl From<io::Error> for Error {
|
|
fn from(e: io::Error) -> Self {
|
|
Error::ValueReadingError(e)
|
|
}
|
|
}
|
|
|
|
// This implementation is used when parsing system queue settings. The unknown error is returned
|
|
// here because the system is probably seriously broken if those files don't contain numbers.
|
|
impl From<num::ParseIntError> for Error {
|
|
fn from(_: num::ParseIntError) -> Self {
|
|
Error::UnknownInternalError()
|
|
}
|
|
}
|