diff --git a/src/init.cpp b/src/init.cpp index d46318fd45e3c2..579669712eed8b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1109,8 +1109,9 @@ static bool LockDirectory(const fs::path& dir, bool probeOnly) } static bool LockDirectories(bool probeOnly) { - return LockDirectory(gArgs.GetDataDirNet(), probeOnly) && \ - LockDirectory(gArgs.GetBlocksDirPath(), probeOnly); + // Only allow probing the blocks directory, the BlockManager takes the lock internally. + return LockDirectory(gArgs.GetDataDirNet(), probeOnly) && + (probeOnly ? LockDirectory(gArgs.GetBlocksDirPath(), probeOnly) : true); } bool AppInitSanityChecks(const kernel::Context& kernel) diff --git a/src/init/common.cpp b/src/init/common.cpp index 70c4230cfdb00e..616202328bd7e5 100644 --- a/src/init/common.cpp +++ b/src/init/common.cpp @@ -117,9 +117,10 @@ bool StartLogging(const ArgsManager& args) } if (!LogInstance().m_log_timestamps) - LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); - LogPrintf("Default data directory %s\n", fs::PathToString(GetDefaultDataDir())); - LogPrintf("Using data directory %s\n", fs::PathToString(gArgs.GetDataDirNet())); + LogInfo("Startup time: %s", FormatISO8601DateTime(GetTime())); + LogInfo("Default data directory %s", fs::PathToString(GetDefaultDataDir())); + LogInfo("Using data directory %s", fs::PathToString(gArgs.GetDataDirNet())); + LogInfo("Using blocks directory %s", fs::PathToString(gArgs.GetBlocksDirPath())); // Only log conf file usage message if conf file actually exists. fs::path config_file_path = args.GetConfigFilePath(); diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index 372395dd24d4d5..58de0c34841b20 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -4,6 +4,8 @@ #include +#include // IWYU pragma: keep + #include #include #include @@ -31,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1164,8 +1167,29 @@ static auto InitBlocksdirXorKey(const BlockManager::Options& opts) return std::vector{xor_key.begin(), xor_key.end()}; } +BlockDirLock::BlockDirLock(const fs::path& blocks_dir) + : m_path{blocks_dir} +{ + // Make sure only a single BlockManager is using the blocks directory. + switch (util::LockDirectory(blocks_dir, ".lock", false)) { + case util::LockResult::ErrorWrite: + throw std::runtime_error(strprintf(_("Cannot write to block directory '%s'; check permissions."), fs::PathToString(blocks_dir)).original); + case util::LockResult::ErrorLock: + throw std::runtime_error(strprintf(_("Cannot obtain a lock on block directory %s. %s is probably already running."), fs::PathToString(blocks_dir), CLIENT_NAME).original); + case util::LockResult::Success: + return; + } // no default case, so the compiler can warn about missing cases + assert(false); +} + +BlockDirLock::~BlockDirLock() +{ + UnlockDirectory(m_path, ".lock"); +} + BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts) - : m_prune_mode{opts.prune_target > 0}, + : m_lock{BlockDirLock(opts.blocks_dir)}, + m_prune_mode{opts.prune_target > 0}, m_xor_key{InitBlocksdirXorKey(opts)}, m_opts{std::move(opts)}, m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}}, diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 8a34efadfea192..b68780cb60b0fd 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -127,6 +127,14 @@ struct BlockfileCursor { std::ostream& operator<<(std::ostream& os, const BlockfileCursor& cursor); +class BlockDirLock +{ + fs::path m_path; + +public: + explicit BlockDirLock(const fs::path& blocks_dir); + ~BlockDirLock(); +}; /** * Maintains a tree of blocks (stored in `m_block_index`) which is consulted @@ -141,6 +149,7 @@ class BlockManager friend ChainstateManager; private: + BlockDirLock m_lock; const CChainParams& GetParams() const { return m_opts.chainparams; } const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); } /**