diff options
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 122 |
1 files changed, 86 insertions, 36 deletions
diff --git a/src/util.cpp b/src/util.cpp index ab262b4063..84d8175389 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2017 The Bitcoin Core developers +// Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -71,8 +71,6 @@ #include <malloc.h> #endif -#include <boost/interprocess/sync/file_lock.hpp> -#include <boost/program_options/detail/config_file.hpp> #include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> @@ -87,8 +85,6 @@ const char * const BITCOIN_PID_FILENAME = "bitcoind.pid"; ArgsManager gArgs; -CTranslationInterface translationInterface; - /** Init OpenSSL library multithreading support */ static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS @@ -142,7 +138,7 @@ instance_of_cinit; * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks * is called. */ -static std::map<std::string, std::unique_ptr<boost::interprocess::file_lock>> dir_locks; +static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks; /** Mutex to protect dir_locks. */ static std::mutex cs_dir_locks; @@ -159,18 +155,13 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b // Create empty lock file if it doesn't exist. FILE* file = fsbridge::fopen(pathLockFile, "a"); if (file) fclose(file); - - try { - auto lock = MakeUnique<boost::interprocess::file_lock>(pathLockFile.string().c_str()); - if (!lock->try_lock()) { - return false; - } - if (!probe_only) { - // Lock successful and we're not just probing, put it into the map - dir_locks.emplace(pathLockFile.string(), std::move(lock)); - } - } catch (const boost::interprocess::interprocess_exception& e) { - return error("Error while attempting to lock directory %s: %s", directory.string(), e.what()); + auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile); + if (!lock->TryLock()) { + return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason()); + } + if (!probe_only) { + // Lock successful and we're not just probing, put it into the map + dir_locks.emplace(pathLockFile.string(), std::move(lock)); } return true; } @@ -225,7 +216,7 @@ public: /** Determine whether to use config settings in the default section, * See also comments around ArgsManager::ArgsManager() below. */ - static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg) + static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg) EXCLUSIVE_LOCKS_REQUIRED(am.cs_args) { return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0); } @@ -304,7 +295,7 @@ public: /* Special test for -testnet and -regtest args, because we * don't want to be confused by craziness like "[regtest] testnet=1" */ - static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg) + static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg) EXCLUSIVE_LOCKS_REQUIRED(am.cs_args) { std::pair<bool,std::string> found_result(false,std::string()); found_result = GetArgHelper(am.m_override_args, net_arg, true); @@ -381,6 +372,8 @@ ArgsManager::ArgsManager() : void ArgsManager::WarnForSectionOnlyArgs() { + LOCK(cs_args); + // if there's no section selected, don't worry if (m_network.empty()) return; @@ -409,6 +402,7 @@ void ArgsManager::WarnForSectionOnlyArgs() void ArgsManager::SelectConfigNetwork(const std::string& network) { + LOCK(cs_args); m_network = network; } @@ -447,7 +441,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin // Check that the arg is known if (!(IsSwitchChar(key[0]) && key.size() == 1)) { - if (!IsArgKnown(key, error)) { + if (!IsArgKnown(key)) { error = strprintf("Invalid parameter %s", key.c_str()); return false; } @@ -467,7 +461,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin return true; } -bool ArgsManager::IsArgKnown(const std::string& key, std::string& error) +bool ArgsManager::IsArgKnown(const std::string& key) const { size_t option_index = key.find('.'); std::string arg_no_net; @@ -477,6 +471,7 @@ bool ArgsManager::IsArgKnown(const std::string& key, std::string& error) arg_no_net = std::string("-") + key.substr(option_index + 1, std::string::npos); } + LOCK(cs_args); for (const auto& arg_map : m_available_args) { if (arg_map.second.count(arg_no_net)) return true; } @@ -580,6 +575,7 @@ void ArgsManager::AddArg(const std::string& name, const std::string& help, const eq_index = name.size(); } + LOCK(cs_args); std::map<std::string, Arg>& arg_map = m_available_args[cat]; auto ret = arg_map.emplace(name.substr(0, eq_index), Arg(name.substr(eq_index, name.size() - eq_index), help, debug_only)); assert(ret.second); // Make sure an insertion actually happened @@ -592,11 +588,12 @@ void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names) } } -std::string ArgsManager::GetHelpMessage() +std::string ArgsManager::GetHelpMessage() const { const bool show_debug = gArgs.GetBoolArg("-help-debug", false); std::string usage = ""; + LOCK(cs_args); for (const auto& arg_map : m_available_args) { switch(arg_map.first) { case OptionsCategory::OPTIONS: @@ -811,17 +808,60 @@ fs::path GetConfigFile(const std::string& confPath) return AbsPathForConfigVal(fs::path(confPath), false); } -bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys) +static std::string TrimString(const std::string& str, const std::string& pattern) { - LOCK(cs_args); + std::string::size_type front = str.find_first_not_of(pattern); + if (front == std::string::npos) { + return std::string(); + } + std::string::size_type end = str.find_last_not_of(pattern); + return str.substr(front, end - front + 1); +} - std::set<std::string> setOptions; - setOptions.insert("*"); +static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>> &options) +{ + std::string str, prefix; + std::string::size_type pos; + int linenr = 1; + while (std::getline(stream, str)) { + if ((pos = str.find('#')) != std::string::npos) { + str = str.substr(0, pos); + } + const static std::string pattern = " \t\r\n"; + str = TrimString(str, pattern); + if (!str.empty()) { + if (*str.begin() == '[' && *str.rbegin() == ']') { + prefix = str.substr(1, str.size() - 2) + '.'; + } else if (*str.begin() == '-') { + error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str); + return false; + } else if ((pos = str.find('=')) != std::string::npos) { + std::string name = prefix + TrimString(str.substr(0, pos), pattern); + std::string value = TrimString(str.substr(pos + 1), pattern); + options.emplace_back(name, value); + } else { + error = strprintf("parse error on line %i: %s", linenr, str); + if (str.size() >= 2 && str.substr(0, 2) == "no") { + error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str); + } + return false; + } + } + ++linenr; + } + return true; +} - for (boost::program_options::detail::config_file_iterator it(stream, setOptions), end; it != end; ++it) - { - std::string strKey = std::string("-") + it->string_key; - std::string strValue = it->value[0]; +bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys) +{ + LOCK(cs_args); + std::vector<std::pair<std::string, std::string>> options; + if (!GetConfigOptions(stream, error, options)) { + return false; + } + for (const std::pair<std::string, std::string>& option : options) { + std::string strKey = std::string("-") + option.first; + std::string strValue = option.second; if (InterpretNegatedOption(strKey, strValue)) { m_config_args[strKey].clear(); @@ -830,9 +870,13 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, boo } // Check that the arg is known - if (!IsArgKnown(strKey, error) && !ignore_invalid_keys) { - error = strprintf("Invalid configuration value %s", it->string_key.c_str()); - return false; + if (!IsArgKnown(strKey)) { + if (!ignore_invalid_keys) { + error = strprintf("Invalid configuration value %s", option.first.c_str()); + return false; + } else { + LogPrintf("Ignoring unknown configuration value %s\n", option.first); + } } } return true; @@ -855,7 +899,12 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) } // if there is an -includeconf in the override args, but it is empty, that means the user // passed '-noincludeconf' on the command line, in which case we should not include anything - if (m_override_args.count("-includeconf") == 0) { + bool emptyIncludeConf; + { + LOCK(cs_args); + emptyIncludeConf = m_override_args.count("-includeconf") == 0; + } + if (emptyIncludeConf) { std::string chain_id = GetChainName(); std::vector<std::string> includeconf(GetArgs("-includeconf")); { @@ -915,6 +964,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) std::string ArgsManager::GetChainName() const { + LOCK(cs_args); bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest"); bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet"); @@ -992,7 +1042,7 @@ bool FileCommit(FILE *file) LogPrintf("%s: fdatasync failed: %d\n", __func__, errno); return false; } - #elif defined(__APPLE__) && defined(F_FULLFSYNC) + #elif defined(MAC_OSX) && defined(F_FULLFSYNC) if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno); return false; |