use anyhow::{Context, Result};
use fsmon::config::Config;
use fsmon::DaemonLock;
use fsmon::monitor::Monitor;
use fsmon::managed::Managed;
use std::fs;
use std::path::Path;
use super::parse_path_entries;
pub async fn cmd_daemon() -> Result<()> {
let (uid, _gid) = fsmon::config::resolve_uid_gid();
let _lock = DaemonLock::acquire(uid)?;
let mut cfg = Config::load()?;
cfg.resolve_paths()?;
eprintln!("Config loaded:");
eprintln!(" Managed path database: {}", cfg.managed.path.display());
eprintln!(" Event logs: {}", cfg.logging.path.display());
eprintln!(" Command socket: {}", cfg.socket.path.display());
let store = Managed::load(&cfg.managed.path)?;
let socket_path = cfg.socket.path.clone();
if socket_path.exists() {
fs::remove_file(&socket_path)?;
}
if let Some(parent) = socket_path.parent() {
fs::create_dir_all(parent)?;
}
let socket_listener = tokio::net::UnixListener::bind(&socket_path)
.with_context(|| format!("Failed to bind socket at {}", socket_path.display()))?;
set_socket_permissions(&socket_path)?;
let (uid, gid) = fsmon::config::resolve_uid_gid();
if let Some(parent) = cfg.managed.path.parent() {
chown_path(parent, uid, gid);
}
let paths_and_options = parse_path_entries(&store.entries)?;
let store_path = cfg.managed.path.clone();
let mut monitor = Monitor::new(
paths_and_options,
Some(cfg.logging.path.clone()),
Some(store_path),
None,
Some(socket_listener),
)?;
if !store.entries.is_empty() {
eprintln!("Managed paths ({}):", store.entries.len());
for entry in &store.entries {
eprintln!(" {}", entry.path.display());
}
}
monitor.run().await?;
Ok(())
}
pub fn chown_path(path: &Path, uid: u32, gid: u32) {
if let Ok(cpath) = std::ffi::CString::new(path.to_string_lossy().as_bytes()) {
let _ = nix::unistd::chown(
cpath.as_c_str(),
Some(nix::unistd::Uid::from_raw(uid)),
Some(nix::unistd::Gid::from_raw(gid)),
);
}
}
pub fn set_socket_permissions(path: &Path) -> Result<()> {
use std::os::unix::fs::PermissionsExt;
let perm = fs::Permissions::from_mode(0o666);
fs::set_permissions(path, perm)
.with_context(|| format!("Failed to set socket permissions on {}", path.display()))?;
Ok(())
}