Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
configfile.cpp
Go to the documentation of this file.
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 <common/args.h>
6
7#include <logging.h>
8#include <sync.h>
9#include <tinyformat.h>
10#include <univalue.h>
11#include <util/fs.h>
12#include <util/settings.h>
13#include <util/string.h>
14
15#include <algorithm>
16#include <cassert>
17#include <cstdlib>
18#include <fstream>
19#include <iostream>
20#include <list>
21#include <map>
22#include <memory>
23#include <optional>
24#include <string>
25#include <string_view>
26#include <utility>
27#include <vector>
28
32 /*net_specific=*/false);
33}
34
35static bool
36GetConfigOptions(std::istream &stream, const std::string &filepath,
37 std::string &error,
38 std::vector<std::pair<std::string, std::string>> &options,
39 std::list<SectionInfo> &sections) {
40 std::string str, prefix;
41 std::string::size_type pos;
42 int linenr = 1;
43 while (std::getline(stream, str)) {
44 bool used_hash = false;
45 if ((pos = str.find('#')) != std::string::npos) {
46 str = str.substr(0, pos);
47 used_hash = true;
48 }
49 const static std::string pattern = " \t\r\n";
50 str = TrimString(str, pattern);
51 if (!str.empty()) {
52 if (*str.begin() == '[' && *str.rbegin() == ']') {
53 const std::string section = str.substr(1, str.size() - 2);
55 prefix = section + '.';
56 } else if (*str.begin() == '-') {
58 "parse error on line %i: %s, options in configuration file "
59 "must be specified without leading -",
60 linenr, str);
61 return false;
62 } else if ((pos = str.find('=')) != std::string::npos) {
63 std::string name =
64 prefix + TrimString(str.substr(0, pos), pattern);
65 std::string value = TrimString(str.substr(pos + 1), pattern);
66 if (used_hash &&
67 name.find("rpcpassword") != std::string::npos) {
69 "parse error on line %i, using # in rpcpassword can be "
70 "ambiguous and should be avoided",
71 linenr);
72 return false;
73 }
74 options.emplace_back(name, value);
75 if ((pos = name.rfind('.')) != std::string::npos &&
76 prefix.length() <= pos) {
77 sections.emplace_back(
78 SectionInfo{name.substr(0, pos), filepath, linenr});
79 }
80 } else {
81 error = strprintf("parse error on line %i: %s", linenr, str);
82 if (str.size() >= 2 && str.substr(0, 2) == "no") {
83 error += strprintf(", if you intended to specify a negated "
84 "option, use %s=1 instead",
85 str);
86 }
87 return false;
88 }
89 }
90 ++linenr;
91 }
92 return true;
93}
94
95bool ArgsManager::ReadConfigStream(std::istream &stream,
96 const std::string &filepath,
97 std::string &error,
100 std::vector<std::pair<std::string, std::string>> options;
101 if (!GetConfigOptions(stream, filepath, error, options,
103 return false;
104 }
105 for (const std::pair<std::string, std::string> &option : options) {
106 std::string section;
107 std::string key = option.first;
108 util::SettingsValue value =
109 InterpretOption(section, key, option.second);
110 std::optional<unsigned int> flags = GetArgFlags('-' + key);
111 if (flags) {
112 if (!CheckValid(key, value, *flags, error)) {
113 return false;
114 }
115 m_settings.ro_config[section][key].push_back(value);
116 } else {
118 LogPrintf("Ignoring unknown configuration value %s\n",
119 option.first);
120 } else {
121 error = strprintf("Invalid configuration value %s",
122 option.first.c_str());
123 return false;
124 }
125 }
126 }
127 return true;
128}
129
131 bool ignore_invalid_keys) {
132 {
133 LOCK(cs_args);
134 m_settings.ro_config.clear();
135 m_config_sections.clear();
136 }
137
138 const auto conf_path{GetConfigFilePath()};
139 std::ifstream stream{conf_path};
140
141 // ok to not have a config file
142 if (stream.good()) {
145 return false;
146 }
147 // `-includeconf` cannot be included in the command line arguments
148 // except as `-noincludeconf` (which indicates that no included conf
149 // file should be used).
150 bool use_conf_file{true};
151 {
152 LOCK(cs_args);
153 if (auto *includes = util::FindKey(m_settings.command_line_options,
154 "includeconf")) {
155 // ParseParameters() fails if a non-negated -includeconf is
156 // passed on the command-line
158 use_conf_file = false;
159 }
160 }
161 if (use_conf_file) {
162 std::string chain_id = GetChainName();
163 std::vector<std::string> conf_file_names;
164
165 auto add_includes = [&](const std::string &network,
166 size_t skip = 0) {
167 size_t num_values = 0;
168 LOCK(cs_args);
169 if (auto *section =
170 util::FindKey(m_settings.ro_config, network)) {
171 if (auto *values = util::FindKey(*section, "includeconf")) {
172 for (size_t i = std::max(
173 skip, util::SettingsSpan(*values).negated());
174 i < values->size(); ++i) {
175 conf_file_names.push_back((*values)[i].get_str());
176 }
177 num_values = values->size();
178 }
179 }
180 return num_values;
181 };
182
183 // We haven't set m_network yet (that happens in SelectParams()), so
184 // manually check for network.includeconf args.
185 const size_t chain_includes = add_includes(chain_id);
186 const size_t default_includes = add_includes({});
187
188 for (const std::string &conf_file_name : conf_file_names) {
189 std::ifstream conf_file_stream{
191 if (conf_file_stream.good()) {
194 return false;
195 }
196 LogPrintf("Included configuration file %s\n",
198 } else {
199 error = "Failed to include configuration file " +
201 return false;
202 }
203 }
204
205 // Warn about recursive -includeconf
206 conf_file_names.clear();
208 add_includes({}, /* skip= */ default_includes);
209 std::string chain_id_final = GetChainName();
210 if (chain_id_final != chain_id) {
211 // Also warn about recursive includeconf for the chain that was
212 // specified in one of the includeconfs
214 }
215 for (const std::string &conf_file_name : conf_file_names) {
216 tfm::format(std::cerr,
217 "warning: -includeconf cannot be used from "
218 "included files; ignoring -includeconf=%s\n",
220 }
221 }
222 }
223
224 // If datadir is changed in .conf file:
226 if (!CheckDataDirOption(*this)) {
227 error = strprintf("specified data directory \"%s\" does not exist.",
228 GetArg("-datadir", "").c_str());
229 return false;
230 }
231 return true;
232}
233
235 bool net_specific) {
236 if (path.is_absolute()) {
237 return path;
238 }
240 net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
241}
bool CheckValid(const std::string &key, const util::SettingsValue &val, unsigned int flags, std::string &error)
Check settings value validity according to flags.
Definition args.cpp:117
bool CheckDataDirOption(const ArgsManager &args)
Definition args.cpp:784
util::SettingsValue InterpretOption(std::string &section, std::string &key, const std::string &value)
Interpret -nofoo as if the user supplied -foo=0.
Definition args.cpp:87
fs::path GetConfigFile(const ArgsManager &args, const fs::path &configuration_file_path)
int flags
const fs::path & GetDataDirBase() const
Get data directory path.
Definition args.h:206
std::optional< unsigned int > GetArgFlags(const std::string &name) const
Return Flags for known arg.
Definition args.cpp:264
void ClearPathCache()
Clear cached directory paths.
Definition args.cpp:363
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition args.h:215
fs::path GetConfigFilePath() const
Return config file path (read-only)
Definition args.cpp:789
RecursiveMutex cs_args
Definition args.h:122
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition args.cpp:494
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false)
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition args.cpp:793
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:30
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)
fs::path AbsPathForConfigVal(const ArgsManager &args, const fs::path &path, bool net_specific)
Most paths passed as configuration arguments are treated as relative to the datadir if they are not a...
fs::path GetConfigFile(const ArgsManager &args, const fs::path &configuration_file_path)
bool error(const char *fmt, const Args &...args)
Definition logging.h:226
#define LogPrintf(...)
Definition logging.h:207
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition fs.h:142
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition fs.h:165
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition fs.cpp:39
void format(std::ostream &out, const char *fmt, const Args &...args)
Format list of arguments to the stream according to given format string.
auto FindKey(Map &&map, Key &&key) -> decltype(&map.at(key))
Map lookup helper.
Definition settings.h:115
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
const char * prefix
Definition rest.cpp:817
const char * name
Definition rest.cpp:47
std::string TrimString(const std::string &str, const std::string &pattern=" \f\n\r\t\v")
Definition string.h:28
Accessor for list of settings that skips negated values when iterated over.
Definition settings.h:91
size_t negated() const
Number of negated values.
Definition settings.cpp:296
bool last_negated() const
True if the last value is negated.
Definition settings.cpp:293
#define LOCK(cs)
Definition sync.h:306
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
assert(!tx.IsCoinBase())