use std::{env, os::unix::net::UnixListener, path::PathBuf};
use anyhow::Context;
use tracing::{info, instrument};
use crate::{config, consts, daemonize, hooks};
mod etc_environment;
pub(crate) mod events;
mod exit_notify;
pub mod keybindings;
mod pager;
mod server;
mod shell;
mod shell_inject;
mod show_motd;
mod signals;
mod systemd;
mod trie;
mod ttl_reaper;
#[instrument(skip_all)]
pub fn run(
config_manager: config::Manager,
runtime_dir: PathBuf,
hooks: Box<dyn hooks::Hooks + Send + Sync>,
log_level_handle: tracing_subscriber::reload::Handle<
tracing_subscriber::filter::LevelFilter,
tracing_subscriber::registry::Registry,
>,
socket: PathBuf,
) -> anyhow::Result<()> {
let pid_guard = if let Ok(daemonize) = env::var(consts::AUTODAEMONIZE_VAR) {
if daemonize == "true" {
unsafe {
env::remove_var(consts::AUTODAEMONIZE_VAR); }
let pid_file = socket.with_file_name("daemonized-shpool.pid");
info!("daemonizing with pid_file={:?}", pid_file);
Some(unsafe { daemonize::daemonize(pid_file) }.context("daemonizing")?)
} else {
None
}
} else {
None
};
info!("\n\n======================== STARTING DAEMON ============================\n\n");
let events_socket = events::socket_path(&socket);
let (events_bus, _events_handle) =
events::EventBus::start(events_socket.clone()).context("starting events bus")?;
let server =
server::Server::new(config_manager, hooks, runtime_dir, log_level_handle, events_bus)?;
let (cleanup_socket, listener) = match systemd::activation_socket() {
Ok(l) => {
info!("using systemd activation socket");
(None, l)
}
Err(e) => {
info!("no systemd activation socket: {:?}", e);
if let Err(connect_err) = std::os::unix::net::UnixStream::connect(&socket) {
if connect_err.kind() == std::io::ErrorKind::ConnectionRefused {
info!("removing stale socket file at {:?}", socket);
std::fs::remove_file(&socket).context("removing stale socket before bind")?;
}
}
(Some(socket.clone()), UnixListener::bind(&socket).context("binding to socket")?)
}
};
let mut socks_to_clean: Vec<PathBuf> = cleanup_socket.iter().cloned().collect();
socks_to_clean.push(events_socket.clone());
if let Some(pid_guard) = pid_guard.as_ref().map(|g| g.path().clone()) {
socks_to_clean.push(pid_guard);
}
signals::Handler::new(socks_to_clean).spawn().context("spawning signal handler")?;
server::Server::serve(server, listener)?;
if let Some(sock) = cleanup_socket {
std::fs::remove_file(sock).context("cleaning up socket on exit")?;
} else {
info!("systemd manages the socket, so not cleaning it up");
}
Ok(())
}