diff options
author | Jim Posen <jim.posen@gmail.com> | 2018-10-22 15:51:11 -0700 |
---|---|---|
committer | Jim Posen <jim.posen@gmail.com> | 2018-11-04 22:46:07 -0800 |
commit | 2068f089c8b7b90eb4557d3f67ea0f0ed2059a23 (patch) | |
tree | bbbd0304b01d48831c60cf6b528c758d62f4949c /src/util.cpp | |
parent | 742ee213499194f97e59dae4971f1474ae7d57ad (diff) |
scripted-diff: Move util files to separate directory.
-BEGIN VERIFY SCRIPT-
mkdir -p src/util
git mv src/util.h src/util/system.h
git mv src/util.cpp src/util/system.cpp
git mv src/utilmemory.h src/util/memory.h
git mv src/utilmoneystr.h src/util/moneystr.h
git mv src/utilmoneystr.cpp src/util/moneystr.cpp
git mv src/utilstrencodings.h src/util/strencodings.h
git mv src/utilstrencodings.cpp src/util/strencodings.cpp
git mv src/utiltime.h src/util/time.h
git mv src/utiltime.cpp src/util/time.cpp
sed -i 's/<util\.h>/<util\/system\.h>/g' $(git ls-files 'src/*.h' 'src/*.cpp')
sed -i 's/<utilmemory\.h>/<util\/memory\.h>/g' $(git ls-files 'src/*.h' 'src/*.cpp')
sed -i 's/<utilmoneystr\.h>/<util\/moneystr\.h>/g' $(git ls-files 'src/*.h' 'src/*.cpp')
sed -i 's/<utilstrencodings\.h>/<util\/strencodings\.h>/g' $(git ls-files 'src/*.h' 'src/*.cpp')
sed -i 's/<utiltime\.h>/<util\/time\.h>/g' $(git ls-files 'src/*.h' 'src/*.cpp')
sed -i 's/BITCOIN_UTIL_H/BITCOIN_UTIL_SYSTEM_H/g' src/util/system.h
sed -i 's/BITCOIN_UTILMEMORY_H/BITCOIN_UTIL_MEMORY_H/g' src/util/memory.h
sed -i 's/BITCOIN_UTILMONEYSTR_H/BITCOIN_UTIL_MONEYSTR_H/g' src/util/moneystr.h
sed -i 's/BITCOIN_UTILSTRENCODINGS_H/BITCOIN_UTIL_STRENCODINGS_H/g' src/util/strencodings.h
sed -i 's/BITCOIN_UTILTIME_H/BITCOIN_UTIL_TIME_H/g' src/util/time.h
sed -i 's/ util\.\(h\|cpp\)/ util\/system\.\1/g' src/Makefile.am
sed -i 's/utilmemory\.\(h\|cpp\)/util\/memory\.\1/g' src/Makefile.am
sed -i 's/utilmoneystr\.\(h\|cpp\)/util\/moneystr\.\1/g' src/Makefile.am
sed -i 's/utilstrencodings\.\(h\|cpp\)/util\/strencodings\.\1/g' src/Makefile.am
sed -i 's/utiltime\.\(h\|cpp\)/util\/time\.\1/g' src/Makefile.am
sed -i 's/-> util ->/-> util\/system ->/' test/lint/lint-circular-dependencies.sh
sed -i 's/src\/util\.cpp/src\/util\/system\.cpp/g' test/lint/lint-format-strings.py test/lint/lint-locale-dependence.sh
sed -i 's/src\/utilmoneystr\.cpp/src\/util\/moneystr\.cpp/g' test/lint/lint-locale-dependence.sh
sed -i 's/src\/utilstrencodings\.\(h\|cpp\)/src\/util\/strencodings\.\1/g' test/lint/lint-locale-dependence.sh
sed -i 's/src\\utilstrencodings\.cpp/src\\util\\strencodings\.cpp/' build_msvc/libbitcoinconsensus/libbitcoinconsensus.vcxproj
-END VERIFY SCRIPT-
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 1299 |
1 files changed, 0 insertions, 1299 deletions
diff --git a/src/util.cpp b/src/util.cpp deleted file mode 100644 index 6479b9b9ce..0000000000 --- a/src/util.cpp +++ /dev/null @@ -1,1299 +0,0 @@ -// Copyright (c) 2009-2010 Satoshi Nakamoto -// 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. - -#include <util.h> - -#include <chainparamsbase.h> -#include <random.h> -#include <serialize.h> -#include <utilstrencodings.h> - -#include <stdarg.h> - -#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) -#include <pthread.h> -#include <pthread_np.h> -#endif - -#ifndef WIN32 -// for posix_fallocate -#ifdef __linux__ - -#ifdef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE -#endif - -#define _POSIX_C_SOURCE 200112L - -#endif // __linux__ - -#include <algorithm> -#include <fcntl.h> -#include <sched.h> -#include <sys/resource.h> -#include <sys/stat.h> - -#else - -#ifdef _MSC_VER -#pragma warning(disable:4786) -#pragma warning(disable:4804) -#pragma warning(disable:4805) -#pragma warning(disable:4717) -#endif - -#ifdef _WIN32_WINNT -#undef _WIN32_WINNT -#endif -#define _WIN32_WINNT 0x0501 - -#ifdef _WIN32_IE -#undef _WIN32_IE -#endif -#define _WIN32_IE 0x0501 - -#define WIN32_LEAN_AND_MEAN 1 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include <codecvt> - -#include <io.h> /* for _commit */ -#include <shellapi.h> -#include <shlobj.h> -#endif - -#ifdef HAVE_SYS_PRCTL_H -#include <sys/prctl.h> -#endif - -#ifdef HAVE_MALLOPT_ARENA_MAX -#include <malloc.h> -#endif - -#include <boost/thread.hpp> -#include <openssl/crypto.h> -#include <openssl/rand.h> -#include <openssl/conf.h> -#include <thread> - -// Application startup time (used for uptime calculation) -const int64_t nStartupTime = GetTime(); - -const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf"; -const char * const BITCOIN_PID_FILENAME = "bitcoind.pid"; - -ArgsManager gArgs; - -/** 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 -{ - if (mode & CRYPTO_LOCK) { - ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]); - } else { - LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]); - } -} - -// Singleton for wrapping OpenSSL setup/teardown. -class CInit -{ -public: - CInit() - { - // Init OpenSSL library multithreading support - ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]); - CRYPTO_set_locking_callback(locking_callback); - - // OpenSSL can optionally load a config file which lists optional loadable modules and engines. - // We don't use them so we don't require the config. However some of our libs may call functions - // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing - // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be - // that the config appears to have been loaded and there are no modules/engines available. - OPENSSL_no_config(); - -#ifdef WIN32 - // Seed OpenSSL PRNG with current contents of the screen - RAND_screen(); -#endif - - // Seed OpenSSL PRNG with performance counter - RandAddSeed(); - } - ~CInit() - { - // Securely erase the memory used by the PRNG - RAND_cleanup(); - // Shutdown OpenSSL library multithreading support - CRYPTO_set_locking_callback(nullptr); - // Clear the set of locks now to maintain symmetry with the constructor. - ppmutexOpenSSL.reset(); - } -} -instance_of_cinit; - -/** A map that contains all the currently held directory locks. After - * successful locking, these will be held here until the global destructor - * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks - * is called. - */ -static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks; -/** Mutex to protect dir_locks. */ -static std::mutex cs_dir_locks; - -bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only) -{ - std::lock_guard<std::mutex> ulock(cs_dir_locks); - fs::path pathLockFile = directory / lockfile_name; - - // If a lock for this directory already exists in the map, don't try to re-lock it - if (dir_locks.count(pathLockFile.string())) { - return true; - } - - // Create empty lock file if it doesn't exist. - FILE* file = fsbridge::fopen(pathLockFile, "a"); - if (file) fclose(file); - 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; -} - -void ReleaseDirectoryLocks() -{ - std::lock_guard<std::mutex> ulock(cs_dir_locks); - dir_locks.clear(); -} - -bool DirIsWritable(const fs::path& directory) -{ - fs::path tmpFile = directory / fs::unique_path(); - - FILE* file = fsbridge::fopen(tmpFile, "a"); - if (!file) return false; - - fclose(file); - remove(tmpFile); - - return true; -} - -/** - * Interpret a string argument as a boolean. - * - * The definition of atoi() requires that non-numeric string values like "foo", - * return 0. This means that if a user unintentionally supplies a non-integer - * argument here, the return value is always false. This means that -foo=false - * does what the user probably expects, but -foo=true is well defined but does - * not do what they probably expected. - * - * The return value of atoi() is undefined when given input not representable as - * an int. On most systems this means string value between "-2147483648" and - * "2147483647" are well defined (this method will return true). Setting - * -txindex=2147483648 on most systems, however, is probably undefined. - * - * For a more extensive discussion of this topic (and a wide range of opinions - * on the Right Way to change this code), see PR12713. - */ -static bool InterpretBool(const std::string& strValue) -{ - if (strValue.empty()) - return true; - return (atoi(strValue) != 0); -} - -/** Internal helper functions for ArgsManager */ -class ArgsManagerHelper { -public: - typedef std::map<std::string, std::vector<std::string>> MapArgs; - - /** 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) EXCLUSIVE_LOCKS_REQUIRED(am.cs_args) - { - return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0); - } - - /** Convert regular argument into the network-specific setting */ - static inline std::string NetworkArg(const ArgsManager& am, const std::string& arg) - { - assert(arg.length() > 1 && arg[0] == '-'); - return "-" + am.m_network + "." + arg.substr(1); - } - - /** Find arguments in a map and add them to a vector */ - static inline void AddArgs(std::vector<std::string>& res, const MapArgs& map_args, const std::string& arg) - { - auto it = map_args.find(arg); - if (it != map_args.end()) { - res.insert(res.end(), it->second.begin(), it->second.end()); - } - } - - /** Return true/false if an argument is set in a map, and also - * return the first (or last) of the possibly multiple values it has - */ - static inline std::pair<bool,std::string> GetArgHelper(const MapArgs& map_args, const std::string& arg, bool getLast = false) - { - auto it = map_args.find(arg); - - if (it == map_args.end() || it->second.empty()) { - return std::make_pair(false, std::string()); - } - - if (getLast) { - return std::make_pair(true, it->second.back()); - } else { - return std::make_pair(true, it->second.front()); - } - } - - /* Get the string value of an argument, returning a pair of a boolean - * indicating the argument was found, and the value for the argument - * if it was found (or the empty string if not found). - */ - static inline std::pair<bool,std::string> GetArg(const ArgsManager &am, const std::string& arg) - { - LOCK(am.cs_args); - std::pair<bool,std::string> found_result(false, std::string()); - - // We pass "true" to GetArgHelper in order to return the last - // argument value seen from the command line (so "bitcoind -foo=bar - // -foo=baz" gives GetArg(am,"foo")=={true,"baz"} - found_result = GetArgHelper(am.m_override_args, arg, true); - if (found_result.first) { - return found_result; - } - - // But in contrast we return the first argument seen in a config file, - // so "foo=bar \n foo=baz" in the config file gives - // GetArg(am,"foo")={true,"bar"} - if (!am.m_network.empty()) { - found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg)); - if (found_result.first) { - return found_result; - } - } - - if (UseDefaultSection(am, arg)) { - found_result = GetArgHelper(am.m_config_args, arg); - if (found_result.first) { - return found_result; - } - } - - return found_result; - } - - /* 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) 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); - if (!found_result.first) { - found_result = GetArgHelper(am.m_config_args, net_arg, true); - if (!found_result.first) { - return false; // not set - } - } - return InterpretBool(found_result.second); // is set, so evaluate - } -}; - -/** - * Interpret -nofoo as if the user supplied -foo=0. - * - * This method also tracks when the -no form was supplied, and if so, - * checks whether there was a double-negative (-nofoo=0 -> -foo=1). - * - * If there was not a double negative, it removes the "no" from the key, - * and returns true, indicating the caller should clear the args vector - * to indicate a negated option. - * - * If there was a double negative, it removes "no" from the key, sets the - * value to "1" and returns false. - * - * If there was no "no", it leaves key and value untouched and returns - * false. - * - * Where an option was negated can be later checked using the - * IsArgNegated() method. One use case for this is to have a way to disable - * options that are not normally boolean (e.g. using -nodebuglogfile to request - * that debug log output is not sent to any file at all). - */ -static bool InterpretNegatedOption(std::string& key, std::string& val) -{ - assert(key[0] == '-'); - - size_t option_index = key.find('.'); - if (option_index == std::string::npos) { - option_index = 1; - } else { - ++option_index; - } - if (key.substr(option_index, 2) == "no") { - bool bool_val = InterpretBool(val); - key.erase(option_index, 2); - if (!bool_val ) { - // Double negatives like -nofoo=0 are supported (but discouraged) - LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val); - val = "1"; - } else { - return true; - } - } - return false; -} - -ArgsManager::ArgsManager() : - /* These options would cause cross-contamination if values for - * mainnet were used while running on regtest/testnet (or vice-versa). - * Setting them as section_only_args ensures that sharing a config file - * between mainnet and regtest/testnet won't cause problems due to these - * parameters by accident. */ - m_network_only_args{ - "-addnode", "-connect", - "-port", "-bind", - "-rpcport", "-rpcbind", - "-wallet", - } -{ - // nothing to do -} - -void ArgsManager::WarnForSectionOnlyArgs() -{ - LOCK(cs_args); - - // if there's no section selected, don't worry - if (m_network.empty()) return; - - // if it's okay to use the default section for this network, don't worry - if (m_network == CBaseChainParams::MAIN) return; - - for (const auto& arg : m_network_only_args) { - std::pair<bool, std::string> found_result; - - // if this option is overridden it's fine - found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg); - if (found_result.first) continue; - - // if there's a network-specific value for this option, it's fine - found_result = ArgsManagerHelper::GetArgHelper(m_config_args, ArgsManagerHelper::NetworkArg(*this, arg)); - if (found_result.first) continue; - - // if there isn't a default value for this option, it's fine - found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg); - if (!found_result.first) continue; - - // otherwise, issue a warning - LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network); - } -} - -void ArgsManager::SelectConfigNetwork(const std::string& network) -{ - LOCK(cs_args); - m_network = network; -} - -bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error) -{ - LOCK(cs_args); - m_override_args.clear(); - - for (int i = 1; i < argc; i++) { - std::string key(argv[i]); - std::string val; - size_t is_index = key.find('='); - if (is_index != std::string::npos) { - val = key.substr(is_index + 1); - key.erase(is_index); - } -#ifdef WIN32 - std::transform(key.begin(), key.end(), key.begin(), ::tolower); - if (key[0] == '/') - key[0] = '-'; -#endif - - if (key[0] != '-') - break; - - // Transform --foo to -foo - if (key.length() > 1 && key[1] == '-') - key.erase(0, 1); - - // Check for -nofoo - if (InterpretNegatedOption(key, val)) { - m_override_args[key].clear(); - } else { - m_override_args[key].push_back(val); - } - - // Check that the arg is known - if (!(IsSwitchChar(key[0]) && key.size() == 1)) { - if (!IsArgKnown(key)) { - error = strprintf("Invalid parameter %s", key.c_str()); - return false; - } - } - } - - // we do not allow -includeconf from command line, so we clear it here - auto it = m_override_args.find("-includeconf"); - if (it != m_override_args.end()) { - if (it->second.size() > 0) { - for (const auto& ic : it->second) { - error += "-includeconf cannot be used from commandline; -includeconf=" + ic + "\n"; - } - return false; - } - } - return true; -} - -bool ArgsManager::IsArgKnown(const std::string& key) const -{ - size_t option_index = key.find('.'); - std::string arg_no_net; - if (option_index == std::string::npos) { - arg_no_net = key; - } else { - 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; - } - return false; -} - -std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const -{ - std::vector<std::string> result = {}; - if (IsArgNegated(strArg)) return result; // special case - - LOCK(cs_args); - - ArgsManagerHelper::AddArgs(result, m_override_args, strArg); - if (!m_network.empty()) { - ArgsManagerHelper::AddArgs(result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg)); - } - - if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) { - ArgsManagerHelper::AddArgs(result, m_config_args, strArg); - } - - return result; -} - -bool ArgsManager::IsArgSet(const std::string& strArg) const -{ - if (IsArgNegated(strArg)) return true; // special case - return ArgsManagerHelper::GetArg(*this, strArg).first; -} - -bool ArgsManager::IsArgNegated(const std::string& strArg) const -{ - LOCK(cs_args); - - const auto& ov = m_override_args.find(strArg); - if (ov != m_override_args.end()) return ov->second.empty(); - - if (!m_network.empty()) { - const auto& cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg)); - if (cfs != m_config_args.end()) return cfs->second.empty(); - } - - const auto& cf = m_config_args.find(strArg); - if (cf != m_config_args.end()) return cf->second.empty(); - - return false; -} - -std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const -{ - if (IsArgNegated(strArg)) return "0"; - std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg); - if (found_res.first) return found_res.second; - return strDefault; -} - -int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const -{ - if (IsArgNegated(strArg)) return 0; - std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg); - if (found_res.first) return atoi64(found_res.second); - return nDefault; -} - -bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const -{ - if (IsArgNegated(strArg)) return false; - std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg); - if (found_res.first) return InterpretBool(found_res.second); - return fDefault; -} - -bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue) -{ - LOCK(cs_args); - if (IsArgSet(strArg)) return false; - ForceSetArg(strArg, strValue); - return true; -} - -bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue) -{ - if (fValue) - return SoftSetArg(strArg, std::string("1")); - else - return SoftSetArg(strArg, std::string("0")); -} - -void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue) -{ - LOCK(cs_args); - m_override_args[strArg] = {strValue}; -} - -void ArgsManager::AddArg(const std::string& name, const std::string& help, const bool debug_only, const OptionsCategory& cat) -{ - // Split arg name from its help param - size_t eq_index = name.find('='); - if (eq_index == std::string::npos) { - 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 -} - -void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names) -{ - for (const std::string& name : names) { - AddArg(name, "", false, OptionsCategory::HIDDEN); - } -} - -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: - usage += HelpMessageGroup("Options:"); - break; - case OptionsCategory::CONNECTION: - usage += HelpMessageGroup("Connection options:"); - break; - case OptionsCategory::ZMQ: - usage += HelpMessageGroup("ZeroMQ notification options:"); - break; - case OptionsCategory::DEBUG_TEST: - usage += HelpMessageGroup("Debugging/Testing options:"); - break; - case OptionsCategory::NODE_RELAY: - usage += HelpMessageGroup("Node relay options:"); - break; - case OptionsCategory::BLOCK_CREATION: - usage += HelpMessageGroup("Block creation options:"); - break; - case OptionsCategory::RPC: - usage += HelpMessageGroup("RPC server options:"); - break; - case OptionsCategory::WALLET: - usage += HelpMessageGroup("Wallet options:"); - break; - case OptionsCategory::WALLET_DEBUG_TEST: - if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:"); - break; - case OptionsCategory::CHAINPARAMS: - usage += HelpMessageGroup("Chain selection options:"); - break; - case OptionsCategory::GUI: - usage += HelpMessageGroup("UI Options:"); - break; - case OptionsCategory::COMMANDS: - usage += HelpMessageGroup("Commands:"); - break; - case OptionsCategory::REGISTER_COMMANDS: - usage += HelpMessageGroup("Register Commands:"); - break; - default: - break; - } - - // When we get to the hidden options, stop - if (arg_map.first == OptionsCategory::HIDDEN) break; - - for (const auto& arg : arg_map.second) { - if (show_debug || !arg.second.m_debug_only) { - std::string name; - if (arg.second.m_help_param.empty()) { - name = arg.first; - } else { - name = arg.first + arg.second.m_help_param; - } - usage += HelpMessageOpt(name, arg.second.m_help_text); - } - } - } - return usage; -} - -bool HelpRequested(const ArgsManager& args) -{ - return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug"); -} - -static const int screenWidth = 79; -static const int optIndent = 2; -static const int msgIndent = 7; - -std::string HelpMessageGroup(const std::string &message) { - return std::string(message) + std::string("\n\n"); -} - -std::string HelpMessageOpt(const std::string &option, const std::string &message) { - return std::string(optIndent,' ') + std::string(option) + - std::string("\n") + std::string(msgIndent,' ') + - FormatParagraph(message, screenWidth - msgIndent, msgIndent) + - std::string("\n\n"); -} - -static std::string FormatException(const std::exception* pex, const char* pszThread) -{ -#ifdef WIN32 - char pszModule[MAX_PATH] = ""; - GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule)); -#else - const char* pszModule = "bitcoin"; -#endif - if (pex) - return strprintf( - "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread); - else - return strprintf( - "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread); -} - -void PrintExceptionContinue(const std::exception* pex, const char* pszThread) -{ - std::string message = FormatException(pex, pszThread); - LogPrintf("\n\n************************\n%s\n", message); - fprintf(stderr, "\n\n************************\n%s\n", message.c_str()); -} - -fs::path GetDefaultDataDir() -{ - // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin - // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin - // Mac: ~/Library/Application Support/Bitcoin - // Unix: ~/.bitcoin -#ifdef WIN32 - // Windows - return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; -#else - fs::path pathRet; - char* pszHome = getenv("HOME"); - if (pszHome == nullptr || strlen(pszHome) == 0) - pathRet = fs::path("/"); - else - pathRet = fs::path(pszHome); -#ifdef MAC_OSX - // Mac - return pathRet / "Library/Application Support/Bitcoin"; -#else - // Unix - return pathRet / ".bitcoin"; -#endif -#endif -} - -static fs::path g_blocks_path_cached; -static fs::path g_blocks_path_cache_net_specific; -static fs::path pathCached; -static fs::path pathCachedNetSpecific; -static CCriticalSection csPathCached; - -const fs::path &GetBlocksDir(bool fNetSpecific) -{ - - LOCK(csPathCached); - - fs::path &path = fNetSpecific ? g_blocks_path_cache_net_specific : g_blocks_path_cached; - - // This can be called during exceptions by LogPrintf(), so we cache the - // value so we don't have to do memory allocations after that. - if (!path.empty()) - return path; - - if (gArgs.IsArgSet("-blocksdir")) { - path = fs::system_complete(gArgs.GetArg("-blocksdir", "")); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDataDir(false); - } - if (fNetSpecific) - path /= BaseParams().DataDir(); - - path /= "blocks"; - fs::create_directories(path); - return path; -} - -const fs::path &GetDataDir(bool fNetSpecific) -{ - - LOCK(csPathCached); - - fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached; - - // This can be called during exceptions by LogPrintf(), so we cache the - // value so we don't have to do memory allocations after that. - if (!path.empty()) - return path; - - if (gArgs.IsArgSet("-datadir")) { - path = fs::system_complete(gArgs.GetArg("-datadir", "")); - if (!fs::is_directory(path)) { - path = ""; - return path; - } - } else { - path = GetDefaultDataDir(); - } - if (fNetSpecific) - path /= BaseParams().DataDir(); - - if (fs::create_directories(path)) { - // This is the first run, create wallets subdirectory too - fs::create_directories(path / "wallets"); - } - - return path; -} - -void ClearDatadirCache() -{ - LOCK(csPathCached); - - pathCached = fs::path(); - pathCachedNetSpecific = fs::path(); - g_blocks_path_cached = fs::path(); - g_blocks_path_cache_net_specific = fs::path(); -} - -fs::path GetConfigFile(const std::string& confPath) -{ - return AbsPathForConfigVal(fs::path(confPath), false); -} - -static std::string TrimString(const std::string& str, const std::string& pattern) -{ - 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); -} - -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; -} - -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(); - } else { - m_config_args[strKey].push_back(strValue); - } - - // Check that the arg is known - 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; -} - -bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) -{ - { - LOCK(cs_args); - m_config_args.clear(); - } - - const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME); - fsbridge::ifstream stream(GetConfigFile(confPath)); - - // ok to not have a config file - if (stream.good()) { - if (!ReadConfigStream(stream, error, ignore_invalid_keys)) { - return false; - } - // 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 - 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")); - { - // We haven't set m_network yet (that happens in SelectParams()), so manually check - // for network.includeconf args. - std::vector<std::string> includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf")); - includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end()); - } - - // Remove -includeconf from configuration, so we can warn about recursion - // later - { - LOCK(cs_args); - m_config_args.erase("-includeconf"); - m_config_args.erase(std::string("-") + chain_id + ".includeconf"); - } - - for (const std::string& to_include : includeconf) { - fsbridge::ifstream include_config(GetConfigFile(to_include)); - if (include_config.good()) { - if (!ReadConfigStream(include_config, error, ignore_invalid_keys)) { - return false; - } - LogPrintf("Included configuration file %s\n", to_include.c_str()); - } else { - error = "Failed to include configuration file " + to_include; - return false; - } - } - - // Warn about recursive -includeconf - includeconf = GetArgs("-includeconf"); - { - std::vector<std::string> includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf")); - includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end()); - std::string chain_id_final = GetChainName(); - if (chain_id_final != chain_id) { - // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs - includeconf_net = GetArgs(std::string("-") + chain_id_final + ".includeconf"); - includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end()); - } - } - for (const std::string& to_include : includeconf) { - fprintf(stderr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str()); - } - } - } - - // If datadir is changed in .conf file: - ClearDatadirCache(); - if (!fs::is_directory(GetDataDir(false))) { - error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()); - return false; - } - return true; -} - -std::string ArgsManager::GetChainName() const -{ - LOCK(cs_args); - bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest"); - bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet"); - - if (fTestNet && fRegTest) - throw std::runtime_error("Invalid combination of -regtest and -testnet."); - if (fRegTest) - return CBaseChainParams::REGTEST; - if (fTestNet) - return CBaseChainParams::TESTNET; - return CBaseChainParams::MAIN; -} - -#ifndef WIN32 -fs::path GetPidFile() -{ - return AbsPathForConfigVal(fs::path(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME))); -} - -void CreatePidFile(const fs::path &path, pid_t pid) -{ - FILE* file = fsbridge::fopen(path, "w"); - if (file) - { - fprintf(file, "%d\n", pid); - fclose(file); - } -} -#endif - -bool RenameOver(fs::path src, fs::path dest) -{ -#ifdef WIN32 - return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), - MOVEFILE_REPLACE_EXISTING) != 0; -#else - int rc = std::rename(src.string().c_str(), dest.string().c_str()); - return (rc == 0); -#endif /* WIN32 */ -} - -/** - * Ignores exceptions thrown by Boost's create_directories if the requested directory exists. - * Specifically handles case where path p exists, but it wasn't possible for the user to - * write to the parent directory. - */ -bool TryCreateDirectories(const fs::path& p) -{ - try - { - return fs::create_directories(p); - } catch (const fs::filesystem_error&) { - if (!fs::exists(p) || !fs::is_directory(p)) - throw; - } - - // create_directories didn't create the directory, it had to have existed already - return false; -} - -bool FileCommit(FILE *file) -{ - if (fflush(file) != 0) { // harmless if redundantly called - LogPrintf("%s: fflush failed: %d\n", __func__, errno); - return false; - } -#ifdef WIN32 - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); - if (FlushFileBuffers(hFile) == 0) { - LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError()); - return false; - } -#else - #if defined(__linux__) || defined(__NetBSD__) - if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync - LogPrintf("%s: fdatasync failed: %d\n", __func__, errno); - return false; - } - #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; - } - #else - if (fsync(fileno(file)) != 0 && errno != EINVAL) { - LogPrintf("%s: fsync failed: %d\n", __func__, errno); - return false; - } - #endif -#endif - return true; -} - -bool TruncateFile(FILE *file, unsigned int length) { -#if defined(WIN32) - return _chsize(_fileno(file), length) == 0; -#else - return ftruncate(fileno(file), length) == 0; -#endif -} - -/** - * this function tries to raise the file descriptor limit to the requested number. - * It returns the actual file descriptor limit (which may be more or less than nMinFD) - */ -int RaiseFileDescriptorLimit(int nMinFD) { -#if defined(WIN32) - return 2048; -#else - struct rlimit limitFD; - if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { - if (limitFD.rlim_cur < (rlim_t)nMinFD) { - limitFD.rlim_cur = nMinFD; - if (limitFD.rlim_cur > limitFD.rlim_max) - limitFD.rlim_cur = limitFD.rlim_max; - setrlimit(RLIMIT_NOFILE, &limitFD); - getrlimit(RLIMIT_NOFILE, &limitFD); - } - return limitFD.rlim_cur; - } - return nMinFD; // getrlimit failed, assume it's fine -#endif -} - -/** - * this function tries to make a particular range of a file allocated (corresponding to disk space) - * it is advisory, and the range specified in the arguments will never contain live data - */ -void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { -#if defined(WIN32) - // Windows-specific version - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); - LARGE_INTEGER nFileSize; - int64_t nEndPos = (int64_t)offset + length; - nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; - nFileSize.u.HighPart = nEndPos >> 32; - SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); - SetEndOfFile(hFile); -#elif defined(MAC_OSX) - // OSX specific version - fstore_t fst; - fst.fst_flags = F_ALLOCATECONTIG; - fst.fst_posmode = F_PEOFPOSMODE; - fst.fst_offset = 0; - fst.fst_length = (off_t)offset + length; - fst.fst_bytesalloc = 0; - if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { - fst.fst_flags = F_ALLOCATEALL; - fcntl(fileno(file), F_PREALLOCATE, &fst); - } - ftruncate(fileno(file), fst.fst_length); -#elif defined(__linux__) - // Version using posix_fallocate - off_t nEndPos = (off_t)offset + length; - posix_fallocate(fileno(file), 0, nEndPos); -#else - // Fallback version - // TODO: just write one byte per block - static const char buf[65536] = {}; - if (fseek(file, offset, SEEK_SET)) { - return; - } - while (length > 0) { - unsigned int now = 65536; - if (length < now) - now = length; - fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway - length -= now; - } -#endif -} - -#ifdef WIN32 -fs::path GetSpecialFolderPath(int nFolder, bool fCreate) -{ - WCHAR pszPath[MAX_PATH] = L""; - - if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) - { - return fs::path(pszPath); - } - - LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n"); - return fs::path(""); -} -#endif - -void runCommand(const std::string& strCommand) -{ - if (strCommand.empty()) return; -#ifndef WIN32 - int nErr = ::system(strCommand.c_str()); -#else - int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str()); -#endif - if (nErr) - LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr); -} - -void RenameThread(const char* name) -{ -#if defined(PR_SET_NAME) - // Only the first 15 characters are used (16 - NUL terminator) - ::prctl(PR_SET_NAME, name, 0, 0, 0); -#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)) - pthread_set_name_np(pthread_self(), name); - -#elif defined(MAC_OSX) - pthread_setname_np(name); -#else - // Prevent warnings for unused parameters... - (void)name; -#endif -} - -void SetupEnvironment() -{ -#ifdef HAVE_MALLOPT_ARENA_MAX - // glibc-specific: On 32-bit systems set the number of arenas to 1. - // By default, since glibc 2.10, the C library will create up to two heap - // arenas per core. This is known to cause excessive virtual address space - // usage in our usage. Work around it by setting the maximum number of - // arenas to 1. - if (sizeof(void*) == 4) { - mallopt(M_ARENA_MAX, 1); - } -#endif - // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale - // may be invalid, in which case the "C" locale is used as fallback. -#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) - try { - std::locale(""); // Raises a runtime error if current locale is invalid - } catch (const std::runtime_error&) { - setenv("LC_ALL", "C", 1); - } -#elif defined(WIN32) - // Set the default input/output charset is utf-8 - SetConsoleCP(CP_UTF8); - SetConsoleOutputCP(CP_UTF8); -#endif - // The path locale is lazy initialized and to avoid deinitialization errors - // in multithreading environments, it is set explicitly by the main thread. - // A dummy locale is used to extract the internal default locale, used by - // fs::path, which is then used to explicitly imbue the path. - std::locale loc = fs::path::imbue(std::locale::classic()); -#ifndef WIN32 - fs::path::imbue(loc); -#else - fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>())); -#endif -} - -bool SetupNetworking() -{ -#ifdef WIN32 - // Initialize Windows Sockets - WSADATA wsadata; - int ret = WSAStartup(MAKEWORD(2,2), &wsadata); - if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2) - return false; -#endif - return true; -} - -int GetNumCores() -{ - return std::thread::hardware_concurrency(); -} - -std::string CopyrightHolders(const std::string& strPrefix) -{ - std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION)); - - // Check for untranslated substitution to make sure Bitcoin Core copyright is not removed by accident - if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Bitcoin Core") == std::string::npos) { - strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers"; - } - return strCopyrightHolders; -} - -// Obtain the application startup time (used for uptime calculation) -int64_t GetStartupTime() -{ - return nStartupTime; -} - -fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific) -{ - return fs::absolute(path, GetDataDir(net_specific)); -} - -int ScheduleBatchPriority() -{ -#ifdef SCHED_BATCH - const static sched_param param{0}; - if (int ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m)) { - LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno)); - return ret; - } - return 0; -#else - return 1; -#endif -} - -namespace util { -#ifdef WIN32 -WinCmdLineArgs::WinCmdLineArgs() -{ - wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); - std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt; - argv = new char*[argc]; - args.resize(argc); - for (int i = 0; i < argc; i++) { - args[i] = utf8_cvt.to_bytes(wargv[i]); - argv[i] = &*args[i].begin(); - } - LocalFree(wargv); -} - -WinCmdLineArgs::~WinCmdLineArgs() -{ - delete[] argv; -} - -std::pair<int, char**> WinCmdLineArgs::get() -{ - return std::make_pair(argc, argv); -} -#endif -} // namespace util |