/bitcoin/src/common/init.cpp
Line | Count | Source |
1 | | // Copyright (c) 2023 The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #include <chainparams.h> |
6 | | #include <common/args.h> |
7 | | #include <common/init.h> |
8 | | #include <logging.h> |
9 | | #include <tinyformat.h> |
10 | | #include <util/fs.h> |
11 | | #include <util/translation.h> |
12 | | |
13 | | #include <algorithm> |
14 | | #include <exception> |
15 | | #include <optional> |
16 | | |
17 | | namespace common { |
18 | | std::optional<ConfigError> InitConfig(ArgsManager& args, SettingsAbortFn settings_abort_fn) |
19 | 11.0k | { |
20 | 11.0k | try { |
21 | 11.0k | if (!CheckDataDirOption(args)) { Branch (21:13): [True: 0, False: 11.0k]
|
22 | 0 | return ConfigError{ConfigStatus::FAILED, strprintf(_("Specified data directory \"%s\" does not exist."), args.GetArg("-datadir", ""))}; |
23 | 0 | } |
24 | | |
25 | | // Record original datadir and config paths before parsing the config |
26 | | // file. It is possible for the config file to contain a datadir= line |
27 | | // that changes the datadir path after it is parsed. This is useful for |
28 | | // CLI tools to let them use a different data storage location without |
29 | | // needing to pass it every time on the command line. (It is not |
30 | | // possible for the config file to cause another configuration to be |
31 | | // used, though. Specifying a conf= option in the config file causes a |
32 | | // parse error, and specifying a datadir= location containing another |
33 | | // bitcoin.conf file just ignores the other file.) |
34 | 11.0k | const fs::path orig_datadir_path{args.GetDataDirBase()}; |
35 | 11.0k | const fs::path orig_config_path{AbsPathForConfigVal(args, args.GetPathArg("-conf", BITCOIN_CONF_FILENAME), /*net_specific=*/false)}; |
36 | | |
37 | 11.0k | std::string error; |
38 | 11.0k | if (!args.ReadConfigFiles(error, true)) { Branch (38:13): [True: 0, False: 11.0k]
|
39 | 0 | return ConfigError{ConfigStatus::FAILED, strprintf(_("Error reading configuration file: %s"), error)}; |
40 | 0 | } |
41 | | |
42 | | // Check for chain settings (Params() calls are only valid after this clause) |
43 | 11.0k | SelectParams(args.GetChainType()); |
44 | | |
45 | | // Create datadir if it does not exist. |
46 | 11.0k | const auto base_path{args.GetDataDirBase()}; |
47 | 11.0k | if (!fs::exists(base_path)) { Branch (47:13): [True: 0, False: 11.0k]
|
48 | | // When creating a *new* datadir, also create a "wallets" subdirectory, |
49 | | // whether or not the wallet is enabled now, so if the wallet is enabled |
50 | | // in the future, it will use the "wallets" subdirectory for creating |
51 | | // and listing wallets, rather than the top-level directory where |
52 | | // wallets could be mixed up with other files. For backwards |
53 | | // compatibility, wallet code will use the "wallets" subdirectory only |
54 | | // if it already exists, but never create it itself. There is discussion |
55 | | // in https://github.com/bitcoin/bitcoin/issues/16220 about ways to |
56 | | // change wallet code so it would no longer be necessary to create |
57 | | // "wallets" subdirectories here. |
58 | 0 | fs::create_directories(base_path / "wallets"); |
59 | 0 | } |
60 | 11.0k | const auto net_path{args.GetDataDirNet()}; |
61 | 11.0k | if (!fs::exists(net_path)) { Branch (61:13): [True: 11.0k, False: 0]
|
62 | 11.0k | fs::create_directories(net_path / "wallets"); |
63 | 11.0k | } |
64 | | |
65 | | // Show an error or warn/log if there is a bitcoin.conf file in the |
66 | | // datadir that is being ignored. |
67 | 11.0k | const fs::path base_config_path = base_path / BITCOIN_CONF_FILENAME; |
68 | 11.0k | if (fs::exists(base_config_path)) { Branch (68:13): [True: 0, False: 11.0k]
|
69 | 0 | if (orig_config_path.empty()) { Branch (69:17): [True: 0, False: 0]
|
70 | 0 | LogInfo( |
71 | 0 | "Data directory %s contains a %s file which is explicitly ignored using -noconf.", |
72 | 0 | fs::quoted(fs::PathToString(base_path)), |
73 | 0 | fs::quoted(BITCOIN_CONF_FILENAME)); |
74 | 0 | } else if (!fs::equivalent(orig_config_path, base_config_path)) { Branch (74:24): [True: 0, False: 0]
|
75 | 0 | const std::string cli_config_path = args.GetArg("-conf", ""); |
76 | 0 | const std::string config_source = cli_config_path.empty() Branch (76:51): [True: 0, False: 0]
|
77 | 0 | ? strprintf("data directory %s", fs::quoted(fs::PathToString(orig_datadir_path))) |
78 | 0 | : strprintf("command line argument %s", fs::quoted("-conf=" + cli_config_path)); |
79 | 0 | std::string error = strprintf( |
80 | 0 | "Data directory %1$s contains a %2$s file which is ignored, because a different configuration file " |
81 | 0 | "%3$s from %4$s is being used instead. Possible ways to address this would be to:\n" |
82 | 0 | "- Delete or rename the %2$s file in data directory %1$s.\n" |
83 | 0 | "- Change datadir= or conf= options to specify one configuration file, not two, and use " |
84 | 0 | "includeconf= to include any other configuration files.", |
85 | 0 | fs::quoted(fs::PathToString(base_path)), |
86 | 0 | fs::quoted(BITCOIN_CONF_FILENAME), |
87 | 0 | fs::quoted(fs::PathToString(orig_config_path)), |
88 | 0 | config_source); |
89 | 0 | if (args.GetBoolArg("-allowignoredconf", false)) { Branch (89:21): [True: 0, False: 0]
|
90 | 0 | LogWarning("%s", error); |
91 | 0 | } else { |
92 | 0 | error += "\n- Set allowignoredconf=1 option to treat this condition as a warning, not an error."; |
93 | 0 | return ConfigError{ConfigStatus::FAILED, Untranslated(error)}; |
94 | 0 | } |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | // Create settings.json if -nosettings was not specified. |
99 | 11.0k | if (args.GetSettingsPath()) { Branch (99:13): [True: 11.0k, False: 0]
|
100 | 11.0k | std::vector<std::string> details; |
101 | 11.0k | if (!args.ReadSettingsFile(&details)) { Branch (101:17): [True: 0, False: 11.0k]
|
102 | 0 | const bilingual_str& message = _("Settings file could not be read"); |
103 | 0 | if (!settings_abort_fn) { Branch (103:21): [True: 0, False: 0]
|
104 | 0 | return ConfigError{ConfigStatus::FAILED, message, details}; |
105 | 0 | } else if (settings_abort_fn(message, details)) { Branch (105:28): [True: 0, False: 0]
|
106 | 0 | return ConfigError{ConfigStatus::ABORTED, message, details}; |
107 | 0 | } else { |
108 | 0 | details.clear(); // User chose to ignore the error and proceed. |
109 | 0 | } |
110 | 0 | } |
111 | 11.0k | if (!args.WriteSettingsFile(&details)) { Branch (111:17): [True: 0, False: 11.0k]
|
112 | 0 | const bilingual_str& message = _("Settings file could not be written"); |
113 | 0 | return ConfigError{ConfigStatus::FAILED_WRITE, message, details}; |
114 | 0 | } |
115 | 11.0k | } |
116 | 11.0k | } catch (const std::exception& e) { |
117 | 0 | return ConfigError{ConfigStatus::FAILED, Untranslated(e.what())}; |
118 | 0 | } |
119 | 11.0k | return {}; |
120 | 11.0k | } |
121 | | } // namespace common |