From: Ian Jackson Date: Sun, 25 Sep 2022 13:36:01 +0000 (+0100) Subject: daemon: wip X-Git-Tag: hippotat/1.0.0~62 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=60c1d014cce86523fb9068fda40afe42de98cef8;p=hippotat.git daemon: wip Signed-off-by: Ian Jackson --- diff --git a/server/daemon.rs b/server/daemon.rs index 3946eeb..14cd1c2 100644 --- a/server/daemon.rs +++ b/server/daemon.rs @@ -12,6 +12,7 @@ use std::io::IoSlice; use std::os::unix::io::RawFd; use std::slice; use std::str; +use std::thread::panicking; use extend::ext; @@ -19,6 +20,7 @@ use nix::errno::*; use nix::fcntl::*; use nix::unistd::*; use nix::sys::stat::*; +use nix::sys::signal::*; use nix::sys::uio::*; use nix::sys::wait::*; @@ -26,6 +28,8 @@ use hippotat::prelude as prelude; use prelude::default; pub struct Daemoniser { + drop_bomb: Option<()>, + intermediate_pid: Pid, null_fd: RawFd, st_wfd: RawFd, } @@ -94,6 +98,14 @@ unsafe fn mdup2(oldfd: RawFd, newfd: RawFd, what: &str) { } } +unsafe fn write_status(st_wfd: RawFd, estatus: u8) { + match write(st_wfd, slice::from_ref(&estatus)) { + Ok(1) => {} + Ok(_) => crashm("write child startup exit status: short write"), + Err(e) => crashe("write child startup exit status", e), + } +} + unsafe fn parent(st_rfd: RawFd) -> ! { let mut exitstatus = 0u8; loop { @@ -107,7 +119,7 @@ unsafe fn parent(st_rfd: RawFd) -> ! { } } -unsafe fn intermediate(child: Pid, report_pipe: RawFd) -> ! { +unsafe fn intermediate(child: Pid, st_wfd: RawFd) -> ! { let mut wstatus: c_int = 0; let r = libc::waitpid(child.as_raw(), &mut wstatus, 0); @@ -122,11 +134,8 @@ unsafe fn intermediate(child: Pid, report_pipe: RawFd) -> ! { let estatus: u8 = estatus.try_into() .unwrap_or_else(|_| crashm( "await child startup status: exit status out of range!")); - match write(report_pipe, slice::from_ref(&estatus)) { - Ok(1) => libc::_exit(0), - Ok(_) => crashm("write child startup exit status: short write"), - Err(e) => crashe("write child startup exit status", e), - } + write_status(st_wfd, estatus); + libc::_exit(0); } WaitStatus::Signaled(_, signal, coredump) => { @@ -160,6 +169,7 @@ impl Daemoniser { close(st_rfd).context("close st_rfd pipe"); setsid().context("setsid"); + let intermediate_pid = Pid::this(); match fork().context("fork (2)") { ForkResult::Child => { } @@ -169,10 +179,43 @@ impl Daemoniser { } Daemoniser { + drop_bomb: Some(()), + intermediate_pid, null_fd, st_wfd, } } } + + pub fn complete(mut self) { + unsafe { + mdup2(self.null_fd, 1, "null over stdin"); + + if Pid::parent() != self.intermediate_pid { + crashm( + "startup complete, but our parent is no longer the intermediate?"); + } + kill(self.intermediate_pid, Some(Signal::SIGKILL)) + .context("kill intermediate (after startup complete)"); + + write_status(self.st_wfd, 0); + mdup2(self.null_fd, 2, "null over stderrr"); + + self.drop_bomb.take(); + } + } } +impl Drop for Daemoniser { + fn drop(&mut self) { + if let Some(()) = self.drop_bomb.take() { + if panicking() { + // We will crash in due course, having printed some messages + // to stderr, presumably. + return + } else { + panic!("Daemonizer object dropped unexpectedly, startup failed"); + } + } + } +}