diff --git a/Cargo.lock b/Cargo.lock index 110aebe8e..369276de3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1151,6 +1151,7 @@ version = "1.1.0-alpha.12-dev" dependencies = [ "clap", "clap_complete", + "fs2", "kanidm_lib_file_permissions", "kanidm_proto", "kanidmd_core", @@ -1519,6 +1520,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "futures" version = "0.3.28" diff --git a/Cargo.toml b/Cargo.toml index 99a12c03d..b9e8ad2e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ dialoguer = "0.10.4" dyn-clone = "^1.0.11" fernet = "^0.2.1" filetime = "^0.2.21" +fs2 = "^0.4.3" futures = "^0.3.28" futures-concurrency = "^3.1.0" futures-util = { version = "^0.3.21", features = ["sink"] } diff --git a/server/daemon/Cargo.toml b/server/daemon/Cargo.toml index c2b4b7588..829b78282 100644 --- a/server/daemon/Cargo.toml +++ b/server/daemon/Cargo.toml @@ -22,6 +22,7 @@ kanidm_proto.workspace = true kanidmd_core.workspace = true kanidm_lib_file_permissions.workspace = true sketching.workspace = true +fs2.workspace = true clap = { workspace = true, features = ["env"] } reqwest = { workspace = true } diff --git a/server/daemon/src/main.rs b/server/daemon/src/main.rs index 154aa129a..6334f422c 100644 --- a/server/daemon/src/main.rs +++ b/server/daemon/src/main.rs @@ -14,7 +14,9 @@ #[global_allocator] static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -use std::fs::metadata; +use std::fs::{metadata, File}; +// This works on both unix and windows. +use fs2::FileExt; #[cfg(target_family = "unix")] use std::os::unix::fs::MetadataExt; use std::path::PathBuf; @@ -235,6 +237,25 @@ async fn main() -> ExitCode { config.update_output_mode(opt.commands.commonopt().output_mode.to_owned().into()); config.update_trust_x_forward_for(sconfig.trust_x_forward_for); + // Okay - Lets now create our lock and go. + let klock_path = format!("{}.klock" ,sconfig.db_path.as_str()); + let flock = match File::create(&klock_path) { + Ok(flock) => flock, + Err(e) => { + error!("ERROR: Refusing to start - unable to create kanidm exclusive lock at {} - {:?}", klock_path, e); + return ExitCode::FAILURE + } + }; + + match flock.try_lock_exclusive() { + Ok(()) => debug!("Acquired kanidm exclusive lock"), + Err(e) => { + error!("ERROR: Refusing to start - unable to lock kanidm exclusive lock at {} - {:?}", klock_path, e); + error!("Is another kanidm process running?"); + return ExitCode::FAILURE + } + }; + /* // Apply any cli overrides, normally debug level. if opt.commands.commonopt().debug.as_ref() { diff --git a/server/lib/src/be/idl_sqlite.rs b/server/lib/src/be/idl_sqlite.rs index ccd1e7cc5..cde519da0 100644 --- a/server/lib/src/be/idl_sqlite.rs +++ b/server/lib/src/be/idl_sqlite.rs @@ -1440,7 +1440,10 @@ impl IdlSqlite { // Enable WAL mode, which is just faster and better for our needs. let mut flags = OpenFlags::default(); // Open with multi thread flags and locking options. - flags.insert(OpenFlags::SQLITE_OPEN_NO_MUTEX); + + if cfg!(test) { + flags.insert(OpenFlags::SQLITE_OPEN_NO_MUTEX); + }; // We need to run vacuum in the setup else we hit sqlite lock conditions. if vacuum {