diff options
Diffstat (limited to 'src/daemon.rs')
-rw-r--r-- | src/daemon.rs | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/src/daemon.rs b/src/daemon.rs index fa8f287..8bf8adb 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,7 +1,11 @@ +use log::{debug, error, info}; use nix::sys::signal::kill; use nix::sys::signal::Signal; use nix::unistd::Pid; +use std::ffi::OsStr; use std::fs::read; +use std::os::unix::ffi::OsStrExt; +use std::path::{Path, PathBuf}; use std::process::Command; use std::thread::sleep; use std::time::{Duration, Instant}; @@ -19,6 +23,10 @@ pub enum DaemonError { #[error(transparent)] TempFile(#[from] std::io::Error), + /// Something went wrong read standard output of daemon. + #[error("failed to read daemon stdout: {0}")] + Stdout(std::io::Error), + /// Something went wrong read error output of daemon. #[error("failed to read daemon stderr: {0}")] Stderr(std::io::Error), @@ -67,18 +75,22 @@ impl DaemonManager { /// it reads a configuration file and that has errors. This /// function won't wait for that to happen: it only cares about /// the PID. - pub fn start(&self, argv: &[&str]) -> Result<Daemon, DaemonError> { - let stdout = NamedTempFile::new()?; - let stderr = NamedTempFile::new()?; + pub fn start( + &self, + argv: &[&OsStr], + stdout: &Path, + stderr: &Path, + ) -> Result<Daemon, DaemonError> { + info!("start daemon: {:?}", argv); let pid = NamedTempFile::new()?; let output = Command::new("daemonize") .args(&[ "-c", "/", "-e", - &stderr.path().display().to_string(), + &stderr.display().to_string(), "-o", - &stdout.path().display().to_string(), + &stdout.display().to_string(), "-p", &pid.path().display().to_string(), ]) @@ -91,6 +103,7 @@ impl DaemonManager { std::process::exit(1); } + debug!("waiting for daemon to write PID file"); let time = Instant::now(); while time.elapsed() < self.timeout { // Do we have the pid file? @@ -102,7 +115,8 @@ impl DaemonManager { // Parse as an integer, if possible. if let Ok(pid) = pid.parse() { // We have a pid, stop waiting. - return Ok(Daemon::new(pid)); + info!("got pid for daemon: pid"); + return Ok(Daemon::new(pid, stdout, stderr)); } } sleep_briefly(); @@ -111,8 +125,22 @@ impl DaemonManager { } } - let cmd = argv.join(" "); - let err = read(stderr.path()).map_err(DaemonError::Stderr)?; + error!( + "no PID file within {} ms, giving up", + self.timeout.as_millis() + ); + let mut cmd = String::new(); + for arg in argv { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str( + &String::from_utf8_lossy(arg.as_bytes()) + .to_owned() + .to_string(), + ); + } + let err = read(&stderr).map_err(DaemonError::Stderr)?; let err = String::from_utf8_lossy(&err).into_owned(); Err(DaemonError::Timeout(self.timeout.as_millis(), cmd, err)) } @@ -124,11 +152,18 @@ impl DaemonManager { #[derive(Debug)] pub struct Daemon { pid: Option<i32>, + stdout: PathBuf, + stderr: PathBuf, } impl Daemon { - fn new(pid: i32) -> Self { - Self { pid: Some(pid) } + fn new(pid: i32, stdout: &Path, stderr: &Path) -> Self { + info!("started daemon with PID {}", pid); + Self { + pid: Some(pid), + stdout: stdout.to_path_buf(), + stderr: stderr.to_path_buf(), + } } /// Explicitly stop a daemon. @@ -137,11 +172,22 @@ impl Daemon { /// errors. It can only be called once. pub fn stop(&mut self) -> Result<(), DaemonError> { if let Some(raw_pid) = self.pid.take() { + info!("stopping daemon with PID {}", raw_pid); let pid = Pid::from_raw(raw_pid); kill(pid, Some(Signal::SIGKILL)).map_err(|e| DaemonError::Kill(raw_pid, e))?; } Ok(()) } + + /// Return what the daemon has written to its stderr so far. + pub fn stdout(&self) -> Result<Vec<u8>, DaemonError> { + std::fs::read(&self.stdout).map_err(DaemonError::Stdout) + } + + /// Return what the daemon has written to its stderr so far. + pub fn stderr(&self) -> Result<Vec<u8>, DaemonError> { + std::fs::read(&self.stderr).map_err(DaemonError::Stderr) + } } impl Drop for Daemon { |