use std::{ffi::OsStr, os::unix::net::UnixStream, path::Path, process, thread, time::Duration};
use crate::{config, consts, Args};
use anyhow::{anyhow, Context};
use tracing::info;
pub fn maybe_fork_daemon<B, P>(
config_manager: &config::Manager,
args: &Args,
shpool_bin: B,
control_sock: P,
) -> anyhow::Result<()>
where
B: AsRef<OsStr>,
P: AsRef<Path>,
{
let control_sock = control_sock.as_ref();
match UnixStream::connect(control_sock) {
Ok(_) => {
info!("daemon already running on {:?}, no need to autodaemonize", control_sock);
return Ok(());
}
Err(e) if e.kind() == std::io::ErrorKind::ConnectionRefused => {
info!("stale socket at {:?}, removing before autodaemonizing", control_sock);
std::fs::remove_file(control_sock)
.with_context(|| format!("removing stale socket at {:?}", control_sock))?;
}
Err(_) => {
}
}
info!("no daemon running on {:?}, autodaemonizing", control_sock);
let log_file = control_sock.with_file_name("daemonized-shpool.log");
let mut cmd = process::Command::new(shpool_bin);
if let Some(config_file) = &args.config_file {
cmd.arg("--config-file").arg(config_file);
}
cmd.arg("--log-file")
.arg(log_file)
.arg("--socket")
.arg(control_sock.as_os_str())
.arg("daemon")
.env(consts::AUTODAEMONIZE_VAR, "true")
.stdout(process::Stdio::null())
.stderr(process::Stdio::null())
.spawn()
.context("launching background daemon")?;
info!("launched background daemon");
if config_manager.get().nodaemonize_timeout.unwrap_or(false) {
info!("waiting for daemon to come up with no timeout");
let mut sleep_ms = 10;
let max_sleep_ms = 2000;
loop {
if UnixStream::connect(control_sock).is_ok() {
info!("connected to freshly launched background daemon");
return Ok(());
}
thread::sleep(Duration::from_millis(sleep_ms));
sleep_ms *= 2;
if sleep_ms > max_sleep_ms {
sleep_ms = max_sleep_ms;
}
}
} else {
info!("waiting for daemon to come up with timeout");
let mut sleep_ms = 10;
for _ in 0..9 {
if UnixStream::connect(control_sock).is_ok() {
info!("connected to freshly launched background daemon");
return Ok(());
}
thread::sleep(Duration::from_millis(sleep_ms));
sleep_ms *= 2;
}
}
Err(anyhow!("daemonizing: launched daemon, but control socket never came up"))
}