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.
This commit is contained in:
Wladimir J. van der Laan 2016-10-25 12:03:22 +02:00
parent 0cc8b6bc44
commit 16ca0bfd28

View File

@ -1039,18 +1039,8 @@ bool AppInitParameterInteraction()
return true; 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(); std::string strDataDir = GetDataDir().string();
// Make sure only a single Bitcoin process is using the data directory. // Make sure only a single Bitcoin process is using the data directory.
@ -1063,16 +1053,42 @@ bool AppInitSanityChecks()
if (!lock.try_lock()) { if (!lock.try_lock()) {
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), strDataDir, _(PACKAGE_NAME))); 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) { } 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 InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.") + " %s.", strDataDir, _(PACKAGE_NAME), e.what()));
} }
return true; 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) bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
{ {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
// ********************************************************* Step 4a: application initialization // ********************************************************* 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 #ifndef WIN32
CreatePidFile(GetPidFile(), getpid()); CreatePidFile(GetPidFile(), getpid());