aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/db.cpp
diff options
context:
space:
mode:
authorMeshCollider <dobsonsa68@gmail.com>2017-12-15 11:06:22 +1300
committerMeshCollider <dobsonsa68@gmail.com>2018-01-16 19:02:57 +1300
commite60cb99c580a602a83856769ad2ac882d3cdfcb5 (patch)
tree60d15f0527d6b5289547f411d8717e1e3a67d355 /src/wallet/db.cpp
parentbbc91b7699732efc20ac1526383515c944b66d70 (diff)
Add a lock to the wallet directory
Diffstat (limited to 'src/wallet/db.cpp')
-rw-r--r--src/wallet/db.cpp66
1 files changed, 46 insertions, 20 deletions
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 35ff0e1eec..c0c24ae98b 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -18,6 +18,7 @@
#include <sys/stat.h>
#endif
+#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>
namespace {
@@ -52,6 +53,24 @@ void CheckUniqueFileid(const CDBEnv& env, const std::string& filename, Db& db)
}
}
}
+
+bool LockEnvDirectory(const fs::path& env_path)
+{
+ // Make sure only a single Bitcoin process is using the wallet directory.
+ fs::path lock_file_path = env_path / ".lock";
+ FILE* file = fsbridge::fopen(lock_file_path, "a"); // empty lock file; created if it doesn't exist.
+ if (file) fclose(file);
+
+ try {
+ static boost::interprocess::file_lock lock(lock_file_path.string().c_str());
+ if (!lock.try_lock()) {
+ return false;
+ }
+ } catch (const boost::interprocess::interprocess_exception& e) {
+ return error("Error obtaining lock on wallet directory %s: %s.", env_path.string(), e.what());
+ }
+ return true;
+}
} // namespace
//
@@ -95,13 +114,17 @@ void CDBEnv::Close()
EnvShutdown();
}
-bool CDBEnv::Open(const fs::path& pathIn)
+bool CDBEnv::Open(const fs::path& pathIn, bool retry)
{
if (fDbEnvInit)
return true;
boost::this_thread::interruption_point();
+ if (!LockEnvDirectory(pathIn)) {
+ return false;
+ }
+
strPath = pathIn.string();
fs::path pathLogDir = pathIn / "database";
TryCreateDirectories(pathLogDir);
@@ -134,7 +157,24 @@ bool CDBEnv::Open(const fs::path& pathIn)
S_IRUSR | S_IWUSR);
if (ret != 0) {
dbenv->close(0);
- return error("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
+ LogPrintf("CDBEnv::Open: Error %d opening database environment: %s\n", ret, DbEnv::strerror(ret));
+ if (retry) {
+ // try moving the database env out of the way
+ fs::path pathDatabaseBak = pathIn / strprintf("database.%d.bak", GetTime());
+ try {
+ fs::rename(pathLogDir, pathDatabaseBak);
+ LogPrintf("Moved old %s to %s. Retrying.\n", pathLogDir.string(), pathDatabaseBak.string());
+ } catch (const fs::filesystem_error&) {
+ // failure is ok (well, not really, but it's not worse than what we started with)
+ }
+ // try opening it again one more time
+ if (!Open(pathIn, false)) {
+ // if it still fails, it probably means we can't even create the database env
+ return false;
+ }
+ } else {
+ return false;
+ }
}
fDbEnvInit = true;
@@ -269,25 +309,11 @@ bool CDB::VerifyEnvironment(const std::string& walletFile, const fs::path& walle
return false;
}
- if (!bitdb.Open(walletDir))
- {
- // try moving the database env out of the way
- fs::path pathDatabase = walletDir / "database";
- fs::path pathDatabaseBak = walletDir / strprintf("database.%d.bak", GetTime());
- try {
- fs::rename(pathDatabase, pathDatabaseBak);
- LogPrintf("Moved old %s to %s. Retrying.\n", pathDatabase.string(), pathDatabaseBak.string());
- } catch (const fs::filesystem_error&) {
- // failure is ok (well, not really, but it's not worse than what we started with)
- }
-
- // try again
- if (!bitdb.Open(walletDir)) {
- // if it still fails, it probably means we can't even create the database env
- errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir);
- return false;
- }
+ if (!bitdb.Open(walletDir, true)) {
+ errorStr = strprintf(_("Cannot obtain a lock on wallet directory %s. Another instance of bitcoin may be using it."), walletDir);
+ return false;
}
+
return true;
}