You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
1.8 KiB
Rust

extern crate signal_hook;
use std::thread;
use std::env::set_current_dir;
use std::process::{Stdio, Command};
use nix::unistd::{alarm, Pid, getpid};
use nix::sys::wait::{waitpid, WaitStatus, WaitPidFlag};
use signal_hook::{iterator::Signals, SIGINT, SIGALRM, SIGCHLD, SIGUSR1};
mod config;
fn sig_poweroff() {
if Command::new(config::POWEROFF_CMD[0])
.args(config::POWEROFF_CMD.iter().skip(1))
.output()
.is_err()
{
println!("[RS] poweroff failed");
}
}
fn sig_reap() {
loop {
match waitpid(Pid::from_raw(-1), Some(WaitPidFlag::WNOHANG)) {
Err(_) => break,
Ok(status) => match status {
WaitStatus::Exited(pid, ..)
| WaitStatus::Signaled(pid, ..)
| WaitStatus::Stopped(pid, ..)
| WaitStatus::Continued(pid) =>
if pid.as_raw() <= 0 {
break;
},
_ => (),
},
}
}
alarm::set(config::TIMEOUT);
}
fn sig_reboot() {
if Command::new(config::REBOOT_CMD[0])
.args(config::REBOOT_CMD.iter().skip(1))
.output()
.is_err()
{
println!("[RS] reboot failed");
}
}
fn main() {
if getpid().as_raw() != 1 {
return;
}
let signals = Signals::new(&[SIGUSR1, SIGCHLD, SIGALRM, SIGINT])
.expect("[RS] failed to handle signals");
set_current_dir("/").expect("[RS] failed to chdir");
let init = Command::new(config::INIT_CMD[0])
.args(config::INIT_CMD.iter().skip(1))
.stderr(Stdio::piped())
.spawn()
.expect("[RS] failed to spawn init command");
thread::spawn(|| {
let c = init.wait_with_output().expect("[RS] failed to wait on init command");
if !c.status.success() {
eprintln!("[RS] exited with a non-zero return code, see stderr below:");
eprintln!("{}", String::from_utf8_lossy(&c.stdout));
}
});
for signal in signals.forever() {
match signal {
SIGUSR1 => sig_poweroff(),
SIGCHLD | SIGALRM => sig_reap(),
SIGINT => sig_reboot(),
_ => unreachable!(),
}
}
}