#![forbid(unsafe_code)]
use std::{iter::once, os::unix::ffi::OsStrExt, process::ExitCode};
use nix::{errno::Errno, sys::signal::Signal, unistd::pause};
use syd::ignore_signal;
#[cfg(all(
not(coverage),
not(feature = "prof"),
not(target_os = "android"),
not(target_arch = "riscv64"),
target_page_size_4k,
target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
const MAX_SIGS: usize = 64;
syd::main! {
use lexopt::prelude::*;
syd::set_sigpipe_dfl()?;
{
let mut sigs: [Option<Signal>; MAX_SIGS] = [None; MAX_SIGS];
let mut nsig: usize = 0;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Long("--help") => {
help();
return Ok(ExitCode::SUCCESS);
}
Short('t') => push_sig(&mut sigs, &mut nsig, Signal::SIGTERM)?,
Short('h') => push_sig(&mut sigs, &mut nsig, Signal::SIGHUP)?,
Short('a') => push_sig(&mut sigs, &mut nsig, Signal::SIGALRM)?,
Short('q') => push_sig(&mut sigs, &mut nsig, Signal::SIGQUIT)?,
Short('b') => push_sig(&mut sigs, &mut nsig, Signal::SIGABRT)?,
Short('i') => push_sig(&mut sigs, &mut nsig, Signal::SIGINT)?,
Short('p') => parse_siglist(parser.value()?.as_bytes(), &mut sigs, &mut nsig)?,
_ => return Err(arg.unexpected().into()),
}
}
for sig in sigs.iter().take(nsig).flatten() {
ignore_signal(*sig)?;
}
}
pause();
Ok(ExitCode::SUCCESS)
}
fn help() {
println!("Usage: syd-pause [ -t ] [ -h ] [ -a ] [ -q ] [ -b ] [ -i ] [ -p signal,signal,... ]");
println!("Block forever (until signaled), optionally ignoring selected signals.");
println!("Options:");
println!(" -t Ignore SIGTERM.");
println!(" -h Ignore SIGHUP.");
println!(" -a Ignore SIGALRM.");
println!(" -q Ignore SIGQUIT.");
println!(" -b Ignore SIGABRT.");
println!(" -i Ignore SIGINT.");
println!(" -p signals Ignore a comma-separated list of signal numbers (see signal(7)).");
}
fn push_sig(
buf: &mut [Option<Signal>; MAX_SIGS],
idx: &mut usize,
sig: Signal,
) -> Result<(), Errno> {
if *idx >= MAX_SIGS {
return Err(Errno::EOVERFLOW);
}
buf[*idx] = Some(sig);
*idx += 1;
Ok(())
}
fn parse_siglist(
list: &[u8],
buf: &mut [Option<Signal>; MAX_SIGS],
idx: &mut usize,
) -> Result<(), Errno> {
let mut acc: i32 = -1; for &b in list.iter().chain(once(&b',')) {
if b == b',' {
if acc < 0 {
return Err(Errno::EINVAL);
}
push_sig(buf, idx, Signal::try_from(acc)?)?;
acc = -1;
} else if b.is_ascii_digit() {
let d = (b - b'0') as i32;
acc = if acc < 0 {
d
} else {
acc.checked_mul(10)
.and_then(|v| v.checked_add(d))
.ok_or(Errno::EOVERFLOW)?
};
} else {
return Err(Errno::EINVAL);
}
}
Ok(())
}