LCOV - code coverage report
Current view: top level - src/util - system.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 342 377 90.7 %
Date: 2025-02-23 09:33:43 Functions: 56 57 98.2 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2014-2015 The Dash developers
       4             : // Copyright (c) 2015-2022 The PIVX Core developers
       5             : // Distributed under the MIT software license, see the accompanying
       6             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       7             : 
       8             : #if defined(HAVE_CONFIG_H)
       9             : #include "config/pivx-config.h"
      10             : #endif
      11             : 
      12             : #include "util/system.h"
      13             : 
      14             : #include "chainparamsbase.h"
      15             : #include "random.h"
      16             : #include "support/allocators/zeroafterfree.h"
      17             : #include "utilstrencodings.h"
      18             : #include "utiltime.h"
      19             : 
      20             : #include <librustzcash.h>
      21             : 
      22             : #include <stdarg.h>
      23             : #include <thread>
      24             : 
      25             : #ifndef WIN32
      26             : // for posix_fallocate
      27             : #ifdef __linux__
      28             : 
      29             : #ifdef _POSIX_C_SOURCE
      30             : #undef _POSIX_C_SOURCE
      31             : #endif
      32             : 
      33             : #define _POSIX_C_SOURCE 200112L
      34             : 
      35             : #endif // __linux__
      36             : 
      37             : #include <algorithm>
      38             : #include <fcntl.h>
      39             : #include <sched.h>
      40             : #include <sys/resource.h>
      41             : #include <sys/stat.h>
      42             : 
      43             : #else
      44             : 
      45             : #ifdef _MSC_VER
      46             : #pragma warning(disable : 4786)
      47             : #pragma warning(disable : 4804)
      48             : #pragma warning(disable : 4805)
      49             : #pragma warning(disable : 4717)
      50             : #endif
      51             : 
      52             : #ifdef _WIN32_WINNT
      53             : #undef _WIN32_WINNT
      54             : #endif
      55             : #define _WIN32_WINNT 0x0501
      56             : 
      57             : #ifdef _WIN32_IE
      58             : #undef _WIN32_IE
      59             : #endif
      60             : #define _WIN32_IE 0x0501
      61             : 
      62             : #define WIN32_LEAN_AND_MEAN 1
      63             : #ifndef NOMINMAX
      64             : #define NOMINMAX
      65             : #endif
      66             : #include <codecvt>
      67             : 
      68             : #include <io.h> /* for _commit */
      69             : #include <shellapi.h>
      70             : #include <shlobj.h>
      71             : #endif
      72             : 
      73             : #ifdef HAVE_SYS_PRCTL_H
      74             : #include <sys/prctl.h>
      75             : #endif
      76             : 
      77             : #ifdef MAC_OSX
      78             : #include <CoreFoundation/CoreFoundation.h>
      79             : #endif
      80             : 
      81             : const char * const PIVX_CONF_FILENAME = "pivx.conf";
      82             : const char * const PIVX_MASTERNODE_CONF_FILENAME = "masternode.conf";
      83             : 
      84             : 
      85             : // PIVX only features
      86             : // Masternode
      87             : std::atomic<bool> fMasterNode{false};
      88             : 
      89             : ArgsManager gArgs;
      90             : 
      91             : CTranslationInterface translationInterface;
      92             : 
      93        2826 : bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
      94             : {
      95        2826 :     constexpr uint64_t min_disk_space = 52428800; // 50 MiB
      96             : 
      97        2826 :     uint64_t free_bytes_available = fs::space(dir).available;
      98        2826 :     return free_bytes_available >= min_disk_space + additional_bytes;
      99             : }
     100             : 
     101             : /** A map that contains all the currently held directory locks. After
     102             :  * successful locking, these will be held here until the global destructor
     103             :  * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
     104             :  * is called.
     105             :  */
     106             : static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks;
     107             : /** Mutex to protect dir_locks. */
     108             : static std::mutex cs_dir_locks;
     109             : 
     110        1151 : bool LockDirectory(const fs::path& directory, const std::string& lockfile_name, bool probe_only)
     111             : {
     112        2302 :     std::lock_guard<std::mutex> ulock(cs_dir_locks);
     113        3453 :     fs::path pathLockFile = directory / lockfile_name;
     114             : 
     115             :     // If a lock for this directory already exists in the map, don't try to re-lock it
     116        1151 :     if (dir_locks.count(pathLockFile.string())) {
     117          10 :         return true;
     118             :     }
     119             : 
     120             :     // Create empty lock file if it doesn't exist.
     121        1141 :     FILE* file = fsbridge::fopen(pathLockFile, "a");
     122        1141 :     if (file) fclose(file);
     123        1141 :     auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
     124        1141 :     if (!lock->TryLock()) {
     125          18 :         return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
     126             :     }
     127        1135 :     if (!probe_only) {
     128             :         // Lock successful and we're not just probing, put it into the map
     129        1141 :         dir_locks.emplace(pathLockFile.string(), std::move(lock));
     130             :     }
     131             :     return true;
     132             : }
     133             : 
     134           3 : void ReleaseDirectoryLocks()
     135             : {
     136           3 :     std::lock_guard<std::mutex> ulock(cs_dir_locks);
     137           3 :     dir_locks.clear();
     138           3 : }
     139             : 
     140         760 : bool DirIsWritable(const fs::path& directory)
     141             : {
     142        2280 :     fs::path tmpFile = directory / fs::unique_path();
     143             : 
     144         760 :     FILE* file = fsbridge::fopen(tmpFile, "a");
     145         760 :     if (!file) return false;
     146             : 
     147         759 :     fclose(file);
     148         760 :     remove(tmpFile);
     149             : 
     150             :     return true;
     151             : }
     152             : 
     153             : /**
     154             :  * Interpret a string argument as a boolean.
     155             :  *
     156             :  * The definition of atoi() requires that non-numeric string values like "foo",
     157             :  * return 0. This means that if a user unintentionally supplies a non-integer
     158             :  * argument here, the return value is always false. This means that -foo=false
     159             :  * does what the user probably expects, but -foo=true is well defined but does
     160             :  * not do what they probably expected.
     161             :  *
     162             :  * The return value of atoi() is undefined when given input not representable as
     163             :  * an int. On most systems this means string value between "-2147483648" and
     164             :  * "2147483647" are well defined (this method will return true). Setting
     165             :  * -txindex=2147483648 on most systems, however, is probably undefined.
     166             :  *
     167             :  * For a more extensive discussion of this topic (and a wide range of opinions
     168             :  * on the Right Way to change this code), see upstream PR12713.
     169             :  */
     170        4368 : static bool InterpretBool(const std::string& strValue)
     171             : {
     172        4368 :     if (strValue.empty())
     173             :         return true;
     174        3752 :     return (atoi(strValue) != 0);
     175             : }
     176             : 
     177             : /** Internal helper functions for ArgsManager */
     178             : class ArgsManagerHelper {
     179             : public:
     180             :     typedef std::map<std::string, std::vector<std::string>> MapArgs;
     181             : 
     182             :     /** Determine whether to use config settings in the default section,
     183             :      *  See also comments around ArgsManager::ArgsManager() below. */
     184     2782343 :     static inline bool UseDefaultSection(const ArgsManager& am, const std::string& arg)
     185             :     {
     186     5563931 :         return (am.m_network == CBaseChainParams::MAIN || am.m_network_only_args.count(arg) == 0);
     187             :     }
     188             : 
     189             :     /** Convert regular argument into the network-specific setting */
     190     5585708 :     static inline std::string NetworkArg(const ArgsManager& am, const std::string& arg)
     191             :     {
     192     5585708 :         assert(arg.length() > 1 && arg[0] == '-');
     193    13319536 :         return "-" + am.m_network + "." + arg.substr(1);
     194             :     }
     195             : 
     196             :     /** Find arguments in a map and add them to a vector */
     197       13706 :     static inline void AddArgs(std::vector<std::string>& res, const MapArgs& map_args, const std::string& arg)
     198             :     {
     199       13706 :         auto it = map_args.find(arg);
     200       13706 :         if (it != map_args.end()) {
     201        3203 :             res.insert(res.end(), it->second.begin(), it->second.end());
     202             :         }
     203       13706 :     }
     204             : 
     205             :     /** Return true/false if an argument is set in a map, and also
     206             :      *  return the first (or last) of the possibly multiple values it has
     207             :      */
     208     8369842 :     static inline std::pair<bool,std::string> GetArgHelper(const MapArgs& map_args, const std::string& arg, bool getLast = false)
     209             :     {
     210     8369842 :         auto it = map_args.find(arg);
     211             : 
     212     8369842 :         if (it == map_args.end() || it->second.empty()) {
     213    16691284 :             return std::make_pair(false, std::string());
     214             :         }
     215             : 
     216       24194 :         if (getLast) {
     217       10080 :             return std::make_pair(true, it->second.back());
     218             :         } else {
     219       14114 :             return std::make_pair(true, it->second.front());
     220             :         }
     221             :     }
     222             : 
     223             :     /* Get the string value of an argument, returning a pair of a boolean
     224             :      * indicating the argument was found, and the value for the argument
     225             :      * if it was found (or the empty string if not found).
     226             :      */
     227     2799303 :     static inline std::pair<bool,std::string> GetArg(const ArgsManager& am, const std::string& arg)
     228             :     {
     229     5598616 :         LOCK(am.cs_args);
     230     5598616 :         std::pair<bool,std::string> found_result(false, std::string());
     231             : 
     232             :         // We pass "true" to GetArgHelper in order to return the last
     233             :         // argument value seen from the command line (so "pivxd -foo=bar
     234             :         // -foo=baz" gives GetArg(am,"foo")=={true,"baz"}
     235     5598616 :         found_result = GetArgHelper(am.m_override_args, arg, true);
     236     2799303 :         if (found_result.first) {
     237             :             return found_result;
     238             :         }
     239             : 
     240             :         // But in contrast we return the first argument seen in a config file,
     241             :         // so "foo=bar \n foo=baz" in the config file gives
     242             :         // GetArg(am,"foo")={true,"bar"}
     243     2789667 :         if (!am.m_network.empty()) {
     244     5575060 :             found_result = GetArgHelper(am.m_config_args, NetworkArg(am, arg));
     245     2787530 :             if (found_result.first) {
     246             :                 return found_result;
     247             :             }
     248             :         }
     249             : 
     250     2777043 :         if (UseDefaultSection(am, arg)) {
     251     5551082 :             found_result = GetArgHelper(am.m_config_args, arg);
     252     2775541 :             if (found_result.first) {
     253             :                 return found_result;
     254             :             }
     255             :         }
     256             : 
     257             :         return found_result;
     258             :     }
     259             : 
     260             :     /* Special test for -testnet and -regtest args, because we
     261             :      * don't want to be confused by craziness like "[regtest] testnet=1"
     262             :      */
     263         884 :     static inline bool GetNetBoolArg(const ArgsManager &am, const std::string& net_arg)
     264             :     {
     265        1768 :         std::pair<bool,std::string> found_result(false,std::string());
     266        1768 :         found_result = GetArgHelper(am.m_override_args, net_arg, true);
     267         884 :         if (!found_result.first) {
     268        1704 :             found_result = GetArgHelper(am.m_config_args, net_arg, true);
     269         852 :             if (!found_result.first) {
     270             :                 return false; // not set
     271             :             }
     272             :         }
     273         440 :         return InterpretBool(found_result.second); // is set, so evaluate
     274             :     }
     275             : };
     276             : 
     277             : /**
     278             :  * Interpret -nofoo as if the user supplied -foo=0.
     279             :  *
     280             :  * This method also tracks when the -no form was supplied, and if so,
     281             :  * checks whether there was a double-negative (-nofoo=0 -> -foo=1).
     282             :  *
     283             :  * If there was not a double negative, it removes the "no" from the key,
     284             :  * and returns true, indicating the caller should clear the args vector
     285             :  * to indicate a negated option.
     286             :  *
     287             :  * If there was a double negative, it removes "no" from the key, sets the
     288             :  * value to "1" and returns false.
     289             :  *
     290             :  * If there was no "no", it leaves key and value untouched and returns
     291             :  * false.
     292             :  *
     293             :  * Where an option was negated can be later checked using the
     294             :  * IsArgNegated() method. One use case for this is to have a way to disable
     295             :  * options that are not normally boolean (e.g. using -nodebuglogfile to request
     296             :  * that debug log output is not sent to any file at all).
     297             :  */
     298        8196 : static bool InterpretNegatedOption(std::string& key, std::string& val)
     299             : {
     300        8196 :     assert(key[0] == '-');
     301             : 
     302        8196 :     size_t option_index = key.find('.');
     303        8196 :     if (option_index == std::string::npos) {
     304             :         option_index = 1;
     305             :     } else {
     306        3935 :         ++option_index;
     307             :     }
     308        8196 :     if (key.substr(option_index, 2) == "no") {
     309          51 :         bool bool_val = InterpretBool(val);
     310          51 :         key.erase(option_index, 2);
     311          51 :         if (!bool_val ) {
     312             :             // Double negatives like -nofoo=0 are supported (but discouraged)
     313           8 :             LogPrintf("Warning: parsed potentially confusing double-negative %s=%s\n", key, val);
     314           8 :             val = "1";
     315             :         } else {
     316             :             return true;
     317             :         }
     318             :     }
     319             :     return false;
     320             : }
     321             : 
     322         516 : ArgsManager::ArgsManager() :
     323             :     /* These options would cause cross-contamination if values for
     324             :      * mainnet were used while running on regtest/testnet (or vice-versa).
     325             :      * Setting them as section_only_args ensures that sharing a config file
     326             :      * between mainnet and regtest/testnet won't cause problems due to these
     327             :      * parameters by accident. */
     328             :     m_network_only_args{
     329             :       "-addnode", "-connect",
     330             :       "-port", "-bind",
     331             :       "-rpcport", "-rpcbind",
     332             :       "-wallet",
     333        4128 :     }
     334             : {
     335             :     // nothing to do
     336         516 : }
     337             : 
     338         357 : void ArgsManager::WarnForSectionOnlyArgs()
     339             : {
     340             :     // if there's no section selected, don't worry
     341         357 :     if (m_network.empty()) return;
     342             : 
     343             :     // if it's okay to use the default section for this network, don't worry
     344         357 :     if (m_network == CBaseChainParams::MAIN) return;
     345             : 
     346        2856 :     for (const auto& arg : m_network_only_args) {
     347        2499 :         std::pair<bool, std::string> found_result;
     348             : 
     349             :         // if this option is overridden it's fine
     350        4998 :         found_result = ArgsManagerHelper::GetArgHelper(m_override_args, arg);
     351        4998 :         if (found_result.first) continue;
     352             : 
     353             :         // if there's a network-specific value for this option, it's fine
     354        4292 :         found_result = ArgsManagerHelper::GetArgHelper(m_config_args, ArgsManagerHelper::NetworkArg(*this, arg));
     355        2146 :         if (found_result.first) continue;
     356             : 
     357             :         // if there isn't a default value for this option, it's fine
     358        2172 :         found_result = ArgsManagerHelper::GetArgHelper(m_config_args, arg);
     359        1086 :         if (!found_result.first) continue;
     360             : 
     361             :         // otherwise, issue a warning
     362           0 :         LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network);
     363             :     }
     364             : }
     365             : 
     366         957 : void ArgsManager::SelectConfigNetwork(const std::string& network)
     367             : {
     368         957 :     m_network = network;
     369         957 : }
     370             : 
     371         486 : void ArgsManager::ParseParameters(int argc, const char* const argv[])
     372             : {
     373         486 :     LOCK(cs_args);
     374         486 :     m_override_args.clear();
     375             : 
     376        4281 :     for (int i = 1; i < argc; i++) {
     377        7613 :         std::string key(argv[i]);
     378        7613 :         std::string val;
     379        3818 :         size_t is_index = key.find('=');
     380        3818 :         if (is_index != std::string::npos) {
     381        2802 :             val = key.substr(is_index + 1);
     382        2802 :             key.erase(is_index);
     383             :         }
     384             : #ifdef WIN32
     385             :         std::transform(key.begin(), key.end(), key.begin(), ::tolower);
     386             :         if (key[0] == '/')
     387             :             key[0] = '-';
     388             : #endif
     389             : 
     390        3818 :         if (key[0] != '-')
     391             :             break;
     392             : 
     393             :         // Transform --foo to -foo
     394        3795 :         if (key.length() > 1 && key[1] == '-')
     395           6 :             key.erase(0, 1);
     396             : 
     397             :         // Check for -nofoo
     398        3795 :         if (InterpretNegatedOption(key, val)) {
     399        3795 :             m_override_args[key].clear();
     400             :         } else {
     401        3762 :             m_override_args[key].push_back(val);
     402             :         }
     403             :     }
     404         486 : }
     405             : 
     406        5312 : std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
     407             : {
     408        5312 :     std::vector<std::string> result = {};
     409        5312 :     if (IsArgNegated(strArg)) return result; // special case
     410             : 
     411       10615 :     LOCK(cs_args);
     412             : 
     413        5303 :     ArgsManagerHelper::AddArgs(result, m_override_args, strArg);
     414        5303 :     if (!m_network.empty()) {
     415       10534 :         ArgsManagerHelper::AddArgs(result, m_config_args, ArgsManagerHelper::NetworkArg(*this, strArg));
     416             :     }
     417             : 
     418        5303 :     if (ArgsManagerHelper::UseDefaultSection(*this, strArg)) {
     419        3136 :         ArgsManagerHelper::AddArgs(result, m_config_args, strArg);
     420             :     }
     421             : 
     422        5303 :     return result;
     423             : }
     424             : 
     425      395971 : bool ArgsManager::IsArgSet(const std::string& strArg) const
     426             : {
     427      395971 :     if (IsArgNegated(strArg)) return true; // special case
     428      396457 :     return ArgsManagerHelper::GetArg(*this, strArg).first;
     429             : }
     430             : 
     431     2805111 : bool ArgsManager::IsArgNegated(const std::string& strArg) const
     432             : {
     433     5610222 :     LOCK(cs_args);
     434             : 
     435     2805111 :     const auto& ov = m_override_args.find(strArg);
     436     2805111 :     if (ov != m_override_args.end()) return ov->second.empty();
     437             : 
     438     2792975 :     if (!m_network.empty()) {
     439     5581538 :         const auto& cfs = m_config_args.find(ArgsManagerHelper::NetworkArg(*this, strArg));
     440     2790764 :         if (cfs != m_config_args.end()) return cfs->second.empty();
     441             :     }
     442             : 
     443     2779611 :     const auto& cf = m_config_args.find(strArg);
     444     2779611 :     if (cf != m_config_args.end()) return cf->second.empty();
     445             : 
     446             :     return false;
     447             : }
     448             : 
     449      403910 : std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
     450             : {
     451      403910 :     if (IsArgNegated(strArg)) return "0";
     452      807803 :     std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
     453      403893 :     if (found_res.first) return found_res.second;
     454      804863 :     return strDefault;
     455             : }
     456             : 
     457     1471990 : int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
     458             : {
     459     1471990 :     if (IsArgNegated(strArg)) return 0;
     460     2943980 :     std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
     461     1471990 :     if (found_res.first) return atoi64(found_res.second);
     462             :     return nDefault;
     463             : }
     464             : 
     465      527506 : bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
     466             : {
     467      527506 :     if (IsArgNegated(strArg)) return false;
     468     1054964 :     std::pair<bool,std::string> found_res = ArgsManagerHelper::GetArg(*this, strArg);
     469      527459 :     if (found_res.first) return InterpretBool(found_res.second);
     470             :     return fDefault;
     471             : }
     472             : 
     473        1229 : bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
     474             : {
     475        2458 :     LOCK(cs_args);
     476        1229 :     if (IsArgSet(strArg)) return false;
     477         734 :     ForceSetArg(strArg, strValue);
     478             :     return true;
     479             : }
     480             : 
     481         853 : bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
     482             : {
     483         853 :     if (fValue)
     484         767 :         return SoftSetArg(strArg, std::string("1"));
     485             :     else
     486          86 :         return SoftSetArg(strArg, std::string("0"));
     487             : }
     488             : 
     489         910 : void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
     490             : {
     491         910 :     LOCK(cs_args);
     492        2730 :     m_override_args[strArg] = {strValue};
     493         910 : }
     494             : 
     495             : static const int screenWidth = 79;
     496             : static const int optIndent = 2;
     497             : static const int msgIndent = 7;
     498             : 
     499          11 : std::string HelpMessageGroup(const std::string &message) {
     500          33 :     return std::string(message) + std::string("\n\n");
     501             : }
     502             : 
     503         119 : std::string HelpMessageOpt(const std::string &option, const std::string &message) {
     504         411 :     return std::string(optIndent,' ') + std::string(option) +
     505         476 :            std::string("\n") + std::string(msgIndent,' ') +
     506         357 :            FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
     507         357 :            std::string("\n\n");
     508             : }
     509             : 
     510           3 : static std::string FormatException(const std::exception* pex, const char* pszThread)
     511             : {
     512             : #ifdef WIN32
     513             :     char pszModule[MAX_PATH] = "";
     514             :     GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
     515             : #else
     516           3 :     const char* pszModule = "pivx";
     517             : #endif
     518           3 :     if (pex)
     519           3 :         return strprintf(
     520           3 :             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
     521             :     else
     522           0 :         return strprintf(
     523           0 :             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);
     524             : }
     525             : 
     526           3 : void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
     527             : {
     528           3 :     std::string message = FormatException(pex, pszThread);
     529           3 :     LogPrintf("\n\n************************\n%s\n", message);
     530           3 :     fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
     531           3 : }
     532             : 
     533         376 : fs::path GetDefaultDataDir()
     534             : {
     535             : // Windows < Vista: C:\Documents and Settings\Username\Application Data\PIVX
     536             : // Windows >= Vista: C:\Users\Username\AppData\Roaming\PIVX
     537             : // Mac: ~/Library/Application Support/PIVX
     538             : // Unix: ~/.pivx
     539             : #ifdef WIN32
     540             :     // Windows
     541             :     return GetSpecialFolderPath(CSIDL_APPDATA) / "PIVX";
     542             : #else
     543         376 :     fs::path pathRet;
     544         376 :     char* pszHome = getenv("HOME");
     545         376 :     if (pszHome == nullptr || strlen(pszHome) == 0)
     546           0 :         pathRet = fs::path("/");
     547             :     else
     548         376 :         pathRet = fs::path(pszHome);
     549             : #ifdef MAC_OSX
     550             :     // Mac
     551             :     pathRet /= "Library/Application Support";
     552             :     TryCreateDirectories(pathRet);
     553             :     return pathRet / "PIVX";
     554             : #else
     555             :     // Unix
     556         752 :     return pathRet / ".pivx";
     557             : #endif
     558             : #endif
     559             : }
     560             : 
     561             : static fs::path g_blocks_path_cache_net_specific;
     562             : static fs::path pathCached;
     563             : static fs::path pathCachedNetSpecific;
     564             : static fs::path zc_paramsPathCached;
     565             : static RecursiveMutex csPathCached;
     566             : 
     567         387 : static fs::path ZC_GetBaseParamsDir()
     568             : {
     569             :     // Copied from GetDefaultDataDir and adapter for zcash params.
     570             :     // Windows < Vista: C:\Documents and Settings\Username\Application Data\PIVXParams
     571             :     // Windows >= Vista: C:\Users\Username\AppData\Roaming\PIVXParams
     572             :     // Mac: ~/Library/Application Support/PIVXParams
     573             :     // Unix: ~/.pivx-params
     574             : #ifdef WIN32
     575             :     // Windows
     576             :     return GetSpecialFolderPath(CSIDL_APPDATA) / "PIVXParams";
     577             : #else
     578         387 :     fs::path pathRet;
     579         387 :     char* pszHome = getenv("HOME");
     580         387 :     if (pszHome == nullptr || strlen(pszHome) == 0)
     581           0 :         pathRet = fs::path("/");
     582             :     else
     583         387 :         pathRet = fs::path(pszHome);
     584             : #ifdef MAC_OSX
     585             :     // Mac
     586             :     pathRet /= "Library/Application Support";
     587             :     TryCreateDirectories(pathRet);
     588             :     return pathRet / "PIVXParams";
     589             : #else
     590             :     // Unix
     591         774 :     return pathRet / ".pivx-params";
     592             : #endif
     593             : #endif
     594             : }
     595             : 
     596         424 : const fs::path &ZC_GetParamsDir()
     597             : {
     598         848 :     LOCK(csPathCached); // Reuse the same lock as upstream.
     599             : 
     600         424 :     fs::path &path = zc_paramsPathCached;
     601             : 
     602             :     // This can be called during exceptions by LogPrintf(), so we cache the
     603             :     // value so we don't have to do memory allocations after that.
     604         424 :     if (!path.empty())
     605             :         return path;
     606             : 
     607             : #ifdef USE_CUSTOM_PARAMS
     608             :     path = fs::system_complete(PARAMS_DIR);
     609             : #else
     610         387 :     if (gArgs.IsArgSet("-paramsdir")) {
     611           0 :         path = fs::system_complete(gArgs.GetArg("-paramsdir", ""));
     612           0 :         if (!fs::is_directory(path)) {
     613         424 :             path = "";
     614             :             return path;
     615             :         }
     616             :     } else {
     617         774 :         path = ZC_GetBaseParamsDir();
     618             :     }
     619             : #endif
     620             : 
     621             :     return path;
     622             : }
     623             : 
     624         423 : void initZKSNARKS()
     625             : {
     626         423 :     const fs::path& path = ZC_GetParamsDir();
     627         423 :     fs::path sapling_spend = path / "sapling-spend.params";
     628         846 :     fs::path sapling_output = path / "sapling-output.params";
     629             : 
     630         423 :     bool fParamsFound = false;
     631         846 :     if (fs::exists(sapling_spend) && fs::exists(sapling_output)) {
     632             :         fParamsFound = true;
     633             :     } else {
     634             : #ifdef MAC_OSX
     635             :         // macOS fallback path for params located within the app bundle
     636             :         // This is a somewhat convoluted series of CoreFoundation calls
     637             :         // that will result in the full path to the app bundle's "Resources"
     638             :         // directory, which will contain the sapling params.
     639             :         LogPrintf("Attempting to find params in app bundle...\n");
     640             :         CFBundleRef mainBundle = CFBundleGetMainBundle();
     641             :         CFURLRef bundleURL = CFBundleCopyBundleURL(mainBundle);
     642             : 
     643             :         CFStringRef strBundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
     644             :         const char* pathBundle = CFStringGetCStringPtr(strBundlePath, CFStringGetSystemEncoding());
     645             : 
     646             :         fs::path bundle_path = fs::path(pathBundle);
     647             :         LogPrintf("App bundle Resources path: %s\n", bundle_path);
     648             :         sapling_spend = bundle_path / "Contents/Resources/sapling-spend.params";
     649             :         sapling_output = bundle_path / "Contents/Resources/sapling-output.params";
     650             : 
     651             :         // Release the CF objects
     652             :         CFRelease(strBundlePath);
     653             :         CFRelease(bundleURL);
     654             :         CFRelease(mainBundle);
     655             : #else
     656             :         // Linux fallback path for debuild/ppa based installs
     657           0 :         sapling_spend = "/usr/share/pivx/sapling-spend.params";
     658           0 :         sapling_output = "/usr/share/pivx/sapling-output.params";
     659           0 :         if (fs::exists(sapling_spend) && fs::exists(sapling_output)) {
     660             :             fParamsFound = true;
     661             :         } else {
     662             :             // Linux fallback for local installs
     663           0 :             sapling_spend = "/usr/local/share/pivx/sapling-spend.params";
     664           0 :             sapling_output = "/usr/local/share/pivx/sapling-output.params";
     665             :         }
     666             : #endif
     667           0 :         if (fs::exists(sapling_spend) && fs::exists(sapling_output))
     668           0 :             fParamsFound = true;
     669             :     }
     670         423 :     if (!fParamsFound)
     671           0 :         throw std::runtime_error("Sapling params don't exist");
     672             : 
     673         423 :     static_assert(
     674             :         sizeof(fs::path::value_type) == sizeof(codeunit),
     675             :         "librustzcash not configured correctly");
     676         846 :     auto sapling_spend_str = sapling_spend.native();
     677         846 :     auto sapling_output_str = sapling_output.native();
     678             : 
     679             :     //LogPrintf("Loading Sapling (Spend) parameters from %s\n", sapling_spend.string().c_str());
     680             : 
     681         423 :     librustzcash_init_zksnark_params(
     682         423 :         reinterpret_cast<const codeunit*>(sapling_spend_str.c_str()),
     683             :         sapling_spend_str.length(),
     684             :         "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c",
     685         423 :         reinterpret_cast<const codeunit*>(sapling_output_str.c_str()),
     686             :         sapling_output_str.length(),
     687             :         "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028",
     688             :         nullptr,    // sprout_path
     689             :         0,          // sprout_path_len
     690             :         ""          // sprout_hash
     691             :     );
     692             : 
     693             :     //std::cout << "### Sapling params initialized ###" << std::endl;
     694         423 : }
     695             : 
     696      457332 : const fs::path &GetBlocksDir()
     697             : {
     698             : 
     699      914664 :     LOCK(csPathCached);
     700             : 
     701      457332 :     fs::path &path = g_blocks_path_cache_net_specific;
     702             : 
     703             :     // This can be called during exceptions by LogPrintf(), so we cache the
     704             :     // value so we don't have to do memory allocations after that.
     705      457332 :     if (!path.empty())
     706             :         return path;
     707             : 
     708         505 :     if (gArgs.IsArgSet("-blocksdir")) {
     709           8 :         path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
     710           2 :         if (!fs::is_directory(path)) {
     711           1 :             path = "";
     712             :             return path;
     713             :         }
     714             :     } else {
     715         503 :         path = GetDataDir(false);
     716             :     }
     717             : 
     718         504 :     path /= BaseParams().DataDir();
     719         504 :     path /= "blocks";
     720      457332 :     fs::create_directories(path);
     721             :     return path;
     722             : }
     723             : 
     724       18944 : const fs::path& GetDataDir(bool fNetSpecific)
     725             : {
     726       37888 :     LOCK(csPathCached);
     727             : 
     728       18944 :     fs::path& path = fNetSpecific ? pathCachedNetSpecific : pathCached;
     729             : 
     730             :     // This can be called during exceptions by LogPrintf(), so we cache the
     731             :     // value so we don't have to do memory allocations after that.
     732       18944 :     if (!path.empty()) return path;
     733             : 
     734       21744 :     std::string datadir = gArgs.GetArg("-datadir", "");
     735        1400 :     if (!datadir.empty()) {
     736        3354 :         path = fs::system_complete(datadir);
     737        1400 :         if (!fs::is_directory(path)) {
     738        1400 :             path = "";
     739             :             return path;
     740             :         }
     741             :     } else {
     742           0 :         path = GetDefaultDataDir();
     743             :     }
     744        1400 :     if (fNetSpecific)
     745         508 :         path /= BaseParams().DataDir();
     746             : 
     747        1400 :     if (fs::create_directories(path)) {
     748             :         // This is the first run, create wallets subdirectory too
     749         687 :         fs::create_directories(path / "wallets");
     750             :     }
     751             : 
     752             :     return path;
     753             : }
     754             : 
     755         783 : bool CheckDataDirOption()
     756             : {
     757        1566 :     std::string datadir = gArgs.GetArg("-datadir", "");
     758        4686 :     return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
     759             : }
     760             : 
     761         509 : void ClearDatadirCache()
     762             : {
     763         509 :     LOCK(csPathCached);
     764             : 
     765         509 :     pathCached = fs::path();
     766         509 :     pathCachedNetSpecific = fs::path();
     767         509 :     g_blocks_path_cache_net_specific = fs::path();
     768         509 : }
     769             : 
     770         767 : fs::path GetConfigFile(const std::string& confPath)
     771             : {
     772         767 :     fs::path pathConfigFile(confPath);
     773        1534 :     return AbsPathForConfigVal(pathConfigFile, false);
     774             : }
     775             : 
     776         368 : fs::path GetMasternodeConfigFile()
     777             : {
     778         736 :     fs::path pathConfigFile(gArgs.GetArg("-mnconf", PIVX_MASTERNODE_CONF_FILENAME));
     779         736 :     return AbsPathForConfigVal(pathConfigFile);
     780             : }
     781             : 
     782       13620 : static std::string TrimString(const std::string& str, const std::string& pattern)
     783             : {
     784       13620 :     std::string::size_type front = str.find_first_not_of(pattern);
     785       13620 :     if (front == std::string::npos) {
     786           4 :         return std::string();
     787             :     }
     788       13616 :     std::string::size_type end = str.find_last_not_of(pattern);
     789       13616 :     return str.substr(front, end - front + 1);
     790             : }
     791             : 
     792         417 : static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::istream& stream)
     793             : {
     794         417 :     std::vector<std::pair<std::string, std::string>> options;
     795         834 :     std::string str, prefix;
     796        5235 :     std::string::size_type pos;
     797        5235 :     while (std::getline(stream, str)) {
     798        4818 :         if ((pos = str.find('#')) != std::string::npos) {
     799           0 :             str = str.substr(0, pos);
     800             :         }
     801        4818 :         const static std::string pattern = " \t\r\n";
     802        4818 :         str = TrimString(str, pattern);
     803        4818 :         if (!str.empty()) {
     804        4816 :             if (*str.begin() == '[' && *str.rbegin() == ']') {
     805         415 :                 prefix = str.substr(1, str.size() - 2) + '.';
     806        4401 :             } else if ((pos = str.find('=')) != std::string::npos) {
     807       13203 :                 std::string name = prefix + TrimString(str.substr(0, pos), pattern);
     808        8802 :                 std::string value = TrimString(str.substr(pos + 1), pattern);
     809        4401 :                 options.emplace_back(name, value);
     810             :             }
     811             :         }
     812             :     }
     813         834 :     return options;
     814             : }
     815             : 
     816         417 : void ArgsManager::ReadConfigStream(std::istream& stream)
     817             : {
     818         417 :     LOCK(cs_args);
     819             : 
     820        4818 :     for (const std::pair<std::string, std::string>& option : GetConfigOptions(stream)) {
     821        8802 :         std::string strKey = std::string("-") + option.first;
     822        8802 :         std::string strValue = option.second;
     823             : 
     824        4401 :         if (InterpretNegatedOption(strKey, strValue)) {
     825        4401 :             m_config_args[strKey].clear();
     826             :         } else {
     827        4391 :             m_config_args[strKey].push_back(strValue);
     828             :         }
     829             :     }
     830         417 : }
     831             : 
     832         391 : void ArgsManager::ReadConfigFile(const std::string& confPath)
     833             : {
     834         391 :     {
     835         391 :         LOCK(cs_args);
     836         391 :         m_config_args.clear();
     837             :     }
     838             : 
     839         782 :     fsbridge::ifstream stream(GetConfigFile(confPath));
     840             : 
     841             :     // ok to not have a config file
     842         391 :     if (stream.good()) {
     843         391 :         ReadConfigStream(stream);
     844             :     }
     845             : 
     846             :     // If datadir is changed in .conf file:
     847         391 :     ClearDatadirCache();
     848         391 :     if (!CheckDataDirOption()) {
     849           3 :         throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
     850             :     }
     851         390 : }
     852             : 
     853        3033 : fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
     854             : {
     855        3033 :     if (path.is_absolute()) {
     856           8 :         return path;
     857             :     }
     858        3025 :     return fs::absolute(path, GetDataDir(net_specific));
     859             : }
     860             : 
     861         442 : std::string ArgsManager::GetChainName() const
     862             : {
     863         442 :     bool fRegTest = ArgsManagerHelper::GetNetBoolArg(*this, "-regtest");
     864         442 :     bool fTestNet = ArgsManagerHelper::GetNetBoolArg(*this, "-testnet");
     865             : 
     866         442 :     if (fTestNet && fRegTest)
     867          10 :         throw std::runtime_error("Invalid combination of -regtest and -testnet.");
     868         432 :     if (fRegTest)
     869         392 :         return CBaseChainParams::REGTEST;
     870          40 :     if (fTestNet)
     871          16 :         return CBaseChainParams::TESTNET;
     872         456 :     return CBaseChainParams::MAIN;
     873             : }
     874             : 
     875        1270 : bool RenameOver(fs::path src, fs::path dest)
     876             : {
     877             : #ifdef WIN32
     878             :     return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
     879             :                        MOVEFILE_REPLACE_EXISTING) != 0;
     880             : #else
     881        1270 :     int rc = std::rename(src.string().c_str(), dest.string().c_str());
     882        1270 :     return (rc == 0);
     883             : #endif /* WIN32 */
     884             : }
     885             : 
     886             : /**
     887             :  * Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
     888             :  * Specifically handles case where path p exists, but it wasn't possible for the user to
     889             :  * write to the parent directory.
     890             :  */
     891        3267 : bool TryCreateDirectories(const fs::path& p)
     892             : {
     893        3267 :     try {
     894        3267 :         return fs::create_directories(p);
     895           2 :     } catch (const fs::filesystem_error&) {
     896           2 :         if (!fs::exists(p) || !fs::is_directory(p))
     897           1 :             throw;
     898             :     }
     899             : 
     900             :     // create_directories didn't create the directory, it had to have existed already
     901           0 :     return false;
     902             : }
     903             : 
     904        2888 : bool FileCommit(FILE* file)
     905             : {
     906        2888 :     if (fflush(file) != 0) { // harmless if redundantly called
     907           0 :         LogPrintf("%s: fflush failed: %d\n", __func__, errno);
     908           0 :         return false;
     909             :     }
     910             : #ifdef WIN32
     911             :     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     912             :     if (FlushFileBuffers(hFile) == 0) {
     913             :         LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
     914             :         return false;
     915             :     }
     916             : #else
     917             :     #if defined(__linux__) || defined(__NetBSD__)
     918        2888 :     if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
     919           0 :         LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
     920           0 :         return false;
     921             :     }
     922             :     #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
     923             :     if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
     924             :         LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
     925             :         return false;
     926             :     }
     927             :     #else
     928             :     if (fsync(fileno(file)) != 0 && errno != EINVAL) {
     929             :         LogPrintf("%s: fsync failed: %d\n", __func__, errno);
     930             :         return false;
     931             :     }
     932             :     #endif
     933             : #endif
     934             :     return true;
     935             : }
     936             : 
     937           3 : bool TruncateFile(FILE* file, unsigned int length)
     938             : {
     939             : #if defined(WIN32)
     940             :     return _chsize(_fileno(file), length) == 0;
     941             : #else
     942           3 :     return ftruncate(fileno(file), length) == 0;
     943             : #endif
     944             : }
     945             : 
     946             : /**
     947             :  * this function tries to raise the file descriptor limit to the requested number.
     948             :  * It returns the actual file descriptor limit (which may be more or less than nMinFD)
     949             :  */
     950         386 : int RaiseFileDescriptorLimit(int nMinFD)
     951             : {
     952             : #if defined(WIN32)
     953             :     return 2048;
     954             : #else
     955         386 :     struct rlimit limitFD;
     956         386 :     if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
     957         386 :         if (limitFD.rlim_cur < (rlim_t)nMinFD) {
     958           0 :             limitFD.rlim_cur = nMinFD;
     959           0 :             if (limitFD.rlim_cur > limitFD.rlim_max)
     960           0 :                 limitFD.rlim_cur = limitFD.rlim_max;
     961           0 :             setrlimit(RLIMIT_NOFILE, &limitFD);
     962           0 :             getrlimit(RLIMIT_NOFILE, &limitFD);
     963             :         }
     964         386 :         return limitFD.rlim_cur;
     965             :     }
     966             :     return nMinFD; // getrlimit failed, assume it's fine
     967             : #endif
     968             : }
     969             : 
     970             : /**
     971             :  * this function tries to make a particular range of a file allocated (corresponding to disk space)
     972             :  * it is advisory, and the range specified in the arguments will never contain live data
     973             :  */
     974         502 : void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length)
     975             : {
     976             : #if defined(WIN32)
     977             :     // Windows-specific version
     978             :     HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
     979             :     LARGE_INTEGER nFileSize;
     980             :     int64_t nEndPos = (int64_t)offset + length;
     981             :     nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
     982             :     nFileSize.u.HighPart = nEndPos >> 32;
     983             :     SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
     984             :     SetEndOfFile(hFile);
     985             : #elif defined(MAC_OSX)
     986             :     // OSX specific version
     987             :     fstore_t fst;
     988             :     fst.fst_flags = F_ALLOCATECONTIG;
     989             :     fst.fst_posmode = F_PEOFPOSMODE;
     990             :     fst.fst_offset = 0;
     991             :     fst.fst_length = (off_t)offset + length;
     992             :     fst.fst_bytesalloc = 0;
     993             :     if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
     994             :         fst.fst_flags = F_ALLOCATEALL;
     995             :         fcntl(fileno(file), F_PREALLOCATE, &fst);
     996             :     }
     997             :     ftruncate(fileno(file), fst.fst_length);
     998             : #elif defined(__linux__)
     999             :     // Version using posix_fallocate
    1000         502 :     off_t nEndPos = (off_t)offset + length;
    1001         502 :     posix_fallocate(fileno(file), 0, nEndPos);
    1002             : #else
    1003             :     // Fallback version
    1004             :     // TODO: just write one byte per block
    1005             :     static const char buf[65536] = {};
    1006             :     fseek(file, offset, SEEK_SET);
    1007             :     while (length > 0) {
    1008             :         unsigned int now = 65536;
    1009             :         if (length < now)
    1010             :             now = length;
    1011             :         fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
    1012             :         length -= now;
    1013             :     }
    1014             : #endif
    1015         502 : }
    1016             : 
    1017             : #ifdef WIN32
    1018             : fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
    1019             : {
    1020             :     WCHAR pszPath[MAX_PATH] = L"";
    1021             : 
    1022             :     if (SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) {
    1023             :         return fs::path(pszPath);
    1024             :     }
    1025             : 
    1026             :     LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
    1027             :     return fs::path("");
    1028             : }
    1029             : #endif
    1030             : 
    1031         137 : void runCommand(std::string strCommand)
    1032             : {
    1033         137 :     if (strCommand.empty()) return;
    1034             : #ifndef WIN32
    1035         137 :     int nErr = ::system(strCommand.c_str());
    1036             : #else
    1037             :     int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
    1038             : #endif
    1039         137 :     if (nErr)
    1040           0 :         LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
    1041             : }
    1042             : 
    1043         831 : void SetupEnvironment()
    1044             : {
    1045             : // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
    1046             : // may be invalid, in which case the "C" locale is used as fallback.
    1047             : #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
    1048         831 :     try {
    1049         831 :         std::locale(""); // Raises a runtime error if current locale is invalid
    1050           0 :     } catch (const std::runtime_error&) {
    1051           0 :         setenv("LC_ALL", "C", 1);
    1052             :     }
    1053             : #elif defined(WIN32)
    1054             :     // Set the default input/output charset is utf-8
    1055             :     SetConsoleCP(CP_UTF8);
    1056             :     SetConsoleOutputCP(CP_UTF8);
    1057             : #endif
    1058             :     // The path locale is lazy initialized and to avoid deinitialization errors
    1059             :     // in multithreading environments, it is set explicitly by the main thread.
    1060             :     // A dummy locale is used to extract the internal default locale, used by
    1061             :     // fs::path, which is then used to explicitly imbue the path.
    1062         831 :     std::locale loc = fs::path::imbue(std::locale::classic());
    1063             : #ifndef WIN32
    1064         831 :     fs::path::imbue(loc);
    1065             : #else
    1066             :     fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>()));
    1067             : #endif
    1068         831 : }
    1069             : 
    1070         390 : bool SetupNetworking()
    1071             : {
    1072             : #ifdef WIN32
    1073             :     // Initialize Windows Sockets
    1074             :     WSADATA wsadata;
    1075             :     int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
    1076             :     if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
    1077             :         return false;
    1078             : #endif
    1079         390 :     return true;
    1080             : }
    1081             : 
    1082           0 : void SetThreadPriority(int nPriority)
    1083             : {
    1084             : #ifdef WIN32
    1085             :     SetThreadPriority(GetCurrentThread(), nPriority);
    1086             : #else // WIN32
    1087             : #ifdef PRIO_THREAD
    1088             :     setpriority(PRIO_THREAD, 0, nPriority);
    1089             : #else  // PRIO_THREAD
    1090           0 :     setpriority(PRIO_PROCESS, 0, nPriority);
    1091             : #endif // PRIO_THREAD
    1092             : #endif // WIN32
    1093           0 : }
    1094             : 
    1095         735 : int GetNumCores()
    1096             : {
    1097         735 :     return std::thread::hardware_concurrency();
    1098             : }
    1099             : 
    1100             : 
    1101         355 : int ScheduleBatchPriority(void)
    1102             : {
    1103             : #ifdef SCHED_BATCH
    1104         355 :     const static sched_param param{0};
    1105         355 :     if (int ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, &param)) {
    1106           0 :         LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(errno));
    1107           0 :         return ret;
    1108             :     }
    1109             :     return 0;
    1110             : #else
    1111             :     return 1;
    1112             : #endif
    1113             : }
    1114             : 
    1115             : namespace util {
    1116             : #ifdef WIN32
    1117             :     WinCmdLineArgs::WinCmdLineArgs()
    1118             : {
    1119             :     wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
    1120             :     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
    1121             :     argv = new char*[argc];
    1122             :     args.resize(argc);
    1123             :     for (int i = 0; i < argc; i++) {
    1124             :         args[i] = utf8_cvt.to_bytes(wargv[i]);
    1125             :         argv[i] = &*args[i].begin();
    1126             :     }
    1127             :     LocalFree(wargv);
    1128             : }
    1129             : 
    1130             : WinCmdLineArgs::~WinCmdLineArgs()
    1131             : {
    1132             :     delete[] argv;
    1133             : }
    1134             : 
    1135             : std::pair<int, char**> WinCmdLineArgs::get()
    1136             : {
    1137             :     return std::make_pair(argc, argv);
    1138             : }
    1139             : #endif
    1140             : } // namespace util
    1141             : 

Generated by: LCOV version 1.14