Implement crude reboot/poweroff/halt handling
This commit is contained in:
parent
0fdd5b9c37
commit
1518937f3a
|
@ -1,10 +1,12 @@
|
||||||
use clap::Clap;
|
use clap::Clap;
|
||||||
|
|
||||||
use nix::sys::signal::{killpg, Signal};
|
use nix::sys::reboot::{reboot, RebootMode};
|
||||||
|
use nix::sys::signal::{kill, Signal, SigHandler};
|
||||||
use nix::sys::wait;
|
use nix::sys::wait;
|
||||||
use nix::unistd;
|
use nix::unistd;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::io::Write;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use syndicate::actor::*;
|
use syndicate::actor::*;
|
||||||
|
@ -42,13 +44,24 @@ impl Pid1Listener {
|
||||||
impl Entity<AnyValue> for Pid1Listener {
|
impl Entity<AnyValue> for Pid1Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_sigchld_and_waitpid() -> ActorResult {
|
fn ignore_signal(kind: SignalKind) -> ActorResult {
|
||||||
|
let sig: Signal = kind.as_raw_value().try_into()?;
|
||||||
|
unsafe { nix::sys::signal::signal(sig, SigHandler::SigIgn) }?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_sigchld_and_waitpid() -> Result<RebootMode, ActorError> {
|
||||||
|
// For now, we use Alpine's userland reboot, poweroff and halt tools.
|
||||||
|
// These send SIGTERM, SIGUSR2 and SIGUSR1, respectively.
|
||||||
|
|
||||||
let mut sigchlds = signal(SignalKind::child())?;
|
let mut sigchlds = signal(SignalKind::child())?;
|
||||||
let mut sigints = signal(SignalKind::interrupt())?;
|
let mut sigints = signal(SignalKind::interrupt())?;
|
||||||
let mut sigterms = signal(SignalKind::terminate())?;
|
let mut sigterms = signal(SignalKind::terminate())?;
|
||||||
|
let mut sigusr2s = signal(SignalKind::user_defined2())?;
|
||||||
|
let mut sigusr1s = signal(SignalKind::user_defined1())?;
|
||||||
|
|
||||||
tracing::info!("Awaiting signals...");
|
tracing::info!("Awaiting signals...");
|
||||||
loop {
|
let next_step = loop {
|
||||||
select! {
|
select! {
|
||||||
_ = sigchlds.recv() => {
|
_ = sigchlds.recv() => {
|
||||||
loop {
|
loop {
|
||||||
|
@ -70,26 +83,49 @@ async fn handle_sigchld_and_waitpid() -> ActorResult {
|
||||||
}
|
}
|
||||||
_ = sigints.recv() => {
|
_ = sigints.recv() => {
|
||||||
tracing::debug!("Received SIGINT");
|
tracing::debug!("Received SIGINT");
|
||||||
let result = killpg(unistd::getpgrp(), Some(Signal::SIGINT));
|
break RebootMode::RB_AUTOBOOT;
|
||||||
tracing::debug!("killpg result: {:?}", result);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
_ = sigterms.recv() => {
|
_ = sigterms.recv() => {
|
||||||
tracing::debug!("Received SIGTERM");
|
tracing::debug!("Received SIGTERM");
|
||||||
let result = killpg(unistd::getpgrp(), Some(Signal::SIGTERM));
|
break RebootMode::RB_AUTOBOOT;
|
||||||
tracing::debug!("killpg result: {:?}", result);
|
}
|
||||||
break;
|
_ = sigusr2s.recv() => {
|
||||||
|
tracing::debug!("Received SIGUSR2");
|
||||||
|
break RebootMode::RB_POWER_OFF;
|
||||||
|
}
|
||||||
|
_ = sigusr1s.recv() => {
|
||||||
|
tracing::debug!("Received SIGUSR1");
|
||||||
|
break RebootMode::RB_HALT_SYSTEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Ok(())
|
ignore_signal(SignalKind::interrupt())?;
|
||||||
|
ignore_signal(SignalKind::terminate())?;
|
||||||
|
ignore_signal(SignalKind::user_defined2())?;
|
||||||
|
ignore_signal(SignalKind::user_defined1())?;
|
||||||
|
|
||||||
|
tracing::info!("Terminating, {:?}", next_step);
|
||||||
|
|
||||||
|
std::io::stdout().flush()?;
|
||||||
|
std::io::stderr().flush()?;
|
||||||
|
nix::unistd::sync();
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
|
||||||
|
nix::unistd::sync();
|
||||||
|
let _ = kill(unistd::Pid::from_raw(-1), Some(Signal::SIGINT));
|
||||||
|
// ^ ignore result! We're about to reboot anyway
|
||||||
|
|
||||||
|
nix::unistd::sync();
|
||||||
|
Ok(next_step)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> ActorResult {
|
async fn main() -> ActorResult {
|
||||||
syndicate::convenient_logging()?;
|
syndicate::convenient_logging()?;
|
||||||
|
|
||||||
|
tracing::info!("Startup with PID {}", unistd::getpid());
|
||||||
|
|
||||||
match unistd::setsid() {
|
match unistd::setsid() {
|
||||||
Ok(_pid) => tracing::info!("setsid(2): new session is {}", _pid),
|
Ok(_pid) => tracing::info!("setsid(2): new session is {}", _pid),
|
||||||
Err(e) => tracing::info!("setsid(2) failed: {:?}", &e),
|
Err(e) => tracing::info!("setsid(2) failed: {:?}", &e),
|
||||||
|
@ -141,7 +177,7 @@ async fn main() -> ActorResult {
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
||||||
handle_sigchld_and_waitpid().await?;
|
reboot(handle_sigchld_and_waitpid().await?)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue