aboutsummaryrefslogtreecommitdiff
path: root/src/util/system.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/system.cpp')
-rw-r--r--src/util/system.cpp131
1 files changed, 124 insertions, 7 deletions
diff --git a/src/util/system.cpp b/src/util/system.cpp
index 7e7ba840c..00aa53df7 100644
--- a/src/util/system.cpp
+++ b/src/util/system.cpp
@@ -6,6 +6,10 @@
#include <sync.h>
#include <util/system.h>
+#ifdef HAVE_BOOST_PROCESS
+#include <boost/process.hpp>
+#endif // HAVE_BOOST_PROCESS
+
#include <chainparamsbase.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -44,12 +48,6 @@
#pragma warning(disable:4717)
#endif
-#ifdef _WIN32_IE
-#undef _WIN32_IE
-#endif
-#define _WIN32_IE 0x0501
-
-#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
@@ -73,6 +71,7 @@
const int64_t nStartupTime = GetTime();
const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
+const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
ArgsManager gArgs;
@@ -372,6 +371,84 @@ bool ArgsManager::IsArgSet(const std::string& strArg) const
return !GetSetting(strArg).isNull();
}
+bool ArgsManager::InitSettings(std::string& error)
+{
+ if (!GetSettingsPath()) {
+ return true; // Do nothing if settings file disabled.
+ }
+
+ std::vector<std::string> errors;
+ if (!ReadSettingsFile(&errors)) {
+ error = strprintf("Failed loading settings file:\n- %s\n", Join(errors, "\n- "));
+ return false;
+ }
+ if (!WriteSettingsFile(&errors)) {
+ error = strprintf("Failed saving settings file:\n- %s\n", Join(errors, "\n- "));
+ return false;
+ }
+ return true;
+}
+
+bool ArgsManager::GetSettingsPath(fs::path* filepath, bool temp) const
+{
+ if (IsArgNegated("-settings")) {
+ return false;
+ }
+ if (filepath) {
+ std::string settings = GetArg("-settings", BITCOIN_SETTINGS_FILENAME);
+ *filepath = fs::absolute(temp ? settings + ".tmp" : settings, GetDataDir(/* net_specific= */ true));
+ }
+ return true;
+}
+
+static void SaveErrors(const std::vector<std::string> errors, std::vector<std::string>* error_out)
+{
+ for (const auto& error : errors) {
+ if (error_out) {
+ error_out->emplace_back(error);
+ } else {
+ LogPrintf("%s\n", error);
+ }
+ }
+}
+
+bool ArgsManager::ReadSettingsFile(std::vector<std::string>* errors)
+{
+ fs::path path;
+ if (!GetSettingsPath(&path, /* temp= */ false)) {
+ return true; // Do nothing if settings file disabled.
+ }
+
+ LOCK(cs_args);
+ m_settings.rw_settings.clear();
+ std::vector<std::string> read_errors;
+ if (!util::ReadSettings(path, m_settings.rw_settings, read_errors)) {
+ SaveErrors(read_errors, errors);
+ return false;
+ }
+ return true;
+}
+
+bool ArgsManager::WriteSettingsFile(std::vector<std::string>* errors) const
+{
+ fs::path path, path_tmp;
+ if (!GetSettingsPath(&path, /* temp= */ false) || !GetSettingsPath(&path_tmp, /* temp= */ true)) {
+ throw std::logic_error("Attempt to write settings file when dynamic settings are disabled.");
+ }
+
+ LOCK(cs_args);
+ std::vector<std::string> write_errors;
+ if (!util::WriteSettings(path_tmp, m_settings.rw_settings, write_errors)) {
+ SaveErrors(write_errors, errors);
+ return false;
+ }
+ if (!RenameOver(path_tmp, path)) {
+ SaveErrors({strprintf("Failed renaming settings file %s to %s\n", path_tmp.string(), path.string())}, errors);
+ return false;
+ }
+ return true;
+}
+
bool ArgsManager::IsArgNegated(const std::string& strArg) const
{
return GetSetting(strArg).isFalse();
@@ -893,6 +970,9 @@ void ArgsManager::LogArgs() const
for (const auto& section : m_settings.ro_config) {
logArgsPrefix("Config file arg:", section.first, section.second);
}
+ for (const auto& setting : m_settings.rw_settings) {
+ LogPrintf("Setting file arg: %s = %s\n", setting.first, setting.second.write());
+ }
logArgsPrefix("Command-line arg:", "", m_settings.command_line_options);
}
@@ -939,7 +1019,7 @@ bool FileCommit(FILE *file)
return false;
}
#else
- #if defined(__linux__) || defined(__NetBSD__)
+ #if defined(HAVE_FDATASYNC)
if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync
LogPrintf("%s: fdatasync failed: %d\n", __func__, errno);
return false;
@@ -1079,6 +1159,43 @@ void runCommand(const std::string& strCommand)
}
#endif
+#ifdef HAVE_BOOST_PROCESS
+UniValue RunCommandParseJSON(const std::string& str_command, const std::string& str_std_in)
+{
+ namespace bp = boost::process;
+
+ UniValue result_json;
+ bp::opstream stdin_stream;
+ bp::ipstream stdout_stream;
+ bp::ipstream stderr_stream;
+
+ if (str_command.empty()) return UniValue::VNULL;
+
+ bp::child c(
+ str_command,
+ bp::std_out > stdout_stream,
+ bp::std_err > stderr_stream,
+ bp::std_in < stdin_stream
+ );
+ if (!str_std_in.empty()) {
+ stdin_stream << str_std_in << std::endl;
+ }
+ stdin_stream.pipe().close();
+
+ std::string result;
+ std::string error;
+ std::getline(stdout_stream, result);
+ std::getline(stderr_stream, error);
+
+ c.wait();
+ const int n_error = c.exit_code();
+ if (n_error) throw std::runtime_error(strprintf("RunCommandParseJSON error: process(%s) returned %d: %s\n", str_command, n_error, error));
+ if (!result_json.read(result)) throw std::runtime_error("Unable to parse JSON: " + result);
+
+ return result_json;
+}
+#endif // HAVE_BOOST_PROCESS
+
void SetupEnvironment()
{
#ifdef HAVE_MALLOPT_ARENA_MAX