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()
 | 
						|
    }
 | 
						|
}
 |