Add proper exit codes mirroring sysexits from FreeBSD

pull/38/head v0.10.1
Chip Senkbeil 3 years ago
parent 86e4d7f2fc
commit e2fd3a9bae
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131

2
Cargo.lock generated

@ -179,7 +179,7 @@ dependencies = [
[[package]]
name = "distant"
version = "0.10.0"
version = "0.10.1"
dependencies = [
"bytes",
"derive_more",

@ -2,7 +2,7 @@
name = "distant"
description = "Operate on a remote computer through file and process manipulation"
categories = ["command-line-utilities"]
version = "0.10.0"
version = "0.10.1"
authors = ["Chip Senkbeil <chip@senkbeil.org>"]
edition = "2018"
homepage = "https://github.com/chipsenkbeil/distant"

@ -4,6 +4,7 @@ use crate::{
constants::{SESSION_FILE_PATH_STR, SESSION_SOCKET_PATH_STR, TIMEOUT_STR},
data::RequestData,
},
ExitCodeError,
};
use derive_more::{Display, Error, From, IsVariant};
use lazy_static::lazy_static;
@ -95,7 +96,7 @@ pub enum Subcommand {
impl Subcommand {
/// Runs the subcommand, returning the result
pub fn run(self, opt: CommonOpt) -> Result<(), Box<dyn std::error::Error>> {
pub fn run(self, opt: CommonOpt) -> Result<(), Box<dyn ExitCodeError>> {
match self {
Self::Action(cmd) => subcommand::action::run(cmd, opt)?,
Self::Launch(cmd) => subcommand::launch::run(cmd, opt)?,

@ -6,6 +6,7 @@ use crate::{
session::{Session, SessionFile},
utils,
},
ExitCode, ExitCodeError,
};
use derive_more::{Display, Error, From};
use log::*;
@ -22,6 +23,16 @@ pub enum Error {
MissingOperation,
}
impl ExitCodeError for Error {
fn to_exit_code(&self) -> ExitCode {
match self {
Self::IoError(x) => x.to_exit_code(),
Self::TransportError(x) => x.to_exit_code(),
Self::MissingOperation => ExitCode::Usage,
}
}
}
pub fn run(cmd: ActionSubcommand, opt: CommonOpt) -> Result<(), Error> {
let rt = tokio::runtime::Runtime::new()?;

@ -7,12 +7,11 @@ use crate::{
session::{Session, SessionFile},
utils,
},
ExitCode, ExitCodeError,
};
use derive_more::{Display, Error, From};
use fork::{daemon, Fork};
use hex::FromHexError;
use log::*;
use orion::errors::UnknownCryptoError;
use std::{marker::Unpin, path::Path, string::FromUtf8Error, sync::Arc};
use tokio::{
io::{self, AsyncRead, AsyncWrite},
@ -28,12 +27,21 @@ pub enum Error {
MissingSessionData,
ForkError(#[error(not(source))] i32),
BadKey(UnknownCryptoError),
HexError(FromHexError),
IoError(io::Error),
Utf8Error(FromUtf8Error),
}
impl ExitCodeError for Error {
fn to_exit_code(&self) -> ExitCode {
match self {
Self::MissingSessionData => ExitCode::NoInput,
Self::ForkError(_) => ExitCode::OsErr,
Self::IoError(x) => x.to_exit_code(),
Self::Utf8Error(_) => ExitCode::DataErr,
}
}
}
/// Represents state associated with a connection
#[derive(Default)]
struct ConnState {

@ -7,6 +7,7 @@ use crate::{
state::ServerState,
utils,
},
ExitCode, ExitCodeError,
};
use derive_more::{Display, Error, From};
use fork::{daemon, Fork};
@ -29,6 +30,16 @@ pub enum Error {
IoError(io::Error),
}
impl ExitCodeError for Error {
fn to_exit_code(&self) -> ExitCode {
match self {
Self::ConvertToIpAddrError(_) => ExitCode::NoHost,
Self::ForkError => ExitCode::OsErr,
Self::IoError(x) => x.to_exit_code(),
}
}
}
pub fn run(cmd: ListenSubcommand, opt: CommonOpt) -> Result<(), Error> {
if cmd.daemon {
// NOTE: We keep the stdin, stdout, stderr open so we can print out the pid with the parent

@ -3,13 +3,84 @@ mod core;
use log::error;
/// Represents an error that can be converted into an exit code
pub trait ExitCodeError: std::error::Error {
fn to_exit_code(&self) -> ExitCode;
fn to_i32(&self) -> i32 {
self.to_exit_code() as i32
}
}
impl ExitCodeError for std::io::Error {
fn to_exit_code(&self) -> ExitCode {
use std::io::ErrorKind;
match self.kind() {
ErrorKind::ConnectionAborted
| ErrorKind::ConnectionRefused
| ErrorKind::ConnectionReset
| ErrorKind::NotConnected => ExitCode::Unavailable,
ErrorKind::InvalidData => ExitCode::DataErr,
ErrorKind::TimedOut => ExitCode::TempFail,
_ => ExitCode::IoError,
}
}
}
impl ExitCodeError for core::net::TransportError {
fn to_exit_code(&self) -> ExitCode {
match self {
core::net::TransportError::IoError(x) => x.to_exit_code(),
_ => ExitCode::Protocol,
}
}
}
impl<T: ExitCodeError + 'static> From<T> for Box<dyn ExitCodeError> {
fn from(x: T) -> Self {
Box::new(x)
}
}
/// Exit codes following https://www.freebsd.org/cgi/man.cgi?query=sysexits&sektion=3
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum ExitCode {
/// EX_USAGE (64) - being used when arguments missing or bad arguments provided to CLI
Usage = 64,
/// EX_DATAERR (65) - being used when bad data received not in UTF-8 format or transport data
/// is bad
DataErr = 65,
/// EX_NOINPUT (66) - being used when not getting expected data from launch
NoInput = 66,
/// EX_NOHOST (68) - being used when failed to resolve a host
NoHost = 68,
/// EX_UNAVAILABLE (69) - being used when IO error encountered where connection is problem
Unavailable = 69,
/// EX_OSERR (71) - being used when fork failed
OsErr = 71,
/// EX_IOERR (74) - being used as catchall for IO errors
IoError = 74,
/// EX_TEMPFAIL (75) - being used when we get a timeout
TempFail = 75,
/// EX_PROTOCOL (76) - being used as catchall for transport errors
Protocol = 76,
}
/// Main entrypoint into the program
pub fn run() {
let opt = cli::opt::Opt::load();
init_logging(&opt.common);
if let Err(x) = opt.subcommand.run(opt.common) {
error!("{}", x);
std::process::exit(-1);
std::process::exit(x.to_i32());
}
}

Loading…
Cancel
Save