Coverage Report

Created: 2024-09-19 18:47

/root/bitcoin/src/common/args.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2023 The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_COMMON_ARGS_H
6
#define BITCOIN_COMMON_ARGS_H
7
8
#include <common/settings.h>
9
#include <compat/compat.h>
10
#include <sync.h>
11
#include <util/chaintype.h>
12
#include <util/fs.h>
13
14
#include <iosfwd>
15
#include <list>
16
#include <map>
17
#include <optional>
18
#include <set>
19
#include <stdint.h>
20
#include <string>
21
#include <variant>
22
#include <vector>
23
24
class ArgsManager;
25
26
extern const char * const BITCOIN_CONF_FILENAME;
27
extern const char * const BITCOIN_SETTINGS_FILENAME;
28
29
// Return true if -datadir option points to a valid directory or is not specified.
30
bool CheckDataDirOption(const ArgsManager& args);
31
32
/**
33
 * Most paths passed as configuration arguments are treated as relative to
34
 * the datadir if they are not absolute.
35
 *
36
 * @param args Parsed arguments and settings.
37
 * @param path The path to be conditionally prefixed with datadir.
38
 * @param net_specific Use network specific datadir variant
39
 * @return The normalized path.
40
 */
41
fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific = true);
42
43
inline bool IsSwitchChar(char c)
44
0
{
45
#ifdef WIN32
46
    return c == '-' || c == '/';
47
#else
48
0
    return c == '-';
49
0
#endif
50
0
}
51
52
enum class OptionsCategory {
53
    OPTIONS,
54
    CONNECTION,
55
    WALLET,
56
    WALLET_DEBUG_TEST,
57
    ZMQ,
58
    DEBUG_TEST,
59
    CHAINPARAMS,
60
    NODE_RELAY,
61
    BLOCK_CREATION,
62
    RPC,
63
    GUI,
64
    COMMANDS,
65
    REGISTER_COMMANDS,
66
    CLI_COMMANDS,
67
    IPC,
68
69
    HIDDEN // Always the last option to avoid printing these in the help
70
};
71
72
struct KeyInfo {
73
    std::string name;
74
    std::string section;
75
    bool negated{false};
76
};
77
78
KeyInfo InterpretKey(std::string key);
79
80
std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
81
                                                         unsigned int flags, std::string& error);
82
83
struct SectionInfo {
84
    std::string m_name;
85
    std::string m_file;
86
    int m_line;
87
};
88
89
std::string SettingToString(const common::SettingsValue&, const std::string&);
90
std::optional<std::string> SettingToString(const common::SettingsValue&);
91
92
int64_t SettingToInt(const common::SettingsValue&, int64_t);
93
std::optional<int64_t> SettingToInt(const common::SettingsValue&);
94
95
bool SettingToBool(const common::SettingsValue&, bool);
96
std::optional<bool> SettingToBool(const common::SettingsValue&);
97
98
class ArgsManager
99
{
100
public:
101
    /**
102
     * Flags controlling how config and command line arguments are validated and
103
     * interpreted.
104
     */
105
    enum Flags : uint32_t {
106
        ALLOW_ANY = 0x01,         //!< disable validation
107
        // ALLOW_BOOL = 0x02,     //!< unimplemented, draft implementation in #16545
108
        // ALLOW_INT = 0x04,      //!< unimplemented, draft implementation in #16545
109
        // ALLOW_STRING = 0x08,   //!< unimplemented, draft implementation in #16545
110
        // ALLOW_LIST = 0x10,     //!< unimplemented, draft implementation in #16545
111
        DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
112
        DISALLOW_ELISION = 0x40,  //!< disallow -foo syntax that doesn't assign any value
113
114
        DEBUG_ONLY = 0x100,
115
        /* Some options would cause cross-contamination if values for
116
         * mainnet were used while running on regtest/testnet (or vice-versa).
117
         * Setting them as NETWORK_ONLY ensures that sharing a config file
118
         * between mainnet and regtest/testnet won't cause problems due to these
119
         * parameters by accident. */
120
        NETWORK_ONLY = 0x200,
121
        // This argument's value is sensitive (such as a password).
122
        SENSITIVE = 0x400,
123
        COMMAND = 0x800,
124
    };
125
126
protected:
127
    struct Arg
128
    {
129
        std::string m_help_param;
130
        std::string m_help_text;
131
        unsigned int m_flags;
132
    };
133
134
    mutable RecursiveMutex cs_args;
135
    common::Settings m_settings GUARDED_BY(cs_args);
136
    std::vector<std::string> m_command GUARDED_BY(cs_args);
137
    std::string m_network GUARDED_BY(cs_args);
138
    std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
139
    std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
140
    bool m_accept_any_command GUARDED_BY(cs_args){true};
141
    std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
142
    std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
143
    mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
144
    mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
145
    mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
146
147
    [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
148
149
    /**
150
     * Returns true if settings values from the default section should be used,
151
     * depending on the current network and whether the setting is
152
     * network-specific.
153
     */
154
    bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
155
156
 public:
157
    /**
158
     * Get setting value.
159
     *
160
     * Result will be null if setting was unset, true if "-setting" argument was passed
161
     * false if "-nosetting" argument was passed, and a string if a "-setting=value"
162
     * argument was passed.
163
     */
164
    common::SettingsValue GetSetting(const std::string& arg) const;
165
166
    /**
167
     * Get list of setting values.
168
     */
169
    std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;
170
171
    ArgsManager();
172
    ~ArgsManager();
173
174
    /**
175
     * Select the network in use
176
     */
177
    void SelectConfigNetwork(const std::string& network);
178
179
    [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
180
181
    /**
182
     * Return config file path (read-only)
183
     */
184
    fs::path GetConfigFilePath() const;
185
    void SetConfigFilePath(fs::path);
186
    [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
187
188
    /**
189
     * Log warnings for options in m_section_only_args when
190
     * they are specified in the default section but not overridden
191
     * on the command line or in a network-specific section in the
192
     * config file.
193
     */
194
    std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
195
196
    /**
197
     * Log warnings for unrecognized section names in the config file.
198
     */
199
    std::list<SectionInfo> GetUnrecognizedSections() const;
200
201
    struct Command {
202
        /** The command (if one has been registered with AddCommand), or empty */
203
        std::string command;
204
        /**
205
         * If command is non-empty: Any args that followed it
206
         * If command is empty: The unregistered command and any args that followed it
207
         */
208
        std::vector<std::string> args;
209
    };
210
    /**
211
     * Get the command and command args (returns std::nullopt if no command provided)
212
     */
213
    std::optional<const Command> GetCommand() const;
214
215
    /**
216
     * Get blocks directory path
217
     *
218
     * @return Blocks path which is network specific
219
     */
220
    fs::path GetBlocksDirPath() const;
221
222
    /**
223
     * Get data directory path
224
     *
225
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
226
     */
227
0
    fs::path GetDataDirBase() const { return GetDataDir(false); }
228
229
    /**
230
     * Get data directory path with appended network identifier
231
     *
232
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
233
     */
234
0
    fs::path GetDataDirNet() const { return GetDataDir(true); }
235
236
    /**
237
     * Clear cached directory paths
238
     */
239
    void ClearPathCache();
240
241
    /**
242
     * Return a vector of strings of the given argument
243
     *
244
     * @param strArg Argument to get (e.g. "-foo")
245
     * @return command-line arguments
246
     */
247
    std::vector<std::string> GetArgs(const std::string& strArg) const;
248
249
    /**
250
     * Return true if the given argument has been manually set
251
     *
252
     * @param strArg Argument to get (e.g. "-foo")
253
     * @return true if the argument has been set
254
     */
255
    bool IsArgSet(const std::string& strArg) const;
256
257
    /**
258
     * Return true if the argument was originally passed as a negated option,
259
     * i.e. -nofoo.
260
     *
261
     * @param strArg Argument to get (e.g. "-foo")
262
     * @return true if the argument was passed negated
263
     */
264
    bool IsArgNegated(const std::string& strArg) const;
265
266
    /**
267
     * Return string argument or default value
268
     *
269
     * @param strArg Argument to get (e.g. "-foo")
270
     * @param strDefault (e.g. "1")
271
     * @return command-line argument or default value
272
     */
273
    std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
274
    std::optional<std::string> GetArg(const std::string& strArg) const;
275
276
    /**
277
     * Return path argument or default value
278
     *
279
     * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
280
     * @param default_value Optional default value to return instead of the empty path.
281
     * @return normalized path if argument is set, with redundant "." and ".."
282
     * path components and trailing separators removed (see patharg unit test
283
     * for examples or implementation for details). If argument is empty or not
284
     * set, default_value is returned unchanged.
285
     */
286
    fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;
287
288
    /**
289
     * Return integer argument or default value
290
     *
291
     * @param strArg Argument to get (e.g. "-foo")
292
     * @param nDefault (e.g. 1)
293
     * @return command-line argument (0 if invalid number) or default value
294
     */
295
    int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
296
    std::optional<int64_t> GetIntArg(const std::string& strArg) const;
297
298
    /**
299
     * Return boolean argument or default value
300
     *
301
     * @param strArg Argument to get (e.g. "-foo")
302
     * @param fDefault (true or false)
303
     * @return command-line argument or default value
304
     */
305
    bool GetBoolArg(const std::string& strArg, bool fDefault) const;
306
    std::optional<bool> GetBoolArg(const std::string& strArg) const;
307
308
    /**
309
     * Set an argument if it doesn't already have a value
310
     *
311
     * @param strArg Argument to set (e.g. "-foo")
312
     * @param strValue Value (e.g. "1")
313
     * @return true if argument gets set, false if it already had a value
314
     */
315
    bool SoftSetArg(const std::string& strArg, const std::string& strValue);
316
317
    /**
318
     * Set a boolean argument if it doesn't already have a value
319
     *
320
     * @param strArg Argument to set (e.g. "-foo")
321
     * @param fValue Value (e.g. false)
322
     * @return true if argument gets set, false if it already had a value
323
     */
324
    bool SoftSetBoolArg(const std::string& strArg, bool fValue);
325
326
    // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
327
    // been set. Also called directly in testing.
328
    void ForceSetArg(const std::string& strArg, const std::string& strValue);
329
330
    /**
331
     * Returns the appropriate chain type from the program arguments.
332
     * @return ChainType::MAIN by default; raises runtime error if an invalid
333
     * combination, or unknown chain is given.
334
     */
335
    ChainType GetChainType() const;
336
337
    /**
338
     * Returns the appropriate chain type string from the program arguments.
339
     * @return ChainType::MAIN string by default; raises runtime error if an
340
     * invalid combination is given.
341
     */
342
    std::string GetChainTypeString() const;
343
344
    /**
345
     * Add argument
346
     */
347
    void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
348
349
    /**
350
     * Add subcommand
351
     */
352
    void AddCommand(const std::string& cmd, const std::string& help);
353
354
    /**
355
     * Add many hidden arguments
356
     */
357
    void AddHiddenArgs(const std::vector<std::string>& args);
358
359
    /**
360
     * Clear available arguments
361
     */
362
1
    void ClearArgs() {
363
1
        LOCK(cs_args);
364
1
        m_available_args.clear();
365
1
        m_network_only_args.clear();
366
1
    }
367
368
    /**
369
     * Check CLI command args
370
     *
371
     * @throws std::runtime_error when multiple CLI_COMMAND arguments are specified
372
     */
373
    void CheckMultipleCLIArgs() const;
374
375
    /**
376
     * Get the help string
377
     */
378
    std::string GetHelpMessage() const;
379
380
    /**
381
     * Return Flags for known arg.
382
     * Return nullopt for unknown arg.
383
     */
384
    std::optional<unsigned int> GetArgFlags(const std::string& name) const;
385
386
    /**
387
     * Get settings file path, or return false if read-write settings were
388
     * disabled with -nosettings.
389
     */
390
    bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;
391
392
    /**
393
     * Read settings file. Push errors to vector, or log them if null.
394
     */
395
    bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
396
397
    /**
398
     * Write settings file or backup settings file. Push errors to vector, or
399
     * log them if null.
400
     */
401
    bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;
402
403
    /**
404
     * Get current setting from config file or read/write settings file,
405
     * ignoring nonpersistent command line or forced settings values.
406
     */
407
    common::SettingsValue GetPersistentSetting(const std::string& name) const;
408
409
    /**
410
     * Access settings with lock held.
411
     */
412
    template <typename Fn>
413
    void LockSettings(Fn&& fn)
414
0
    {
415
0
        LOCK(cs_args);
416
0
        fn(m_settings);
417
0
    }
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl16isSettingIgnoredERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl15updateRwSettingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERK8UniValueEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl12forceSettingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERK8UniValueEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl13resetSettingsEvEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_19ChainImpl12getRwSettingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEUlRKN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_19ChainImpl15updateRwSettingERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt8functionIFSt8optionalIN10interfaces14SettingsActionEER8UniValueEEEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_19ChainImpl16deleteRwSettingsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEbEUlRN6common8SettingsEE_EEvOT_
418
419
    /**
420
     * Log the config file options and the command line arguments,
421
     * useful for troubleshooting.
422
     */
423
    void LogArgs() const;
424
425
private:
426
    /**
427
     * Get data directory path
428
     *
429
     * @param net_specific Append network identifier to the returned path
430
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
431
     */
432
    fs::path GetDataDir(bool net_specific) const;
433
434
    /**
435
     * Return -regtest/-signet/-testnet/-testnet4/-chain= setting as a ChainType enum if a
436
     * recognized chain type was set, or as a string if an unrecognized chain
437
     * name was set. Raise an exception if an invalid combination of flags was
438
     * provided.
439
     */
440
    std::variant<ChainType, std::string> GetChainArg() const;
441
442
    // Helper function for LogArgs().
443
    void logArgsPrefix(
444
        const std::string& prefix,
445
        const std::string& section,
446
        const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
447
};
448
449
extern ArgsManager gArgs;
450
451
/**
452
 * @return true if help has been requested via a command-line arg
453
 */
454
bool HelpRequested(const ArgsManager& args);
455
456
/** Add help options to the args manager */
457
void SetupHelpOptions(ArgsManager& args);
458
459
extern const std::vector<std::string> TEST_OPTIONS_DOC;
460
461
/** Checks if a particular test option is present in -test command-line arg options */
462
bool HasTestOption(const ArgsManager& args, const std::string& test_option);
463
464
/**
465
 * Format a string to be used as group of options in help messages
466
 *
467
 * @param message Group name (e.g. "RPC server options:")
468
 * @return the formatted string
469
 */
470
std::string HelpMessageGroup(const std::string& message);
471
472
/**
473
 * Format a string to be used as option description in help messages
474
 *
475
 * @param option Option message (e.g. "-rpcuser=<user>")
476
 * @param message Option description (e.g. "Username for JSON-RPC connections")
477
 * @return the formatted string
478
 */
479
std::string HelpMessageOpt(const std::string& option, const std::string& message);
480
481
namespace common {
482
#ifdef WIN32
483
class WinCmdLineArgs
484
{
485
public:
486
    WinCmdLineArgs();
487
    ~WinCmdLineArgs();
488
    std::pair<int, char**> get();
489
490
private:
491
    int argc;
492
    char** argv;
493
    std::vector<std::string> args;
494
};
495
#endif
496
} // namespace common
497
498
#endif // BITCOIN_COMMON_ARGS_H