Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2021 The Bitcoin Core developers
3 : // Copyright (c) 2014-2025 The Dash Core developers
4 : // Distributed under the MIT software license, see the accompanying
5 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 :
7 : /**
8 : * Server/client environment: argument handling, config file parsing,
9 : * thread wrappers, startup time
10 : */
11 : #ifndef BITCOIN_UTIL_SYSTEM_H
12 : #define BITCOIN_UTIL_SYSTEM_H
13 :
14 : #if defined(HAVE_CONFIG_H)
15 : #include <config/bitcoin-config.h>
16 : #endif
17 :
18 : #include <compat/assumptions.h>
19 : #include <compat/compat.h>
20 : #include <consensus/amount.h>
21 : #include <fs.h>
22 : #include <logging.h>
23 : #include <sync.h>
24 : #include <util/settings.h>
25 : #include <util/time.h>
26 :
27 : #include <exception>
28 : #include <map>
29 : #include <optional>
30 : #include <set>
31 : #include <stdint.h>
32 : #include <string>
33 : #include <utility>
34 : #include <vector>
35 :
36 : //Dash only features
37 :
38 : extern int nWalletBackups;
39 : extern const std::string gCoinJoinName;
40 :
41 : class UniValue;
42 :
43 : // Application startup time (used for uptime calculation)
44 : int64_t GetStartupTime();
45 :
46 : extern const char * const BITCOIN_CONF_FILENAME;
47 : extern const char * const BITCOIN_SETTINGS_FILENAME;
48 :
49 : void SetupEnvironment();
50 : bool SetupNetworking();
51 :
52 : template<typename... Args>
53 290 : bool error(const char* fmt, const Args&... args)
54 : {
55 290 : LogPrintf("ERROR: %s\n", SafeStringFormat(fmt, args...));
56 290 : return false;
57 0 : }
58 :
59 : void PrintExceptionContinue(const std::exception_ptr pex, const char* pszExceptionOrigin);
60 :
61 : /**
62 : * Ensure file contents are fully committed to disk, using a platform-specific
63 : * feature analogous to fsync().
64 : */
65 : bool FileCommit(FILE *file);
66 :
67 : /**
68 : * Sync directory contents. This is required on some environments to ensure that
69 : * newly created files are committed to disk.
70 : */
71 : void DirectoryCommit(const fs::path &dirname);
72 :
73 : bool TruncateFile(FILE *file, unsigned int length);
74 : int RaiseFileDescriptorLimit(int nMinFD);
75 : void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
76 :
77 : /**
78 : * Rename src to dest.
79 : * @return true if the rename was successful.
80 : */
81 : [[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
82 :
83 : bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only=false);
84 : void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name);
85 : bool DirIsWritable(const fs::path& directory);
86 : bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);
87 :
88 : /** Get the size of a file by scanning it.
89 : *
90 : * @param[in] path The file path
91 : * @param[in] max Stop seeking beyond this limit
92 : * @return The file size or max
93 : */
94 : std::streampos GetFileSize(const char* path, std::streamsize max = std::numeric_limits<std::streamsize>::max());
95 :
96 : /** Release all directory locks. This is used for unit testing only, at runtime
97 : * the global destructor will take care of the locks.
98 : */
99 : /** Dash: We also use this to release locks earlier when restarting the client */
100 : void ReleaseDirectoryLocks();
101 :
102 : bool TryCreateDirectories(const fs::path& p);
103 : fs::path GetDefaultDataDir();
104 : // Return true if -datadir option points to a valid directory or is not specified.
105 : bool CheckDataDirOption();
106 : fs::path GetConfigFile(const fs::path& configuration_file_path);
107 : #ifdef WIN32
108 : fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
109 : #endif
110 : #ifndef WIN32
111 : std::string ShellEscape(const std::string& arg);
112 : #endif
113 : #if HAVE_SYSTEM
114 : void runCommand(const std::string& strCommand);
115 : #endif
116 :
117 : /**
118 : * Most paths passed as configuration arguments are treated as relative to
119 : * the datadir if they are not absolute.
120 : *
121 : * @param path The path to be conditionally prefixed with datadir.
122 : * @param net_specific Use network specific datadir variant
123 : * @return The normalized path.
124 : */
125 : fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific = true);
126 :
127 146 : inline bool IsSwitchChar(char c)
128 : {
129 : #ifdef WIN32
130 : return c == '-' || c == '/';
131 : #else
132 146 : return c == '-';
133 : #endif
134 : }
135 :
136 : enum class OptionsCategory {
137 : OPTIONS,
138 : CONNECTION,
139 : INDEXING,
140 : MASTERNODE,
141 : STATSD,
142 : WALLET,
143 : WALLET_FEE,
144 : WALLET_HD,
145 : WALLET_COINJOIN,
146 : WALLET_DEBUG_TEST,
147 : ZMQ,
148 : DEBUG_TEST,
149 : CHAINPARAMS,
150 : NODE_RELAY,
151 : BLOCK_CREATION,
152 : RPC,
153 : GUI,
154 : COMMANDS,
155 : REGISTER_COMMANDS,
156 :
157 : HIDDEN // Always the last option to avoid printing these in the help
158 : };
159 :
160 0 : struct SectionInfo
161 : {
162 : std::string m_name;
163 : std::string m_file;
164 : int m_line;
165 : };
166 :
167 : std::string SettingToString(const util::SettingsValue&, const std::string&);
168 : int64_t SettingToInt(const util::SettingsValue&, int64_t);
169 : bool SettingToBool(const util::SettingsValue&, bool);
170 :
171 : class ArgsManager
172 : {
173 : public:
174 : /**
175 : * Flags controlling how config and command line arguments are validated and
176 : * interpreted.
177 : */
178 : enum Flags : uint32_t {
179 : ALLOW_ANY = 0x01, //!< disable validation
180 : // ALLOW_BOOL = 0x02, //!< unimplemented, draft implementation in #16545
181 : // ALLOW_INT = 0x04, //!< unimplemented, draft implementation in #16545
182 : // ALLOW_STRING = 0x08, //!< unimplemented, draft implementation in #16545
183 : // ALLOW_LIST = 0x10, //!< unimplemented, draft implementation in #16545
184 : DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
185 : DISALLOW_ELISION = 0x40, //!< disallow -foo syntax that doesn't assign any value
186 :
187 : DEBUG_ONLY = 0x100,
188 : /* Some options would cause cross-contamination if values for
189 : * mainnet were used while running on regtest/testnet (or vice-versa).
190 : * Setting them as NETWORK_ONLY ensures that sharing a config file
191 : * between mainnet and regtest/testnet won't cause problems due to these
192 : * parameters by accident. */
193 : NETWORK_ONLY = 0x200,
194 : // This argument's value is sensitive (such as a password).
195 : SENSITIVE = 0x400,
196 : COMMAND = 0x800,
197 : };
198 :
199 : protected:
200 : struct Arg
201 : {
202 : std::string m_help_param;
203 : std::string m_help_text;
204 : unsigned int m_flags;
205 : };
206 :
207 : mutable RecursiveMutex cs_args;
208 : util::Settings m_settings GUARDED_BY(cs_args);
209 : std::vector<std::string> m_command GUARDED_BY(cs_args);
210 : std::string m_network GUARDED_BY(cs_args);
211 : std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
212 : std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
213 : bool m_accept_any_command GUARDED_BY(cs_args){true};
214 : std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
215 : mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
216 : mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
217 : mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
218 :
219 : [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
220 :
221 : /**
222 : * Returns true if settings values from the default section should be used,
223 : * depending on the current network and whether the setting is
224 : * network-specific.
225 : */
226 : bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
227 :
228 : public:
229 : /**
230 : * Get setting value.
231 : *
232 : * Result will be null if setting was unset, true if "-setting" argument was passed
233 : * false if "-nosetting" argument was passed, and a string if a "-setting=value"
234 : * argument was passed.
235 : */
236 : util::SettingsValue GetSetting(const std::string& arg) const;
237 :
238 : /**
239 : * Get list of setting values.
240 : */
241 : std::vector<util::SettingsValue> GetSettingsList(const std::string& arg) const;
242 :
243 : ArgsManager();
244 : ~ArgsManager();
245 :
246 : /**
247 : * Select the network in use
248 : */
249 : void SelectConfigNetwork(const std::string& network);
250 :
251 : [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
252 :
253 : /**
254 : * Return config file path (read-only)
255 : */
256 : fs::path GetConfigFilePath() const;
257 : [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
258 :
259 : /**
260 : * Log warnings for options in m_section_only_args when
261 : * they are specified in the default section but not overridden
262 : * on the command line or in a network-specific section in the
263 : * config file.
264 : */
265 : std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
266 :
267 : /**
268 : * Log warnings for unrecognized section names in the config file.
269 : */
270 : std::list<SectionInfo> GetUnrecognizedSections() const;
271 :
272 : struct Command {
273 : /** The command (if one has been registered with AddCommand), or empty */
274 : std::string command;
275 : /**
276 : * If command is non-empty: Any args that followed it
277 : * If command is empty: The unregistered command and any args that followed it
278 : */
279 : std::vector<std::string> args;
280 : };
281 : /**
282 : * Get the command and command args (returns std::nullopt if no command provided)
283 : */
284 : std::optional<const Command> GetCommand() const;
285 :
286 : /**
287 : * Return the map of all the args passed via the command line
288 : */
289 : std::map<std::string, std::vector<util::SettingsValue>> GetCommandLineArgs() const;
290 :
291 : /**
292 : * Get blocks directory path
293 : *
294 : * @return Blocks path which is network specific
295 : */
296 : fs::path GetBlocksDirPath() const;
297 :
298 : /**
299 : * Get data directory path
300 : *
301 : * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
302 : */
303 851 : fs::path GetDataDirBase() const { return GetDataDir(false); }
304 :
305 : /**
306 : * Get data directory path with appended network identifier
307 : *
308 : * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
309 : */
310 4382 : fs::path GetDataDirNet() const { return GetDataDir(true); }
311 :
312 : fs::path GetBackupsDirPath();
313 :
314 : /**
315 : * Clear cached directory paths
316 : */
317 : void ClearPathCache();
318 :
319 : /**
320 : * Return a vector of strings of the given argument
321 : *
322 : * @param strArg Argument to get (e.g. "-foo")
323 : * @return command-line arguments
324 : */
325 : std::vector<std::string> GetArgs(const std::string& strArg) const;
326 :
327 : /**
328 : * Return true if the given argument has been manually set
329 : *
330 : * @param strArg Argument to get (e.g. "-foo")
331 : * @return true if the argument has been set
332 : */
333 : bool IsArgSet(const std::string& strArg) const;
334 :
335 : /**
336 : * Return true if the argument was originally passed as a negated option,
337 : * i.e. -nofoo.
338 : *
339 : * @param strArg Argument to get (e.g. "-foo")
340 : * @return true if the argument was passed negated
341 : */
342 : bool IsArgNegated(const std::string& strArg) const;
343 :
344 : /**
345 : * Return string argument or default value
346 : *
347 : * @param strArg Argument to get (e.g. "-foo")
348 : * @param strDefault (e.g. "1")
349 : * @return command-line argument or default value
350 : */
351 : std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
352 :
353 : /**
354 : * Return path argument or default value
355 : *
356 : * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
357 : * @param default_value Optional default value to return instead of the empty path.
358 : * @return normalized path if argument is set, with redundant "." and ".."
359 : * path components and trailing separators removed (see patharg unit test
360 : * for examples or implementation for details). If argument is empty or not
361 : * set, default_value is returned unchanged.
362 : */
363 : fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;
364 :
365 : /**
366 : * Return integer argument or default value
367 : *
368 : * @param strArg Argument to get (e.g. "-foo")
369 : * @param nDefault (e.g. 1)
370 : * @return command-line argument (0 if invalid number) or default value
371 : */
372 : int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
373 :
374 : /**
375 : * Return boolean argument or default value
376 : *
377 : * @param strArg Argument to get (e.g. "-foo")
378 : * @param fDefault (true or false)
379 : * @return command-line argument or default value
380 : */
381 : bool GetBoolArg(const std::string& strArg, bool fDefault) const;
382 :
383 : /**
384 : * Set an argument if it doesn't already have a value
385 : *
386 : * @param strArg Argument to set (e.g. "-foo")
387 : * @param strValue Value (e.g. "1")
388 : * @return true if argument gets set, false if it already had a value
389 : */
390 : bool SoftSetArg(const std::string& strArg, const std::string& strValue);
391 :
392 : /**
393 : * Set a boolean argument if it doesn't already have a value
394 : *
395 : * @param strArg Argument to set (e.g. "-foo")
396 : * @param fValue Value (e.g. false)
397 : * @return true if argument gets set, false if it already had a value
398 : */
399 : bool SoftSetBoolArg(const std::string& strArg, bool fValue);
400 :
401 : // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
402 : // been set. Also called directly in testing.
403 : void ForceSetArg(const std::string& strArg, const std::string& strValue);
404 : void ForceRemoveArg(const std::string& strArg);
405 :
406 : /**
407 : * Returns the appropriate chain name from the program arguments.
408 : * @return CBaseChainParams::MAIN by default; raises runtime error if an invalid combination is given.
409 : */
410 : std::string GetChainName() const;
411 :
412 : /**
413 : * Looks for -devnet and returns either "devnet-<name>" or simply "devnet" if no name was specified.
414 : * This function should never be called for non-devnets.
415 : * @return either "devnet-<name>" or "devnet"; raises runtime error if no -devent was specified.
416 : */
417 : std::string GetDevNetName() const;
418 :
419 : /**
420 : * Add argument
421 : */
422 : void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
423 :
424 : /**
425 : * Add subcommand
426 : */
427 : void AddCommand(const std::string& cmd, const std::string& help);
428 :
429 : /**
430 : * Add many hidden arguments
431 : */
432 : void AddHiddenArgs(const std::vector<std::string>& args);
433 :
434 : /**
435 : * Clear available arguments
436 : */
437 626 : void ClearArgs() {
438 626 : LOCK(cs_args);
439 626 : m_available_args.clear();
440 626 : m_network_only_args.clear();
441 626 : }
442 :
443 : /**
444 : * Get the help string
445 : */
446 : std::string GetHelpMessage() const;
447 :
448 : /**
449 : * Return Flags for known arg.
450 : * Return nullopt for unknown arg.
451 : */
452 : std::optional<unsigned int> GetArgFlags(const std::string& name) const;
453 :
454 : /**
455 : * Read and update settings file with saved settings. This needs to be
456 : * called after SelectParams() because the settings file location is
457 : * network-specific.
458 : */
459 : bool InitSettings(std::string& error);
460 :
461 : /**
462 : * Get settings file path, or return false if read-write settings were
463 : * disabled with -nosettings.
464 : */
465 : bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;
466 :
467 : /**
468 : * Read settings file. Push errors to vector, or log them if null.
469 : */
470 : bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
471 :
472 : /**
473 : * Write settings file or backup settings file. Push errors to vector, or
474 : * log them if null.
475 : */
476 : bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;
477 :
478 : /**
479 : * Get current setting from config file or read/write settings file,
480 : * ignoring nonpersistent command line or forced settings values.
481 : */
482 : util::SettingsValue GetPersistentSetting(const std::string& name) const;
483 :
484 : /**
485 : * Access settings with lock held.
486 : */
487 : template <typename Fn>
488 15 : void LockSettings(Fn&& fn)
489 : {
490 15 : LOCK(cs_args);
491 15 : fn(m_settings);
492 15 : }
493 :
494 : /**
495 : * Log the config file options and the command line arguments,
496 : * useful for troubleshooting.
497 : */
498 : void LogArgs() const;
499 :
500 : /**
501 : * If datadir does not exist, create it along with wallets/
502 : * subdirectory(s).
503 : */
504 : void EnsureDataDir() const;
505 :
506 : private:
507 : /**
508 : * Get data directory path
509 : *
510 : * @param net_specific Append network identifier to the returned path
511 : * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
512 : */
513 : fs::path GetDataDir(bool net_specific) const;
514 :
515 : // Helper function for LogArgs().
516 : void logArgsPrefix(
517 : const std::string& prefix,
518 : const std::string& section,
519 : const std::map<std::string, std::vector<util::SettingsValue>>& args) const;
520 : };
521 :
522 : extern ArgsManager gArgs;
523 :
524 : /**
525 : * @return true if help has been requested via a command-line arg
526 : */
527 : bool HelpRequested(const ArgsManager& args);
528 :
529 : /** Add help options to the args manager */
530 : void SetupHelpOptions(ArgsManager& args);
531 :
532 : /**
533 : * Format a string to be used as group of options in help messages
534 : *
535 : * @param message Group name (e.g. "RPC server options:")
536 : * @return the formatted string
537 : */
538 : std::string HelpMessageGroup(const std::string& message);
539 :
540 : /**
541 : * Format a string to be used as option description in help messages
542 : *
543 : * @param option Option message (e.g. "-rpcuser=<user>")
544 : * @param message Option description (e.g. "Username for JSON-RPC connections")
545 : * @return the formatted string
546 : */
547 : std::string HelpMessageOpt(const std::string& option, const std::string& message);
548 :
549 : /**
550 : * Return the number of cores available on the current system.
551 : * @note This does count virtual cores, such as those provided by HyperThreading.
552 : */
553 : int GetNumCores();
554 :
555 : namespace ctpl {
556 : class thread_pool;
557 : }
558 : void RenameThreadPool(ctpl::thread_pool& tp, const char* baseName);
559 :
560 : /**
561 : * On platforms that support it, tell the kernel the calling thread is
562 : * CPU-intensive and non-interactive. See SCHED_BATCH in sched(7) for details.
563 : *
564 : */
565 : void ScheduleBatchPriority();
566 :
567 : namespace util {
568 :
569 : //! Simplification of std insertion
570 : template <typename Tdst, typename Tsrc>
571 : inline void insert(Tdst& dst, const Tsrc& src) {
572 : dst.insert(dst.begin(), src.begin(), src.end());
573 : }
574 : template <typename TsetT, typename Tsrc>
575 145572 : inline void insert(std::set<TsetT>& dst, const Tsrc& src) {
576 145572 : dst.insert(src.begin(), src.end());
577 145572 : }
578 :
579 : #ifdef WIN32
580 : class WinCmdLineArgs
581 : {
582 : public:
583 : WinCmdLineArgs();
584 : ~WinCmdLineArgs();
585 : std::pair<int, char**> get();
586 :
587 : private:
588 : int argc;
589 : char** argv;
590 : std::vector<std::string> args;
591 : };
592 : #endif
593 :
594 : } // namespace util
595 :
596 : #endif // BITCOIN_UTIL_SYSTEM_H
|