From 16ca0bfd2848424de7deae307283d9eb9de8a978 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 25 Oct 2016 12:03:22 +0200 Subject: [PATCH] init: Try to aquire datadir lock before and after daemonization Before daemonization, just probe the data directory lock and print an early error message if possible. After daemonization get the data directory lock again and hold on to it until exit This creates a slight window for a race condition to happen, however this condition is harmless: it will at most make us exit without printing a message to console. $ src/bitcoind -testnet -daemon Bitcoin server starting $ src/bitcoind -testnet -daemon Error: Cannot obtain a lock on data directory /home/orion/.bitcoin/testnet3. Bitcoin Core is probably already running. --- src/init.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4f435dc7cf..b70e6e9158 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1039,18 +1039,8 @@ bool AppInitParameterInteraction() return true; } -bool AppInitSanityChecks() +static bool LockDataDirectory(bool probeOnly) { - // ********************************************************* Step 4: sanity checks - - // Initialize elliptic curve code - ECC_Start(); - globalVerifyHandle.reset(new ECCVerifyHandle()); - - // Sanity check - if (!InitSanityCheck()) - return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); - std::string strDataDir = GetDataDir().string(); // Make sure only a single Bitcoin process is using the data directory. @@ -1063,16 +1053,42 @@ bool AppInitSanityChecks() if (!lock.try_lock()) { return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); } + if (probeOnly) { + lock.unlock(); + } } catch(const boost::interprocess::interprocess_exception& e) { return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what())); } return true; } +bool AppInitSanityChecks() +{ + // ********************************************************* Step 4: sanity checks + + // Initialize elliptic curve code + ECC_Start(); + globalVerifyHandle.reset(new ECCVerifyHandle()); + + // Sanity check + if (!InitSanityCheck()) + return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); + + // Probe the data directory lock to give an early error message, if possible + return LockDataDirectory(true); +} + bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) { const CChainParams& chainparams = Params(); // ********************************************************* Step 4a: application initialization + // After daemonization get the data directory lock again and hold on to it until exit + // This creates a slight window for a race condition to happen, however this condition is harmless: it + // will at most make us exit without printing a message to console. + if (!LockDataDirectory(false)) { + // Detailed error printed inside LockDataDirectory + return false; + } #ifndef WIN32 CreatePidFile(GetPidFile(), getpid());