mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Add file locking to lqosd
The file locking is "smart": it checks to see if a lock is valid before refusing to run (and updates the lock if it can run anyway). The locking mechanism will fail if you manually create the lock file and dump random data into it that doesn't readily convert to an i32. Affects issue #54 and issue #52 * Add a new structure `FileLock` to `lqosd`. * FileLock first checks /run/lqos/lqosd.lock. If it exists, it opens it and attempts to read a PID from it. If that PID is running and the associated name includes "lqosd", the FileLock returns an error. * If no lock exists, then a file is created in /run/lqos/lqosd.lock containing the running PID. * Includes Drop and signal termination support.
This commit is contained in:
parent
357bec9ad2
commit
ed07a4666b
1
src/rust/Cargo.lock
generated
1
src/rust/Cargo.lock
generated
@ -1391,6 +1391,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"signal-hook 0.3.14",
|
||||
"sysinfo",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
@ -24,3 +24,4 @@ env_logger = "0"
|
||||
log = "0"
|
||||
nix = "0"
|
||||
rayon = "1"
|
||||
sysinfo = "0"
|
||||
|
76
src/rust/lqosd/src/file_lock.rs
Normal file
76
src/rust/lqosd/src/file_lock.rs
Normal file
@ -0,0 +1,76 @@
|
||||
use std::{ffi::CString, path::Path, fs::{File, remove_file}, io::{Write, Read}};
|
||||
use anyhow::{Result, Error};
|
||||
use nix::libc::{mode_t, getpid};
|
||||
use sysinfo::{System, SystemExt, Pid, ProcessExt};
|
||||
|
||||
const LOCK_PATH: &str = "/run/lqos/lqosd.lock";
|
||||
const LOCK_DIR: &str = "/run/lqos/.";
|
||||
|
||||
pub struct FileLock {}
|
||||
|
||||
impl FileLock {
|
||||
pub fn new() -> Result<Self> {
|
||||
Self::check_directory()?;
|
||||
let lock_path = Path::new(LOCK_PATH);
|
||||
if lock_path.exists() {
|
||||
if Self::is_lock_valid()? {
|
||||
return Err(Error::msg("lqosd is already running"));
|
||||
}
|
||||
|
||||
// It's a stale pid, so we need to replace it
|
||||
Self::create_lock()?;
|
||||
|
||||
Ok(Self{})
|
||||
} else {
|
||||
Self::create_lock()?;
|
||||
Ok(Self{})
|
||||
}
|
||||
}
|
||||
|
||||
fn is_lock_valid() -> Result<bool> {
|
||||
let mut f = File::open(LOCK_PATH)?;
|
||||
let mut contents = String::new();
|
||||
f.read_to_string(&mut contents)?;
|
||||
let pid: i32 = contents.parse()?;
|
||||
|
||||
let sys = System::new_all();
|
||||
if let Some(process) = sys.processes().get(&Pid::from(pid)) {
|
||||
if process.name().contains("lqosd") {
|
||||
return Ok(true)
|
||||
}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn create_lock() -> Result<()> {
|
||||
let pid = unsafe { getpid() };
|
||||
let pid_format = format!("{pid}");
|
||||
let mut f = File::create(LOCK_PATH)?;
|
||||
f.write_all(pid_format.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_directory() -> Result<()> {
|
||||
let dir_path = std::path::Path::new(LOCK_DIR);
|
||||
if dir_path.exists() && dir_path.is_dir() {
|
||||
Ok(())
|
||||
} else {
|
||||
std::fs::create_dir(dir_path)?;
|
||||
let unix_path = CString::new(LOCK_DIR)?;
|
||||
unsafe {
|
||||
nix::libc::chmod(unix_path.as_ptr(), mode_t::from_le(666));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_lock() {
|
||||
let _ = remove_file(LOCK_PATH); // Ignore result
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FileLock {
|
||||
fn drop(&mut self) {
|
||||
Self::remove_lock();
|
||||
}
|
||||
}
|
@ -4,7 +4,8 @@ mod lqos_daht_test;
|
||||
mod program_control;
|
||||
mod throughput_tracker;
|
||||
mod tuning;
|
||||
use crate::{ip_mapping::{clear_ip_flows, del_ip_flow, list_mapped_ips, map_ip_to_flow}};
|
||||
mod file_lock;
|
||||
use crate::{ip_mapping::{clear_ip_flows, del_ip_flow, list_mapped_ips, map_ip_to_flow}, file_lock::FileLock};
|
||||
use anyhow::Result;
|
||||
use log::{info, warn};
|
||||
use lqos_bus::{BusResponse, BusRequest, UnixSocketServer};
|
||||
@ -26,6 +27,15 @@ async fn main() -> Result<()> {
|
||||
env_logger::init_from_env(
|
||||
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "warn"),
|
||||
);
|
||||
let file_lock = FileLock::new();
|
||||
match file_lock {
|
||||
Err(e) => {
|
||||
log::error!("File lock error: {:?}", e);
|
||||
std::process::exit(0);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
info!("LibreQoS Daemon Starting");
|
||||
let config = LibreQoSConfig::load()?;
|
||||
tuning::tune_lqosd_from_config_file(&config)?;
|
||||
@ -61,6 +71,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
std::mem::drop(kernels);
|
||||
UnixSocketServer::signal_cleanup();
|
||||
std::mem::drop(file_lock);
|
||||
std::process::exit(0);
|
||||
}
|
||||
SIGHUP => {
|
||||
|
Loading…
Reference in New Issue
Block a user