LCOV - code coverage report
Current view: top level - src/common - args.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 91.8 % 546 501
Test Date: 2026-08-07 06:44:34 Functions: 75.2 % 101 76
Branches: 58.5 % 992 580

             Branch data     Line data    Source code
       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 <sync.h>
      11                 :             : #include <tinyformat.h>
      12                 :             : #include <univalue.h>
      13                 :             : #include <util/chaintype.h>
      14                 :             : #include <util/check.h>
      15                 :             : #include <util/fs.h>
      16                 :             : #include <util/fs_helpers.h>
      17                 :             : #include <util/log.h>
      18                 :             : #include <util/strencodings.h>
      19                 :             : #include <util/string.h>
      20                 :             : 
      21                 :             : #ifdef WIN32
      22                 :             : #include <shlobj.h>
      23                 :             : #endif
      24                 :             : 
      25                 :             : #include <algorithm>
      26                 :             : #include <cstdlib>
      27                 :             : #include <cstring>
      28                 :             : #include <map>
      29                 :             : #include <optional>
      30                 :             : #include <stdexcept>
      31                 :             : #include <string>
      32                 :             : #include <utility>
      33                 :             : #include <variant>
      34                 :             : 
      35                 :             : const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
      36                 :             : const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
      37                 :             : 
      38                 :             : ArgsManager gArgs;
      39                 :             : 
      40                 :             : /**
      41                 :             :  * Interpret a string argument as a boolean.
      42                 :             :  *
      43                 :             :  * The definition of LocaleIndependentAtoi<int>() requires that non-numeric string values
      44                 :             :  * like "foo", return 0. This means that if a user unintentionally supplies a
      45                 :             :  * non-integer argument here, the return value is always false. This means that
      46                 :             :  * -foo=false does what the user probably expects, but -foo=true is well defined
      47                 :             :  * but does not do what they probably expected.
      48                 :             :  *
      49                 :             :  * The return value of LocaleIndependentAtoi<int>(...) is zero when given input not
      50                 :             :  * representable as an int.
      51                 :             :  *
      52                 :             :  * For a more extensive discussion of this topic (and a wide range of opinions
      53                 :             :  * on the Right Way to change this code), see PR12713.
      54                 :             :  */
      55                 :      377850 : static bool InterpretBool(const std::string& strValue)
      56                 :             : {
      57         [ +  + ]:      377850 :     if (strValue.empty())
      58                 :             :         return true;
      59         [ -  + ]:      358974 :     return (LocaleIndependentAtoi<int>(strValue) != 0);
      60                 :             : }
      61                 :             : 
      62                 :     1234572 : static std::string SettingName(const std::string& arg)
      63                 :             : {
      64   [ -  +  +  -  :     1235830 :     return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
                   +  + ]
      65                 :             : }
      66                 :             : 
      67                 :             : /**
      68                 :             :  * Parse "name", "section.name", "noname", "section.noname" settings keys.
      69                 :             :  *
      70                 :             :  * @note Where an option was negated can be later checked using the
      71                 :             :  * IsArgNegated() method. One use case for this is to have a way to disable
      72                 :             :  * options that are not normally boolean (e.g. using -nodebuglogfile to request
      73                 :             :  * that debug log output is not sent to any file at all).
      74                 :             :  */
      75                 :      390721 : KeyInfo InterpretKey(std::string key)
      76                 :             : {
      77   [ +  +  +  + ]:      781442 :     KeyInfo result;
      78                 :             :     // Split section name from key name for keys like "testnet.foo" or "regtest.bar"
      79                 :      390721 :     size_t option_index = key.find('.');
      80         [ +  + ]:      390721 :     if (option_index != std::string::npos) {
      81         [ +  - ]:      141208 :         result.section = key.substr(0, option_index);
      82         [ +  - ]:      141208 :         key.erase(0, option_index + 1);
      83                 :             :     }
      84   [ -  +  +  + ]:      390721 :     if (key.starts_with("no")) {
      85         [ +  - ]:      105633 :         key.erase(0, 2);
      86                 :      105633 :         result.negated = true;
      87                 :             :     }
      88         [ +  - ]:      390721 :     result.name = key;
      89                 :      390721 :     return result;
      90                 :           0 : }
      91                 :             : 
      92                 :             : /**
      93                 :             :  * Interpret settings value based on registered flags.
      94                 :             :  *
      95                 :             :  * @param[in]   key      key information to know if key was negated
      96                 :             :  * @param[in]   value    string value of setting to be parsed
      97                 :             :  * @param[in]   flags    ArgsManager registered argument flags
      98                 :             :  * @param[out]  error    Error description if settings value is not valid
      99                 :             :  *
     100                 :             :  * @return parsed settings value if it is valid, otherwise nullopt accompanied
     101                 :             :  * by a descriptive error string
     102                 :             :  */
     103                 :      369046 : std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
     104                 :             :                                                   unsigned int flags, std::string& error)
     105                 :             : {
     106                 :             :     // Return negated settings as false values.
     107         [ +  + ]:      369046 :     if (key.negated) {
     108         [ -  + ]:      105632 :         if (flags & ArgsManager::DISALLOW_NEGATION) {
     109                 :           0 :             error = strprintf("Negating of -%s is meaningless and therefore forbidden", key.name);
     110                 :           0 :             return std::nullopt;
     111                 :             :         }
     112                 :             :         // Double negatives like -nofoo=0 are supported (but discouraged)
     113   [ +  +  +  + ]:      105632 :         if (value && !InterpretBool(*value)) {
     114                 :          12 :             LogWarning("Parsed potentially confusing double-negative -%s=%s", key.name, *value);
     115                 :          12 :             return true;
     116                 :             :         }
     117                 :      105620 :         return false;
     118                 :             :     }
     119   [ +  +  +  + ]:      263414 :     if (!value && (flags & ArgsManager::DISALLOW_ELISION)) {
     120                 :           1 :         error = strprintf("Can not set -%s with no value. Please specify value with -%s=value.", key.name, key.name);
     121                 :           1 :         return std::nullopt;
     122                 :             :     }
     123         [ +  - ]:      263413 :     return value ? *value : "";
     124                 :             : }
     125                 :             : 
     126                 :             : // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
     127                 :             : // #include class definitions for all members.
     128                 :             : // For example, m_settings has an internal dependency on univalue.
     129                 :       52246 : ArgsManager::ArgsManager() = default;
     130         [ +  + ]:      261225 : ArgsManager::~ArgsManager() = default;
     131                 :             : 
     132                 :       49410 : std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
     133                 :             : {
     134         [ +  - ]:       49410 :     std::set<std::string> unsuitables;
     135                 :             : 
     136         [ +  - ]:       49410 :     LOCK(cs_args);
     137                 :             : 
     138                 :             :     // if there's no section selected, don't worry
     139         [ -  + ]:       49410 :     if (m_network.empty()) return std::set<std::string> {};
     140                 :             : 
     141                 :             :     // if it's okay to use the default section for this network, don't worry
     142   [ +  -  +  + ]:       49410 :     if (m_network == ChainTypeToString(ChainType::MAIN)) return std::set<std::string> {};
     143                 :             : 
     144         [ +  + ]:       65259 :     for (const auto& arg : m_network_only_args) {
     145   [ +  -  +  -  :       28328 :         if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) {
                   +  + ]
     146         [ +  - ]:        1753 :             unsuitables.insert(arg);
     147                 :             :         }
     148                 :             :     }
     149                 :       36931 :     return unsuitables;
     150                 :       49410 : }
     151                 :             : 
     152                 :        1921 : std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
     153                 :             : {
     154                 :             :     // Section names to be recognized in the config file.
     155                 :        1921 :     static const std::set<std::string> available_sections{
     156                 :             :         ChainTypeToString(ChainType::REGTEST),
     157                 :             :         ChainTypeToString(ChainType::SIGNET),
     158                 :             :         ChainTypeToString(ChainType::TESTNET),
     159                 :             :         ChainTypeToString(ChainType::TESTNET4),
     160                 :             :         ChainTypeToString(ChainType::MAIN),
     161   [ +  +  +  -  :        9925 :     };
          -  +  +  +  -  
                      - ]
     162                 :             : 
     163                 :        1921 :     LOCK(cs_args);
     164         [ +  - ]:        1921 :     std::list<SectionInfo> unrecognized = m_config_sections;
     165                 :        3131 :     unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.contains(appeared.m_name); });
     166         [ +  - ]:        1921 :     return unrecognized;
     167   [ +  -  +  -  :        3255 : }
          +  -  +  -  +  
                -  -  - ]
     168                 :             : 
     169                 :       51035 : void ArgsManager::SelectConfigNetwork(const std::string& network)
     170                 :             : {
     171                 :       51035 :     LOCK(cs_args);
     172   [ +  -  +  - ]:      102070 :     m_network = network;
     173                 :       51035 : }
     174                 :             : 
     175                 :       52170 : bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
     176                 :             : {
     177                 :       52170 :     LOCK(cs_args);
     178                 :       52170 :     m_settings.command_line_options.clear();
     179                 :             : 
     180         [ +  + ]:      205267 :     for (int i = 1; i < argc; i++) {
     181         [ +  - ]:      154001 :         std::string key(argv[i]);
     182                 :             : 
     183                 :             : #ifdef __APPLE__
     184                 :             :         // At the first time when a user gets the "App downloaded from the
     185                 :             :         // internet" warning, and clicks the Open button, macOS passes
     186                 :             :         // a unique process serial number (PSN) as -psn_... command-line
     187                 :             :         // argument, which we filter out.
     188                 :             :         if (key.starts_with("-psn_")) continue;
     189                 :             : #endif
     190                 :             : 
     191         [ +  + ]:      154001 :         if (key == "-") break; //bitcoin-tx using stdin
     192                 :      153989 :         std::optional<std::string> val;
     193                 :      153989 :         size_t is_index = key.find('=');
     194         [ +  + ]:      153989 :         if (is_index != std::string::npos) {
     195         [ +  - ]:      140867 :             val = key.substr(is_index + 1);
     196         [ +  - ]:      140867 :             key.erase(is_index);
     197                 :             :         }
     198                 :             : #ifdef WIN32
     199                 :             :         key = ToLower(key);
     200                 :             :         if (key[0] == '/')
     201                 :             :             key[0] = '-';
     202                 :             : #endif
     203                 :             : 
     204         [ +  + ]:      153989 :         if (key[0] != '-') {
     205   [ +  +  +  - ]:         880 :             if (!m_accept_any_command && m_command.empty()) {
     206                 :             :                 // The first non-dash arg is a registered command
     207         [ +  - ]:          65 :                 std::optional<unsigned int> flags = GetArgFlags_(key);
     208   [ +  +  -  + ]:          65 :                 if (!flags || !(*flags & ArgsManager::COMMAND)) {
     209         [ +  - ]:           5 :                     error = strprintf("Invalid command '%s'", argv[i]);
     210                 :           5 :                     return false;
     211                 :             :                 }
     212                 :             :             }
     213         [ +  - ]:         875 :             m_command.push_back(key);
     214         [ +  + ]:        1933 :             while (++i < argc) {
     215                 :             :                 // The remaining args are command args
     216         [ +  - ]:        1058 :                 m_command.emplace_back(argv[i]);
     217                 :             :             }
     218                 :         875 :             break;
     219                 :             :         }
     220                 :             : 
     221                 :             :         // Transform --foo to -foo
     222   [ -  +  +  -  :      153109 :         if (key.length() > 1 && key[1] == '-')
                   +  + ]
     223         [ +  - ]:           6 :             key.erase(0, 1);
     224                 :             : 
     225                 :             :         // Transform -foo to foo
     226         [ +  - ]:      153109 :         key.erase(0, 1);
     227   [ -  +  +  - ]:      306218 :         KeyInfo keyinfo = InterpretKey(key);
     228   [ +  -  +  - ]:      153109 :         std::optional<unsigned int> flags = GetArgFlags_('-' + keyinfo.name);
     229                 :             : 
     230                 :             :         // Unknown command line options and command line options with dot
     231                 :             :         // characters (which are returned from InterpretKey with nonempty
     232                 :             :         // section strings) are not valid.
     233   [ +  +  +  + ]:      153109 :         if (!flags || !keyinfo.section.empty()) {
     234         [ +  - ]:          11 :             error = strprintf("Invalid parameter %s", argv[i]);
     235                 :          11 :             return false;
     236                 :             :         }
     237                 :             : 
     238   [ +  +  +  - ]:      165418 :         std::optional<common::SettingsValue> value = InterpretValue(keyinfo, val ? &*val : nullptr, *flags, error);
     239         [ +  + ]:      153098 :         if (!value) return false;
     240                 :             : 
     241   [ +  -  +  - ]:      153097 :         m_settings.command_line_options[keyinfo.name].push_back(*value);
     242                 :      307986 :     }
     243                 :             : 
     244                 :             :     // we do not allow -includeconf from command line, only -noincludeconf
     245   [ +  -  +  + ]:       52153 :     if (auto* includes = common::FindKey(m_settings.command_line_options, "includeconf")) {
     246                 :           5 :         const common::SettingsSpan values{*includes};
     247                 :             :         // Range may be empty if -noincludeconf was passed
     248   [ +  -  +  + ]:           5 :         if (!values.empty()) {
     249   [ +  -  +  -  :           4 :             error = "-includeconf cannot be used from commandline; -includeconf=" + values.begin()->write();
                   +  - ]
     250                 :           4 :             return false; // pick first value as example
     251                 :             :         }
     252                 :             :     }
     253                 :             :     return true;
     254                 :       52170 : }
     255                 :             : 
     256                 :      433486 : std::optional<unsigned int> ArgsManager::GetArgFlags_(const std::string& name) const
     257                 :             : {
     258                 :      433486 :     AssertLockHeld(cs_args);
     259         [ +  + ]:      908004 :     for (const auto& arg_map : m_available_args) {
     260                 :      886456 :         const auto search = arg_map.second.find(name);
     261         [ +  + ]:      886456 :         if (search != arg_map.second.end()) {
     262                 :      411938 :             return search->second.m_flags;
     263                 :             :         }
     264                 :             :     }
     265                 :       21548 :     return m_default_flags;
     266                 :             : }
     267                 :             : 
     268                 :           0 : std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
     269                 :             : {
     270                 :           0 :     LOCK(cs_args);
     271         [ #  # ]:           0 :     return GetArgFlags_(name);
     272                 :           0 : }
     273                 :             : 
     274                 :           0 : void ArgsManager::SetDefaultFlags(std::optional<unsigned int> flags)
     275                 :             : {
     276                 :           0 :     LOCK(cs_args);
     277         [ #  # ]:           0 :     m_default_flags = flags;
     278                 :           0 : }
     279                 :             : 
     280                 :       31055 : fs::path ArgsManager::GetPathArg_(std::string arg, const fs::path& default_value) const
     281                 :             : {
     282                 :       31055 :     AssertLockHeld(cs_args);
     283                 :       31055 :     const auto value = GetSetting_(arg);
     284         [ +  + ]:       31055 :     if (value.isFalse()) return {};
     285   [ +  -  +  - ]:       31045 :     std::string path_str = SettingToString(value, "");
     286   [ +  +  +  - ]:       44501 :     if (path_str.empty()) return default_value;
     287   [ +  -  +  - ]:       40368 :     fs::path result = fs::PathFromString(path_str).lexically_normal();
     288                 :             :     // Remove trailing slash, if present.
     289   [ +  +  +  -  :       40368 :     return result.has_filename() ? result : result.parent_path();
                   +  - ]
     290                 :       44511 : }
     291                 :             : 
     292                 :       21201 : fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const
     293                 :             : {
     294                 :       21201 :     LOCK(cs_args);
     295   [ +  -  +  - ]:       42402 :     return GetPathArg_(std::move(arg), default_value);
     296                 :       21201 : }
     297                 :             : 
     298                 :        9004 : fs::path ArgsManager::GetBlocksDirPath() const
     299                 :             : {
     300                 :        9004 :     LOCK(cs_args);
     301                 :        9004 :     fs::path& path = m_cached_blocks_path;
     302                 :             : 
     303                 :             :     // Cache the path to avoid calling fs::create_directories on every call of
     304                 :             :     // this function
     305   [ +  +  +  - ]:        9004 :     if (!path.empty()) return path;
     306                 :             : 
     307   [ +  -  +  -  :        2089 :     if (!GetSetting_("-blocksdir").isNull()) {
                   +  + ]
     308   [ +  -  +  -  :          12 :         path = fs::absolute(GetPathArg_("-blocksdir"));
                   +  - ]
     309   [ +  -  +  + ]:           3 :         if (!fs::is_directory(path)) {
     310         [ +  - ]:           1 :             path = "";
     311         [ +  - ]:           1 :             return path;
     312                 :             :         }
     313                 :             :     } else {
     314         [ +  - ]:        6258 :         path = GetDataDir(/*net_specific=*/false);
     315                 :             :     }
     316                 :             : 
     317   [ +  -  +  - ]:        4176 :     path /= fs::PathFromString(BaseParams().DataDir());
     318         [ +  - ]:        2088 :     path /= "blocks";
     319         [ +  - ]:        2088 :     fs::create_directories(path);
     320   [ +  -  +  - ]:        9004 :     return path;
     321                 :        9004 : }
     322                 :             : 
     323                 :        3932 : fs::path ArgsManager::GetDataDirBase() const {
     324                 :        3932 :     LOCK(cs_args);
     325         [ +  - ]:        3932 :     return GetDataDir(/*net_specific=*/false);
     326                 :        3932 : }
     327                 :             : 
     328                 :       36371 : fs::path ArgsManager::GetDataDirNet() const {
     329                 :       36371 :     LOCK(cs_args);
     330         [ +  - ]:       36371 :     return GetDataDir(/*net_specific=*/true);
     331                 :       36371 : }
     332                 :             : 
     333                 :       44653 : fs::path ArgsManager::GetDataDir(bool net_specific) const
     334                 :             : {
     335                 :       44653 :     AssertLockHeld(cs_args);
     336         [ +  + ]:       44653 :     fs::path& path = net_specific ? m_cached_network_datadir_path : m_cached_datadir_path;
     337                 :             : 
     338                 :             :     // Used cached path if available
     339         [ +  + ]:       44653 :     if (!path.empty()) return path;
     340                 :             : 
     341   [ +  -  +  - ]:       15154 :     const fs::path datadir{GetPathArg_("-datadir")};
     342         [ +  + ]:        7577 :     if (!datadir.empty()) {
     343         [ +  - ]:       15144 :         path = fs::absolute(datadir);
     344   [ +  -  -  + ]:        7572 :         if (!fs::is_directory(path)) {
     345         [ #  # ]:           0 :             path = "";
     346         [ #  # ]:           0 :             return path;
     347                 :             :         }
     348                 :             :     } else {
     349         [ +  - ]:          15 :         path = GetDefaultDataDir();
     350                 :             :     }
     351                 :             : 
     352   [ +  +  +  -  :        7577 :     if (net_specific && !BaseParams().DataDir().empty()) {
                   +  + ]
     353   [ +  -  +  - ]:        7419 :         path /= fs::PathFromString(BaseParams().DataDir());
     354                 :             :     }
     355                 :             : 
     356         [ +  - ]:        7577 :     return path;
     357                 :        7577 : }
     358                 :             : 
     359                 :        2973 : void ArgsManager::ClearPathCache()
     360                 :             : {
     361                 :        2973 :     LOCK(cs_args);
     362                 :             : 
     363                 :        2973 :     m_cached_datadir_path = fs::path();
     364                 :        2973 :     m_cached_network_datadir_path = fs::path();
     365         [ +  - ]:        5946 :     m_cached_blocks_path = fs::path();
     366                 :        2973 : }
     367                 :             : 
     368                 :          62 : std::optional<const ArgsManager::Command> ArgsManager::GetCommand() const
     369                 :             : {
     370         [ +  - ]:          62 :     Command ret;
     371         [ +  - ]:          62 :     LOCK(cs_args);
     372         [ +  + ]:          62 :     auto it = m_command.begin();
     373         [ +  + ]:          62 :     if (it == m_command.end()) {
     374                 :             :         // No command was passed
     375                 :           2 :         return std::nullopt;
     376                 :             :     }
     377         [ +  - ]:          60 :     if (!m_accept_any_command) {
     378                 :             :         // The registered command
     379         [ +  - ]:          60 :         ret.command = *(it++);
     380                 :             :     }
     381         [ +  + ]:          72 :     while (it != m_command.end()) {
     382                 :             :         // The unregistered command and args (if any)
     383         [ +  - ]:          12 :         ret.args.push_back(*(it++));
     384                 :             :     }
     385                 :          60 :     return ret;
     386                 :         124 : }
     387                 :             : 
     388                 :          44 : bool ArgsManager::CheckCommandOptions(const std::string& command, std::vector<std::string>* errors) const
     389                 :             : {
     390                 :          44 :     LOCK(cs_args);
     391                 :             : 
     392                 :          44 :     auto command_options = m_available_args.find(OptionsCategory::COMMAND_OPTIONS);
     393         [ +  - ]:          44 :     if (command_options == m_available_args.end()) {
     394                 :             :         // There are no command-specific options at all, so everything is fine
     395                 :             :         return true;
     396                 :             :     }
     397                 :             : 
     398                 :          44 :     const auto command_args = m_command_args.find(command);
     399                 :          76 :     auto is_valid_opt = [&](const auto& opt) EXCLUSIVE_LOCKS_REQUIRED(cs_args) -> bool {
     400         [ +  + ]:          32 :         if (command_args == m_command_args.end()) {
     401                 :             :             // Caller may not have checked that command actually exists
     402                 :             :             // before calling this function.  In that case, treat it as
     403                 :             :             // having no valid command-specific options.
     404                 :             :             return false;
     405                 :             :         } else {
     406                 :          27 :             return command_args->second.contains(opt);
     407                 :             :         }
     408                 :          44 :     };
     409                 :             : 
     410                 :          44 :     bool ok = true;
     411   [ +  -  +  + ]:         101 :     for (const auto& [arg, _] : command_options->second) {
     412   [ +  -  +  +  :          82 :         if (!GetSetting_(arg).isNull() && !is_valid_opt(arg)) {
             +  +  +  + ]
     413                 :           7 :             ok = false;
     414         [ +  - ]:           7 :             if (errors != nullptr) {
     415   [ +  -  +  - ]:          14 :                 errors->emplace_back(strprintf("The %s option cannot be used with the '%s' command.", arg, command));
     416                 :             :             }
     417                 :             :         }
     418                 :             :     }
     419                 :             :     return ok;
     420                 :          44 : }
     421                 :             : 
     422                 :      235185 : std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
     423                 :             : {
     424                 :      235185 :     std::vector<std::string> result;
     425   [ +  -  +  + ]:      331321 :     for (const common::SettingsValue& value : GetSettingsList(strArg)) {
     426   [ -  +  -  -  :      288404 :         result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
          +  +  +  -  +  
             -  -  +  +  
                      - ]
     427                 :             :     }
     428                 :      235185 :     return result;
     429                 :           0 : }
     430                 :             : 
     431                 :       78310 : bool ArgsManager::IsArgSet(const std::string& strArg) const
     432                 :             : {
     433                 :       78310 :     return !GetSetting(strArg).isNull();
     434                 :             : }
     435                 :             : 
     436                 :        5292 : bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp, bool backup) const
     437                 :             : {
     438   [ +  -  +  - ]:       10584 :     fs::path settings = GetPathArg("-settings", BITCOIN_SETTINGS_FILENAME);
     439         [ +  + ]:        5292 :     if (settings.empty()) {
     440                 :             :         return false;
     441                 :             :     }
     442         [ -  + ]:        5289 :     if (backup) {
     443         [ #  # ]:           0 :         settings += ".bak";
     444                 :             :     }
     445         [ +  + ]:        5289 :     if (filepath) {
     446   [ +  +  +  -  :       27238 :         *filepath = fsbridge::AbsPathJoin(GetDataDirNet(), temp ? settings + ".tmp" : settings);
          +  -  +  -  +  
                +  -  - ]
     447                 :             :     }
     448                 :             :     return true;
     449                 :        5292 : }
     450                 :             : 
     451                 :           4 : static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out)
     452                 :             : {
     453         [ +  + ]:           8 :     for (const auto& error : errors) {
     454         [ +  + ]:           4 :         if (error_out) {
     455                 :           3 :             error_out->emplace_back(error);
     456                 :             :         } else {
     457                 :           1 :             LogWarning("%s", error);
     458                 :             :         }
     459                 :             :     }
     460                 :           4 : }
     461                 :             : 
     462                 :        1224 : bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
     463                 :             : {
     464                 :        1224 :     fs::path path;
     465   [ +  -  +  - ]:        1224 :     if (!GetSettingsPath(&path, /* temp= */ false)) {
     466                 :             :         return true; // Do nothing if settings file disabled.
     467                 :             :     }
     468                 :             : 
     469         [ +  - ]:        1224 :     LOCK(cs_args);
     470                 :        1224 :     m_settings.rw_settings.clear();
     471                 :        1224 :     std::vector<std::string> read_errors;
     472   [ +  -  +  + ]:        1224 :     if (!common::ReadSettings(path, m_settings.rw_settings, read_errors)) {
     473   [ +  -  +  - ]:           3 :         SaveErrors(read_errors, errors);
     474                 :           3 :         return false;
     475                 :             :     }
     476         [ +  + ]:        1357 :     for (const auto& setting : m_settings.rw_settings) {
     477   [ -  +  +  - ]:         272 :         KeyInfo key = InterpretKey(setting.first); // Split setting key into section and argname
     478   [ +  -  +  -  :         136 :         if (!GetArgFlags_('-' + key.name)) {
                   +  + ]
     479         [ +  - ]:         136 :             LogWarning("Ignoring unknown rw_settings value %s", setting.first);
     480                 :             :         }
     481                 :         136 :     }
     482                 :             :     return true;
     483         [ +  - ]:        3672 : }
     484                 :             : 
     485                 :        1421 : bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors, bool backup) const
     486                 :             : {
     487                 :        1421 :     fs::path path, path_tmp;
     488   [ +  -  +  -  :        1421 :     if (!GetSettingsPath(&path, /*temp=*/false, backup) || !GetSettingsPath(&path_tmp, /*temp=*/true, backup)) {
             +  -  -  + ]
     489         [ #  # ]:           0 :         throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
     490                 :             :     }
     491                 :             : 
     492         [ +  - ]:        1421 :     LOCK(cs_args);
     493                 :        1421 :     std::vector<std::string> write_errors;
     494   [ +  -  -  + ]:        1421 :     if (!common::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
     495   [ #  #  #  # ]:           0 :         SaveErrors(write_errors, errors);
     496                 :           0 :         return false;
     497                 :             :     }
     498   [ +  -  +  -  :        4263 :     if (!RenameOver(path_tmp, path)) {
             +  -  +  + ]
     499   [ -  +  +  -  :           4 :         SaveErrors({strprintf("Failed renaming settings file %s to %s\n", fs::PathToString(path_tmp), fs::PathToString(path))}, errors);
          +  -  +  +  -  
                      - ]
     500                 :           1 :         return false;
     501                 :             :     }
     502                 :             :     return true;
     503   [ -  +  +  -  :        5686 : }
                   +  - ]
     504                 :             : 
     505                 :           0 : common::SettingsValue ArgsManager::GetPersistentSetting(const std::string& name) const
     506                 :             : {
     507                 :           0 :     LOCK(cs_args);
     508   [ #  #  #  #  :           0 :     return common::GetSetting(m_settings, m_network, name, !UseDefaultSection("-" + name),
                   #  # ]
     509         [ #  # ]:           0 :         /*ignore_nonpersistent=*/true, /*get_chain_type=*/false);
     510                 :           0 : }
     511                 :             : 
     512                 :       53911 : bool ArgsManager::IsArgNegated(const std::string& strArg) const
     513                 :             : {
     514                 :       53911 :     return GetSetting(strArg).isFalse();
     515                 :             : }
     516                 :             : 
     517                 :       65726 : std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
     518                 :             : {
     519         [ +  - ]:      131450 :     return GetArg(strArg).value_or(strDefault);
     520                 :             : }
     521                 :             : 
     522                 :      106465 : std::optional<std::string> ArgsManager::GetArg(const std::string& strArg) const
     523                 :             : {
     524                 :      106465 :     const common::SettingsValue value = GetSetting(strArg);
     525         [ +  + ]:      212928 :     return SettingToString(value);
     526                 :      106465 : }
     527                 :             : 
     528                 :      137510 : std::optional<std::string> SettingToString(const common::SettingsValue& value)
     529                 :             : {
     530         [ +  + ]:      137510 :     if (value.isNull()) return std::nullopt;
     531         [ +  + ]:       66844 :     if (value.isFalse()) return "0";
     532         [ +  + ]:       55129 :     if (value.isTrue()) return "1";
     533   [ +  +  -  + ]:       55124 :     if (value.isNum()) return value.getValStr();
     534         [ -  + ]:      110234 :     return value.get_str();
     535                 :             : }
     536                 :             : 
     537                 :       31045 : std::string SettingToString(const common::SettingsValue& value, const std::string& strDefault)
     538                 :             : {
     539         [ +  - ]:       62090 :     return SettingToString(value).value_or(strDefault);
     540                 :             : }
     541                 :             : 
     542                 :             : template <std::integral Int>
     543                 :      103262 : Int ArgsManager::GetArg(const std::string& strArg, Int nDefault) const
     544                 :             : {
     545         [ +  + ]:      103262 :     return GetArg<Int>(strArg).value_or(nDefault);
     546                 :             : }
     547                 :             : 
     548                 :             : template <std::integral Int>
     549                 :      145427 : std::optional<Int> ArgsManager::GetArg(const std::string& strArg) const
     550                 :             : {
     551                 :      145427 :     const common::SettingsValue value = GetSetting(strArg);
     552         [ +  + ]:      290851 :     return SettingTo<Int>(value);
     553                 :      145427 : }
     554                 :             : 
     555                 :             : template <std::integral Int>
     556         [ +  + ]:      145427 : std::optional<Int> SettingTo(const common::SettingsValue& value)
     557                 :             : {
     558         [ +  + ]:      145427 :     if (value.isNull()) return std::nullopt;
     559         [ +  + ]:       15976 :     if (value.isFalse()) return 0;
     560         [ +  + ]:       15971 :     if (value.isTrue()) return 1;
     561         [ +  + ]:       15968 :     if (value.isNum()) return value.getInt<Int>();
     562         [ -  + ]:       15965 :     return LocaleIndependentAtoi<Int>(value.get_str());
     563                 :             : }
     564                 :             : 
     565                 :             : template <std::integral Int>
     566                 :           0 : Int SettingTo(const common::SettingsValue& value, Int nDefault)
     567                 :             : {
     568         [ #  # ]:           0 :     return SettingTo<Int>(value).value_or(nDefault);
     569                 :             : }
     570                 :             : 
     571                 :      376017 : bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
     572                 :             : {
     573         [ +  + ]:      376017 :     return GetBoolArg(strArg).value_or(fDefault);
     574                 :             : }
     575                 :             : 
     576                 :      402178 : std::optional<bool> ArgsManager::GetBoolArg(const std::string& strArg) const
     577                 :             : {
     578                 :      402178 :     const common::SettingsValue value = GetSetting(strArg);
     579         [ +  + ]:      804346 :     return SettingToBool(value);
     580                 :      402178 : }
     581                 :             : 
     582                 :      402178 : std::optional<bool> SettingToBool(const common::SettingsValue& value)
     583                 :             : {
     584         [ +  + ]:      402178 :     if (value.isNull()) return std::nullopt;
     585         [ +  + ]:      266147 :     if (value.isBool()) return value.get_bool();
     586                 :      264518 :     return InterpretBool(value.get_str());
     587                 :             : }
     588                 :             : 
     589                 :           0 : bool SettingToBool(const common::SettingsValue& value, bool fDefault)
     590                 :             : {
     591         [ #  # ]:           0 :     return SettingToBool(value).value_or(fDefault);
     592                 :             : }
     593                 :             : 
     594                 :             : #define INSTANTIATE_INT_TYPE(Type)                                                    \
     595                 :             :     template Type ArgsManager::GetArg<Type>(const std::string&, Type) const;          \
     596                 :             :     template std::optional<Type> ArgsManager::GetArg<Type>(const std::string&) const; \
     597                 :             :     template Type SettingTo<Type>(const common::SettingsValue&, Type);                \
     598                 :             :     template std::optional<Type> SettingTo<Type>(const common::SettingsValue&)
     599                 :             : 
     600                 :             : INSTANTIATE_INT_TYPE(int8_t);
     601                 :             : INSTANTIATE_INT_TYPE(uint8_t);
     602                 :             : INSTANTIATE_INT_TYPE(int16_t);
     603                 :             : INSTANTIATE_INT_TYPE(uint16_t);
     604                 :             : INSTANTIATE_INT_TYPE(int32_t);
     605                 :             : INSTANTIATE_INT_TYPE(uint32_t);
     606                 :             : INSTANTIATE_INT_TYPE(int64_t);
     607                 :             : INSTANTIATE_INT_TYPE(uint64_t);
     608                 :             : 
     609                 :             : #undef INSTANTIATE_INT_TYPE
     610                 :             : 
     611                 :       52529 : bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
     612                 :             : {
     613                 :       52529 :     LOCK(cs_args);
     614   [ +  -  +  + ]:       52529 :     if (!GetSetting_(strArg).isNull()) return false;
     615   [ +  -  +  -  :        2015 :     m_settings.forced_settings[SettingName(strArg)] = strValue;
                   +  - ]
     616                 :        2015 :     return true;
     617                 :       52529 : }
     618                 :             : 
     619                 :        5033 : bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
     620                 :             : {
     621         [ +  + ]:        5033 :     if (fValue)
     622         [ +  - ]:        2412 :         return SoftSetArg(strArg, std::string("1"));
     623                 :             :     else
     624         [ +  - ]:        2621 :         return SoftSetArg(strArg, std::string("0"));
     625                 :             : }
     626                 :             : 
     627                 :       51065 : void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
     628                 :             : {
     629                 :       51065 :     LOCK(cs_args);
     630   [ +  -  +  -  :       51065 :     m_settings.forced_settings[SettingName(strArg)] = strValue;
             +  -  +  - ]
     631                 :       51065 : }
     632                 :             : 
     633                 :         238 : void ArgsManager::AddCommand(const std::string& cmd, const std::string& help, std::set<std::string> options)
     634                 :             : {
     635         [ -  + ]:         238 :     Assert(cmd.find('=') == std::string::npos);
     636         [ -  + ]:         238 :     Assert(cmd.at(0) != '-');
     637                 :             : 
     638                 :         238 :     LOCK(cs_args);
     639                 :         238 :     m_accept_any_command = false; // latch to false
     640         [ +  - ]:         238 :     std::map<std::string, Arg>& arg_map = m_available_args[OptionsCategory::COMMANDS];
     641   [ +  -  -  +  :         476 :     auto ret = arg_map.emplace(cmd, Arg{"", help, ArgsManager::COMMAND});
                   +  - ]
     642         [ +  + ]:         238 :     if (!options.empty()) {
     643         [ +  - ]:         110 :         auto& cmdopts = m_available_args[OptionsCategory::COMMAND_OPTIONS];
     644                 :         110 :         bool command_has_all_options_defined = true;
     645         [ +  + ]:         236 :         for (const auto& opt : options) {
     646         [ -  + ]:         126 :             if (!cmdopts.contains(opt)) {
     647                 :           0 :                 command_has_all_options_defined = false;
     648                 :             :             }
     649                 :             :         }
     650         [ -  + ]:         110 :         Assert(command_has_all_options_defined);
     651                 :             : 
     652         [ +  - ]:         110 :         m_command_args.try_emplace(cmd, std::move(options));
     653                 :             :     }
     654   [ -  +  +  - ]:         238 :     Assert(ret.second); // Fail on duplicate commands
     655                 :         238 : }
     656                 :             : 
     657                 :      475886 : void ArgsManager::AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat)
     658                 :             : {
     659         [ -  + ]:      475886 :     Assert((flags & ArgsManager::COMMAND) == 0); // use AddCommand
     660                 :             : 
     661                 :             :     // Split arg name from its help param
     662                 :      475886 :     size_t eq_index = name.find('=');
     663         [ +  + ]:      475886 :     if (eq_index == std::string::npos) {
     664         [ -  + ]:      245267 :         eq_index = name.size();
     665                 :             :     }
     666                 :      475886 :     std::string arg_name = name.substr(0, eq_index);
     667                 :             : 
     668         [ +  - ]:      475886 :     LOCK(cs_args);
     669                 :             : 
     670                 :             :     // Allow duplicates involving HIDDEN — it is used as a placeholder for args
     671                 :             :     // unavailable in this binary but tolerated for shared config files (see #13441).
     672         [ +  + ]:     2895146 :     for (const auto& arg_map : m_available_args) {
     673   [ +  +  +  + ]:     2419260 :         if (arg_map.first == OptionsCategory::HIDDEN || cat == OptionsCategory::HIDDEN) continue;
     674         [ -  + ]:     2419260 :         Assert(!arg_map.second.contains(arg_name));
     675                 :             :     }
     676                 :             : 
     677         [ +  - ]:      475886 :     std::map<std::string, Arg>& arg_map = m_available_args[cat];
     678   [ -  +  +  -  :      951772 :     auto ret = arg_map.emplace(arg_name, Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
             -  +  +  - ]
     679         [ -  + ]:      475886 :     assert(ret.second); // Make sure an insertion actually happened
     680                 :             : 
     681         [ +  + ]:      475886 :     if (flags & ArgsManager::NETWORK_ONLY) {
     682         [ +  - ]:       40522 :         m_network_only_args.emplace(arg_name);
     683                 :             :     }
     684                 :      475886 : }
     685                 :             : 
     686                 :        5111 : void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
     687                 :             : {
     688         [ +  + ]:       27117 :     for (const std::string& name : names) {
     689         [ +  - ]:       44012 :         AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
     690                 :             :     }
     691                 :        5111 : }
     692                 :             : 
     693                 :         708 : void ArgsManager::ClearArgs()
     694                 :             : {
     695                 :         708 :     LOCK(cs_args);
     696                 :         708 :     m_settings = {};
     697                 :         708 :     m_available_args.clear();
     698                 :         708 :     m_command_args.clear();
     699                 :         708 :     m_network_only_args.clear();
     700         [ +  - ]:         708 :     m_config_sections.clear();
     701                 :         708 : }
     702                 :             : 
     703                 :        1025 : void ArgsManager::CheckMultipleCLIArgs() const
     704                 :             : {
     705                 :        1025 :     LOCK(cs_args);
     706                 :        1025 :     std::vector<std::string> found{};
     707                 :        1025 :     auto cmds = m_available_args.find(OptionsCategory::CLI_COMMANDS);
     708         [ +  - ]:        1025 :     if (cmds != m_available_args.end()) {
     709   [ +  -  +  + ]:        5125 :         for (const auto& [cmd, argspec] : cmds->second) {
     710   [ +  -  -  + ]:        4100 :             if (!GetSetting_(cmd).isNull()) {
     711         [ #  # ]:           0 :                 found.push_back(cmd);
     712                 :             :             }
     713                 :             :         }
     714   [ -  +  -  + ]:        1025 :         if (found.size() > 1) {
     715   [ #  #  #  #  :           0 :             throw std::runtime_error(strprintf("Only one of %s may be specified.", util::Join(found, ", ")));
                   #  # ]
     716                 :             :         }
     717                 :             :     }
     718         [ +  - ]:        2050 : }
     719                 :             : 
     720                 :           2 : std::string ArgsManager::GetHelpMessage() const
     721                 :             : {
     722         [ +  - ]:           2 :     const bool show_debug = GetBoolArg("-help-debug", false);
     723                 :             : 
     724         [ +  - ]:           2 :     std::string usage;
     725         [ +  - ]:           2 :     LOCK(cs_args);
     726                 :             : 
     727                 :           2 :     const auto command_options = m_available_args.find(OptionsCategory::COMMAND_OPTIONS);
     728         [ +  - ]:           1 :     const auto for_matching_cmd_opts = [&](const std::set<std::string>& select, auto&& fn) EXCLUSIVE_LOCKS_REQUIRED(cs_args) {
     729         [ +  - ]:           1 :         if (select.empty()) return;
     730         [ +  - ]:           1 :         if (command_options == m_available_args.end()) return;
     731   [ +  -  +  + ]:           2 :         for (const auto& [name, info] : command_options->second) {
     732   [ +  -  -  + ]:           1 :             if (!show_debug && (info.m_flags & ArgsManager::DEBUG_ONLY)) continue;
     733         [ -  + ]:           1 :             if (!select.contains(name)) continue;
     734                 :           1 :             fn(name, info);
     735                 :             :         }
     736                 :           2 :     };
     737                 :             : 
     738   [ +  +  +  +  :          14 :     for (const auto& [category, category_args] : m_available_args) {
          +  +  +  -  +  
          +  +  -  +  -  
             -  +  +  + ]
     739   [ +  +  +  +  :          13 :         switch(category) {
          +  +  +  -  +  
          +  +  -  +  -  
                   -  + ]
     740                 :           1 :             case OptionsCategory::OPTIONS:
     741   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Options:");
     742                 :           1 :                 break;
     743                 :           1 :             case OptionsCategory::CONNECTION:
     744   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Connection options:");
     745                 :           1 :                 break;
     746                 :           1 :             case OptionsCategory::ZMQ:
     747   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("ZeroMQ notification options:");
     748                 :           1 :                 break;
     749                 :           1 :             case OptionsCategory::DEBUG_TEST:
     750   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Debugging/Testing options:");
     751                 :           1 :                 break;
     752                 :           1 :             case OptionsCategory::NODE_RELAY:
     753   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Node relay options:");
     754                 :           1 :                 break;
     755                 :           1 :             case OptionsCategory::BLOCK_CREATION:
     756   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Block creation options:");
     757                 :           1 :                 break;
     758                 :           1 :             case OptionsCategory::RPC:
     759   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("RPC server options:");
     760                 :           1 :                 break;
     761                 :           0 :             case OptionsCategory::IPC:
     762   [ #  #  #  # ]:           0 :                 usage += HelpMessageGroup("IPC interprocess connection options:");
     763                 :           0 :                 break;
     764                 :           1 :             case OptionsCategory::WALLET:
     765   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Wallet options:");
     766                 :           1 :                 break;
     767                 :           1 :             case OptionsCategory::WALLET_DEBUG_TEST:
     768   [ -  +  -  -  :           1 :                 if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
                   -  - ]
     769                 :             :                 break;
     770                 :           1 :             case OptionsCategory::CHAINPARAMS:
     771   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Chain selection options:");
     772                 :           1 :                 break;
     773                 :           0 :             case OptionsCategory::GUI:
     774   [ #  #  #  # ]:           0 :                 usage += HelpMessageGroup("UI Options:");
     775                 :           0 :                 break;
     776                 :           1 :             case OptionsCategory::COMMANDS:
     777   [ +  -  +  - ]:           2 :                 usage += HelpMessageGroup("Commands:");
     778                 :           1 :                 break;
     779                 :           0 :             case OptionsCategory::REGISTER_COMMANDS:
     780   [ #  #  #  # ]:           0 :                 usage += HelpMessageGroup("Register Commands:");
     781                 :           0 :                 break;
     782                 :           0 :             case OptionsCategory::CLI_COMMANDS:
     783   [ #  #  #  # ]:           0 :                 usage += HelpMessageGroup("CLI Commands:");
     784                 :           0 :                 break;
     785                 :             :             case OptionsCategory::COMMAND_OPTIONS:
     786                 :             :             case OptionsCategory::HIDDEN:
     787                 :             :                 break;
     788                 :             :         } // no default case, so the compiler can warn about missing cases
     789                 :             : 
     790         [ +  + ]:          13 :         if (category == OptionsCategory::COMMAND_OPTIONS) continue;
     791                 :             : 
     792                 :             :         // When we get to the hidden options, stop
     793         [ +  + ]:          12 :         if (category == OptionsCategory::HIDDEN) break;
     794                 :             : 
     795   [ +  -  +  + ]:         195 :         for (const auto& [arg_name, arg_info] : category_args) {
     796   [ +  -  +  + ]:         184 :             if (show_debug || !(arg_info.m_flags & ArgsManager::DEBUG_ONLY)) {
     797   [ -  +  -  +  :         286 :                 usage += HelpMessageOpt(arg_name, arg_info.m_help_param, arg_info.m_help_text);
             -  +  +  - ]
     798                 :             : 
     799         [ +  + ]:         143 :                 if (category == OptionsCategory::COMMANDS) {
     800                 :           1 :                     const auto cmd_args = m_command_args.find(arg_name);
     801         [ -  + ]:           1 :                     if (cmd_args == m_command_args.end()) continue;
     802         [ +  - ]:           1 :                     for_matching_cmd_opts(cmd_args->second, [&](const auto& cmdopt_name, const auto& cmdopt_info) {
     803   [ -  +  -  +  :           2 :                         usage += HelpMessageOpt(cmdopt_name, cmdopt_info.m_help_param, cmdopt_info.m_help_text, /*subopt=*/true);
             -  +  -  + ]
     804                 :           1 :                     });
     805                 :             :                 }
     806                 :             :             }
     807                 :             :         }
     808                 :             :     }
     809         [ +  - ]:           2 :     return usage;
     810                 :           2 : }
     811                 :             : 
     812                 :        2398 : bool HelpRequested(const ArgsManager& args)
     813                 :             : {
     814   [ +  -  +  -  :       11988 :     return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug");
          +  -  +  -  +  
          -  +  +  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  +  +  -  -  
             -  -  -  -  
                      - ]
     815                 :             : }
     816                 :             : 
     817                 :        3147 : void SetupHelpOptions(ArgsManager& args)
     818                 :             : {
     819   [ +  -  +  - ]:        6294 :     args.AddArg("-help", "Print this help message and exit (also -h or -?)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
     820         [ +  - ]:        3147 :     args.AddHiddenArgs({"-h", "-?"});
     821                 :        3147 : }
     822                 :             : 
     823                 :          10 : std::string HelpMessageGroup(const std::string &message) {
     824         [ +  - ]:          30 :     return std::string(message) + std::string("\n\n");
     825                 :             : }
     826                 :             : 
     827                 :         144 : std::string HelpMessageOpt(std::string_view option, std::string_view help_param, std::string_view message, bool subopt)
     828                 :             : {
     829                 :         144 :     constexpr int screen_width = 79;
     830                 :         144 :     int opt_indent = 2;
     831                 :         144 :     int msg_indent = 7;
     832                 :             : 
     833         [ +  + ]:         144 :     if (subopt) {
     834                 :           1 :         int bump = msg_indent - opt_indent;
     835                 :           1 :         opt_indent += bump; // opt_indent now at the old msg_indent level
     836                 :           1 :         msg_indent += bump; // indent by the same amount
     837                 :             :     }
     838                 :         144 :     int msg_width = screen_width - msg_indent;
     839                 :             : 
     840                 :         144 :     return strprintf("%*s%s%s\n%*s%s\n\n",
     841                 :             :                      opt_indent, "", option, help_param,
     842         [ +  - ]:         288 :                      msg_indent, "", FormatParagraph(message, msg_width, msg_indent));
     843                 :             : }
     844                 :             : 
     845                 :             : const std::vector<std::string> TEST_OPTIONS_DOC{
     846                 :             :     "addrman (use deterministic addrman)",
     847                 :             :     "reindex_after_failure_noninteractive_yes (When asked for a reindex after failure interactively, simulate as-if answered with 'yes')",
     848                 :             :     "bip94 (enforce BIP94 consensus rules)",
     849                 :             : };
     850                 :             : 
     851                 :        4569 : bool HasTestOption(const ArgsManager& args, const std::string& test_option)
     852                 :             : {
     853         [ +  - ]:        4569 :     const auto options = args.GetArgs("-test");
     854   [ -  +  -  +  :       54828 :     return std::any_of(options.begin(), options.end(), [test_option](const auto& option) {
          -  +  +  -  -  
          +  +  -  -  +  
          +  -  -  +  +  
                      - ]
     855         [ +  + ]:          31 :         return option == test_option;
     856                 :        4569 :     });
     857                 :        4569 : }
     858                 :             : 
     859                 :        1192 : fs::path GetDefaultDataDir()
     860                 :             : {
     861                 :             :     // Windows:
     862                 :             :     //   old: C:\Users\Username\AppData\Roaming\Bitcoin
     863                 :             :     //   new: C:\Users\Username\AppData\Local\Bitcoin
     864                 :             :     // macOS: ~/Library/Application Support/Bitcoin
     865                 :             :     // Unix-like: ~/.bitcoin
     866                 :             : #ifdef WIN32
     867                 :             :     // Windows
     868                 :             :     // Check for existence of datadir in old location and keep it there
     869                 :             :     fs::path legacy_path = GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
     870                 :             :     if (fs::exists(legacy_path)) return legacy_path;
     871                 :             : 
     872                 :             :     // Otherwise, fresh installs can start in the new, "proper" location
     873                 :             :     return GetSpecialFolderPath(CSIDL_LOCAL_APPDATA) / "Bitcoin";
     874                 :             : #else
     875                 :        1192 :     fs::path pathRet;
     876                 :        1192 :     char* pszHome = getenv("HOME");
     877   [ +  -  -  + ]:        1192 :     if (pszHome == nullptr || strlen(pszHome) == 0)
     878         [ #  # ]:           0 :         pathRet = fs::path("/");
     879                 :             :     else
     880         [ +  - ]:        2384 :         pathRet = fs::path(pszHome);
     881                 :             : #ifdef __APPLE__
     882                 :             :     // macOS
     883                 :             :     return pathRet / "Library/Application Support/Bitcoin";
     884                 :             : #else
     885                 :             :     // Unix-like
     886   [ +  -  +  - ]:        3576 :     return pathRet / ".bitcoin";
     887                 :             : #endif
     888                 :             : #endif
     889                 :        1192 : }
     890                 :             : 
     891                 :        4569 : bool CheckDataDirOption(const ArgsManager& args)
     892                 :             : {
     893   [ +  -  +  - ]:        9138 :     const fs::path datadir{args.GetPathArg("-datadir")};
     894   [ +  +  +  -  :        9133 :     return datadir.empty() || fs::is_directory(fs::absolute(datadir));
             +  -  +  + ]
     895                 :        4569 : }
     896                 :             : 
     897                 :        3464 : fs::path ArgsManager::GetConfigFilePath() const
     898                 :             : {
     899                 :        3464 :     LOCK(cs_args);
     900   [ -  +  +  -  :        3464 :     return *Assert(m_config_path);
                   +  - ]
     901                 :        3464 : }
     902                 :             : 
     903                 :           1 : void ArgsManager::SetConfigFilePath(fs::path path)
     904                 :             : {
     905                 :           1 :     LOCK(cs_args);
     906         [ -  + ]:           1 :     assert(!m_config_path);
     907         [ +  - ]:           1 :     m_config_path = path;
     908                 :           1 : }
     909                 :             : 
     910                 :        4333 : ChainType ArgsManager::GetChainType() const
     911                 :             : {
     912                 :        4333 :     std::variant<ChainType, std::string> arg = GetChainArg();
     913         [ +  - ]:        4333 :     if (auto* parsed = std::get_if<ChainType>(&arg)) return *parsed;
     914   [ #  #  #  #  :           0 :     throw std::runtime_error(strprintf("Unknown chain %s.", std::get<std::string>(arg)));
                   #  # ]
     915                 :        4333 : }
     916                 :             : 
     917                 :        5929 : std::string ArgsManager::GetChainTypeString() const
     918                 :             : {
     919                 :        5929 :     auto arg = GetChainArg();
     920   [ +  -  +  - ]:        5742 :     if (auto* parsed = std::get_if<ChainType>(&arg)) return ChainTypeToString(*parsed);
     921   [ -  -  -  - ]:        5742 :     return std::get<std::string>(arg);
     922                 :        5742 : }
     923                 :             : 
     924                 :       10262 : std::variant<ChainType, std::string> ArgsManager::GetChainArg() const
     925                 :             : {
     926                 :       51310 :     auto get_net = [&](const std::string& arg) {
     927                 :       41048 :         LOCK(cs_args);
     928   [ +  -  +  - ]:       82096 :         common::SettingsValue value = common::GetSetting(m_settings, /* section= */ "", SettingName(arg),
     929                 :             :             /* ignore_default_section_config= */ false,
     930                 :             :             /*ignore_nonpersistent=*/false,
     931         [ +  - ]:       41048 :             /* get_chain_type= */ true);
     932   [ +  +  -  +  :       41048 :         return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
          -  -  +  -  +  
                      - ]
     933         [ +  - ]:       82096 :     };
     934                 :             : 
     935         [ +  - ]:       10262 :     const bool fRegTest = get_net("-regtest");
     936         [ +  - ]:       10262 :     const bool fSigNet  = get_net("-signet");
     937         [ +  - ]:       10262 :     const bool fTestNet = get_net("-testnet");
     938         [ +  - ]:       10262 :     const bool fTestNet4 = get_net("-testnet4");
     939         [ +  - ]:       10262 :     const auto chain_arg = GetArg("-chain");
     940                 :             : 
     941         [ +  + ]:       10262 :     if ((int)chain_arg.has_value() + (int)fRegTest + (int)fSigNet + (int)fTestNet + (int)fTestNet4 > 1) {
     942         [ +  - ]:         187 :         throw std::runtime_error("Invalid combination of -regtest, -signet, -testnet, -testnet4 and -chain. Can use at most one.");
     943                 :             :     }
     944         [ +  + ]:       10075 :     if (chain_arg) {
     945   [ -  +  +  -  :          32 :         if (auto parsed = ChainTypeFromString(*chain_arg)) return *parsed;
                   +  - ]
     946                 :             :         // Not a known string, so return original string
     947         [ #  # ]:           0 :         return *chain_arg;
     948                 :             :     }
     949         [ +  + ]:       10043 :     if (fRegTest) return ChainType::REGTEST;
     950         [ +  + ]:        1864 :     if (fSigNet) return ChainType::SIGNET;
     951         [ +  + ]:        1735 :     if (fTestNet) return ChainType::TESTNET;
     952         [ +  + ]:        1726 :     if (fTestNet4) return ChainType::TESTNET4;
     953                 :        1387 :     return ChainType::MAIN;
     954                 :       10075 : }
     955                 :             : 
     956                 :     1112116 : bool ArgsManager::UseDefaultSection(const std::string& arg) const
     957                 :             : {
     958                 :     1112116 :     AssertLockHeld(cs_args);
     959   [ +  +  +  + ]:     1112116 :     return m_network == ChainTypeToString(ChainType::MAIN) || !m_network_only_args.contains(arg);
     960                 :             : }
     961                 :             : 
     962                 :      876147 : common::SettingsValue ArgsManager::GetSetting_(const std::string& arg) const
     963                 :             : {
     964                 :      876147 :     AssertLockHeld(cs_args);
     965                 :      876147 :     return common::GetSetting(
     966                 :      876147 :         m_settings, m_network, SettingName(arg), !UseDefaultSection(arg),
     967         [ +  - ]:     1752294 :         /*ignore_nonpersistent=*/false, /*get_chain_type=*/false);
     968                 :             : }
     969                 :             : 
     970                 :      786317 : common::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
     971                 :             : {
     972                 :      786317 :     LOCK(cs_args);
     973         [ +  - ]:      786317 :     return GetSetting_(arg);
     974                 :      786317 : }
     975                 :             : 
     976                 :      235969 : std::vector<common::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
     977                 :             : {
     978                 :      235969 :     LOCK(cs_args);
     979   [ +  -  +  -  :      471938 :     return common::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
             +  -  +  - ]
     980                 :      235969 : }
     981                 :             : 
     982                 :        3554 : void ArgsManager::logArgsPrefix(
     983                 :             :     const std::string& prefix,
     984                 :             :     const std::string& section,
     985                 :             :     const std::map<std::string, std::vector<common::SettingsValue>>& args) const
     986                 :             : {
     987                 :        3554 :     AssertLockHeld(cs_args);
     988   [ +  +  +  - ]:        4736 :     std::string section_str = section.empty() ? "" : "[" + section + "] ";
     989         [ +  + ]:       44880 :     for (const auto& arg : args) {
     990         [ +  + ]:       84026 :         for (const auto& value : arg.second) {
     991   [ +  -  +  - ]:       42700 :             std::optional<unsigned int> flags = GetArgFlags_('-' + arg.first);
     992         [ +  - ]:       42700 :             if (flags) {
     993   [ +  +  +  -  :       42700 :                 std::string value_str = (*flags & SENSITIVE) ? "****" : value.write();
                   +  - ]
     994         [ +  - ]:       42700 :                 LogInfo("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);
     995                 :       42700 :             }
     996                 :             :         }
     997                 :             :     }
     998                 :        3554 : }
     999                 :             : 
    1000                 :        1188 : void ArgsManager::LogArgs() const
    1001                 :             : {
    1002                 :        1188 :     LOCK(cs_args);
    1003         [ +  + ]:        3554 :     for (const auto& section : m_settings.ro_config) {
    1004   [ +  -  +  - ]:        4732 :         logArgsPrefix("Config file arg:", section.first, section.second);
    1005                 :             :     }
    1006         [ +  + ]:        1319 :     for (const auto& setting : m_settings.rw_settings) {
    1007   [ +  -  +  - ]:         131 :         LogInfo("Setting file arg: %s = %s\n", setting.first, setting.second.write());
    1008                 :             :     }
    1009   [ +  -  +  -  :        2376 :     logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
             +  -  +  - ]
    1010                 :        1188 : }
        

Generated by: LCOV version 2.0-1