diff options
Diffstat (limited to 'src/util/system.cpp')
-rw-r--r-- | src/util/system.cpp | 167 |
1 files changed, 120 insertions, 47 deletions
diff --git a/src/util/system.cpp b/src/util/system.cpp index aa9122106b..1953a9f836 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -6,7 +6,16 @@ #include <util/system.h> #ifdef ENABLE_EXTERNAL_SIGNER +#if defined(__GNUC__) +// Boost 1.78 requires the following workaround. +// See: https://github.com/boostorg/process/issues/235 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnarrowing" +#endif #include <boost/process.hpp> +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #endif // ENABLE_EXTERNAL_SIGNER #include <chainparamsbase.h> @@ -16,6 +25,7 @@ #include <util/getuniquepath.h> #include <util/strencodings.h> #include <util/string.h> +#include <util/syserror.h> #include <util/translation.h> @@ -45,16 +55,6 @@ #else -#ifdef _MSC_VER -#pragma warning(disable:4786) -#pragma warning(disable:4804) -#pragma warning(disable:4805) -#pragma warning(disable:4717) -#endif - -#ifndef NOMINMAX -#define NOMINMAX -#endif #include <codecvt> #include <io.h> /* for _commit */ @@ -66,7 +66,6 @@ #include <malloc.h> #endif -#include <boost/algorithm/string/replace.hpp> #include <univalue.h> #include <fstream> @@ -87,7 +86,7 @@ const char * const BITCOIN_SETTINGS_FILENAME = "settings.json"; ArgsManager gArgs; /** Mutex to protect dir_locks. */ -static Mutex cs_dir_locks; +static GlobalMutex cs_dir_locks; /** 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 @@ -95,7 +94,7 @@ static Mutex cs_dir_locks; */ static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks); -bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only) +bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only) { LOCK(cs_dir_locks); fs::path pathLockFile = directory / lockfile_name; @@ -119,7 +118,7 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b return true; } -void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name) +void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name) { LOCK(cs_dir_locks); dir_locks.erase(fs::PathToString(directory / lockfile_name)); @@ -227,7 +226,7 @@ KeyInfo InterpretKey(std::string key) * @return parsed settings value if it is valid, otherwise nullopt accompanied * by a descriptive error string */ -static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string& value, +static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value, unsigned int flags, std::string& error) { // Return negated settings as false values. @@ -237,20 +236,24 @@ static std::optional<util::SettingsValue> InterpretValue(const KeyInfo& key, con return std::nullopt; } // Double negatives like -nofoo=0 are supported (but discouraged) - if (!InterpretBool(value)) { - LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, value); + if (value && !InterpretBool(*value)) { + LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value); return true; } return false; } - return value; + if (!value && (flags & ArgsManager::DISALLOW_ELISION)) { + error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name); + return std::nullopt; + } + return value ? *value : ""; } // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. -ArgsManager::ArgsManager() {} -ArgsManager::~ArgsManager() {} +ArgsManager::ArgsManager() = default; +ArgsManager::~ArgsManager() = default; const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const { @@ -311,7 +314,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin #endif if (key == "-") break; //bitcoin-tx using stdin - std::string val; + std::optional<std::string> val; size_t is_index = key.find('='); if (is_index != std::string::npos) { val = key.substr(is_index + 1); @@ -357,7 +360,7 @@ bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::strin return false; } - std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val, *flags, error); + std::optional<util::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error); if (!value) return false; m_settings.command_line_options[keyinfo.name].push_back(*value); @@ -387,9 +390,12 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } -fs::path ArgsManager::GetPathArg(std::string pathlike_arg) const +fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const { - auto result = fs::PathFromString(GetArg(pathlike_arg, "")).lexically_normal(); + if (IsArgNegated(arg)) return fs::path{}; + std::string path_str = GetArg(arg, ""); + if (path_str.empty()) return default_value; + fs::path result = fs::PathFromString(path_str).lexically_normal(); // Remove trailing slash, if present. return result.has_filename() ? result : result.parent_path(); } @@ -514,14 +520,17 @@ bool ArgsManager::InitSettings(std::string& error) return true; } -bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const +bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const { - if (IsArgNegated("-settings")) { + fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME); + if (settings.empty()) { return false; } + if (backup) { + settings += ".bak"; + } if (filepath) { - std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME); - *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), fs::PathFromString(temp ? settings + ".tmp" : settings)); + *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings); } return true; } @@ -560,10 +569,10 @@ bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors) return true; } -bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const +bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backup) const { fs::path path, path_tmp; - if (!GetSettingsPath(&path, /* temp= */ false) || !GetSettingsPath(&path_tmp, /* temp= */ true)) { + if (!GetSettingsPath(&path, /*temp=*/false, backup) || !GetSettingsPath(&path_tmp, /*temp=*/true, backup)) { throw std::logic_error("Attempt to write settings file when dynamic settings are disabled."); } @@ -580,6 +589,13 @@ bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const return true; } +util::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const +{ + LOCK(cs_args); + return util::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name), + /*ignore_nonpersistent=*/true, /*get_chain_name=*/false); +} + bool ArgsManager::IsArgNegated(const std::string& strArg) const { return GetSetting(strArg).isFalse(); @@ -587,20 +603,75 @@ bool ArgsManager::IsArgNegated(const std::string& strArg) const std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const { + return GetArg(strArg).value_or(strDefault); +} + +std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const +{ const util::SettingsValue value = GetSetting(strArg); - return value.isNull() ? strDefault : value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str(); + return SettingToString(value); +} + +std::optional<std::string> SettingToString(const util::SettingsValue& value) +{ + if (value.isNull()) return std::nullopt; + if (value.isFalse()) return "0"; + if (value.isTrue()) return "1"; + if (value.isNum()) return value.getValStr(); + return value.get_str(); +} + +std::string SettingToString(const util::SettingsValue& value, const std::string& strDefault) +{ + return SettingToString(value).value_or(strDefault); } int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const { + return GetIntArg(strArg).value_or(nDefault); +} + +std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const +{ const util::SettingsValue value = GetSetting(strArg); - return value.isNull() ? nDefault : value.isFalse() ? 0 : value.isTrue() ? 1 : value.isNum() ? value.get_int64() : LocaleIndependentAtoi<int64_t>(value.get_str()); + return SettingToInt(value); +} + +std::optional<int64_t> SettingToInt(const util::SettingsValue& value) +{ + if (value.isNull()) return std::nullopt; + if (value.isFalse()) return 0; + if (value.isTrue()) return 1; + if (value.isNum()) return value.getInt<int64_t>(); + return LocaleIndependentAtoi<int64_t>(value.get_str()); +} + +int64_t SettingToInt(const util::SettingsValue& value, int64_t nDefault) +{ + return SettingToInt(value).value_or(nDefault); } bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const { + return GetBoolArg(strArg).value_or(fDefault); +} + +std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const +{ const util::SettingsValue value = GetSetting(strArg); - return value.isNull() ? fDefault : value.isBool() ? value.get_bool() : InterpretBool(value.get_str()); + return SettingToBool(value); +} + +std::optional<bool> SettingToBool(const util::SettingsValue& value) +{ + if (value.isNull()) return std::nullopt; + if (value.isBool()) return value.get_bool(); + return InterpretBool(value.get_str()); +} + +bool SettingToBool(const util::SettingsValue& value, bool fDefault) +{ + return SettingToBool(value).value_or(fDefault); } bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue) @@ -669,7 +740,7 @@ std::string ArgsManager::GetHelpMessage() const { const bool show_debug = GetBoolArg("-help-debug", false); - std::string usage = ""; + std::string usage; LOCK(cs_args); for (const auto& arg_map : m_available_args) { switch(arg_map.first) { @@ -814,9 +885,9 @@ bool CheckDataDirOption() return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } -fs::path GetConfigFile(const std::string& confPath) +fs::path GetConfigFile(const fs::path& configuration_file_path) { - return AbsPathForConfigVal(fs::PathFromString(confPath), false); + return AbsPathForConfigVal(configuration_file_path, /*net_specific=*/false); } static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections) @@ -841,8 +912,8 @@ static bool GetConfigOptions(std::istream& stream, const std::string& filepath, 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); + std::string name = prefix + TrimString(std::string_view{str}.substr(0, pos), pattern); + std::string_view value = TrimStringView(std::string_view{str}.substr(pos + 1), pattern); if (used_hash && name.find("rpcpassword") != std::string::npos) { error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr); return false; @@ -875,7 +946,7 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& file KeyInfo key = InterpretKey(option.first); std::optional<unsigned int> flags = GetArgFlags('-' + key.name); if (flags) { - std::optional<util::SettingsValue> value = InterpretValue(key, option.second, *flags, error); + std::optional<util::SettingsValue> value = InterpretValue(key, &option.second, *flags, error); if (!value) { return false; } @@ -900,17 +971,17 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) m_config_sections.clear(); } - const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME); - std::ifstream stream{GetConfigFile(confPath)}; + const fs::path conf_path = GetPathArg("-conf", BITCOIN_CONF_FILENAME); + std::ifstream stream{GetConfigFile(conf_path)}; // not ok to have a config file specified that cannot be opened if (IsArgSet("-conf") && !stream.good()) { - error = strprintf("specified config file \"%s\" could not be opened.", confPath); + error = strprintf("specified config file \"%s\" could not be opened.", fs::PathToString(conf_path)); return false; } // ok to not have a config file if (stream.good()) { - if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) { + if (!ReadConfigStream(stream, fs::PathToString(conf_path), error, ignore_invalid_keys)) { return false; } // `-includeconf` cannot be included in the command line arguments except @@ -948,7 +1019,7 @@ bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys) const size_t default_includes = add_includes({}); for (const std::string& conf_file_name : conf_file_names) { - std::ifstream conf_file_stream{GetConfigFile(conf_file_name)}; + std::ifstream conf_file_stream{GetConfigFile(fs::PathFromString(conf_file_name))}; if (conf_file_stream.good()) { if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) { return false; @@ -990,6 +1061,7 @@ std::string ArgsManager::GetChainName() const LOCK(cs_args); util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg), /* ignore_default_section_config= */ false, + /*ignore_nonpersistent=*/false, /* get_chain_name= */ true); return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str()); }; @@ -1022,7 +1094,8 @@ util::SettingsValue ArgsManager::GetSetting(const std::string& arg) const { LOCK(cs_args); return util::GetSetting( - m_settings, m_network, SettingName(arg), !UseDefaultSection(arg), /* get_chain_name= */ false); + m_settings, m_network, SettingName(arg), !UseDefaultSection(arg), + /*ignore_nonpersistent=*/false, /*get_chain_name=*/false); } std::vector<util::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const @@ -1240,7 +1313,7 @@ fs::path GetSpecialFolderPath(int nFolder, bool fCreate) std::string ShellEscape(const std::string& arg) { std::string escaped = arg; - boost::replace_all(escaped, "'", "'\"'\"'"); + ReplaceAll(escaped, "'", "'\"'\"'"); return "'" + escaped + "'"; } #endif @@ -1362,7 +1435,7 @@ void ScheduleBatchPriority() const static sched_param param{}; const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m); if (rc != 0) { - LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(rc)); + LogPrintf("Failed to pthread_setschedparam: %s\n", SysErrorString(rc)); } #endif } |