LCOV - code coverage report
Current view: top level - src/util - system.h (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 19 21 90.5 %
Date: 2026-06-25 07:23:51 Functions: 27 77 35.1 %

          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

Generated by: LCOV version 1.16