LCOV - code coverage report
Current view: top level - src/common - args.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 78.5 % 540 424
Test Date: 2026-11-01 05:53:53 Functions: 68.1 % 91 62
Branches: 49.5 % 976 483

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

Generated by: LCOV version 2.5.0-full