/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_ |
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 |