#![allow(dead_code)]
use std::fs::{self, File};
use std::io;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
pub fn persist_dir() -> io::Result<PathBuf> {
if let Ok(xdg) = std::env::var("XDG_RUNTIME_DIR") {
let dir = PathBuf::from(xdg).join("term39");
return ensure_dir(dir);
}
let uid = unsafe { libc::getuid() };
if let Ok(tmpdir) = std::env::var("TMPDIR") {
let dir = PathBuf::from(tmpdir).join(format!("term39-{}", uid));
return ensure_dir(dir);
}
let dir = PathBuf::from(format!("/tmp/term39-{}", uid));
ensure_dir(dir)
}
pub fn socket_path() -> io::Result<PathBuf> {
Ok(persist_dir()?.join("term39.sock"))
}
pub fn lock_path() -> io::Result<PathBuf> {
Ok(persist_dir()?.join("term39.lock"))
}
fn ensure_dir(dir: PathBuf) -> io::Result<PathBuf> {
if !dir.exists() {
fs::create_dir_all(&dir)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
fs::set_permissions(&dir, fs::Permissions::from_mode(0o700))?;
}
}
Ok(dir)
}
pub fn is_daemon_alive() -> bool {
let lock = match lock_path() {
Ok(p) => p,
Err(_) => return false,
};
if !lock.exists() {
return false;
}
match fs::read_to_string(&lock) {
Ok(pid_str) => {
if let Ok(pid) = pid_str.trim().parse::<i32>() {
unsafe { libc::kill(pid, 0) == 0 }
} else {
false
}
}
Err(_) => false,
}
}
pub fn read_daemon_pid() -> Option<i32> {
let lock = lock_path().ok()?;
let pid_str = fs::read_to_string(lock).ok()?;
pid_str.trim().parse::<i32>().ok()
}
pub fn write_lock_file(pid: i32) -> io::Result<()> {
let lock = lock_path()?;
fs::write(lock, pid.to_string())
}
pub fn acquire_lock_file(pid: i32) -> io::Result<File> {
let lock = lock_path()?;
let file = File::create(&lock)?;
let rc = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
if rc != 0 {
return Err(io::Error::last_os_error());
}
fs::write(&lock, pid.to_string())?;
Ok(file)
}
pub fn is_daemon_lock_held() -> bool {
let lock = match lock_path() {
Ok(p) => p,
Err(_) => return false,
};
let file = match File::open(&lock) {
Ok(f) => f,
Err(_) => return false,
};
let rc = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
if rc == 0 {
unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_UN) };
false
} else {
true
}
}
pub fn cleanup_files() {
if let Ok(sock) = socket_path() {
let _ = fs::remove_file(sock);
}
if let Ok(lock) = lock_path() {
let _ = fs::remove_file(lock);
}
}
pub fn socket_exists() -> bool {
socket_path().map(|p| p.exists()).unwrap_or(false)
}