/Users/eugenesiegel/btc/bitcoin/src/common/args.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2009-2010 Satoshi Nakamoto | 
| 2 |  | // Copyright (c) 2009-present The Bitcoin Core developers | 
| 3 |  | // Distributed under the MIT software license, see the accompanying | 
| 4 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 5 |  |  | 
| 6 |  | #include <common/args.h> | 
| 7 |  |  | 
| 8 |  | #include <chainparamsbase.h> | 
| 9 |  | #include <common/settings.h> | 
| 10 |  | #include <logging.h> | 
| 11 |  | #include <sync.h> | 
| 12 |  | #include <tinyformat.h> | 
| 13 |  | #include <univalue.h> | 
| 14 |  | #include <util/chaintype.h> | 
| 15 |  | #include <util/check.h> | 
| 16 |  | #include <util/fs.h> | 
| 17 |  | #include <util/fs_helpers.h> | 
| 18 |  | #include <util/strencodings.h> | 
| 19 |  | #include <util/string.h> | 
| 20 |  |  | 
| 21 |  | #ifdef WIN32 | 
| 22 |  | #include <codecvt> | 
| 23 |  | #include <shellapi.h> | 
| 24 |  | #include <shlobj.h> | 
| 25 |  | #endif | 
| 26 |  |  | 
| 27 |  | #include <algorithm> | 
| 28 |  | #include <cassert> | 
| 29 |  | #include <cstdint> | 
| 30 |  | #include <cstdlib> | 
| 31 |  | #include <cstring> | 
| 32 |  | #include <map> | 
| 33 |  | #include <optional> | 
| 34 |  | #include <stdexcept> | 
| 35 |  | #include <string> | 
| 36 |  | #include <utility> | 
| 37 |  | #include <variant> | 
| 38 |  |  | 
| 39 |  | const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf"; | 
| 40 |  | const char * const BITCOIN_SETTINGS_FILENAME = "settings.json"; | 
| 41 |  |  | 
| 42 |  | ArgsManager gArgs; | 
| 43 |  |  | 
| 44 |  | /** | 
| 45 |  |  * Interpret a string argument as a boolean. | 
| 46 |  |  * | 
| 47 |  |  * The definition of LocaleIndependentAtoi<int>() requires that non-numeric string values | 
| 48 |  |  * like "foo", return 0. This means that if a user unintentionally supplies a | 
| 49 |  |  * non-integer argument here, the return value is always false. This means that | 
| 50 |  |  * -foo=false does what the user probably expects, but -foo=true is well defined | 
| 51 |  |  * but does not do what they probably expected. | 
| 52 |  |  * | 
| 53 |  |  * The return value of LocaleIndependentAtoi<int>(...) is zero when given input not | 
| 54 |  |  * representable as an int. | 
| 55 |  |  * | 
| 56 |  |  * For a more extensive discussion of this topic (and a wide range of opinions | 
| 57 |  |  * on the Right Way to change this code), see PR12713. | 
| 58 |  |  */ | 
| 59 |  | static bool InterpretBool(const std::string& strValue) | 
| 60 | 205k | { | 
| 61 | 205k |     if (strValue.empty()) | 
| 62 | 153k |         return true; | 
| 63 | 51.2k |     return (LocaleIndependentAtoi<int>(strValue) != 0); | 
| 64 | 205k | } | 
| 65 |  |  | 
| 66 |  | static std::string SettingName(const std::string& arg) | 
| 67 | 8.48M | { | 
| 68 | 8.48M |     return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg0; | 
| 69 | 8.48M | } | 
| 70 |  |  | 
| 71 |  | /** | 
| 72 |  |  * Parse "name", "section.name", "noname", "section.noname" settings keys. | 
| 73 |  |  * | 
| 74 |  |  * @note Where an option was negated can be later checked using the | 
| 75 |  |  * IsArgNegated() method. One use case for this is to have a way to disable | 
| 76 |  |  * options that are not normally boolean (e.g. using -nodebuglogfile to request | 
| 77 |  |  * that debug log output is not sent to any file at all). | 
| 78 |  |  */ | 
| 79 |  | KeyInfo InterpretKey(std::string key) | 
| 80 | 615k | { | 
| 81 | 615k |     KeyInfo result; | 
| 82 |  |     // Split section name from key name for keys like "testnet.foo" or "regtest.bar" | 
| 83 | 615k |     size_t option_index = key.find('.'); | 
| 84 | 615k |     if (option_index != std::string::npos) { | 
| 85 | 0 |         result.section = key.substr(0, option_index); | 
| 86 | 0 |         key.erase(0, option_index + 1); | 
| 87 | 0 |     } | 
| 88 | 615k |     if (key.starts_with("no")) { | 
| 89 | 102k |         key.erase(0, 2); | 
| 90 | 102k |         result.negated = true; | 
| 91 | 102k |     } | 
| 92 | 615k |     result.name = key; | 
| 93 | 615k |     return result; | 
| 94 | 615k | } | 
| 95 |  |  | 
| 96 |  | /** | 
| 97 |  |  * Interpret settings value based on registered flags. | 
| 98 |  |  * | 
| 99 |  |  * @param[in]   key      key information to know if key was negated | 
| 100 |  |  * @param[in]   value    string value of setting to be parsed | 
| 101 |  |  * @param[in]   flags    ArgsManager registered argument flags | 
| 102 |  |  * @param[out]  error    Error description if settings value is not valid | 
| 103 |  |  * | 
| 104 |  |  * @return parsed settings value if it is valid, otherwise nullopt accompanied | 
| 105 |  |  * by a descriptive error string | 
| 106 |  |  */ | 
| 107 |  | std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value, | 
| 108 |  |                                                   unsigned int flags, std::string& error) | 
| 109 | 615k | { | 
| 110 |  |     // Return negated settings as false values. | 
| 111 | 615k |     if (key.negated) { | 
| 112 | 102k |         if (flags & ArgsManager::DISALLOW_NEGATION) { | 
| 113 | 0 |             error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 114 | 0 |             return std::nullopt; | 
| 115 | 0 |         } | 
| 116 |  |         // Double negatives like -nofoo=0 are supported (but discouraged) | 
| 117 | 102k |         if (value && !InterpretBool(*value)0) { | 
| 118 | 0 |             LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key.name, *value);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 119 | 0 |             return true; | 
| 120 | 0 |         } | 
| 121 | 102k |         return false; | 
| 122 | 102k |     } | 
| 123 | 512k |     if (!value && (flags & ArgsManager::DISALLOW_ELISION)205k) { | 
| 124 | 0 |         error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 125 | 0 |         return std::nullopt; | 
| 126 | 0 |     } | 
| 127 | 512k |     return value ? *value307k: ""205k; | 
| 128 | 512k | } | 
| 129 |  |  | 
| 130 |  | // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to | 
| 131 |  | // #include class definitions for all members. | 
| 132 |  | // For example, m_settings has an internal dependency on univalue. | 
| 133 | 51.2k | ArgsManager::ArgsManager() = default; | 
| 134 | 51.2k | ArgsManager::~ArgsManager() = default; | 
| 135 |  |  | 
| 136 |  | std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const | 
| 137 | 51.2k | { | 
| 138 | 51.2k |     std::set<std::string> unsuitables; | 
| 139 |  |  | 
| 140 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 141 |  |  | 
| 142 |  |     // if there's no section selected, don't worry | 
| 143 | 51.2k |     if (m_network.empty()) return std::set<std::string> {}0; | 
| 144 |  |  | 
| 145 |  |     // if it's okay to use the default section for this network, don't worry | 
| 146 | 51.2k |     if (m_network == ChainTypeToString(ChainType::MAIN)) return std::set<std::string> {}0; | 
| 147 |  |  | 
| 148 | 410k |     for (const auto& arg : m_network_only_args)51.2k{ | 
| 149 | 410k |         if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) { | 
| 150 | 0 |             unsuitables.insert(arg); | 
| 151 | 0 |         } | 
| 152 | 410k |     } | 
| 153 | 51.2k |     return unsuitables; | 
| 154 | 51.2k | } | 
| 155 |  |  | 
| 156 |  | std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const | 
| 157 | 51.2k | { | 
| 158 |  |     // Section names to be recognized in the config file. | 
| 159 | 51.2k |     static const std::set<std::string> available_sections{ | 
| 160 | 51.2k |         ChainTypeToString(ChainType::REGTEST), | 
| 161 | 51.2k |         ChainTypeToString(ChainType::SIGNET), | 
| 162 | 51.2k |         ChainTypeToString(ChainType::TESTNET), | 
| 163 | 51.2k |         ChainTypeToString(ChainType::TESTNET4), | 
| 164 | 51.2k |         ChainTypeToString(ChainType::MAIN), | 
| 165 | 51.2k |     }; | 
| 166 |  |  | 
| 167 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 168 | 51.2k |     std::list<SectionInfo> unrecognized = m_config_sections; | 
| 169 | 51.2k |     unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.find(appeared.m_name) != available_sections.end(); }0); | 
| 170 | 51.2k |     return unrecognized; | 
| 171 | 51.2k | } | 
| 172 |  |  | 
| 173 |  | void ArgsManager::SelectConfigNetwork(const std::string& network) | 
| 174 | 51.2k | { | 
| 175 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 176 | 51.2k |     m_network = network; | 
| 177 | 51.2k | } | 
| 178 |  |  | 
| 179 |  | bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error) | 
| 180 | 51.2k | { | 
| 181 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 182 | 51.2k |     m_settings.command_line_options.clear(); | 
| 183 |  |  | 
| 184 | 666k |     for (int i = 1; i < argc; i++615k) { | 
| 185 | 615k |         std::string key(argv[i]); | 
| 186 |  |  | 
| 187 | 615k | #ifdef __APPLE__ | 
| 188 |  |         // At the first time when a user gets the "App downloaded from the | 
| 189 |  |         // internet" warning, and clicks the Open button, macOS passes | 
| 190 |  |         // a unique process serial number (PSN) as -psn_... command-line | 
| 191 |  |         // argument, which we filter out. | 
| 192 | 615k |         if (key.starts_with("-psn_")) continue0; | 
| 193 | 615k | #endif | 
| 194 |  |  | 
| 195 | 615k |         if (key == "-") break0; //bitcoin-tx using stdin | 
| 196 | 615k |         std::optional<std::string> val; | 
| 197 | 615k |         size_t is_index = key.find('='); | 
| 198 | 615k |         if (is_index != std::string::npos) { | 
| 199 | 307k |             val = key.substr(is_index + 1); | 
| 200 | 307k |             key.erase(is_index); | 
| 201 | 307k |         } | 
| 202 |  | #ifdef WIN32 | 
| 203 |  |         key = ToLower(key); | 
| 204 |  |         if (key[0] == '/') | 
| 205 |  |             key[0] = '-'; | 
| 206 |  | #endif | 
| 207 |  |  | 
| 208 | 615k |         if (key[0] != '-') { | 
| 209 | 0 |             if (!m_accept_any_command && m_command.empty()) { | 
| 210 |  |                 // The first non-dash arg is a registered command | 
| 211 | 0 |                 std::optional<unsigned int> flags = GetArgFlags(key); | 
| 212 | 0 |                 if (!flags || !(*flags & ArgsManager::COMMAND)) { | 
| 213 | 0 |                     error = strprintf("Invalid command '%s'", argv[i]);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 214 | 0 |                     return false; | 
| 215 | 0 |                 } | 
| 216 | 0 |             } | 
| 217 | 0 |             m_command.push_back(key); | 
| 218 | 0 |             while (++i < argc) { | 
| 219 |  |                 // The remaining args are command args | 
| 220 | 0 |                 m_command.emplace_back(argv[i]); | 
| 221 | 0 |             } | 
| 222 | 0 |             break; | 
| 223 | 0 |         } | 
| 224 |  |  | 
| 225 |  |         // Transform --foo to -foo | 
| 226 | 615k |         if (key.length() > 1 && key[1] == '-') | 
| 227 | 0 |             key.erase(0, 1); | 
| 228 |  |  | 
| 229 |  |         // Transform -foo to foo | 
| 230 | 615k |         key.erase(0, 1); | 
| 231 | 615k |         KeyInfo keyinfo = InterpretKey(key); | 
| 232 | 615k |         std::optional<unsigned int> flags = GetArgFlags('-' + keyinfo.name); | 
| 233 |  |  | 
| 234 |  |         // Unknown command line options and command line options with dot | 
| 235 |  |         // characters (which are returned from InterpretKey with nonempty | 
| 236 |  |         // section strings) are not valid. | 
| 237 | 615k |         if (!flags || !keyinfo.section.empty()) { | 
| 238 | 0 |             error = strprintf("Invalid parameter %s", argv[i]);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 239 | 0 |             return false; | 
| 240 | 0 |         } | 
| 241 |  |  | 
| 242 | 615k |         std::optional<common::SettingsValue> value = InterpretValue(keyinfo, val ? &*val307k: nullptr307k, *flags, error); | 
| 243 | 615k |         if (!value) return false0; | 
| 244 |  |  | 
| 245 | 615k |         m_settings.command_line_options[keyinfo.name].push_back(*value); | 
| 246 | 615k |     } | 
| 247 |  |  | 
| 248 |  |     // we do not allow -includeconf from command line, only -noincludeconf | 
| 249 | 51.2k |     if (auto* includes = common::FindKey(m_settings.command_line_options, "includeconf")) { | 
| 250 | 0 |         const common::SettingsSpan values{*includes}; | 
| 251 |  |         // Range may be empty if -noincludeconf was passed | 
| 252 | 0 |         if (!values.empty()) { | 
| 253 | 0 |             error = "-includeconf cannot be used from commandline; -includeconf=" + values.begin()->write(); | 
| 254 | 0 |             return false; // pick first value as example | 
| 255 | 0 |         } | 
| 256 | 0 |     } | 
| 257 | 51.2k |     return true; | 
| 258 | 51.2k | } | 
| 259 |  |  | 
| 260 |  | std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const | 
| 261 | 615k | { | 
| 262 | 615k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 615k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 615k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 615k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 615k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 263 | 2.87M |     for (const auto& arg_map : m_available_args) { | 
| 264 | 2.87M |         const auto search = arg_map.second.find(name); | 
| 265 | 2.87M |         if (search != arg_map.second.end()) { | 
| 266 | 615k |             return search->second.m_flags; | 
| 267 | 615k |         } | 
| 268 | 2.87M |     } | 
| 269 | 0 |     return m_default_flags; | 
| 270 | 615k | } | 
| 271 |  |  | 
| 272 |  | void ArgsManager::SetDefaultFlags(std::optional<unsigned int> flags) | 
| 273 | 0 | { | 
| 274 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 275 | 0 |     m_default_flags = flags; | 
| 276 | 0 | } | 
| 277 |  |  | 
| 278 |  | fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const | 
| 279 | 307k | { | 
| 280 | 307k |     if (IsArgNegated(arg)) return fs::path{}51.2k; | 
| 281 | 256k |     std::string path_str = GetArg(arg, ""); | 
| 282 | 256k |     if (path_str.empty()) return default_value0; | 
| 283 | 256k |     fs::path result = fs::PathFromString(path_str).lexically_normal(); | 
| 284 |  |     // Remove trailing slash, if present. | 
| 285 | 256k |     return result.has_filename() ? result : result.parent_path()0; | 
| 286 | 256k | } | 
| 287 |  |  | 
| 288 |  | fs::path ArgsManager::GetBlocksDirPath() const | 
| 289 | 153k | { | 
| 290 | 153k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 153k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 153k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 153k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 153k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 291 | 153k |     fs::path& path = m_cached_blocks_path; | 
| 292 |  |  | 
| 293 |  |     // Cache the path to avoid calling fs::create_directories on every call of | 
| 294 |  |     // this function | 
| 295 | 153k |     if (!path.empty()) return path51.2k; | 
| 296 |  |  | 
| 297 | 102k |     if (IsArgSet("-blocksdir")) { | 
| 298 | 0 |         path = fs::absolute(GetPathArg("-blocksdir")); | 
| 299 | 0 |         if (!fs::is_directory(path)) { | 
| 300 | 0 |             path = ""; | 
| 301 | 0 |             return path; | 
| 302 | 0 |         } | 
| 303 | 102k |     } else { | 
| 304 | 102k |         path = GetDataDirBase(); | 
| 305 | 102k |     } | 
| 306 |  |  | 
| 307 | 102k |     path /= fs::PathFromString(BaseParams().DataDir()); | 
| 308 | 102k |     path /= "blocks"; | 
| 309 | 102k |     fs::create_directories(path); | 
| 310 | 102k |     return path; | 
| 311 | 102k | } | 
| 312 |  |  | 
| 313 |  | fs::path ArgsManager::GetDataDir(bool net_specific) const | 
| 314 | 358k | { | 
| 315 | 358k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 358k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 358k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 358k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 358k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 316 | 358k |     fs::path& path = net_specific ? m_cached_network_datadir_path205k: m_cached_datadir_path153k; | 
| 317 |  |  | 
| 318 |  |     // Used cached path if available | 
| 319 | 358k |     if (!path.empty()) return path153k; | 
| 320 |  |  | 
| 321 | 205k |     const fs::path datadir{GetPathArg("-datadir")}; | 
| 322 | 205k |     if (!datadir.empty()) { | 
| 323 | 205k |         path = fs::absolute(datadir); | 
| 324 | 205k |         if (!fs::is_directory(path)) { | 
| 325 | 0 |             path = ""; | 
| 326 | 0 |             return path; | 
| 327 | 0 |         } | 
| 328 | 205k |     } else { | 
| 329 | 0 |         path = GetDefaultDataDir(); | 
| 330 | 0 |     } | 
| 331 |  |  | 
| 332 | 205k |     if (net_specific && !BaseParams().DataDir().empty()102k) { | 
| 333 | 102k |         path /= fs::PathFromString(BaseParams().DataDir()); | 
| 334 | 102k |     } | 
| 335 |  |  | 
| 336 | 205k |     return path; | 
| 337 | 205k | } | 
| 338 |  |  | 
| 339 |  | void ArgsManager::ClearPathCache() | 
| 340 | 51.2k | { | 
| 341 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 342 |  |  | 
| 343 | 51.2k |     m_cached_datadir_path = fs::path(); | 
| 344 | 51.2k |     m_cached_network_datadir_path = fs::path(); | 
| 345 | 51.2k |     m_cached_blocks_path = fs::path(); | 
| 346 | 51.2k | } | 
| 347 |  |  | 
| 348 |  | std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const | 
| 349 | 0 | { | 
| 350 | 0 |     Command ret; | 
| 351 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 352 | 0 |     auto it = m_command.begin(); | 
| 353 | 0 |     if (it == m_command.end()) { | 
| 354 |  |         // No command was passed | 
| 355 | 0 |         return std::nullopt; | 
| 356 | 0 |     } | 
| 357 | 0 |     if (!m_accept_any_command) { | 
| 358 |  |         // The registered command | 
| 359 | 0 |         ret.command = *(it++); | 
| 360 | 0 |     } | 
| 361 | 0 |     while (it != m_command.end()) { | 
| 362 |  |         // The unregistered command and args (if any) | 
| 363 | 0 |         ret.args.push_back(*(it++)); | 
| 364 | 0 |     } | 
| 365 | 0 |     return ret; | 
| 366 | 0 | } | 
| 367 |  |  | 
| 368 |  | std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const | 
| 369 | 721k | { | 
| 370 | 721k |     std::vector<std::string> result; | 
| 371 | 721k |     for (const common::SettingsValue& value : GetSettingsList(strArg)) { | 
| 372 | 153k |         result.push_back(value.isFalse() ? "0"0: value.isTrue() ? "1"0: value.get_str()); | 
| 373 | 153k |     } | 
| 374 | 721k |     return result; | 
| 375 | 721k | } | 
| 376 |  |  | 
| 377 |  | bool ArgsManager::IsArgSet(const std::string& strArg) const | 
| 378 | 410k | { | 
| 379 | 410k |     return !GetSetting(strArg).isNull(); | 
| 380 | 410k | } | 
| 381 |  |  | 
| 382 |  | bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const | 
| 383 | 0 | { | 
| 384 | 0 |     fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME); | 
| 385 | 0 |     if (settings.empty()) { | 
| 386 | 0 |         return false; | 
| 387 | 0 |     } | 
| 388 | 0 |     if (backup) { | 
| 389 | 0 |         settings += ".bak"; | 
| 390 | 0 |     } | 
| 391 | 0 |     if (filepath) { | 
| 392 | 0 |         *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings); | 
| 393 | 0 |     } | 
| 394 | 0 |     return true; | 
| 395 | 0 | } | 
| 396 |  |  | 
| 397 |  | static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out) | 
| 398 | 0 | { | 
| 399 | 0 |     for (const auto& error : errors) { | 
| 400 | 0 |         if (error_out) { | 
| 401 | 0 |             error_out->emplace_back(error); | 
| 402 | 0 |         } else { | 
| 403 | 0 |             LogPrintf("%s\n", error);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 404 | 0 |         } | 
| 405 | 0 |     } | 
| 406 | 0 | } | 
| 407 |  |  | 
| 408 |  | bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors) | 
| 409 | 0 | { | 
| 410 | 0 |     fs::path path; | 
| 411 | 0 |     if (!GetSettingsPath(&path, /* temp= */ false)) { | 
| 412 | 0 |         return true; // Do nothing if settings file disabled. | 
| 413 | 0 |     } | 
| 414 |  |  | 
| 415 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 416 | 0 |     m_settings.rw_settings.clear(); | 
| 417 | 0 |     std::vector<std::string> read_errors; | 
| 418 | 0 |     if (!common::ReadSettings(path, m_settings.rw_settings, read_errors)) { | 
| 419 | 0 |         SaveErrors(read_errors, errors); | 
| 420 | 0 |         return false; | 
| 421 | 0 |     } | 
| 422 | 0 |     for (const auto& setting : m_settings.rw_settings) { | 
| 423 | 0 |         KeyInfo key = InterpretKey(setting.first); // Split setting key into section and argname | 
| 424 | 0 |         if (!GetArgFlags('-' + key.name)) { | 
| 425 | 0 |             LogPrintf("Ignoring unknown rw_settings value %s\n", setting.first);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 426 | 0 |         } | 
| 427 | 0 |     } | 
| 428 | 0 |     return true; | 
| 429 | 0 | } | 
| 430 |  |  | 
| 431 |  | bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backup) const | 
| 432 | 0 | { | 
| 433 | 0 |     fs::path path, path_tmp; | 
| 434 | 0 |     if (!GetSettingsPath(&path, /*temp=*/false, backup) || !GetSettingsPath(&path_tmp, /*temp=*/true, backup)) { | 
| 435 | 0 |         throw std::logic_error("Attempt to write settings file when dynamic settings are disabled."); | 
| 436 | 0 |     } | 
| 437 |  |  | 
| 438 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 439 | 0 |     std::vector<std::string> write_errors; | 
| 440 | 0 |     if (!common::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) { | 
| 441 | 0 |         SaveErrors(write_errors, errors); | 
| 442 | 0 |         return false; | 
| 443 | 0 |     } | 
| 444 | 0 |     if (!RenameOver(path_tmp, path)) { | 
| 445 | 0 |         SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 446 | 0 |         return false; | 
| 447 | 0 |     } | 
| 448 | 0 |     return true; | 
| 449 | 0 | } | 
| 450 |  |  | 
| 451 |  | common::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const | 
| 452 | 0 | { | 
| 453 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 454 | 0 |     return common::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name), | 
| 455 | 0 |         /*ignore_nonpersistent=*/true, /*get_chain_type=*/false); | 
| 456 | 0 | } | 
| 457 |  |  | 
| 458 |  | bool ArgsManager::IsArgNegated(const std::string& strArg) const | 
| 459 | 358k | { | 
| 460 | 358k |     return GetSetting(strArg).isFalse(); | 
| 461 | 358k | } | 
| 462 |  |  | 
| 463 |  | std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const | 
| 464 | 307k | { | 
| 465 | 307k |     return GetArg(strArg).value_or(strDefault); | 
| 466 | 307k | } | 
| 467 |  |  | 
| 468 |  | std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const | 
| 469 | 820k | { | 
| 470 | 820k |     const common::SettingsValue value = GetSetting(strArg); | 
| 471 | 820k |     return SettingToString(value); | 
| 472 | 820k | } | 
| 473 |  |  | 
| 474 |  | std::optional<std::string> SettingToString(const common::SettingsValue& value) | 
| 475 | 820k | { | 
| 476 | 820k |     if (value.isNull()) return std::nullopt564k; | 
| 477 | 256k |     if (value.isFalse()) return "0"0; | 
| 478 | 256k |     if (value.isTrue()) return "1"0; | 
| 479 | 256k |     if (value.isNum()) return value.getValStr()0; | 
| 480 | 256k |     return value.get_str(); | 
| 481 | 256k | } | 
| 482 |  |  | 
| 483 |  | std::string SettingToString(const common::SettingsValue& value, const std::string& strDefault) | 
| 484 | 0 | { | 
| 485 | 0 |     return SettingToString(value).value_or(strDefault); | 
| 486 | 0 | } | 
| 487 |  |  | 
| 488 |  | int64_t ArgsManager::GetIntArg(const std::string& strArg, int64_t nDefault) const | 
| 489 | 1.02M | { | 
| 490 | 1.02M |     return GetIntArg(strArg).value_or(nDefault); | 
| 491 | 1.02M | } | 
| 492 |  |  | 
| 493 |  | std::optional<int64_t> ArgsManager::GetIntArg(const std::string& strArg) const | 
| 494 | 1.84M | { | 
| 495 | 1.84M |     const common::SettingsValue value = GetSetting(strArg); | 
| 496 | 1.84M |     return SettingToInt(value); | 
| 497 | 1.84M | } | 
| 498 |  |  | 
| 499 |  | std::optional<int64_t> SettingToInt(const common::SettingsValue& value) | 
| 500 | 1.84M | { | 
| 501 | 1.84M |     if (value.isNull()) return std::nullopt1.79M; | 
| 502 | 51.2k |     if (value.isFalse()) return 00; | 
| 503 | 51.2k |     if (value.isTrue()) return 10; | 
| 504 | 51.2k |     if (value.isNum()) return value.getInt<int64_t>()0; | 
| 505 | 51.2k |     return LocaleIndependentAtoi<int64_t>(value.get_str()); | 
| 506 | 51.2k | } | 
| 507 |  |  | 
| 508 |  | int64_t SettingToInt(const common::SettingsValue& value, int64_t nDefault) | 
| 509 | 0 | { | 
| 510 | 0 |     return SettingToInt(value).value_or(nDefault); | 
| 511 | 0 | } | 
| 512 |  |  | 
| 513 |  | bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const | 
| 514 | 3.09M | { | 
| 515 | 3.09M |     return GetBoolArg(strArg).value_or(fDefault); | 
| 516 | 3.09M | } | 
| 517 |  |  | 
| 518 |  | std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const | 
| 519 | 3.55M | { | 
| 520 | 3.55M |     const common::SettingsValue value = GetSetting(strArg); | 
| 521 | 3.55M |     return SettingToBool(value); | 
| 522 | 3.55M | } | 
| 523 |  |  | 
| 524 |  | std::optional<bool> SettingToBool(const common::SettingsValue& value) | 
| 525 | 3.55M | { | 
| 526 | 3.55M |     if (value.isNull()) return std::nullopt3.35M; | 
| 527 | 205k |     if (value.isBool()) return value.get_bool()0; | 
| 528 | 205k |     return InterpretBool(value.get_str()); | 
| 529 | 205k | } | 
| 530 |  |  | 
| 531 |  | bool SettingToBool(const common::SettingsValue& value, bool fDefault) | 
| 532 | 0 | { | 
| 533 | 0 |     return SettingToBool(value).value_or(fDefault); | 
| 534 | 0 | } | 
| 535 |  |  | 
| 536 |  | bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue) | 
| 537 | 0 | { | 
| 538 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 539 | 0 |     if (IsArgSet(strArg)) return false; | 
| 540 | 0 |     ForceSetArg(strArg, strValue); | 
| 541 | 0 |     return true; | 
| 542 | 0 | } | 
| 543 |  |  | 
| 544 |  | bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue) | 
| 545 | 0 | { | 
| 546 | 0 |     if (fValue) | 
| 547 | 0 |         return SoftSetArg(strArg, std::string("1")); | 
| 548 | 0 |     else | 
| 549 | 0 |         return SoftSetArg(strArg, std::string("0")); | 
| 550 | 0 | } | 
| 551 |  |  | 
| 552 |  | void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue) | 
| 553 | 153k | { | 
| 554 | 153k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 153k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 153k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 153k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 153k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 555 | 153k |     m_settings.forced_settings[SettingName(strArg)] = strValue; | 
| 556 | 153k | } | 
| 557 |  |  | 
| 558 |  | void ArgsManager::AddCommand(const std::string& cmd, const std::string& help) | 
| 559 | 0 | { | 
| 560 | 0 |     Assert(cmd.find('=') == std::string::npos);| Line | Count | Source |  | 106 | 0 | #define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 561 | 0 |     Assert(cmd.at(0) != '-'); | Line | Count | Source |  | 106 | 0 | #define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 562 |  | 
 | 
| 563 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 564 | 0 |     m_accept_any_command = false; // latch to false | 
| 565 | 0 |     std::map<std::string, Arg>& arg_map = m_available_args[OptionsCategory::COMMANDS]; | 
| 566 | 0 |     auto ret = arg_map.emplace(cmd, Arg{"", help, ArgsManager::COMMAND}); | 
| 567 | 0 |     Assert(ret.second); // Fail on duplicate commands | Line | Count | Source |  | 106 | 0 | #define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 568 | 0 | } | 
| 569 |  |  | 
| 570 |  | void ArgsManager::AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat) | 
| 571 | 9.84M | { | 
| 572 | 9.84M |     Assert((flags & ArgsManager::COMMAND) == 0); // use AddCommand | Line | Count | Source |  | 106 | 9.84M | #define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 573 |  |  | 
| 574 |  |     // Split arg name from its help param | 
| 575 | 9.84M |     size_t eq_index = name.find('='); | 
| 576 | 9.84M |     if (eq_index == std::string::npos) { | 
| 577 | 4.40M |         eq_index = name.size(); | 
| 578 | 4.40M |     } | 
| 579 | 9.84M |     std::string arg_name = name.substr(0, eq_index); | 
| 580 |  |  | 
| 581 | 9.84M |     LOCK(cs_args); | Line | Count | Source |  | 259 | 9.84M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 9.84M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 9.84M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 9.84M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 582 | 9.84M |     std::map<std::string, Arg>& arg_map = m_available_args[cat]; | 
| 583 | 9.84M |     auto ret = arg_map.emplace(arg_name, Arg{name.substr(eq_index, name.size() - eq_index), help, flags}); | 
| 584 | 9.84M |     assert(ret.second); // Make sure an insertion actually happened | 
| 585 |  |  | 
| 586 | 9.84M |     if (flags & ArgsManager::NETWORK_ONLY) { | 
| 587 | 410k |         m_network_only_args.emplace(arg_name); | 
| 588 | 410k |     } | 
| 589 | 9.84M | } | 
| 590 |  |  | 
| 591 |  | void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names) | 
| 592 | 102k | { | 
| 593 | 1.02M |     for (const std::string& name : names) { | 
| 594 | 1.02M |         AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN); | 
| 595 | 1.02M |     } | 
| 596 | 102k | } | 
| 597 |  |  | 
| 598 |  | void ArgsManager::ClearArgs() | 
| 599 | 51.2k | { | 
| 600 | 51.2k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 51.2k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 51.2k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 51.2k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 51.2k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 601 | 51.2k |     m_settings = {}; | 
| 602 | 51.2k |     m_available_args.clear(); | 
| 603 | 51.2k |     m_network_only_args.clear(); | 
| 604 | 51.2k | } | 
| 605 |  |  | 
| 606 |  | void ArgsManager::CheckMultipleCLIArgs() const | 
| 607 | 0 | { | 
| 608 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 609 | 0 |     std::vector<std::string> found{}; | 
| 610 | 0 |     auto cmds = m_available_args.find(OptionsCategory::CLI_COMMANDS); | 
| 611 | 0 |     if (cmds != m_available_args.end()) { | 
| 612 | 0 |         for (const auto& [cmd, argspec] : cmds->second) { | 
| 613 | 0 |             if (IsArgSet(cmd)) { | 
| 614 | 0 |                 found.push_back(cmd); | 
| 615 | 0 |             } | 
| 616 | 0 |         } | 
| 617 | 0 |         if (found.size() > 1) { | 
| 618 | 0 |             throw std::runtime_error(strprintf("Only one of %s may be specified.", util::Join(found, ", ")));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 619 | 0 |         } | 
| 620 | 0 |     } | 
| 621 | 0 | } | 
| 622 |  |  | 
| 623 |  | std::string ArgsManager::GetHelpMessage() const | 
| 624 | 0 | { | 
| 625 | 0 |     const bool show_debug = GetBoolArg("-help-debug", false); | 
| 626 |  | 
 | 
| 627 | 0 |     std::string usage; | 
| 628 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 629 | 0 |     for (const auto& arg_map : m_available_args) { | 
| 630 | 0 |         switch(arg_map.first) { | 
| 631 | 0 |             case OptionsCategory::OPTIONS: | 
| 632 | 0 |                 usage += HelpMessageGroup("Options:"); | 
| 633 | 0 |                 break; | 
| 634 | 0 |             case OptionsCategory::CONNECTION: | 
| 635 | 0 |                 usage += HelpMessageGroup("Connection options:"); | 
| 636 | 0 |                 break; | 
| 637 | 0 |             case OptionsCategory::ZMQ: | 
| 638 | 0 |                 usage += HelpMessageGroup("ZeroMQ notification options:"); | 
| 639 | 0 |                 break; | 
| 640 | 0 |             case OptionsCategory::DEBUG_TEST: | 
| 641 | 0 |                 usage += HelpMessageGroup("Debugging/Testing options:"); | 
| 642 | 0 |                 break; | 
| 643 | 0 |             case OptionsCategory::NODE_RELAY: | 
| 644 | 0 |                 usage += HelpMessageGroup("Node relay options:"); | 
| 645 | 0 |                 break; | 
| 646 | 0 |             case OptionsCategory::BLOCK_CREATION: | 
| 647 | 0 |                 usage += HelpMessageGroup("Block creation options:"); | 
| 648 | 0 |                 break; | 
| 649 | 0 |             case OptionsCategory::RPC: | 
| 650 | 0 |                 usage += HelpMessageGroup("RPC server options:"); | 
| 651 | 0 |                 break; | 
| 652 | 0 |             case OptionsCategory::IPC: | 
| 653 | 0 |                 usage += HelpMessageGroup("IPC interprocess connection options:"); | 
| 654 | 0 |                 break; | 
| 655 | 0 |             case OptionsCategory::WALLET: | 
| 656 | 0 |                 usage += HelpMessageGroup("Wallet options:"); | 
| 657 | 0 |                 break; | 
| 658 | 0 |             case OptionsCategory::WALLET_DEBUG_TEST: | 
| 659 | 0 |                 if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:"); | 
| 660 | 0 |                 break; | 
| 661 | 0 |             case OptionsCategory::CHAINPARAMS: | 
| 662 | 0 |                 usage += HelpMessageGroup("Chain selection options:"); | 
| 663 | 0 |                 break; | 
| 664 | 0 |             case OptionsCategory::GUI: | 
| 665 | 0 |                 usage += HelpMessageGroup("UI Options:"); | 
| 666 | 0 |                 break; | 
| 667 | 0 |             case OptionsCategory::COMMANDS: | 
| 668 | 0 |                 usage += HelpMessageGroup("Commands:"); | 
| 669 | 0 |                 break; | 
| 670 | 0 |             case OptionsCategory::REGISTER_COMMANDS: | 
| 671 | 0 |                 usage += HelpMessageGroup("Register Commands:"); | 
| 672 | 0 |                 break; | 
| 673 | 0 |             case OptionsCategory::CLI_COMMANDS: | 
| 674 | 0 |                 usage += HelpMessageGroup("CLI Commands:"); | 
| 675 | 0 |                 break; | 
| 676 | 0 |             default: | 
| 677 | 0 |                 break; | 
| 678 | 0 |         } | 
| 679 |  |  | 
| 680 |  |         // When we get to the hidden options, stop | 
| 681 | 0 |         if (arg_map.first == OptionsCategory::HIDDEN) break; | 
| 682 |  |  | 
| 683 | 0 |         for (const auto& arg : arg_map.second) { | 
| 684 | 0 |             if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) { | 
| 685 | 0 |                 std::string name; | 
| 686 | 0 |                 if (arg.second.m_help_param.empty()) { | 
| 687 | 0 |                     name = arg.first; | 
| 688 | 0 |                 } else { | 
| 689 | 0 |                     name = arg.first + arg.second.m_help_param; | 
| 690 | 0 |                 } | 
| 691 | 0 |                 usage += HelpMessageOpt(name, arg.second.m_help_text); | 
| 692 | 0 |             } | 
| 693 | 0 |         } | 
| 694 | 0 |     } | 
| 695 | 0 |     return usage; | 
| 696 | 0 | } | 
| 697 |  |  | 
| 698 |  | bool HelpRequested(const ArgsManager& args) | 
| 699 | 0 | { | 
| 700 | 0 |     return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug"); | 
| 701 | 0 | } | 
| 702 |  |  | 
| 703 |  | void SetupHelpOptions(ArgsManager& args) | 
| 704 | 51.2k | { | 
| 705 | 51.2k |     args.AddArg("-help", "Print this help message and exit (also -h or -?)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | 
| 706 | 51.2k |     args.AddHiddenArgs({"-h", "-?"}); | 
| 707 | 51.2k | } | 
| 708 |  |  | 
| 709 |  | static const int screenWidth = 79; | 
| 710 |  | static const int optIndent = 2; | 
| 711 |  | static const int msgIndent = 7; | 
| 712 |  |  | 
| 713 | 0 | std::string HelpMessageGroup(const std::string &message) { | 
| 714 | 0 |     return std::string(message) + std::string("\n\n"); | 
| 715 | 0 | } | 
| 716 |  |  | 
| 717 | 0 | std::string HelpMessageOpt(const std::string &option, const std::string &message) { | 
| 718 | 0 |     return std::string(optIndent,' ') + std::string(option) + | 
| 719 | 0 |            std::string("\n") + std::string(msgIndent,' ') + | 
| 720 | 0 |            FormatParagraph(message, screenWidth - msgIndent, msgIndent) + | 
| 721 | 0 |            std::string("\n\n"); | 
| 722 | 0 | } | 
| 723 |  |  | 
| 724 |  | const std::vector<std::string> TEST_OPTIONS_DOC{ | 
| 725 |  |     "addrman (use deterministic addrman)", | 
| 726 |  |     "reindex_after_failure_noninteractive_yes (When asked for a reindex after failure interactively, simulate as-if answered with 'yes')", | 
| 727 |  |     "bip94 (enforce BIP94 consensus rules)", | 
| 728 |  | }; | 
| 729 |  |  | 
| 730 |  | bool HasTestOption(const ArgsManager& args, const std::string& test_option) | 
| 731 | 102k | { | 
| 732 | 102k |     const auto options = args.GetArgs("-test"); | 
| 733 | 102k |     return std::any_of(options.begin(), options.end(), [test_option](const auto& option) { | 
| 734 | 0 |         return option == test_option; | 
| 735 | 0 |     }); | 
| 736 | 102k | } | 
| 737 |  |  | 
| 738 |  | fs::path GetDefaultDataDir() | 
| 739 | 0 | { | 
| 740 |  |     // Windows: | 
| 741 |  |     //   old: C:\Users\Username\AppData\Roaming\Bitcoin | 
| 742 |  |     //   new: C:\Users\Username\AppData\Local\Bitcoin | 
| 743 |  |     // macOS: ~/Library/Application Support/Bitcoin | 
| 744 |  |     // Unix-like: ~/.bitcoin | 
| 745 |  | #ifdef WIN32 | 
| 746 |  |     // Windows | 
| 747 |  |     // Check for existence of datadir in old location and keep it there | 
| 748 |  |     fs::path legacy_path = GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin"; | 
| 749 |  |     if (fs::exists(legacy_path)) return legacy_path; | 
| 750 |  |  | 
| 751 |  |     // Otherwise, fresh installs can start in the new, "proper" location | 
| 752 |  |     return GetSpecialFolderPath(CSIDL_LOCAL_APPDATA) / "Bitcoin"; | 
| 753 |  | #else | 
| 754 | 0 |     fs::path pathRet; | 
| 755 | 0 |     char* pszHome = getenv("HOME"); | 
| 756 | 0 |     if (pszHome == nullptr || strlen(pszHome) == 0) | 
| 757 | 0 |         pathRet = fs::path("/"); | 
| 758 | 0 |     else | 
| 759 | 0 |         pathRet = fs::path(pszHome); | 
| 760 | 0 | #ifdef __APPLE__ | 
| 761 |  |     // macOS | 
| 762 | 0 |     return pathRet / "Library/Application Support/Bitcoin"; | 
| 763 |  | #else | 
| 764 |  |     // Unix-like | 
| 765 |  |     return pathRet / ".bitcoin"; | 
| 766 |  | #endif | 
| 767 | 0 | #endif | 
| 768 | 0 | } | 
| 769 |  |  | 
| 770 |  | bool CheckDataDirOption(const ArgsManager& args) | 
| 771 | 0 | { | 
| 772 | 0 |     const fs::path datadir{args.GetPathArg("-datadir")}; | 
| 773 | 0 |     return datadir.empty() || fs::is_directory(fs::absolute(datadir)); | 
| 774 | 0 | } | 
| 775 |  |  | 
| 776 |  | fs::path ArgsManager::GetConfigFilePath() const | 
| 777 | 0 | { | 
| 778 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 779 | 0 |     return *Assert(m_config_path); | Line | Count | Source |  | 106 | 0 | #define Assert(val) inline_assertion_check<true>(val, __FILE__, __LINE__, __func__, #val) | 
 | 
| 780 | 0 | } | 
| 781 |  |  | 
| 782 |  | void ArgsManager::SetConfigFilePath(fs::path path) | 
| 783 | 0 | { | 
| 784 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 785 | 0 |     assert(!m_config_path); | 
| 786 | 0 |     m_config_path = path; | 
| 787 | 0 | } | 
| 788 |  |  | 
| 789 |  | ChainType ArgsManager::GetChainType() const | 
| 790 | 51.2k | { | 
| 791 | 51.2k |     std::variant<ChainType, std::string> arg = GetChainArg(); | 
| 792 | 51.2k |     if (auto* parsed = std::get_if<ChainType>(&arg)) return *parsed; | 
| 793 | 0 |     throw std::runtime_error(strprintf("Unknown chain %s.", std::get<std::string>(arg)));| Line | Count | Source |  | 1172 | 0 | #define strprintf tfm::format | 
 | 
| 794 | 51.2k | } | 
| 795 |  |  | 
| 796 |  | std::string ArgsManager::GetChainTypeString() const | 
| 797 | 0 | { | 
| 798 | 0 |     auto arg = GetChainArg(); | 
| 799 | 0 |     if (auto* parsed = std::get_if<ChainType>(&arg)) return ChainTypeToString(*parsed); | 
| 800 | 0 |     return std::get<std::string>(arg); | 
| 801 | 0 | } | 
| 802 |  |  | 
| 803 |  | std::variant<ChainType, std::string> ArgsManager::GetChainArg() const | 
| 804 | 51.2k | { | 
| 805 | 205k |     auto get_net = [&](const std::string& arg) { | 
| 806 | 205k |         LOCK(cs_args); | Line | Count | Source |  | 259 | 205k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 205k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 205k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 205k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 807 | 205k |         common::SettingsValue value = common::GetSetting(m_settings, /* section= */ "", SettingName(arg), | 
| 808 | 205k |             /* ignore_default_section_config= */ false, | 
| 809 | 205k |             /*ignore_nonpersistent=*/false, | 
| 810 | 205k |             /* get_chain_type= */ true); | 
| 811 | 205k |         return value.isNull() ? false : value.isBool()0? value.get_bool()0: InterpretBool(value.get_str())0; | 
| 812 | 205k |     }; | 
| 813 |  |  | 
| 814 | 51.2k |     const bool fRegTest = get_net("-regtest"); | 
| 815 | 51.2k |     const bool fSigNet  = get_net("-signet"); | 
| 816 | 51.2k |     const bool fTestNet = get_net("-testnet"); | 
| 817 | 51.2k |     const bool fTestNet4 = get_net("-testnet4"); | 
| 818 | 51.2k |     const auto chain_arg = GetArg("-chain"); | 
| 819 |  |  | 
| 820 | 51.2k |     if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet + (int)fTestNet4 > 1) { | 
| 821 | 0 |         throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet, -testnet4 and -chain. Can use at most one."); | 
| 822 | 0 |     } | 
| 823 | 51.2k |     if (chain_arg) { | 
| 824 | 0 |         if (auto parsed = ChainTypeFromString(*chain_arg)) return *parsed; | 
| 825 |  |         // Not a known string, so return original string | 
| 826 | 0 |         return *chain_arg; | 
| 827 | 0 |     } | 
| 828 | 51.2k |     if (fRegTest) return ChainType::REGTEST0; | 
| 829 | 51.2k |     if (fSigNet) return ChainType::SIGNET0; | 
| 830 | 51.2k |     if (fTestNet) return ChainType::TESTNET0; | 
| 831 | 51.2k |     if (fTestNet4) return ChainType::TESTNET40; | 
| 832 | 51.2k |     return ChainType::MAIN; | 
| 833 | 51.2k | } | 
| 834 |  |  | 
| 835 |  | bool ArgsManager::UseDefaultSection(const std::string& arg) const | 
| 836 | 7.71M | { | 
| 837 | 7.71M |     return m_network == ChainTypeToString(ChainType::MAIN) || m_network_only_args.count(arg) == 0; | 
| 838 | 7.71M | } | 
| 839 |  |  | 
| 840 |  | common::SettingsValue ArgsManager::GetSetting(const std::string& arg) const | 
| 841 | 6.99M | { | 
| 842 | 6.99M |     LOCK(cs_args); | Line | Count | Source |  | 259 | 6.99M | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 6.99M | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 6.99M | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 6.99M | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 843 | 6.99M |     return common::GetSetting( | 
| 844 | 6.99M |         m_settings, m_network, SettingName(arg), !UseDefaultSection(arg), | 
| 845 | 6.99M |         /*ignore_nonpersistent=*/false, /*get_chain_type=*/false); | 
| 846 | 6.99M | } | 
| 847 |  |  | 
| 848 |  | std::vector<common::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const | 
| 849 | 721k | { | 
| 850 | 721k |     LOCK(cs_args); | Line | Count | Source |  | 259 | 721k | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 721k | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 721k | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 721k | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 851 | 721k |     return common::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg)); | 
| 852 | 721k | } | 
| 853 |  |  | 
| 854 |  | void ArgsManager::logArgsPrefix( | 
| 855 |  |     const std::string& prefix, | 
| 856 |  |     const std::string& section, | 
| 857 |  |     const std::map<std::string, std::vector<common::SettingsValue>>& args) const | 
| 858 | 0 | { | 
| 859 | 0 |     std::string section_str = section.empty() ? "" : "[" + section + "] "; | 
| 860 | 0 |     for (const auto& arg : args) { | 
| 861 | 0 |         for (const auto& value : arg.second) { | 
| 862 | 0 |             std::optional<unsigned int> flags = GetArgFlags('-' + arg.first); | 
| 863 | 0 |             if (flags) { | 
| 864 | 0 |                 std::string value_str = (*flags & SENSITIVE) ? "****" : value.write(); | 
| 865 | 0 |                 LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 866 | 0 |             } | 
| 867 | 0 |         } | 
| 868 | 0 |     } | 
| 869 | 0 | } | 
| 870 |  |  | 
| 871 |  | void ArgsManager::LogArgs() const | 
| 872 | 0 | { | 
| 873 | 0 |     LOCK(cs_args); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 874 | 0 |     for (const auto& section : m_settings.ro_config) { | 
| 875 | 0 |         logArgsPrefix("Config file arg:", section.first, section.second); | 
| 876 | 0 |     } | 
| 877 | 0 |     for (const auto& setting : m_settings.rw_settings) { | 
| 878 | 0 |         LogPrintf("Setting file arg: %s = %s\n", setting.first, setting.second.write());| Line | Count | Source |  | 361 | 0 | #define LogPrintf(...) LogInfo(__VA_ARGS__) | Line | Count | Source |  | 356 | 0 | #define LogInfo(...) LogPrintLevel_(BCLog::LogFlags::ALL, BCLog::Level::Info, /*should_ratelimit=*/true, __VA_ARGS__) | Line | Count | Source |  | 350 | 0 | #define LogPrintLevel_(category, level, should_ratelimit, ...) LogPrintFormatInternal(std::source_location::current(), category, level, should_ratelimit, __VA_ARGS__) | 
 | 
 | 
 | 
| 879 | 0 |     } | 
| 880 | 0 |     logArgsPrefix("Command-line arg:", "", m_settings.command_line_options); | 
| 881 | 0 | } | 
| 882 |  |  | 
| 883 |  | namespace common { | 
| 884 |  | #ifdef WIN32 | 
| 885 |  | WinCmdLineArgs::WinCmdLineArgs() | 
| 886 |  | { | 
| 887 |  |     wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); | 
| 888 |  |     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt; | 
| 889 |  |     argv = new char*[argc]; | 
| 890 |  |     args.resize(argc); | 
| 891 |  |     for (int i = 0; i < argc; i++) { | 
| 892 |  |         args[i] = utf8_cvt.to_bytes(wargv[i]); | 
| 893 |  |         argv[i] = &*args[i].begin(); | 
| 894 |  |     } | 
| 895 |  |     LocalFree(wargv); | 
| 896 |  | } | 
| 897 |  |  | 
| 898 |  | WinCmdLineArgs::~WinCmdLineArgs() | 
| 899 |  | { | 
| 900 |  |     delete[] argv; | 
| 901 |  | } | 
| 902 |  |  | 
| 903 |  | std::pair<int, char**> WinCmdLineArgs::get() | 
| 904 |  | { | 
| 905 |  |     return std::make_pair(argc, argv); | 
| 906 |  | } | 
| 907 |  | #endif | 
| 908 |  | } // namespace common |