//! Stop a world child after a deadline. Expiration returns status 124. use sausage_spawn::Command; use std::time::{Duration, Instant}; fn run() -> Result> { let mut args = std::env::args().skip(1); let duration = args.next().ok_or("a duration is required")?; let (number, multiplier) = match duration.as_bytes().last() { Some(b's') => (&duration[..duration.len()-1], 1.0), Some(b'm') => (&duration[..duration.len()-1], 60.0), Some(b'h') => (&duration[..duration.len()-1], 3600.0), Some(b'd') => (&duration[..duration.len()-1], 86400.0), _ => (&duration[..], 1.0), }; let duration = Duration::try_from_secs_f64(number.parse::()? * multiplier)?; let program = args.next().ok_or("a command is required")?; let child = Command::new(program).args(args).new_group().spawn()?; if duration.is_zero() { return Ok(child.wait()); } let deadline = Instant::now() + duration; loop { if let Some(code) = child.try_wait() { return Ok(code); } if Instant::now() >= deadline { child.kill(); child.wait(); return Ok(124); } std::thread::sleep(Duration::from_millis(10).min(deadline.saturating_duration_since(Instant::now()))); } } fn main() { std::process::exit(match run() { Ok(code) => code, Err(e) => { eprintln!("timeout: {e}"); 125 } }); }