Bitcoin ABC 0.32.12
P2P Digital Currency
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/chaintype.h>
12#include <util/fs.h>
13#include <util/settings.h>
14#include <util/string.h>
15
16#include <algorithm>
17#include <cassert>
18#include <cstdlib>
19#include <fstream>
20#include <iostream>
21#include <list>
22#include <map>
23#include <memory>
24#include <optional>
25#include <string>
26#include <string_view>
27#include <utility>
28#include <vector>
29
32
34 const fs::path &configuration_file_path) {
35 return AbsPathForConfigVal(args, configuration_file_path,
36 /*net_specific=*/false);
37}
38
39static bool
40GetConfigOptions(std::istream &stream, const std::string &filepath,
41 std::string &error,
42 std::vector<std::pair<std::string, std::string>> &options,
43 std::list<SectionInfo> &sections) {
44 std::string str, prefix;
45 std::string::size_type pos;
46 int linenr = 1;
47 while (std::getline(stream, str)) {
48 bool used_hash = false;
49 if ((pos = str.find('#')) != std::string::npos) {
50 str = str.substr(0, pos);
51 used_hash = true;
52 }
53 const static std::string pattern = " \t\r\n";
54 str = TrimString(str, pattern);
55 if (!str.empty()) {
56 if (*str.begin() == '[' && *str.rbegin() == ']') {
57 const std::string section = str.substr(1, str.size() - 2);
58 sections.emplace_back(SectionInfo{section, filepath, linenr});
59 prefix = section + '.';
60 } else if (*str.begin() == '-') {
61 error = strprintf(
62 "parse error on line %i: %s, options in configuration file "
63 "must be specified without leading -",
64 linenr, str);
65 return false;
66 } else if ((pos = str.find('=')) != std::string::npos) {
67 std::string name =
68 prefix +
69 TrimString(std::string_view{str}.substr(0, pos), pattern);
70 std::string_view value = TrimStringView(
71 std::string_view{str}.substr(pos + 1), pattern);
72 if (used_hash &&
73 name.find("rpcpassword") != std::string::npos) {
74 error = strprintf(
75 "parse error on line %i, using # in rpcpassword can be "
76 "ambiguous and should be avoided",
77 linenr);
78 return false;
79 }
80 options.emplace_back(name, value);
81 if ((pos = name.rfind('.')) != std::string::npos &&
82 prefix.length() <= pos) {
83 sections.emplace_back(
84 SectionInfo{name.substr(0, pos), filepath, linenr});
85 }
86 } else {
87 error = strprintf("parse error on line %i: %s", linenr, str);
88 if (str.size() >= 2 && str.substr(0, 2) == "no") {
89 error += strprintf(", if you intended to specify a negated "
90 "option, use %s=1 instead",
91 str);
92 }
93 return false;
94 }
95 }
96 ++linenr;
97 }
98 return true;
99}
100
101bool ArgsManager::ReadConfigStream(std::istream &stream,
102 const std::string &filepath,
103 std::string &error,
104 bool ignore_invalid_keys) {
105 LOCK(cs_args);
106 std::vector<std::pair<std::string, std::string>> options;
107 if (!GetConfigOptions(stream, filepath, error, options,
108 m_config_sections)) {
109 return false;
110 }
111 for (const std::pair<std::string, std::string> &option : options) {
112 KeyInfo key = InterpretKey(option.first);
113 std::optional<unsigned int> flags = GetArgFlags('-' + key.name);
114 if (flags) {
115 std::optional<util::SettingsValue> value =
116 InterpretValue(key, option.second, *flags, error);
117 if (!value) {
118 return false;
119 }
120 m_settings.ro_config[key.section][key.name].push_back(*value);
121 } else {
122 if (ignore_invalid_keys) {
123 LogPrintf("Ignoring unknown configuration value %s\n",
124 option.first);
125 } else {
126 error = strprintf("Invalid configuration value %s",
127 option.first.c_str());
128 return false;
129 }
130 }
131 }
132 return true;
133}
134
135bool ArgsManager::ReadConfigFiles(std::string &error,
136 bool ignore_invalid_keys) {
137 {
138 LOCK(cs_args);
139 m_settings.ro_config.clear();
140 m_config_sections.clear();
141 }
142
143 const auto conf_path{GetConfigFilePath()};
144 std::ifstream stream{conf_path};
145
146 // ok to not have a config file
147 if (stream.good()) {
148 if (!ReadConfigStream(stream, fs::PathToString(conf_path), error,
149 ignore_invalid_keys)) {
150 return false;
151 }
152 // `-includeconf` cannot be included in the command line arguments
153 // except as `-noincludeconf` (which indicates that no included conf
154 // file should be used).
155 bool use_conf_file{true};
156 {
157 LOCK(cs_args);
158 if (auto *includes = util::FindKey(m_settings.command_line_options,
159 "includeconf")) {
160 // ParseParameters() fails if a non-negated -includeconf is
161 // passed on the command-line
163 use_conf_file = false;
164 }
165 }
166 if (use_conf_file) {
167 std::string chain_id = GetChainTypeString();
168 std::vector<std::string> conf_file_names;
169
170 auto add_includes = [&](const std::string &network,
171 size_t skip = 0) {
172 size_t num_values = 0;
173 LOCK(cs_args);
174 if (auto *section =
175 util::FindKey(m_settings.ro_config, network)) {
176 if (auto *values = util::FindKey(*section, "includeconf")) {
177 for (size_t i = std::max(
178 skip, util::SettingsSpan(*values).negated());
179 i < values->size(); ++i) {
180 conf_file_names.push_back((*values)[i].get_str());
181 }
182 num_values = values->size();
183 }
184 }
185 return num_values;
186 };
187
188 // We haven't set m_network yet (that happens in SelectParams()), so
189 // manually check for network.includeconf args.
190 const size_t chain_includes = add_includes(chain_id);
191 const size_t default_includes = add_includes({});
192
193 for (const std::string &conf_file_name : conf_file_names) {
194 std::ifstream conf_file_stream{
195 GetConfigFile(*this, fs::PathFromString(conf_file_name))};
196 if (conf_file_stream.good()) {
197 if (!ReadConfigStream(conf_file_stream, conf_file_name,
198 error, ignore_invalid_keys)) {
199 return false;
200 }
201 LogPrintf("Included configuration file %s\n",
202 conf_file_name);
203 } else {
204 error = "Failed to include configuration file " +
205 conf_file_name;
206 return false;
207 }
208 }
209
210 // Warn about recursive -includeconf
211 conf_file_names.clear();
212 add_includes(chain_id, /* skip= */ chain_includes);
213 add_includes({}, /* skip= */ default_includes);
214 std::string chain_id_final = GetChainTypeString();
215 if (chain_id_final != chain_id) {
216 // Also warn about recursive includeconf for the chain that was
217 // specified in one of the includeconfs
218 add_includes(chain_id_final);
219 }
220 for (const std::string &conf_file_name : conf_file_names) {
221 tfm::format(std::cerr,
222 "warning: -includeconf cannot be used from "
223 "included files; ignoring -includeconf=%s\n",
224 conf_file_name);
225 }
226 }
227 }
228
229 // If datadir is changed in .conf file:
231 if (!CheckDataDirOption(*this)) {
232 error = strprintf("specified data directory \"%s\" does not exist.",
233 GetArg("-datadir", "").c_str());
234 return false;
235 }
236 return true;
237}
238
240 bool net_specific) {
241 if (path.is_absolute()) {
242 return path;
243 }
245 net_specific ? args.GetDataDirNet() : args.GetDataDirBase(), path);
246}
bool CheckDataDirOption(const ArgsManager &args)
Definition: args.cpp:752
std::optional< util::SettingsValue > InterpretValue(const KeyInfo &key, const std::optional< std::string > &value, unsigned int flags, std::string &error)
Interpret settings value based on registered flags.
Definition: args.cpp:106
KeyInfo InterpretKey(std::string key)
Parse "name", "section.name", "noname", "section.noname" settings keys.
Definition: args.cpp:77
int flags
Definition: bitcoin-tx.cpp:546
std::string GetChainTypeString() const
Returns the appropriate chain name string from the program arguments.
Definition: args.cpp:770
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
std::optional< unsigned int > GetArgFlags(const std::string &name) const
Return Flags for known arg.
Definition: args.cpp:274
void ClearPathCache()
Clear cached directory paths.
Definition: args.cpp:353
fs::path GetDataDirBase() const
Get data directory path.
Definition: args.h:230
fs::path GetConfigFilePath() const
Return config file path (read-only)
Definition: args.cpp:757
RecursiveMutex cs_args
Definition: args.h:146
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:462
bool ReadConfigStream(std::istream &stream, const std::string &filepath, std::string &error, bool ignore_invalid_keys=false)
Definition: configfile.cpp:101
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
Definition: configfile.cpp:135
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)
Definition: configfile.cpp:40
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...
Definition: configfile.cpp:239
fs::path GetConfigFile(const ArgsManager &args, const fs::path &configuration_file_path)
Definition: configfile.cpp:33
#define LogPrintf(...)
Definition: logging.h:424
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:147
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:170
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.
Definition: tinyformat.h:1112
std::string_view TrimStringView(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:70
std::string TrimString(std::string_view str, std::string_view pattern=" \f\n\r\t\v")
Definition: string.h:80
auto FindKey(Map &&map, Key &&key) -> decltype(&map.at(key))
Map lookup helper.
Definition: settings.h:115
const char * prefix
Definition: rest.cpp:813
const char * name
Definition: rest.cpp:47
Definition: args.h:79
std::string name
Definition: args.h:80
std::string section
Definition: args.h:81
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...
Definition: tinyformat.h:1202
assert(!tx.IsCoinBase())