procutils-common 0.1.0

Shared utilities for procutils tools (utmp, signal, procmatch, fmt, uid)
Documentation
//! Canonical signal table and signal-name parsing shared by `kill`,
//! `pkill`, `skill` and friends.

use rustix::process::Signal;

/// Canonical (number, name) table of standard Linux signals.
///
/// Signal names are stored without the `SIG` prefix, matching the format
/// expected by procps-ng's `kill -l` and `kill -L` output. This is the
/// list of standard signals (1–31); real-time signals are omitted for
/// now and can be added later if needed.
pub const SIGNALS: &[(i32, &str)] = &[
    (1, "HUP"),
    (2, "INT"),
    (3, "QUIT"),
    (4, "ILL"),
    (5, "TRAP"),
    (6, "ABRT"),
    (7, "BUS"),
    (8, "FPE"),
    (9, "KILL"),
    (10, "USR1"),
    (11, "SEGV"),
    (12, "USR2"),
    (13, "PIPE"),
    (14, "ALRM"),
    (15, "TERM"),
    (16, "STKFLT"),
    (17, "CHLD"),
    (18, "CONT"),
    (19, "STOP"),
    (20, "TSTP"),
    (21, "TTIN"),
    (22, "TTOU"),
    (23, "URG"),
    (24, "XCPU"),
    (25, "XFSZ"),
    (26, "VTALRM"),
    (27, "PROF"),
    (28, "WINCH"),
    (29, "IO"),
    (30, "PWR"),
    (31, "SYS"),
];

/// Parse a signal specification — either a name (with or without `SIG`
/// prefix) or a numeric value — into a `rustix::process::Signal`.
pub fn parse_signal(name: &str) -> Option<Signal> {
    if let Ok(n) = name.parse::<i32>() {
        return Signal::from_named_raw(n);
    }

    let name = name
        .strip_prefix("SIG")
        .unwrap_or(name)
        .to_ascii_uppercase();

    match name.as_str() {
        "HUP" => Some(Signal::HUP),
        "INT" => Some(Signal::INT),
        "QUIT" => Some(Signal::QUIT),
        "ILL" => Some(Signal::ILL),
        "TRAP" => Some(Signal::TRAP),
        "ABRT" | "IOT" => Some(Signal::ABORT),
        "BUS" => Some(Signal::BUS),
        "FPE" => Some(Signal::FPE),
        "KILL" => Some(Signal::KILL),
        "USR1" => Some(Signal::USR1),
        "SEGV" => Some(Signal::SEGV),
        "USR2" => Some(Signal::USR2),
        "PIPE" => Some(Signal::PIPE),
        "ALRM" => Some(Signal::ALARM),
        "TERM" => Some(Signal::TERM),
        "STKFLT" => Some(Signal::STKFLT),
        "CHLD" | "CLD" => Some(Signal::CHILD),
        "CONT" => Some(Signal::CONT),
        "STOP" => Some(Signal::STOP),
        "TSTP" => Some(Signal::TSTP),
        "TTIN" => Some(Signal::TTIN),
        "TTOU" => Some(Signal::TTOU),
        "URG" => Some(Signal::URG),
        "XCPU" => Some(Signal::XCPU),
        "XFSZ" => Some(Signal::XFSZ),
        "VTALRM" => Some(Signal::VTALARM),
        "PROF" => Some(Signal::PROF),
        "WINCH" => Some(Signal::WINCH),
        "IO" | "POLL" => Some(Signal::IO),
        "PWR" => Some(Signal::POWER),
        "SYS" => Some(Signal::SYS),
        _ => None,
    }
}

/// Look up the canonical name (no `SIG` prefix) for a signal number.
pub fn name_for_number(n: i32) -> Option<&'static str> {
    SIGNALS
        .iter()
        .find(|(num, _)| *num == n)
        .map(|(_, name)| *name)
}

/// Look up the signal number for a name. Accepts the name with or
/// without the `SIG` prefix; case-sensitive after stripping the prefix.
pub fn number_for_name(name: &str) -> Option<i32> {
    let name = name
        .strip_prefix("SIG")
        .unwrap_or(name)
        .to_ascii_uppercase();
    SIGNALS
        .iter()
        .find(|(_, n)| *n == name)
        .map(|(num, _)| *num)
}