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