1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

timeout: add ExitStatus enumeration

Add the `ExitStatus` enumeration in a new module `status.rs` to
contain all the magic numbers in the `timeout` utility.
This commit is contained in:
Jeffrey Finkelstein 2022-03-11 22:33:25 -05:00
parent bfd1e14137
commit 2d390233fe
2 changed files with 65 additions and 11 deletions

View file

@ -0,0 +1,51 @@
// * This file is part of the uutils coreutils package.
// *
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
//! Exit status codes produced by `timeout`.
use std::convert::From;
use uucore::error::UError;
/// Enumerates the exit statuses produced by `timeout`.
///
/// Use [`Into::into`] (or [`From::from`]) to convert an enumeration
/// member into a numeric status code. You can also convert into a
/// [`UError`].
///
/// # Examples
///
/// Convert into an [`i32`]:
///
/// ```rust,ignore
/// assert_eq!(i32::from(ExitStatus::CommandTimedOut), 124);
/// ```
pub(crate) enum ExitStatus {
/// When the child process times out and `--preserve-status` is not specified.
CommandTimedOut,
/// When `timeout` itself fails.
TimeoutFailed,
/// When a signal is sent to the child process or `timeout` itself.
SignalSent(usize),
/// When there is a failure while waiting for the child process to terminate.
WaitingFailed,
}
impl From<ExitStatus> for i32 {
fn from(exit_status: ExitStatus) -> Self {
match exit_status {
ExitStatus::CommandTimedOut => 124,
ExitStatus::TimeoutFailed => 125,
ExitStatus::SignalSent(s) => 128 + s as Self,
ExitStatus::WaitingFailed => 124,
}
}
}
impl From<ExitStatus> for Box<dyn UError> {
fn from(exit_status: ExitStatus) -> Self {
Box::from(i32::from(exit_status))
}
}

View file

@ -6,12 +6,14 @@
// * file that was distributed with this source code. // * file that was distributed with this source code.
// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld // spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld
mod status;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
extern crate clap; extern crate clap;
use crate::status::ExitStatus;
use clap::{crate_version, App, AppSettings, Arg}; use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::process::{Child, Command, Stdio}; use std::process::{Child, Command, Stdio};
@ -25,8 +27,6 @@ use uucore::{format_usage, InvalidEncodingHandling};
static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION."; static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";
const USAGE: &str = "{} [OPTION] DURATION COMMAND..."; const USAGE: &str = "{} [OPTION] DURATION COMMAND...";
const ERR_EXIT_STATUS: i32 = 125;
pub mod options { pub mod options {
pub static FOREGROUND: &str = "foreground"; pub static FOREGROUND: &str = "foreground";
pub static KILL_AFTER: &str = "kill-after"; pub static KILL_AFTER: &str = "kill-after";
@ -217,7 +217,7 @@ fn wait_or_kill_process(
if preserve_status { if preserve_status {
Ok(status.code().unwrap_or_else(|| status.signal().unwrap())) Ok(status.code().unwrap_or_else(|| status.signal().unwrap()))
} else { } else {
Ok(124) Ok(ExitStatus::TimeoutFailed.into())
} }
} }
Ok(None) => { Ok(None) => {
@ -225,9 +225,9 @@ fn wait_or_kill_process(
report_if_verbose(signal, cmd, verbose); report_if_verbose(signal, cmd, verbose);
process.send_signal(signal)?; process.send_signal(signal)?;
process.wait()?; process.wait()?;
Ok(137) Ok(ExitStatus::SignalSent(signal).into())
} }
Err(_) => Ok(124), Err(_) => Ok(ExitStatus::WaitingFailed.into()),
} }
} }
@ -282,7 +282,7 @@ fn timeout(
report_if_verbose(signal, &cmd[0], verbose); report_if_verbose(signal, &cmd[0], verbose);
process.send_signal(signal)?; process.send_signal(signal)?;
match kill_after { match kill_after {
None => Err(124.into()), None => Err(ExitStatus::CommandTimedOut.into()),
Some(kill_after) => { Some(kill_after) => {
match wait_or_kill_process( match wait_or_kill_process(
process, process,
@ -292,7 +292,10 @@ fn timeout(
verbose, verbose,
) { ) {
Ok(status) => Err(status.into()), Ok(status) => Err(status.into()),
Err(e) => Err(USimpleError::new(ERR_EXIT_STATUS, format!("{}", e))), Err(e) => Err(USimpleError::new(
ExitStatus::TimeoutFailed.into(),
format!("{}", e),
)),
} }
} }
} }
@ -301,10 +304,10 @@ fn timeout(
// We're going to return ERR_EXIT_STATUS regardless of // We're going to return ERR_EXIT_STATUS regardless of
// whether `send_signal()` succeeds or fails, so just // whether `send_signal()` succeeds or fails, so just
// ignore the return value. // ignore the return value.
process process.send_signal(signal).map_err(|e| {
.send_signal(signal) USimpleError::new(ExitStatus::TimeoutFailed.into(), format!("{}", e))
.map_err(|e| USimpleError::new(ERR_EXIT_STATUS, format!("{}", e)))?; })?;
Err(ERR_EXIT_STATUS.into()) Err(ExitStatus::TimeoutFailed.into())
} }
} }
} }