use std::fs::File;
use std::path::Path;
use anyhow::{Context, Result};
use super::registry;
const LOCK_FILE: &str = "supervisor.lock";
pub struct Claim {
#[allow(dead_code)]
file: File,
}
pub fn claim() -> Result<Claim> {
let home = registry::home()?;
std::fs::create_dir_all(&home)
.with_context(|| format!("failed to create {}", home.display()))?;
take(&home.join(LOCK_FILE))
}
pub fn running() -> bool {
let Ok(home) = registry::home() else {
return false;
};
let path = home.join(LOCK_FILE);
if !path.exists() {
return false;
}
take(&path).is_err()
}
#[cfg(windows)]
fn take(path: &Path) -> Result<Claim> {
use std::os::windows::fs::OpenOptionsExt;
let file = std::fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(false)
.share_mode(0)
.open(path)
.with_context(|| format!("could not claim {}", path.display()))?;
Ok(Claim { file })
}
#[cfg(unix)]
fn take(path: &Path) -> Result<Claim> {
use std::os::unix::io::AsRawFd;
let file = std::fs::OpenOptions::new()
.create(true)
.write(true)
.truncate(false)
.open(path)
.with_context(|| format!("could not open {}", path.display()))?;
let locked = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
if locked != 0 {
anyhow::bail!("{} is held by another supervisor", path.display());
}
Ok(Claim { file })
}