aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorRyan Ofsky <ryan@ofsky.org>2023-02-23 15:56:15 -0500
committerRyan Ofsky <ryan@ofsky.org>2023-02-28 12:04:47 -0500
commit802cc1ef536e11944608fe9ab782d3e962037703 (patch)
tree19008ea3dfb639d73a0d5fbb91c2f793aea8bb8f /src/common
parentd172b5c6718b69200c8ad211fe709860081bd692 (diff)
downloadbitcoin-802cc1ef536e11944608fe9ab782d3e962037703.tar.xz
Deduplicate bitcoind and bitcoin-qt init code
Add common InitConfig function to deduplicate bitcoind and bitcoin-qt code reading config files and creating the datadir. There are a few minor changes in behavior: - In bitcoin-qt, when there is a problem reading the configuration file, the GUI error text has changed from "Error: Cannot parse configuration file:" to "Error reading configuration file:" to be consistent with bitcoind. - In bitcoind, when there is a problem reading the settings.json file, the error text has changed from "Failed loading settings file" to "Settings file could not be read" to be consistent with bitcoin-qt. - In bitcoind, when there is a problem writing the settings.json file, the error text has changed from "Failed saving settings file" to "Settings file could not be written" to be consistent with bitcoin-qt. - In bitcoin-qt, if there datadir is not accessible (e.g. no permission to read), there is an normal error dialog showing "Error: filesystem error: status: Permission denied [.../settings.json]", instead of an uncaught exception
Diffstat (limited to 'src/common')
-rw-r--r--src/common/init.cpp74
-rw-r--r--src/common/init.h39
2 files changed, 113 insertions, 0 deletions
diff --git a/src/common/init.cpp b/src/common/init.cpp
new file mode 100644
index 0000000000..159eb7e2ef
--- /dev/null
+++ b/src/common/init.cpp
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <common/init.h>
+#include <chainparams.h>
+#include <fs.h>
+#include <tinyformat.h>
+#include <util/system.h>
+#include <util/translation.h>
+
+#include <algorithm>
+#include <exception>
+#include <optional>
+
+namespace common {
+std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn settings_abort_fn)
+{
+ try {
+ if (!CheckDataDirOption(args)) {
+ return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), args.GetArg("-datadir", ""))};
+ }
+ std::string error;
+ if (!args.ReadConfigFiles(error, true)) {
+ return ConfigError{ConfigStatus::FAILED, strprintf(_("Error reading configuration file: %s"), error)};
+ }
+
+ // Check for chain settings (Params() calls are only valid after this clause)
+ SelectParams(args.GetChainName());
+
+ // Create datadir if it does not exist.
+ const auto base_path{args.GetDataDirBase()};
+ if (!fs::exists(base_path)) {
+ // When creating a *new* datadir, also create a "wallets" subdirectory,
+ // whether or not the wallet is enabled now, so if the wallet is enabled
+ // in the future, it will use the "wallets" subdirectory for creating
+ // and listing wallets, rather than the top-level directory where
+ // wallets could be mixed up with other files. For backwards
+ // compatibility, wallet code will use the "wallets" subdirectory only
+ // if it already exists, but never create it itself. There is discussion
+ // in https://github.com/bitcoin/bitcoin/issues/16220 about ways to
+ // change wallet code so it would no longer be necessary to create
+ // "wallets" subdirectories here.
+ fs::create_directories(base_path / "wallets");
+ }
+ const auto net_path{args.GetDataDirNet()};
+ if (!fs::exists(net_path)) {
+ fs::create_directories(net_path / "wallets");
+ }
+
+ // Create settings.json if -nosettings was not specified.
+ if (args.GetSettingsPath()) {
+ std::vector<std::string> details;
+ if (!args.ReadSettingsFile(&details)) {
+ const bilingual_str& message = _("Settings file could not be read");
+ if (!settings_abort_fn) {
+ return ConfigError{ConfigStatus::FAILED, message, details};
+ } else if (settings_abort_fn(message, details)) {
+ return ConfigError{ConfigStatus::ABORTED, message, details};
+ } else {
+ details.clear(); // User chose to ignore the error and proceed.
+ }
+ }
+ if (!args.WriteSettingsFile(&details)) {
+ const bilingual_str& message = _("Settings file could not be written");
+ return ConfigError{ConfigStatus::FAILED_WRITE, message, details};
+ }
+ }
+ } catch (const std::exception& e) {
+ return ConfigError{ConfigStatus::FAILED, Untranslated(e.what())};
+ }
+ return {};
+}
+} // namespace common
diff --git a/src/common/init.h b/src/common/init.h
new file mode 100644
index 0000000000..380ac3ac7e
--- /dev/null
+++ b/src/common/init.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_COMMON_INIT_H
+#define BITCOIN_COMMON_INIT_H
+
+#include <util/translation.h>
+
+#include <functional>
+#include <optional>
+#include <string>
+#include <vector>
+
+class ArgsManager;
+
+namespace common {
+enum class ConfigStatus {
+ FAILED, //!< Failed generically.
+ FAILED_WRITE, //!< Failed to write settings.json
+ ABORTED, //!< Aborted by user
+};
+
+struct ConfigError {
+ ConfigStatus status;
+ bilingual_str message{};
+ std::vector<std::string> details{};
+};
+
+//! Callback function to let the user decide whether to abort loading if
+//! settings.json file exists and can't be parsed, or to ignore the error and
+//! overwrite the file.
+using SettingsAbortFn = std::function<bool(const bilingual_str& message, const std::vector<std::string>& details)>;
+
+/* Read config files, and create datadir and settings.json if they don't exist. */
+std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn settings_abort_fn = nullptr);
+} // namespace common
+
+#endif // BITCOIN_COMMON_INIT_H