You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

util.cpp 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. // Copyright (c) 2009-2010 Satoshi Nakamoto
  2. // Copyright (c) 2009-2016 The Starwels developers
  3. // Distributed under the MIT software license, see the accompanying
  4. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5. #if defined(HAVE_CONFIG_H)
  6. #include "config/starwels-config.h"
  7. #endif
  8. #include "util.h"
  9. #include "chainparamsbase.h"
  10. #include "fs.h"
  11. #include "random.h"
  12. #include "serialize.h"
  13. #include "utilstrencodings.h"
  14. #include "utiltime.h"
  15. #include <stdarg.h>
  16. #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
  17. #include <pthread.h>
  18. #include <pthread_np.h>
  19. #endif
  20. #ifndef WIN32
  21. // for posix_fallocate
  22. #ifdef __linux__
  23. #ifdef _POSIX_C_SOURCE
  24. #undef _POSIX_C_SOURCE
  25. #endif
  26. #define _POSIX_C_SOURCE 200112L
  27. #endif // __linux__
  28. #include <algorithm>
  29. #include <fcntl.h>
  30. #include <sys/resource.h>
  31. #include <sys/stat.h>
  32. #else
  33. #ifdef _MSC_VER
  34. #pragma warning(disable:4786)
  35. #pragma warning(disable:4804)
  36. #pragma warning(disable:4805)
  37. #pragma warning(disable:4717)
  38. #endif
  39. #ifdef _WIN32_WINNT
  40. #undef _WIN32_WINNT
  41. #endif
  42. #define _WIN32_WINNT 0x0501
  43. #ifdef _WIN32_IE
  44. #undef _WIN32_IE
  45. #endif
  46. #define _WIN32_IE 0x0501
  47. #define WIN32_LEAN_AND_MEAN 1
  48. #ifndef NOMINMAX
  49. #define NOMINMAX
  50. #endif
  51. #include <io.h> /* for _commit */
  52. #include <shlobj.h>
  53. #endif
  54. #ifdef HAVE_SYS_PRCTL_H
  55. #include <sys/prctl.h>
  56. #endif
  57. #ifdef HAVE_MALLOPT_ARENA_MAX
  58. #include <malloc.h>
  59. #endif
  60. #include <boost/algorithm/string/case_conv.hpp> // for to_lower()
  61. #include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
  62. #include <boost/program_options/detail/config_file.hpp>
  63. #include <boost/thread.hpp>
  64. #include <openssl/crypto.h>
  65. #include <openssl/rand.h>
  66. #include <openssl/conf.h>
  67. // Application startup time (used for uptime calculation)
  68. const int64_t nStartupTime = GetTime();
  69. const char * const STARWELS_CONF_FILENAME = "starwels.conf";
  70. const char * const STARWELS_PID_FILENAME = "starwelsd.pid";
  71. ArgsManager gArgs;
  72. bool fPrintToConsole = false;
  73. bool fPrintToDebugLog = true;
  74. bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS;
  75. bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS;
  76. bool fLogIPs = DEFAULT_LOGIPS;
  77. std::atomic<bool> fReopenDebugLog(false);
  78. CTranslationInterface translationInterface;
  79. /** Log categories bitfield. */
  80. std::atomic<uint32_t> logCategories(0);
  81. /** Init OpenSSL library multithreading support */
  82. static std::unique_ptr<CCriticalSection[]> ppmutexOpenSSL;
  83. void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
  84. {
  85. if (mode & CRYPTO_LOCK) {
  86. ENTER_CRITICAL_SECTION(ppmutexOpenSSL[i]);
  87. } else {
  88. LEAVE_CRITICAL_SECTION(ppmutexOpenSSL[i]);
  89. }
  90. }
  91. // Singleton for wrapping OpenSSL setup/teardown.
  92. class CInit
  93. {
  94. public:
  95. CInit()
  96. {
  97. // Init OpenSSL library multithreading support
  98. ppmutexOpenSSL.reset(new CCriticalSection[CRYPTO_num_locks()]);
  99. CRYPTO_set_locking_callback(locking_callback);
  100. // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
  101. // We don't use them so we don't require the config. However some of our libs may call functions
  102. // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
  103. // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
  104. // that the config appears to have been loaded and there are no modules/engines available.
  105. OPENSSL_no_config();
  106. #ifdef WIN32
  107. // Seed OpenSSL PRNG with current contents of the screen
  108. RAND_screen();
  109. #endif
  110. // Seed OpenSSL PRNG with performance counter
  111. RandAddSeed();
  112. }
  113. ~CInit()
  114. {
  115. // Securely erase the memory used by the PRNG
  116. RAND_cleanup();
  117. // Shutdown OpenSSL library multithreading support
  118. CRYPTO_set_locking_callback(nullptr);
  119. // Clear the set of locks now to maintain symmetry with the constructor.
  120. ppmutexOpenSSL.reset();
  121. }
  122. }
  123. instance_of_cinit;
  124. /**
  125. * LogPrintf() has been broken a couple of times now
  126. * by well-meaning people adding mutexes in the most straightforward way.
  127. * It breaks because it may be called by global destructors during shutdown.
  128. * Since the order of destruction of static/global objects is undefined,
  129. * defining a mutex as a global object doesn't work (the mutex gets
  130. * destroyed, and then some later destructor calls OutputDebugStringF,
  131. * maybe indirectly, and you get a core dump at shutdown trying to lock
  132. * the mutex).
  133. */
  134. static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
  135. /**
  136. * We use boost::call_once() to make sure mutexDebugLog and
  137. * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
  138. *
  139. * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
  140. * are leaked on exit. This is ugly, but will be cleaned up by
  141. * the OS/libc. When the shutdown sequence is fully audited and
  142. * tested, explicit destruction of these objects can be implemented.
  143. */
  144. static FILE* fileout = nullptr;
  145. static boost::mutex* mutexDebugLog = nullptr;
  146. static std::list<std::string>* vMsgsBeforeOpenLog;
  147. static int FileWriteStr(const std::string &str, FILE *fp)
  148. {
  149. return fwrite(str.data(), 1, str.size(), fp);
  150. }
  151. static void DebugPrintInit()
  152. {
  153. assert(mutexDebugLog == nullptr);
  154. mutexDebugLog = new boost::mutex();
  155. vMsgsBeforeOpenLog = new std::list<std::string>;
  156. }
  157. void OpenDebugLog()
  158. {
  159. boost::call_once(&DebugPrintInit, debugPrintInitFlag);
  160. boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
  161. assert(fileout == nullptr);
  162. assert(vMsgsBeforeOpenLog);
  163. fs::path pathDebug = GetDataDir() / "debug.log";
  164. fileout = fsbridge::fopen(pathDebug, "a");
  165. if (fileout) {
  166. setbuf(fileout, nullptr); // unbuffered
  167. // dump buffered messages from before we opened the log
  168. while (!vMsgsBeforeOpenLog->empty()) {
  169. FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
  170. vMsgsBeforeOpenLog->pop_front();
  171. }
  172. }
  173. delete vMsgsBeforeOpenLog;
  174. vMsgsBeforeOpenLog = nullptr;
  175. }
  176. struct CLogCategoryDesc
  177. {
  178. uint32_t flag;
  179. std::string category;
  180. };
  181. const CLogCategoryDesc LogCategories[] =
  182. {
  183. {BCLog::NONE, "0"},
  184. {BCLog::NET, "net"},
  185. {BCLog::TOR, "tor"},
  186. {BCLog::MEMPOOL, "mempool"},
  187. {BCLog::HTTP, "http"},
  188. {BCLog::BENCH, "bench"},
  189. {BCLog::ZMQ, "zmq"},
  190. {BCLog::DB, "db"},
  191. {BCLog::RPC, "rpc"},
  192. {BCLog::ESTIMATEFEE, "estimatefee"},
  193. {BCLog::ADDRMAN, "addrman"},
  194. {BCLog::SELECTCOINS, "selectcoins"},
  195. {BCLog::REINDEX, "reindex"},
  196. {BCLog::CMPCTBLOCK, "cmpctblock"},
  197. {BCLog::RAND, "rand"},
  198. {BCLog::PRUNE, "prune"},
  199. {BCLog::PROXY, "proxy"},
  200. {BCLog::MEMPOOLREJ, "mempoolrej"},
  201. {BCLog::LIBEVENT, "libevent"},
  202. {BCLog::COINDB, "coindb"},
  203. {BCLog::QT, "qt"},
  204. {BCLog::LEVELDB, "leveldb"},
  205. {BCLog::ALL, "1"},
  206. {BCLog::ALL, "all"},
  207. };
  208. bool GetLogCategory(uint32_t *f, const std::string *str)
  209. {
  210. if (f && str) {
  211. if (*str == "") {
  212. *f = BCLog::ALL;
  213. return true;
  214. }
  215. for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
  216. if (LogCategories[i].category == *str) {
  217. *f = LogCategories[i].flag;
  218. return true;
  219. }
  220. }
  221. }
  222. return false;
  223. }
  224. std::string ListLogCategories()
  225. {
  226. std::string ret;
  227. int outcount = 0;
  228. for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
  229. // Omit the special cases.
  230. if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
  231. if (outcount != 0) ret += ", ";
  232. ret += LogCategories[i].category;
  233. outcount++;
  234. }
  235. }
  236. return ret;
  237. }
  238. std::vector<CLogCategoryActive> ListActiveLogCategories()
  239. {
  240. std::vector<CLogCategoryActive> ret;
  241. for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
  242. // Omit the special cases.
  243. if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
  244. CLogCategoryActive catActive;
  245. catActive.category = LogCategories[i].category;
  246. catActive.active = LogAcceptCategory(LogCategories[i].flag);
  247. ret.push_back(catActive);
  248. }
  249. }
  250. return ret;
  251. }
  252. /**
  253. * fStartedNewLine is a state variable held by the calling context that will
  254. * suppress printing of the timestamp when multiple calls are made that don't
  255. * end in a newline. Initialize it to true, and hold it, in the calling context.
  256. */
  257. static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine)
  258. {
  259. std::string strStamped;
  260. if (!fLogTimestamps)
  261. return str;
  262. if (*fStartedNewLine) {
  263. int64_t nTimeMicros = GetTimeMicros();
  264. strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros/1000000);
  265. if (fLogTimeMicros)
  266. strStamped += strprintf(".%06d", nTimeMicros%1000000);
  267. int64_t mocktime = GetMockTime();
  268. if (mocktime) {
  269. strStamped += " (mocktime: " + DateTimeStrFormat("%Y-%m-%d %H:%M:%S", mocktime) + ")";
  270. }
  271. strStamped += ' ' + str;
  272. } else
  273. strStamped = str;
  274. if (!str.empty() && str[str.size()-1] == '\n')
  275. *fStartedNewLine = true;
  276. else
  277. *fStartedNewLine = false;
  278. return strStamped;
  279. }
  280. int LogPrintStr(const std::string &str)
  281. {
  282. int ret = 0; // Returns total number of characters written
  283. static std::atomic_bool fStartedNewLine(true);
  284. std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
  285. if (fPrintToConsole)
  286. {
  287. // print to console
  288. ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout);
  289. fflush(stdout);
  290. }
  291. else if (fPrintToDebugLog)
  292. {
  293. boost::call_once(&DebugPrintInit, debugPrintInitFlag);
  294. boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
  295. // buffer if we haven't opened the log yet
  296. if (fileout == nullptr) {
  297. assert(vMsgsBeforeOpenLog);
  298. ret = strTimestamped.length();
  299. vMsgsBeforeOpenLog->push_back(strTimestamped);
  300. }
  301. else
  302. {
  303. // reopen the log file, if requested
  304. if (fReopenDebugLog) {
  305. fReopenDebugLog = false;
  306. fs::path pathDebug = GetDataDir() / "debug.log";
  307. if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr)
  308. setbuf(fileout, nullptr); // unbuffered
  309. }
  310. ret = FileWriteStr(strTimestamped, fileout);
  311. }
  312. }
  313. return ret;
  314. }
  315. /** Interpret string as boolean, for argument parsing */
  316. static bool InterpretBool(const std::string& strValue)
  317. {
  318. if (strValue.empty())
  319. return true;
  320. return (atoi(strValue) != 0);
  321. }
  322. /** Turn -noX into -X=0 */
  323. static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
  324. {
  325. if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
  326. {
  327. strKey = "-" + strKey.substr(3);
  328. strValue = InterpretBool(strValue) ? "0" : "1";
  329. }
  330. }
  331. void ArgsManager::ParseParameters(int argc, const char* const argv[])
  332. {
  333. LOCK(cs_args);
  334. mapArgs.clear();
  335. mapMultiArgs.clear();
  336. for (int i = 1; i < argc; i++)
  337. {
  338. std::string str(argv[i]);
  339. std::string strValue;
  340. size_t is_index = str.find('=');
  341. if (is_index != std::string::npos)
  342. {
  343. strValue = str.substr(is_index+1);
  344. str = str.substr(0, is_index);
  345. }
  346. #ifdef WIN32
  347. boost::to_lower(str);
  348. if (boost::algorithm::starts_with(str, "/"))
  349. str = "-" + str.substr(1);
  350. #endif
  351. if (str[0] != '-')
  352. break;
  353. // Interpret --foo as -foo.
  354. // If both --foo and -foo are set, the last takes effect.
  355. if (str.length() > 1 && str[1] == '-')
  356. str = str.substr(1);
  357. InterpretNegativeSetting(str, strValue);
  358. mapArgs[str] = strValue;
  359. mapMultiArgs[str].push_back(strValue);
  360. }
  361. }
  362. std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg)
  363. {
  364. LOCK(cs_args);
  365. if (IsArgSet(strArg))
  366. return mapMultiArgs.at(strArg);
  367. return {};
  368. }
  369. bool ArgsManager::IsArgSet(const std::string& strArg)
  370. {
  371. LOCK(cs_args);
  372. return mapArgs.count(strArg);
  373. }
  374. std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault)
  375. {
  376. LOCK(cs_args);
  377. if (mapArgs.count(strArg))
  378. return mapArgs[strArg];
  379. return strDefault;
  380. }
  381. int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault)
  382. {
  383. LOCK(cs_args);
  384. if (mapArgs.count(strArg))
  385. return atoi64(mapArgs[strArg]);
  386. return nDefault;
  387. }
  388. bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault)
  389. {
  390. LOCK(cs_args);
  391. if (mapArgs.count(strArg))
  392. return InterpretBool(mapArgs[strArg]);
  393. return fDefault;
  394. }
  395. bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
  396. {
  397. LOCK(cs_args);
  398. if (mapArgs.count(strArg))
  399. return false;
  400. ForceSetArg(strArg, strValue);
  401. return true;
  402. }
  403. bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
  404. {
  405. if (fValue)
  406. return SoftSetArg(strArg, std::string("1"));
  407. else
  408. return SoftSetArg(strArg, std::string("0"));
  409. }
  410. void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
  411. {
  412. LOCK(cs_args);
  413. mapArgs[strArg] = strValue;
  414. mapMultiArgs[strArg].clear();
  415. mapMultiArgs[strArg].push_back(strValue);
  416. }
  417. static const int screenWidth = 79;
  418. static const int optIndent = 2;
  419. static const int msgIndent = 7;
  420. std::string HelpMessageGroup(const std::string &message) {
  421. return std::string(message) + std::string("\n\n");
  422. }
  423. std::string HelpMessageOpt(const std::string &option, const std::string &message) {
  424. return std::string(optIndent,' ') + std::string(option) +
  425. std::string("\n") + std::string(msgIndent,' ') +
  426. FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
  427. std::string("\n\n");
  428. }
  429. static std::string FormatException(const std::exception* pex, const char* pszThread)
  430. {
  431. #ifdef WIN32
  432. char pszModule[MAX_PATH] = "";
  433. GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
  434. #else
  435. const char* pszModule = "starwels";
  436. #endif
  437. if (pex)
  438. return strprintf(
  439. "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
  440. else
  441. return strprintf(
  442. "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
  443. }
  444. void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
  445. {
  446. std::string message = FormatException(pex, pszThread);
  447. LogPrintf("\n\n************************\n%s\n", message);
  448. fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
  449. }
  450. fs::path GetDefaultDataDir()
  451. {
  452. // Windows < Vista: C:\Documents and Settings\Username\Application Data\Starwels
  453. // Windows >= Vista: C:\Users\Username\AppData\Roaming\Starwels
  454. // Mac: ~/Library/Application Support/Starwels
  455. // Unix: ~/.starwels
  456. #ifdef WIN32
  457. // Windows
  458. return GetSpecialFolderPath(CSIDL_APPDATA) / "Starwels";
  459. #else
  460. fs::path pathRet;
  461. char* pszHome = getenv("HOME");
  462. if (pszHome == nullptr || strlen(pszHome) == 0)
  463. pathRet = fs::path("/");
  464. else
  465. pathRet = fs::path(pszHome);
  466. #ifdef MAC_OSX
  467. // Mac
  468. return pathRet / "Library/Application Support/Starwels";
  469. #else
  470. // Unix
  471. return pathRet / ".starwels";
  472. #endif
  473. #endif
  474. }
  475. static fs::path pathCached;
  476. static fs::path pathCachedNetSpecific;
  477. static CCriticalSection csPathCached;
  478. const fs::path &GetDataDir(bool fNetSpecific)
  479. {
  480. LOCK(csPathCached);
  481. fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
  482. // This can be called during exceptions by LogPrintf(), so we cache the
  483. // value so we don't have to do memory allocations after that.
  484. if (!path.empty())
  485. return path;
  486. if (gArgs.IsArgSet("-datadir")) {
  487. path = fs::system_complete(gArgs.GetArg("-datadir", ""));
  488. if (!fs::is_directory(path)) {
  489. path = "";
  490. return path;
  491. }
  492. } else {
  493. path = GetDefaultDataDir();
  494. }
  495. if (fNetSpecific)
  496. path /= BaseParams().DataDir();
  497. fs::create_directories(path);
  498. return path;
  499. }
  500. void ClearDatadirCache()
  501. {
  502. LOCK(csPathCached);
  503. pathCached = fs::path();
  504. pathCachedNetSpecific = fs::path();
  505. }
  506. fs::path GetConfigFile(const std::string& confPath)
  507. {
  508. fs::path pathConfigFile(confPath);
  509. if (!pathConfigFile.is_complete())
  510. pathConfigFile = GetDataDir(false) / pathConfigFile;
  511. return pathConfigFile;
  512. }
  513. void ArgsManager::ReadConfigFile(const std::string& confPath)
  514. {
  515. fs::ifstream streamConfig(GetConfigFile(confPath));
  516. if (!streamConfig.good())
  517. return; // No starwels.conf file is OK
  518. {
  519. LOCK(cs_args);
  520. std::set<std::string> setOptions;
  521. setOptions.insert("*");
  522. for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
  523. {
  524. // Don't overwrite existing settings so command line settings override starwels.conf
  525. std::string strKey = std::string("-") + it->string_key;
  526. std::string strValue = it->value[0];
  527. InterpretNegativeSetting(strKey, strValue);
  528. if (mapArgs.count(strKey) == 0)
  529. mapArgs[strKey] = strValue;
  530. mapMultiArgs[strKey].push_back(strValue);
  531. }
  532. }
  533. // If datadir is changed in .conf file:
  534. ClearDatadirCache();
  535. }
  536. #ifndef WIN32
  537. fs::path GetPidFile()
  538. {
  539. fs::path pathPidFile(gArgs.GetArg("-pid", STARWELS_PID_FILENAME));
  540. if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile;
  541. return pathPidFile;
  542. }
  543. void CreatePidFile(const fs::path &path, pid_t pid)
  544. {
  545. FILE* file = fsbridge::fopen(path, "w");
  546. if (file)
  547. {
  548. fprintf(file, "%d\n", pid);
  549. fclose(file);
  550. }
  551. }
  552. #endif
  553. bool RenameOver(fs::path src, fs::path dest)
  554. {
  555. #ifdef WIN32
  556. return MoveFileExA(src.string().c_str(), dest.string().c_str(),
  557. MOVEFILE_REPLACE_EXISTING) != 0;
  558. #else
  559. int rc = std::rename(src.string().c_str(), dest.string().c_str());
  560. return (rc == 0);
  561. #endif /* WIN32 */
  562. }
  563. /**
  564. * Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
  565. * Specifically handles case where path p exists, but it wasn't possible for the user to
  566. * write to the parent directory.
  567. */
  568. bool TryCreateDirectories(const fs::path& p)
  569. {
  570. try
  571. {
  572. return fs::create_directories(p);
  573. } catch (const fs::filesystem_error&) {
  574. if (!fs::exists(p) || !fs::is_directory(p))
  575. throw;
  576. }
  577. // create_directories didn't create the directory, it had to have existed already
  578. return false;
  579. }
  580. void FileCommit(FILE *file)
  581. {
  582. fflush(file); // harmless if redundantly called
  583. #ifdef WIN32
  584. HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
  585. FlushFileBuffers(hFile);
  586. #else
  587. #if defined(__linux__) || defined(__NetBSD__)
  588. fdatasync(fileno(file));
  589. #elif defined(__APPLE__) && defined(F_FULLFSYNC)
  590. fcntl(fileno(file), F_FULLFSYNC, 0);
  591. #else
  592. fsync(fileno(file));
  593. #endif
  594. #endif
  595. }
  596. bool TruncateFile(FILE *file, unsigned int length) {
  597. #if defined(WIN32)
  598. return _chsize(_fileno(file), length) == 0;
  599. #else
  600. return ftruncate(fileno(file), length) == 0;
  601. #endif
  602. }
  603. /**
  604. * this function tries to raise the file descriptor limit to the requested number.
  605. * It returns the actual file descriptor limit (which may be more or less than nMinFD)
  606. */
  607. int RaiseFileDescriptorLimit(int nMinFD) {
  608. #if defined(WIN32)
  609. return 2048;
  610. #else
  611. struct rlimit limitFD;
  612. if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
  613. if (limitFD.rlim_cur < (rlim_t)nMinFD) {
  614. limitFD.rlim_cur = nMinFD;
  615. if (limitFD.rlim_cur > limitFD.rlim_max)
  616. limitFD.rlim_cur = limitFD.rlim_max;
  617. setrlimit(RLIMIT_NOFILE, &limitFD);
  618. getrlimit(RLIMIT_NOFILE, &limitFD);
  619. }
  620. return limitFD.rlim_cur;
  621. }
  622. return nMinFD; // getrlimit failed, assume it's fine
  623. #endif
  624. }
  625. /**
  626. * this function tries to make a particular range of a file allocated (corresponding to disk space)
  627. * it is advisory, and the range specified in the arguments will never contain live data
  628. */
  629. void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
  630. #if defined(WIN32)
  631. // Windows-specific version
  632. HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
  633. LARGE_INTEGER nFileSize;
  634. int64_t nEndPos = (int64_t)offset + length;
  635. nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
  636. nFileSize.u.HighPart = nEndPos >> 32;
  637. SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
  638. SetEndOfFile(hFile);
  639. #elif defined(MAC_OSX)
  640. // OSX specific version
  641. fstore_t fst;
  642. fst.fst_flags = F_ALLOCATECONTIG;
  643. fst.fst_posmode = F_PEOFPOSMODE;
  644. fst.fst_offset = 0;
  645. fst.fst_length = (off_t)offset + length;
  646. fst.fst_bytesalloc = 0;
  647. if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
  648. fst.fst_flags = F_ALLOCATEALL;
  649. fcntl(fileno(file), F_PREALLOCATE, &fst);
  650. }
  651. ftruncate(fileno(file), fst.fst_length);
  652. #elif defined(__linux__)
  653. // Version using posix_fallocate
  654. off_t nEndPos = (off_t)offset + length;
  655. posix_fallocate(fileno(file), 0, nEndPos);
  656. #else
  657. // Fallback version
  658. // TODO: just write one byte per block
  659. static const char buf[65536] = {};
  660. fseek(file, offset, SEEK_SET);
  661. while (length > 0) {
  662. unsigned int now = 65536;
  663. if (length < now)
  664. now = length;
  665. fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
  666. length -= now;
  667. }
  668. #endif
  669. }
  670. void ShrinkDebugFile()
  671. {
  672. // Amount of debug.log to save at end when shrinking (must fit in memory)
  673. constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000;
  674. // Scroll debug.log if it's getting too big
  675. fs::path pathLog = GetDataDir() / "debug.log";
  676. FILE* file = fsbridge::fopen(pathLog, "r");
  677. // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE
  678. // trim it down by saving only the last RECENT_DEBUG_HISTORY_SIZE bytes
  679. if (file && fs::file_size(pathLog) > 11 * (RECENT_DEBUG_HISTORY_SIZE / 10))
  680. {
  681. // Restart the file with some of the end
  682. std::vector<char> vch(RECENT_DEBUG_HISTORY_SIZE, 0);
  683. fseek(file, -((long)vch.size()), SEEK_END);
  684. int nBytes = fread(vch.data(), 1, vch.size(), file);
  685. fclose(file);
  686. file = fsbridge::fopen(pathLog, "w");
  687. if (file)
  688. {
  689. fwrite(vch.data(), 1, nBytes, file);
  690. fclose(file);
  691. }
  692. }
  693. else if (file != nullptr)
  694. fclose(file);
  695. }
  696. #ifdef WIN32
  697. fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
  698. {
  699. char pszPath[MAX_PATH] = "";
  700. if(SHGetSpecialFolderPathA(nullptr, pszPath, nFolder, fCreate))
  701. {
  702. return fs::path(pszPath);
  703. }
  704. LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
  705. return fs::path("");
  706. }
  707. #endif
  708. void runCommand(const std::string& strCommand)
  709. {
  710. int nErr = ::system(strCommand.c_str());
  711. if (nErr)
  712. LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
  713. }
  714. void RenameThread(const char* name)
  715. {
  716. #if defined(PR_SET_NAME)
  717. // Only the first 15 characters are used (16 - NUL terminator)
  718. ::prctl(PR_SET_NAME, name, 0, 0, 0);
  719. #elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
  720. pthread_set_name_np(pthread_self(), name);
  721. #elif defined(MAC_OSX)
  722. pthread_setname_np(name);
  723. #else
  724. // Prevent warnings for unused parameters...
  725. (void)name;
  726. #endif
  727. }
  728. void SetupEnvironment()
  729. {
  730. #ifdef HAVE_MALLOPT_ARENA_MAX
  731. // glibc-specific: On 32-bit systems set the number of arenas to 1.
  732. // By default, since glibc 2.10, the C library will create up to two heap
  733. // arenas per core. This is known to cause excessive virtual address space
  734. // usage in our usage. Work around it by setting the maximum number of
  735. // arenas to 1.
  736. if (sizeof(void*) == 4) {
  737. mallopt(M_ARENA_MAX, 1);
  738. }
  739. #endif
  740. // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
  741. // may be invalid, in which case the "C" locale is used as fallback.
  742. #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
  743. try {
  744. std::locale(""); // Raises a runtime error if current locale is invalid
  745. } catch (const std::runtime_error&) {
  746. setenv("LC_ALL", "C", 1);
  747. }
  748. #endif
  749. // The path locale is lazy initialized and to avoid deinitialization errors
  750. // in multithreading environments, it is set explicitly by the main thread.
  751. // A dummy locale is used to extract the internal default locale, used by
  752. // fs::path, which is then used to explicitly imbue the path.
  753. std::locale loc = fs::path::imbue(std::locale::classic());
  754. fs::path::imbue(loc);
  755. }
  756. bool SetupNetworking()
  757. {
  758. #ifdef WIN32
  759. // Initialize Windows Sockets
  760. WSADATA wsadata;
  761. int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
  762. if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
  763. return false;
  764. #endif
  765. return true;
  766. }
  767. int GetNumCores()
  768. {
  769. #if BOOST_VERSION >= 105600
  770. return boost::thread::physical_concurrency();
  771. #else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores
  772. return boost::thread::hardware_concurrency();
  773. #endif
  774. }
  775. std::string CopyrightHolders(const std::string& strPrefix)
  776. {
  777. std::string strCopyrightHolders = strPrefix + strprintf(_(COPYRIGHT_HOLDERS), _(COPYRIGHT_HOLDERS_SUBSTITUTION));
  778. // Check for untranslated substitution to make sure Starwels copyright is not removed by accident
  779. if (strprintf(COPYRIGHT_HOLDERS, COPYRIGHT_HOLDERS_SUBSTITUTION).find("Starwels") == std::string::npos) {
  780. strCopyrightHolders += "\n" + strPrefix + "The Starwels developers";
  781. }
  782. return strCopyrightHolders;
  783. }
  784. // Obtain the application startup time (used for uptime calculation)
  785. int64_t GetStartupTime()
  786. {
  787. return nStartupTime;
  788. }