Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : // Copyright (c) 2009-2020 The Bitcoin Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include <sync.h>
7 : #include <util/system.h>
8 :
9 : #ifdef HAVE_BOOST_PROCESS
10 : #include <boost/process.hpp>
11 : #endif // HAVE_BOOST_PROCESS
12 :
13 : #include <chainparamsbase.h>
14 : #include <util/strencodings.h>
15 : #include <util/string.h>
16 : #include <util/translation.h>
17 :
18 :
19 : #if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
20 : #include <pthread.h>
21 : #include <pthread_np.h>
22 : #endif
23 :
24 : #ifndef WIN32
25 : // for posix_fallocate, in configure.ac we check if it is present after this
26 : #ifdef __linux__
27 :
28 : #ifdef _POSIX_C_SOURCE
29 : #undef _POSIX_C_SOURCE
30 : #endif
31 :
32 : #define _POSIX_C_SOURCE 200112L
33 :
34 : #endif // __linux__
35 :
36 : #include <algorithm>
37 : #include <fcntl.h>
38 : #include <sched.h>
39 : #include <sys/resource.h>
40 : #include <sys/stat.h>
41 :
42 : #else
43 :
44 : #ifdef _MSC_VER
45 : #pragma warning(disable:4786)
46 : #pragma warning(disable:4804)
47 : #pragma warning(disable:4805)
48 : #pragma warning(disable:4717)
49 : #endif
50 :
51 : #ifndef NOMINMAX
52 : #define NOMINMAX
53 : #endif
54 : #include <codecvt>
55 :
56 : #include <io.h> /* for _commit */
57 : #include <shellapi.h>
58 : #include <shlobj.h>
59 : #endif
60 :
61 : #ifdef HAVE_MALLOPT_ARENA_MAX
62 : #include <malloc.h>
63 : #endif
64 :
65 : #include <boost/algorithm/string/replace.hpp>
66 : #include <thread>
67 : #include <typeinfo>
68 : #include <univalue.h>
69 :
70 : // Application startup time (used for uptime calculation)
71 1150 : const int64_t nStartupTime = GetTime();
72 :
73 : const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
74 : const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
75 :
76 1150 : ArgsManager gArgs;
77 :
78 : /** Mutex to protect dir_locks. */
79 1150 : static Mutex cs_dir_locks;
80 : /** A map that contains all the currently held directory locks. After
81 : * successful locking, these will be held here until the global destructor
82 : * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
83 : * is called.
84 : */
85 1150 : static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks);
86 :
87 15046 : bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only)
88 : {
89 15046 : LOCK(cs_dir_locks);
90 15046 : fs::path pathLockFile = directory / lockfile_name;
91 :
92 : // If a lock for this directory already exists in the map, don't try to re-lock it
93 15046 : if (dir_locks.count(pathLockFile.string())) {
94 12996 : return true;
95 : }
96 :
97 : // Create empty lock file if it doesn't exist.
98 2050 : FILE* file = fsbridge::fopen(pathLockFile, "a");
99 2050 : if (file) fclose(file);
100 2050 : auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile);
101 2050 : if (!lock->TryLock()) {
102 10 : return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
103 : }
104 2040 : if (!probe_only) {
105 : // Lock successful and we're not just probing, put it into the map
106 1507 : dir_locks.emplace(pathLockFile.string(), std::move(lock));
107 1507 : }
108 2040 : return true;
109 15046 : }
110 :
111 990 : void UnlockDirectory(const fs::path& directory, const std::string& lockfile_name)
112 : {
113 990 : LOCK(cs_dir_locks);
114 990 : dir_locks.erase((directory / lockfile_name).string());
115 990 : }
116 :
117 3 : void ReleaseDirectoryLocks()
118 : {
119 3 : LOCK(cs_dir_locks);
120 3 : dir_locks.clear();
121 3 : }
122 :
123 1062 : bool DirIsWritable(const fs::path& directory)
124 : {
125 1062 : fs::path tmpFile = directory / fs::unique_path();
126 :
127 1062 : FILE* file = fsbridge::fopen(tmpFile, "a");
128 1062 : if (!file) return false;
129 :
130 1061 : fclose(file);
131 1061 : remove(tmpFile);
132 :
133 1061 : return true;
134 1062 : }
135 :
136 4257 : bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)
137 : {
138 : constexpr uint64_t min_disk_space = 52428800; // 50 MiB
139 :
140 4257 : uint64_t free_bytes_available = fs::space(dir).available;
141 4257 : return free_bytes_available >= min_disk_space + additional_bytes;
142 : }
143 :
144 0 : std::streampos GetFileSize(const char* path, std::streamsize max) {
145 0 : std::ifstream file(path, std::ios::binary);
146 0 : file.ignore(max);
147 0 : return file.gcount();
148 0 : }
149 :
150 : /**
151 : * Interpret a string argument as a boolean.
152 : *
153 : * The definition of atoi() requires that non-numeric string values like "foo",
154 : * return 0. This means that if a user unintentionally supplies a non-integer
155 : * argument here, the return value is always false. This means that -foo=false
156 : * does what the user probably expects, but -foo=true is well defined but does
157 : * not do what they probably expected.
158 : *
159 : * The return value of atoi() is undefined when given input not representable as
160 : * an int. On most systems this means string value between "-2147483648" and
161 : * "2147483647" are well defined (this method will return true). Setting
162 : * -txindex=2147483648 on most systems, however, is probably undefined.
163 : *
164 : * For a more extensive discussion of this topic (and a wide range of opinions
165 : * on the Right Way to change this code), see PR12713.
166 : */
167 70167 : static bool InterpretBool(const std::string& strValue)
168 : {
169 70167 : if (strValue.empty())
170 2646 : return true;
171 67521 : return (atoi(strValue) != 0);
172 70167 : }
173 :
174 1686915 : static std::string SettingName(const std::string& arg)
175 : {
176 1686915 : return arg.size() > 0 && arg[0] == '-' ? arg.substr(1) : arg;
177 : }
178 :
179 : /**
180 : * Interpret -nofoo as if the user supplied -foo=0.
181 : *
182 : * This method also tracks when the -no form was supplied, and if so,
183 : * checks whether there was a double-negative (-nofoo=0 -> -foo=1).
184 : *
185 : * If there was not a double negative, it removes the "no" from the key
186 : * and returns false.
187 : *
188 : * If there was a double negative, it removes "no" from the key, and
189 : * returns true.
190 : *
191 : * If there was no "no", it returns the string value untouched.
192 : *
193 : * Where an option was negated can be later checked using the
194 : * IsArgNegated() method. One use case for this is to have a way to disable
195 : * options that are not normally boolean (e.g. using -nodebuglogfile to request
196 : * that debug log output is not sent to any file at all).
197 : */
198 :
199 183291 : static util::SettingsValue InterpretOption(std::string& section, std::string& key, const std::string& value)
200 : {
201 : // Split section name from key name for keys like "testnet.foo" or "regtest.bar"
202 183291 : size_t option_index = key.find('.');
203 183291 : if (option_index != std::string::npos) {
204 57313 : section = key.substr(0, option_index);
205 57313 : key.erase(0, option_index + 1);
206 57313 : }
207 183291 : if (key.substr(0, 2) == "no") {
208 54429 : key.erase(0, 2);
209 : // Double negatives like -nofoo=0 are supported (but discouraged)
210 54429 : if (!InterpretBool(value)) {
211 13 : LogPrintf("Warning: parsed potentially confusing double-negative -%s=%s\n", key, value);
212 13 : return true;
213 : }
214 54416 : return false;
215 : }
216 128862 : return value;
217 183291 : }
218 :
219 : /**
220 : * Check settings value validity according to flags.
221 : *
222 : * TODO: Add more meaningful error checks here in the future
223 : * See "here's how the flags are meant to behave" in
224 : * https://github.com/bitcoin/bitcoin/pull/16097#issuecomment-514627823
225 : */
226 178685 : static bool CheckValid(const std::string& key, const util::SettingsValue& val, unsigned int flags, std::string& error)
227 : {
228 178685 : if (val.isBool() && !(flags & ArgsManager::ALLOW_BOOL)) {
229 0 : error = strprintf("Negating of -%s is meaningless and therefore forbidden", key);
230 0 : return false;
231 : }
232 178685 : return true;
233 178685 : }
234 :
235 : // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to
236 : // #include class definitions for all members.
237 : // For example, m_settings has an internal dependency on univalue.
238 28902 : ArgsManager::ArgsManager() {}
239 28902 : ArgsManager::~ArgsManager() {}
240 :
241 24738 : const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const
242 : {
243 24738 : std::set<std::string> unsuitables;
244 :
245 24738 : LOCK(cs_args);
246 :
247 : // if there's no section selected, don't worry
248 24738 : if (m_network.empty()) return std::set<std::string> {};
249 :
250 : // if it's okay to use the default section for this network, don't worry
251 24738 : if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {};
252 :
253 22965 : for (const auto& arg : m_network_only_args) {
254 10520 : if (OnlyHasDefaultSectionSetting(m_settings, m_network, SettingName(arg))) {
255 525 : unsuitables.insert(arg);
256 525 : }
257 0 : }
258 12445 : return unsuitables;
259 24738 : }
260 :
261 993 : const std::list<SectionInfo> ArgsManager::GetUnrecognizedSections() const
262 : {
263 : // Section names to be recognized in the config file.
264 2231 : static const std::set<std::string> available_sections{
265 619 : CBaseChainParams::REGTEST,
266 619 : CBaseChainParams::TESTNET,
267 619 : CBaseChainParams::MAIN
268 : };
269 :
270 993 : LOCK(cs_args);
271 993 : std::list<SectionInfo> unrecognized = m_config_sections;
272 1527 : unrecognized.remove_if([](const SectionInfo& appeared){ return available_sections.find(appeared.m_name) != available_sections.end(); });
273 : return unrecognized;
274 993 : }
275 :
276 1823 : void ArgsManager::SelectConfigNetwork(const std::string& network)
277 : {
278 1823 : LOCK(cs_args);
279 1823 : m_network = network;
280 1823 : }
281 :
282 28168 : bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
283 : {
284 28168 : LOCK(cs_args);
285 28168 : m_settings.command_line_options.clear();
286 :
287 102516 : for (int i = 1; i < argc; i++) {
288 74851 : std::string key(argv[i]);
289 :
290 : #ifdef MAC_OSX
291 : // At the first time when a user gets the "App downloaded from the
292 : // internet" warning, and clicks the Open button, macOS passes
293 : // a unique process serial number (PSN) as -psn_... command-line
294 : // argument, which we filter out.
295 74851 : if (key.substr(0, 5) == "-psn_") continue;
296 : #endif
297 :
298 74851 : if (key == "-") break; //bitcoin-tx using stdin
299 74839 : std::string val;
300 74839 : size_t is_index = key.find('=');
301 74839 : if (is_index != std::string::npos) {
302 70777 : val = key.substr(is_index + 1);
303 70777 : key.erase(is_index);
304 : }
305 : #ifdef WIN32
306 : key = ToLower(key);
307 : if (key[0] == '/')
308 : key[0] = '-';
309 : #endif
310 :
311 74839 : if (key[0] != '-')
312 484 : break;
313 :
314 : // Transform --foo to -foo
315 74355 : if (key.length() > 1 && key[1] == '-')
316 6 : key.erase(0, 1);
317 :
318 : // Transform -foo to foo
319 74355 : key.erase(0, 1);
320 74355 : std::string section;
321 74355 : util::SettingsValue value = InterpretOption(section, key, val);
322 74355 : Optional<unsigned int> flags = GetArgFlags('-' + key);
323 :
324 : // Unknown command line options and command line options with dot
325 : // characters (which are returned from InterpretOption with nonempty
326 : // section strings) are not valid.
327 74355 : if (!flags || !section.empty()) {
328 7 : error = strprintf("Invalid parameter %s", argv[i]);
329 7 : return false;
330 : }
331 :
332 74348 : if (!CheckValid(key, value, *flags, error)) return false;
333 :
334 74348 : m_settings.command_line_options[key].push_back(value);
335 74851 : }
336 :
337 : // we do not allow -includeconf from command line
338 28161 : bool success = true;
339 28161 : if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
340 2 : for (const auto& include : util::SettingsSpan(*includes)) {
341 1 : error += "-includeconf cannot be used from commandline; -includeconf=" + include.get_str() + "\n";
342 : success = false;
343 0 : }
344 1 : }
345 28161 : return success;
346 28168 : }
347 :
348 194667 : Optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) const
349 : {
350 194667 : LOCK(cs_args);
351 501713 : for (const auto& arg_map : m_available_args) {
352 307046 : const auto search = arg_map.second.find(name);
353 307046 : if (search != arg_map.second.end()) {
354 190063 : return search->second.m_flags;
355 : }
356 307046 : }
357 4604 : return nullopt;
358 194667 : }
359 :
360 42478 : std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
361 : {
362 42478 : std::vector<std::string> result;
363 91925 : for (const util::SettingsValue& value : GetSettingsList(strArg)) {
364 49447 : result.push_back(value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str());
365 : }
366 : return result;
367 42478 : }
368 :
369 201552 : bool ArgsManager::IsArgSet(const std::string& strArg) const
370 : {
371 201552 : return !GetSetting(strArg).isNull();
372 : }
373 :
374 536 : bool ArgsManager::InitSettings(std::string& error)
375 : {
376 536 : if (!GetSettingsPath()) {
377 2 : return true; // Do nothing if settings file disabled.
378 : }
379 :
380 534 : std::vector<std::string> errors;
381 534 : if (!ReadSettingsFile(&errors)) {
382 3 : error = strprintf("Failed loading settings file:\n- %s\n", Join(errors, "\n- "));
383 3 : return false;
384 : }
385 531 : if (!WriteSettingsFile(&errors)) {
386 0 : error = strprintf("Failed saving settings file:\n- %s\n", Join(errors, "\n- "));
387 0 : return false;
388 : }
389 531 : return true;
390 536 : }
391 :
392 2156 : bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
393 : {
394 2156 : if (IsArgNegated("-settings")) {
395 2 : return false;
396 : }
397 2154 : if (filepath) {
398 1620 : std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
399 1620 : *filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true));
400 1620 : }
401 2154 : return true;
402 2156 : }
403 :
404 5 : static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out)
405 : {
406 10 : for (const auto& error : errors) {
407 5 : if (error_out) {
408 3 : error_out->emplace_back(error);
409 3 : } else {
410 2 : LogPrintf("%s\n", error);
411 : }
412 : }
413 5 : }
414 :
415 536 : bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
416 : {
417 536 : fs::path path;
418 536 : if (!GetSettingsPath(&path, /* temp= */ false)) {
419 0 : return true; // Do nothing if settings file disabled.
420 : }
421 :
422 536 : LOCK(cs_args);
423 536 : m_settings.rw_settings.clear();
424 536 : std::vector<std::string> read_errors;
425 536 : if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
426 3 : SaveErrors(read_errors, errors);
427 3 : return false;
428 : }
429 533 : return true;
430 536 : }
431 :
432 542 : bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const
433 : {
434 542 : fs::path path, path_tmp;
435 542 : if (!GetSettingsPath(&path, /* temp= */ false) || !GetSettingsPath(&path_tmp, /* temp= */ true)) {
436 0 : throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
437 : }
438 :
439 542 : LOCK(cs_args);
440 542 : std::vector<std::string> write_errors;
441 542 : if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
442 0 : SaveErrors(write_errors, errors);
443 0 : return false;
444 : }
445 542 : if (!RenameOver(path_tmp, path)) {
446 2 : SaveErrors({strprintf("Failed renaming settings file %s to %s\n", path_tmp.string(), path.string())}, errors);
447 2 : return false;
448 : }
449 540 : return true;
450 542 : }
451 :
452 26928 : bool ArgsManager::IsArgNegated(const std::string& strArg) const
453 : {
454 26928 : return GetSetting(strArg).isFalse();
455 : }
456 :
457 207601 : std::string ArgsManager::GetArg(const std::string& strArg, const std::string& strDefault) const
458 : {
459 207601 : const util::SettingsValue value = GetSetting(strArg);
460 207601 : return value.isNull() ? strDefault : value.isFalse() ? "0" : value.isTrue() ? "1" : value.get_str();
461 207601 : }
462 :
463 794292 : int64_t ArgsManager::GetArg(const std::string& strArg, int64_t nDefault) const
464 : {
465 794292 : const util::SettingsValue value = GetSetting(strArg);
466 794292 : return value.isNull() ? nDefault : value.isFalse() ? 0 : value.isTrue() ? 1 : value.isNum() ? value.get_int64() : atoi64(value.get_str());
467 794292 : }
468 :
469 365030 : bool ArgsManager::GetBoolArg(const std::string& strArg, bool fDefault) const
470 : {
471 365030 : const util::SettingsValue value = GetSetting(strArg);
472 365030 : return value.isNull() ? fDefault : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
473 365030 : }
474 :
475 24828 : bool ArgsManager::SoftSetArg(const std::string& strArg, const std::string& strValue)
476 : {
477 24828 : LOCK(cs_args);
478 24828 : if (IsArgSet(strArg)) return false;
479 768 : ForceSetArg(strArg, strValue);
480 768 : return true;
481 24828 : }
482 :
483 1083 : bool ArgsManager::SoftSetBoolArg(const std::string& strArg, bool fValue)
484 : {
485 1083 : if (fValue)
486 1068 : return SoftSetArg(strArg, std::string("1"));
487 : else
488 15 : return SoftSetArg(strArg, std::string("0"));
489 1083 : }
490 :
491 25018 : void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strValue)
492 : {
493 25018 : LOCK(cs_args);
494 25018 : m_settings.forced_settings[SettingName(strArg)] = strValue;
495 25018 : }
496 :
497 211118 : void ArgsManager::AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat)
498 : {
499 : // Split arg name from its help param
500 211118 : size_t eq_index = name.find('=');
501 211118 : if (eq_index == std::string::npos) {
502 106679 : eq_index = name.size();
503 106679 : }
504 211118 : std::string arg_name = name.substr(0, eq_index);
505 :
506 211118 : LOCK(cs_args);
507 211118 : std::map<std::string, Arg>& arg_map = m_available_args[cat];
508 211118 : auto ret = arg_map.emplace(arg_name, Arg{name.substr(eq_index, name.size() - eq_index), help, flags});
509 211118 : assert(ret.second); // Make sure an insertion actually happened
510 :
511 211118 : if (flags & ArgsManager::NETWORK_ONLY) {
512 8509 : m_network_only_args.emplace(arg_name);
513 8509 : }
514 211118 : }
515 :
516 3541 : void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
517 : {
518 15673 : for (const std::string& name : names) {
519 12132 : AddArg(name, "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN);
520 : }
521 3541 : }
522 :
523 1 : std::string ArgsManager::GetHelpMessage() const
524 : {
525 1 : const bool show_debug = gArgs.GetBoolArg("-help-debug", false);
526 :
527 1 : std::string usage = "";
528 1 : LOCK(cs_args);
529 12 : for (const auto& arg_map : m_available_args) {
530 11 : switch(arg_map.first) {
531 : case OptionsCategory::OPTIONS:
532 1 : usage += HelpMessageGroup("Options:");
533 1 : break;
534 : case OptionsCategory::CONNECTION:
535 1 : usage += HelpMessageGroup("Connection options:");
536 1 : break;
537 : case OptionsCategory::ZMQ:
538 1 : usage += HelpMessageGroup("ZeroMQ notification options:");
539 1 : break;
540 : case OptionsCategory::DEBUG_TEST:
541 1 : usage += HelpMessageGroup("Debugging/Testing options:");
542 1 : break;
543 : case OptionsCategory::NODE_RELAY:
544 1 : usage += HelpMessageGroup("Node relay options:");
545 1 : break;
546 : case OptionsCategory::BLOCK_CREATION:
547 1 : usage += HelpMessageGroup("Block creation options:");
548 1 : break;
549 : case OptionsCategory::RPC:
550 1 : usage += HelpMessageGroup("RPC server options:");
551 1 : break;
552 : case OptionsCategory::WALLET:
553 1 : usage += HelpMessageGroup("Wallet options:");
554 1 : break;
555 : case OptionsCategory::WALLET_DEBUG_TEST:
556 1 : if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
557 : break;
558 : case OptionsCategory::CHAINPARAMS:
559 1 : usage += HelpMessageGroup("Chain selection options:");
560 1 : break;
561 : case OptionsCategory::GUI:
562 0 : usage += HelpMessageGroup("UI Options:");
563 0 : break;
564 : case OptionsCategory::COMMANDS:
565 0 : usage += HelpMessageGroup("Commands:");
566 0 : break;
567 : case OptionsCategory::REGISTER_COMMANDS:
568 0 : usage += HelpMessageGroup("Register Commands:");
569 0 : break;
570 : default:
571 : break;
572 : }
573 :
574 : // When we get to the hidden options, stop
575 11 : if (arg_map.first == OptionsCategory::HIDDEN) break;
576 :
577 166 : for (const auto& arg : arg_map.second) {
578 156 : if (show_debug || !(arg.second.m_flags & ArgsManager::DEBUG_ONLY)) {
579 120 : std::string name;
580 120 : if (arg.second.m_help_param.empty()) {
581 46 : name = arg.first;
582 : } else {
583 74 : name = arg.first + arg.second.m_help_param;
584 : }
585 120 : usage += HelpMessageOpt(name, arg.second.m_help_text);
586 120 : }
587 0 : }
588 10 : }
589 : return usage;
590 1 : }
591 :
592 1056 : bool HelpRequested(const ArgsManager& args)
593 : {
594 1056 : return args.IsArgSet("-?") || args.IsArgSet("-h") || args.IsArgSet("-help") || args.IsArgSet("-help-debug");
595 0 : }
596 :
597 1521 : void SetupHelpOptions(ArgsManager& args)
598 : {
599 1521 : args.AddArg("-?", "Print this help message and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
600 3042 : args.AddHiddenArgs({"-h", "-help"});
601 1521 : }
602 :
603 : static const int screenWidth = 79;
604 : static const int optIndent = 2;
605 : static const int msgIndent = 7;
606 :
607 9 : std::string HelpMessageGroup(const std::string &message) {
608 9 : return std::string(message) + std::string("\n\n");
609 0 : }
610 :
611 120 : std::string HelpMessageOpt(const std::string &option, const std::string &message) {
612 360 : return std::string(optIndent,' ') + std::string(option) +
613 360 : std::string("\n") + std::string(msgIndent,' ') +
614 240 : FormatParagraph(message, screenWidth - msgIndent, msgIndent) +
615 120 : std::string("\n\n");
616 0 : }
617 :
618 2 : static std::string FormatException(const std::exception* pex, const char* pszThread)
619 : {
620 : #ifdef WIN32
621 : char pszModule[MAX_PATH] = "";
622 : GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
623 : #else
624 2 : const char* pszModule = "bitcoin";
625 : #endif
626 2 : if (pex)
627 2 : return strprintf(
628 2 : "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
629 : else
630 0 : return strprintf(
631 : "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
632 2 : }
633 :
634 2 : void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
635 : {
636 2 : std::string message = FormatException(pex, pszThread);
637 2 : LogPrintf("\n\n************************\n%s\n", message);
638 2 : tfm::format(std::cerr, "\n\n************************\n%s\n", message);
639 2 : }
640 :
641 527 : fs::path GetDefaultDataDir()
642 : {
643 : // Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
644 : // Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
645 : // Mac: ~/Library/Application Support/Bitcoin
646 : // Unix: ~/.bitcoin
647 : #ifdef WIN32
648 : // Windows
649 : return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
650 : #else
651 527 : fs::path pathRet;
652 527 : char* pszHome = getenv("HOME");
653 527 : if (pszHome == nullptr || strlen(pszHome) == 0)
654 0 : pathRet = fs::path("/");
655 : else
656 527 : pathRet = fs::path(pszHome);
657 : #ifdef MAC_OSX
658 : // Mac
659 527 : return pathRet / "Library/Application Support/Bitcoin";
660 : #else
661 : // Unix
662 : return pathRet / ".bitcoin";
663 : #endif
664 : #endif
665 527 : }
666 :
667 1150 : static fs::path g_blocks_path_cache_net_specific;
668 1150 : static fs::path pathCached;
669 1150 : static fs::path pathCachedNetSpecific;
670 1150 : static RecursiveMutex csPathCached;
671 :
672 299992 : const fs::path &GetBlocksDir()
673 : {
674 299992 : LOCK(csPathCached);
675 : fs::path &path = g_blocks_path_cache_net_specific;
676 :
677 : // Cache the path to avoid calling fs::create_directories on every call of
678 : // this function
679 299992 : if (!path.empty()) return path;
680 :
681 993 : if (gArgs.IsArgSet("-blocksdir")) {
682 2 : path = fs::system_complete(gArgs.GetArg("-blocksdir", ""));
683 2 : if (!fs::is_directory(path)) {
684 1 : path = "";
685 1 : return path;
686 : }
687 : } else {
688 991 : path = GetDataDir(false);
689 : }
690 :
691 992 : path /= BaseParams().DataDir();
692 992 : path /= "blocks";
693 992 : fs::create_directories(path);
694 992 : return path;
695 299992 : }
696 :
697 20740 : const fs::path &GetDataDir(bool fNetSpecific)
698 : {
699 20740 : LOCK(csPathCached);
700 20740 : fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
701 :
702 : // Cache the path to avoid calling fs::create_directories on every call of
703 : // this function
704 20740 : if (!path.empty()) return path;
705 :
706 3370 : std::string datadir = gArgs.GetArg("-datadir", "");
707 3370 : if (!datadir.empty()) {
708 3370 : path = fs::system_complete(datadir);
709 3370 : if (!fs::is_directory(path)) {
710 0 : path = "";
711 0 : return path;
712 : }
713 : } else {
714 0 : path = GetDefaultDataDir();
715 : }
716 3370 : if (fNetSpecific)
717 1419 : path /= BaseParams().DataDir();
718 :
719 3370 : if (fs::create_directories(path)) {
720 : // This is the first run, create wallets subdirectory too
721 219 : fs::create_directories(path / "wallets");
722 219 : }
723 :
724 3370 : return path;
725 20740 : }
726 :
727 1926 : bool CheckDataDirOption()
728 : {
729 1926 : std::string datadir = gArgs.GetArg("-datadir", "");
730 1926 : return datadir.empty() || fs::is_directory(fs::system_complete(datadir));
731 1926 : }
732 :
733 1416 : void ClearDatadirCache()
734 : {
735 1416 : LOCK(csPathCached);
736 :
737 1416 : pathCached = fs::path();
738 1416 : pathCachedNetSpecific = fs::path();
739 1416 : g_blocks_path_cache_net_specific = fs::path();
740 1416 : }
741 :
742 1510 : fs::path GetConfigFile(const std::string& confPath)
743 : {
744 1510 : return AbsPathForConfigVal(fs::path(confPath), false);
745 0 : }
746 :
747 27489 : static bool GetConfigOptions(std::istream& stream, const std::string& filepath, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::list<SectionInfo>& sections)
748 : {
749 27489 : std::string str, prefix;
750 : std::string::size_type pos;
751 27489 : int linenr = 1;
752 137421 : while (std::getline(stream, str)) {
753 : bool used_hash = false;
754 109937 : if ((pos = str.find('#')) != std::string::npos) {
755 3 : str = str.substr(0, pos);
756 : used_hash = true;
757 3 : }
758 109937 : const static std::string pattern = " \t\r\n";
759 109937 : str = TrimString(str, pattern);
760 109937 : if (!str.empty()) {
761 109934 : if (*str.begin() == '[' && *str.rbegin() == ']') {
762 987 : const std::string section = str.substr(1, str.size() - 2);
763 987 : sections.emplace_back(SectionInfo{section, filepath, linenr});
764 987 : prefix = section + '.';
765 109934 : } else if (*str.begin() == '-') {
766 1 : error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str);
767 1 : return false;
768 108946 : } else if ((pos = str.find('=')) != std::string::npos) {
769 108945 : std::string name = prefix + TrimString(str.substr(0, pos), pattern);
770 108945 : std::string value = TrimString(str.substr(pos + 1), pattern);
771 108945 : if (used_hash && name.find("rpcpassword") != std::string::npos) {
772 3 : error = strprintf("parse error on line %i, using # in rpcpassword can be ambiguous and should be avoided", linenr);
773 3 : return false;
774 : }
775 108942 : options.emplace_back(name, value);
776 108942 : if ((pos = name.rfind('.')) != std::string::npos && prefix.length() <= pos) {
777 45699 : sections.emplace_back(SectionInfo{name.substr(0, pos), filepath, linenr});
778 45699 : }
779 108945 : } else {
780 1 : error = strprintf("parse error on line %i: %s", linenr, str);
781 1 : if (str.size() >= 2 && str.substr(0, 2) == "no") {
782 1 : error += strprintf(", if you intended to specify a negated option, use %s=1 instead", str);
783 1 : }
784 1 : return false;
785 : }
786 : }
787 109932 : ++linenr;
788 109932 : }
789 27484 : return true;
790 27489 : }
791 :
792 27489 : bool ArgsManager::ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys)
793 : {
794 27489 : LOCK(cs_args);
795 27489 : std::vector<std::pair<std::string, std::string>> options;
796 27489 : if (!GetConfigOptions(stream, filepath, error, options, m_config_sections)) {
797 5 : return false;
798 : }
799 136420 : for (const std::pair<std::string, std::string>& option : options) {
800 108936 : std::string section;
801 108936 : std::string key = option.first;
802 108936 : util::SettingsValue value = InterpretOption(section, key, option.second);
803 108936 : Optional<unsigned int> flags = GetArgFlags('-' + key);
804 108936 : if (flags) {
805 104337 : if (!CheckValid(key, value, *flags, error)) {
806 0 : return false;
807 : }
808 104337 : m_settings.ro_config[section][key].push_back(value);
809 : } else {
810 4599 : if (ignore_invalid_keys) {
811 4599 : LogPrintf("Ignoring unknown configuration value %s\n", option.first);
812 : } else {
813 0 : error = strprintf("Invalid configuration value %s", option.first);
814 0 : return false;
815 : }
816 : }
817 108936 : }
818 27484 : return true;
819 27489 : }
820 :
821 961 : bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
822 : {
823 : {
824 961 : LOCK(cs_args);
825 961 : m_settings.ro_config.clear();
826 961 : m_config_sections.clear();
827 961 : }
828 :
829 961 : const std::string confPath = GetArg("-conf", BITCOIN_CONF_FILENAME);
830 961 : fsbridge::ifstream stream(GetConfigFile(confPath));
831 :
832 : // ok to not have a config file
833 961 : if (stream.good()) {
834 961 : if (!ReadConfigStream(stream, confPath, error, ignore_invalid_keys)) {
835 0 : return false;
836 : }
837 : // `-includeconf` cannot be included in the command line arguments except
838 : // as `-noincludeconf` (which indicates that no included conf file should be used).
839 : bool use_conf_file{true};
840 : {
841 961 : LOCK(cs_args);
842 961 : if (auto* includes = util::FindKey(m_settings.command_line_options, "includeconf")) {
843 : // ParseParameters() fails if a non-negated -includeconf is passed on the command-line
844 0 : assert(util::SettingsSpan(*includes).last_negated());
845 : use_conf_file = false;
846 0 : }
847 961 : }
848 961 : if (use_conf_file) {
849 961 : std::string chain_id = GetChainName();
850 961 : std::vector<std::string> conf_file_names;
851 :
852 4794 : auto add_includes = [&](const std::string& network, size_t skip = 0) {
853 : size_t num_values = 0;
854 3833 : LOCK(cs_args);
855 3833 : if (auto* section = util::FindKey(m_settings.ro_config, network)) {
856 3832 : if (auto* values = util::FindKey(*section, "includeconf")) {
857 49 : for (size_t i = std::max(skip, util::SettingsSpan(*values).negated()); i < values->size(); ++i) {
858 22 : conf_file_names.push_back((*values)[i].get_str());
859 : }
860 27 : num_values = values->size();
861 27 : }
862 3832 : }
863 : return num_values;
864 3833 : };
865 :
866 : // We haven't set m_network yet (that happens in SelectParams()), so manually check
867 : // for network.includeconf args.
868 961 : const size_t chain_includes = add_includes(chain_id);
869 961 : const size_t default_includes = add_includes({});
870 :
871 982 : for (const std::string& conf_file_name : conf_file_names) {
872 21 : fsbridge::ifstream conf_file_stream(GetConfigFile(conf_file_name));
873 21 : if (conf_file_stream.good()) {
874 20 : if (!ReadConfigStream(conf_file_stream, conf_file_name, error, ignore_invalid_keys)) {
875 5 : return false;
876 : }
877 15 : LogPrintf("Included configuration file %s\n", conf_file_name);
878 : } else {
879 1 : error = "Failed to include configuration file " + conf_file_name;
880 1 : return false;
881 : }
882 21 : }
883 :
884 : // Warn about recursive -includeconf
885 955 : conf_file_names.clear();
886 955 : add_includes(chain_id, /* skip= */ chain_includes);
887 955 : add_includes({}, /* skip= */ default_includes);
888 955 : std::string chain_id_final = GetChainName();
889 955 : if (chain_id_final != chain_id) {
890 : // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
891 1 : add_includes(chain_id_final);
892 : }
893 956 : for (const std::string& conf_file_name : conf_file_names) {
894 1 : tfm::format(std::cerr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", conf_file_name);
895 : }
896 961 : }
897 955 : }
898 :
899 : // If datadir is changed in .conf file:
900 955 : ClearDatadirCache();
901 955 : if (!CheckDataDirOption()) {
902 1 : error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", ""));
903 1 : return false;
904 : }
905 954 : return true;
906 961 : }
907 :
908 6722 : std::string ArgsManager::GetChainName() const
909 : {
910 20166 : auto get_net = [&](const std::string& arg) {
911 13444 : LOCK(cs_args);
912 13444 : util::SettingsValue value = util::GetSetting(m_settings, /* section= */ "", SettingName(arg),
913 : /* ignore_default_section_config= */ false,
914 : /* get_chain_name= */ true);
915 13444 : return value.isNull() ? false : value.isBool() ? value.get_bool() : InterpretBool(value.get_str());
916 13444 : };
917 :
918 6722 : const bool fRegTest = get_net("-regtest");
919 6722 : const bool fTestNet = get_net("-testnet");
920 6722 : const bool is_chain_arg_set = IsArgSet("-chain");
921 :
922 6722 : if ((int)is_chain_arg_set + (int)fRegTest + (int)fTestNet > 1) {
923 374 : throw std::runtime_error("Invalid combination of -regtest, -testnet and -chain. Can use at most one.");
924 : }
925 6348 : if (fRegTest)
926 4034 : return CBaseChainParams::REGTEST;
927 2314 : if (fTestNet)
928 672 : return CBaseChainParams::TESTNET;
929 1642 : return GetArg("-chain", CBaseChainParams::MAIN);
930 6348 : }
931 :
932 1637933 : bool ArgsManager::UseDefaultSection(const std::string& arg) const
933 : {
934 1637933 : return m_network == CBaseChainParams::MAIN || m_network_only_args.count(arg) == 0;
935 : }
936 :
937 1595424 : util::SettingsValue ArgsManager::GetSetting(const std::string& arg) const
938 : {
939 1595424 : LOCK(cs_args);
940 1595429 : return util::GetSetting(
941 1595424 : m_settings, m_network, SettingName(arg), !UseDefaultSection(arg), /* get_chain_name= */ false);
942 1595429 : }
943 :
944 42504 : std::vector<util::SettingsValue> ArgsManager::GetSettingsList(const std::string& arg) const
945 : {
946 42504 : LOCK(cs_args);
947 42504 : return util::GetSettingsList(m_settings, m_network, SettingName(arg), !UseDefaultSection(arg));
948 42504 : }
949 :
950 1583 : void ArgsManager::logArgsPrefix(
951 : const std::string& prefix,
952 : const std::string& section,
953 : const std::map<std::string, std::vector<util::SettingsValue>>& args) const
954 : {
955 1583 : std::string section_str = section.empty() ? "" : "[" + section + "] ";
956 12360 : for (const auto& arg : args) {
957 22153 : for (const auto& value : arg.second) {
958 11376 : Optional<unsigned int> flags = GetArgFlags('-' + arg.first);
959 11376 : if (flags) {
960 11376 : std::string value_str = (*flags & SENSITIVE) ? "****" : value.write();
961 11376 : LogPrintf("%s %s%s=%s\n", prefix, section_str, arg.first, value_str);
962 11376 : }
963 11376 : }
964 0 : }
965 1583 : }
966 :
967 528 : void ArgsManager::LogArgs() const
968 : {
969 528 : LOCK(cs_args);
970 1583 : for (const auto& section : m_settings.ro_config) {
971 1055 : logArgsPrefix("Config file arg:", section.first, section.second);
972 0 : }
973 752 : for (const auto& setting : m_settings.rw_settings) {
974 224 : LogPrintf("Setting file arg: %s = %s\n", setting.first, setting.second.write());
975 0 : }
976 528 : logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
977 528 : }
978 :
979 2788 : bool RenameOver(fs::path src, fs::path dest)
980 : {
981 : #ifdef WIN32
982 : return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(),
983 : MOVEFILE_REPLACE_EXISTING) != 0;
984 : #else
985 2788 : int rc = std::rename(src.string().c_str(), dest.string().c_str());
986 2788 : return (rc == 0);
987 : #endif /* WIN32 */
988 : }
989 :
990 : /**
991 : * Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
992 : * Specifically handles case where path p exists, but it wasn't possible for the user to
993 : * write to the parent directory.
994 : */
995 15887 : bool TryCreateDirectories(const fs::path& p)
996 : {
997 : try
998 : {
999 15887 : return fs::create_directories(p);
1000 4 : } catch (const fs::filesystem_error&) {
1001 2 : if (!fs::exists(p) || !fs::is_directory(p))
1002 2 : throw;
1003 2 : }
1004 :
1005 : // create_directories didn't create the directory, it had to have existed already
1006 0 : return false;
1007 15889 : }
1008 :
1009 4476 : bool FileCommit(FILE *file)
1010 : {
1011 4476 : if (fflush(file) != 0) { // harmless if redundantly called
1012 0 : LogPrintf("%s: fflush failed: %d\n", __func__, errno);
1013 0 : return false;
1014 : }
1015 : #ifdef WIN32
1016 : HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
1017 : if (FlushFileBuffers(hFile) == 0) {
1018 : LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError());
1019 : return false;
1020 : }
1021 : #else
1022 : #if HAVE_FDATASYNC
1023 : if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
1024 : LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
1025 : return false;
1026 : }
1027 : #elif defined(MAC_OSX) && defined(F_FULLFSYNC)
1028 4476 : if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success
1029 0 : LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno);
1030 0 : return false;
1031 : }
1032 : #else
1033 : if (fsync(fileno(file)) != 0 && errno != EINVAL) {
1034 : LogPrintf("%s: fsync failed: %d\n", __func__, errno);
1035 : return false;
1036 : }
1037 : #endif
1038 : #endif
1039 4476 : return true;
1040 4476 : }
1041 :
1042 21 : bool TruncateFile(FILE *file, unsigned int length) {
1043 : #if defined(WIN32)
1044 : return _chsize(_fileno(file), length) == 0;
1045 : #else
1046 21 : return ftruncate(fileno(file), length) == 0;
1047 : #endif
1048 : }
1049 :
1050 : /**
1051 : * this function tries to raise the file descriptor limit to the requested number.
1052 : * It returns the actual file descriptor limit (which may be more or less than nMinFD)
1053 : */
1054 992 : int RaiseFileDescriptorLimit(int nMinFD) {
1055 : #if defined(WIN32)
1056 : return 2048;
1057 : #else
1058 992 : struct rlimit limitFD;
1059 992 : if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) {
1060 992 : if (limitFD.rlim_cur < (rlim_t)nMinFD) {
1061 617 : limitFD.rlim_cur = nMinFD;
1062 617 : if (limitFD.rlim_cur > limitFD.rlim_max)
1063 0 : limitFD.rlim_cur = limitFD.rlim_max;
1064 617 : setrlimit(RLIMIT_NOFILE, &limitFD);
1065 617 : getrlimit(RLIMIT_NOFILE, &limitFD);
1066 617 : }
1067 992 : return limitFD.rlim_cur;
1068 : }
1069 0 : return nMinFD; // getrlimit failed, assume it's fine
1070 : #endif
1071 992 : }
1072 :
1073 : /**
1074 : * this function tries to make a particular range of a file allocated (corresponding to disk space)
1075 : * it is advisory, and the range specified in the arguments will never contain live data
1076 : */
1077 557 : void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) {
1078 : #if defined(WIN32)
1079 : // Windows-specific version
1080 : HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file));
1081 : LARGE_INTEGER nFileSize;
1082 : int64_t nEndPos = (int64_t)offset + length;
1083 : nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF;
1084 : nFileSize.u.HighPart = nEndPos >> 32;
1085 : SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN);
1086 : SetEndOfFile(hFile);
1087 : #elif defined(MAC_OSX)
1088 : // OSX specific version
1089 : // NOTE: Contrary to other OS versions, the OSX version assumes that
1090 : // NOTE: offset is the size of the file.
1091 557 : fstore_t fst;
1092 557 : fst.fst_flags = F_ALLOCATECONTIG;
1093 557 : fst.fst_posmode = F_PEOFPOSMODE;
1094 557 : fst.fst_offset = 0;
1095 557 : fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size
1096 557 : fst.fst_bytesalloc = 0;
1097 557 : if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) {
1098 0 : fst.fst_flags = F_ALLOCATEALL;
1099 0 : fcntl(fileno(file), F_PREALLOCATE, &fst);
1100 0 : }
1101 557 : ftruncate(fileno(file), static_cast<off_t>(offset) + length);
1102 : #else
1103 : #if defined(HAVE_POSIX_FALLOCATE)
1104 : // Version using posix_fallocate
1105 : off_t nEndPos = (off_t)offset + length;
1106 : if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return;
1107 : #endif
1108 : // Fallback version
1109 : // TODO: just write one byte per block
1110 : static const char buf[65536] = {};
1111 : if (fseek(file, offset, SEEK_SET)) {
1112 : return;
1113 : }
1114 : while (length > 0) {
1115 : unsigned int now = 65536;
1116 : if (length < now)
1117 : now = length;
1118 : fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway
1119 : length -= now;
1120 : }
1121 : #endif
1122 557 : }
1123 :
1124 : #ifdef WIN32
1125 : fs::path GetSpecialFolderPath(int nFolder, bool fCreate)
1126 : {
1127 : WCHAR pszPath[MAX_PATH] = L"";
1128 :
1129 : if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate))
1130 : {
1131 : return fs::path(pszPath);
1132 : }
1133 :
1134 : LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n");
1135 : return fs::path("");
1136 : }
1137 : #endif
1138 :
1139 : #ifndef WIN32
1140 26 : std::string ShellEscape(const std::string& arg)
1141 : {
1142 26 : std::string escaped = arg;
1143 26 : boost::replace_all(escaped, "'", "'\"'\"'");
1144 26 : return "'" + escaped + "'";
1145 26 : }
1146 : #endif
1147 :
1148 : #if HAVE_SYSTEM
1149 140 : void runCommand(const std::string& strCommand)
1150 : {
1151 140 : if (strCommand.empty()) return;
1152 : #ifndef WIN32
1153 140 : int nErr = ::system(strCommand.c_str());
1154 : #else
1155 : int nErr = ::_wsystem(std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t>().from_bytes(strCommand).c_str());
1156 : #endif
1157 140 : if (nErr)
1158 0 : LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
1159 140 : }
1160 : #endif
1161 :
1162 : #ifdef HAVE_BOOST_PROCESS
1163 : UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
1164 : {
1165 : namespace bp = boost::process;
1166 :
1167 : UniValue result_json;
1168 : bp::opstream stdin_stream;
1169 : bp::ipstream stdout_stream;
1170 : bp::ipstream stderr_stream;
1171 :
1172 : if (str_command.empty()) return UniValue::VNULL;
1173 :
1174 : bp::child c(
1175 : str_command,
1176 : bp::std_out > stdout_stream,
1177 : bp::std_err > stderr_stream,
1178 : bp::std_in < stdin_stream
1179 : );
1180 : if (!str_std_in.empty()) {
1181 : stdin_stream << str_std_in << std::endl;
1182 : }
1183 : stdin_stream.pipe().close();
1184 :
1185 : std::string result;
1186 : std::string error;
1187 : std::getline(stdout_stream, result);
1188 : std::getline(stderr_stream, error);
1189 :
1190 : c.wait();
1191 : const int n_error = c.exit_code();
1192 : if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
1193 : if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
1194 :
1195 : return result_json;
1196 : }
1197 : #endif // HAVE_BOOST_PROCESS
1198 :
1199 1520 : void SetupEnvironment()
1200 : {
1201 : #ifdef HAVE_MALLOPT_ARENA_MAX
1202 : // glibc-specific: On 32-bit systems set the number of arenas to 1.
1203 : // By default, since glibc 2.10, the C library will create up to two heap
1204 : // arenas per core. This is known to cause excessive virtual address space
1205 : // usage in our usage. Work around it by setting the maximum number of
1206 : // arenas to 1.
1207 : if (sizeof(void*) == 4) {
1208 : mallopt(M_ARENA_MAX, 1);
1209 : }
1210 : #endif
1211 : // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale
1212 : // may be invalid, in which case the "C.UTF-8" locale is used as fallback.
1213 : #if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
1214 : try {
1215 : std::locale(""); // Raises a runtime error if current locale is invalid
1216 : } catch (const std::runtime_error&) {
1217 : setenv("LC_ALL", "C.UTF-8", 1);
1218 : }
1219 : #elif defined(WIN32)
1220 : // Set the default input/output charset is utf-8
1221 : SetConsoleCP(CP_UTF8);
1222 : SetConsoleOutputCP(CP_UTF8);
1223 : #endif
1224 : // The path locale is lazy initialized and to avoid deinitialization errors
1225 : // in multithreading environments, it is set explicitly by the main thread.
1226 : // A dummy locale is used to extract the internal default locale, used by
1227 : // fs::path, which is then used to explicitly imbue the path.
1228 1520 : std::locale loc = fs::path::imbue(std::locale::classic());
1229 : #ifndef WIN32
1230 1520 : fs::path::imbue(loc);
1231 : #else
1232 : fs::path::imbue(std::locale(loc, new std::codecvt_utf8_utf16<wchar_t>()));
1233 : #endif
1234 1520 : }
1235 :
1236 1413 : bool SetupNetworking()
1237 : {
1238 : #ifdef WIN32
1239 : // Initialize Windows Sockets
1240 : WSADATA wsadata;
1241 : int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
1242 : if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
1243 : return false;
1244 : #endif
1245 1413 : return true;
1246 : }
1247 :
1248 1539 : int GetNumCores()
1249 : {
1250 1539 : return std::thread::hardware_concurrency();
1251 : }
1252 :
1253 1 : std::string CopyrightHolders(const std::string& strPrefix)
1254 : {
1255 1 : const auto copyright_devs = strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION);
1256 1 : std::string strCopyrightHolders = strPrefix + copyright_devs;
1257 :
1258 : // Make sure Bitcoin Core copyright is not removed by accident
1259 1 : if (copyright_devs.find("Bitcoin Core") == std::string::npos) {
1260 0 : strCopyrightHolders += "\n" + strPrefix + "The Bitcoin Core developers";
1261 0 : }
1262 : return strCopyrightHolders;
1263 1 : }
1264 :
1265 : // Obtain the application startup time (used for uptime calculation)
1266 1 : int64_t GetStartupTime()
1267 : {
1268 1 : return nStartupTime;
1269 : }
1270 :
1271 5574 : fs::path AbsPathForConfigVal(const fs::path& path, bool net_specific)
1272 : {
1273 5574 : if (path.is_absolute()) {
1274 25 : return path;
1275 : }
1276 5549 : return fs::absolute(path, GetDataDir(net_specific));
1277 5574 : }
1278 :
1279 495 : void ScheduleBatchPriority()
1280 : {
1281 : #ifdef SCHED_BATCH
1282 : const static sched_param param{};
1283 : const int rc = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m);
1284 : if (rc != 0) {
1285 : LogPrintf("Failed to pthread_setschedparam: %s\n", strerror(rc));
1286 : }
1287 : #endif
1288 495 : }
1289 :
1290 : namespace util {
1291 : #ifdef WIN32
1292 : WinCmdLineArgs::WinCmdLineArgs()
1293 : {
1294 : wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
1295 : std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
1296 : argv = new char*[argc];
1297 : args.resize(argc);
1298 : for (int i = 0; i < argc; i++) {
1299 : args[i] = utf8_cvt.to_bytes(wargv[i]);
1300 : argv[i] = &*args[i].begin();
1301 : }
1302 : LocalFree(wargv);
1303 : }
1304 :
1305 : WinCmdLineArgs::~WinCmdLineArgs()
1306 : {
1307 : delete[] argv;
1308 : }
1309 :
1310 : std::pair<int, char**> WinCmdLineArgs::get()
1311 : {
1312 : return std::make_pair(argc, argv);
1313 : }
1314 : #endif
1315 : } // namespace util
|