aboutsummaryrefslogtreecommitdiff
path: root/src/util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp239
1 files changed, 186 insertions, 53 deletions
diff --git a/src/util.cpp b/src/util.cpp
index 7dd6884f75..8df23dd08f 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -72,7 +72,6 @@
#endif
#include <boost/interprocess/sync/file_lock.hpp>
-#include <boost/program_options/detail/config_file.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
@@ -412,7 +411,7 @@ void ArgsManager::SelectConfigNetwork(const std::string& network)
m_network = network;
}
-void ArgsManager::ParseParameters(int argc, const char* const argv[])
+bool ArgsManager::ParseParameters(int argc, const char* const argv[], std::string& error)
{
LOCK(cs_args);
m_override_args.clear();
@@ -444,6 +443,14 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
} else {
m_override_args[key].push_back(val);
}
+
+ // Check that the arg is known
+ if (!(IsSwitchChar(key[0]) && key.size() == 1)) {
+ if (!IsArgKnown(key)) {
+ error = strprintf("Invalid parameter %s", key.c_str());
+ return false;
+ }
+ }
}
// we do not allow -includeconf from command line, so we clear it here
@@ -451,11 +458,28 @@ void ArgsManager::ParseParameters(int argc, const char* const argv[])
if (it != m_override_args.end()) {
if (it->second.size() > 0) {
for (const auto& ic : it->second) {
- fprintf(stderr, "warning: -includeconf cannot be used from commandline; ignoring -includeconf=%s\n", ic.c_str());
+ error += "-includeconf cannot be used from commandline; -includeconf=" + ic + "\n";
}
- m_override_args.erase(it);
+ return false;
}
}
+ return true;
+}
+
+bool ArgsManager::IsArgKnown(const std::string& key) const
+{
+ size_t option_index = key.find('.');
+ std::string arg_no_net;
+ if (option_index == std::string::npos) {
+ arg_no_net = key;
+ } else {
+ arg_no_net = std::string("-") + key.substr(option_index + 1, std::string::npos);
+ }
+
+ for (const auto& arg_map : m_available_args) {
+ if (arg_map.second.count(arg_no_net)) return true;
+ }
+ return false;
}
std::vector<std::string> ArgsManager::GetArgs(const std::string& strArg) const
@@ -549,48 +573,87 @@ void ArgsManager::ForceSetArg(const std::string& strArg, const std::string& strV
void ArgsManager::AddArg(const std::string& name, const std::string& help, const bool debug_only, const OptionsCategory& cat)
{
- std::pair<OptionsCategory, std::string> key(cat, name);
- assert(m_available_args.count(key) == 0);
- m_available_args.emplace(key, std::pair<std::string, bool>(help, debug_only));
+ // Split arg name from its help param
+ size_t eq_index = name.find('=');
+ if (eq_index == std::string::npos) {
+ eq_index = name.size();
+ }
+
+ std::map<std::string, Arg>& arg_map = m_available_args[cat];
+ auto ret = arg_map.emplace(name.substr(0, eq_index), Arg(name.substr(eq_index, name.size() - eq_index), help, debug_only));
+ assert(ret.second); // Make sure an insertion actually happened
+}
+
+void ArgsManager::AddHiddenArgs(const std::vector<std::string>& names)
+{
+ for (const std::string& name : names) {
+ AddArg(name, "", false, OptionsCategory::HIDDEN);
+ }
}
-std::string ArgsManager::GetHelpMessage()
+std::string ArgsManager::GetHelpMessage() const
{
const bool show_debug = gArgs.GetBoolArg("-help-debug", false);
- std::string usage = HelpMessageGroup(_("Options:"));
-
- OptionsCategory last_cat = OptionsCategory::OPTIONS;
- for (auto& arg : m_available_args) {
- if (arg.first.first != last_cat) {
- last_cat = arg.first.first;
- if (last_cat == OptionsCategory::CONNECTION)
- usage += HelpMessageGroup(_("Connection options:"));
- else if (last_cat == OptionsCategory::ZMQ)
- usage += HelpMessageGroup(_("ZeroMQ notification options:"));
- else if (last_cat == OptionsCategory::DEBUG_TEST)
- usage += HelpMessageGroup(_("Debugging/Testing options:"));
- else if (last_cat == OptionsCategory::NODE_RELAY)
- usage += HelpMessageGroup(_("Node relay options:"));
- else if (last_cat == OptionsCategory::BLOCK_CREATION)
- usage += HelpMessageGroup(_("Block creation options:"));
- else if (last_cat == OptionsCategory::RPC)
- usage += HelpMessageGroup(_("RPC server options:"));
- else if (last_cat == OptionsCategory::WALLET)
- usage += HelpMessageGroup(_("Wallet options:"));
- else if (last_cat == OptionsCategory::WALLET_DEBUG_TEST && show_debug)
- usage += HelpMessageGroup(_("Wallet debugging/testing options:"));
- else if (last_cat == OptionsCategory::CHAINPARAMS)
- usage += HelpMessageGroup(_("Chain selection options:"));
- else if (last_cat == OptionsCategory::GUI)
- usage += HelpMessageGroup(_("UI Options:"));
- else if (last_cat == OptionsCategory::COMMANDS)
- usage += HelpMessageGroup(_("Commands:"));
- else if (last_cat == OptionsCategory::REGISTER_COMMANDS)
- usage += HelpMessageGroup(_("Register Commands:"));
+ std::string usage = "";
+ for (const auto& arg_map : m_available_args) {
+ switch(arg_map.first) {
+ case OptionsCategory::OPTIONS:
+ usage += HelpMessageGroup("Options:");
+ break;
+ case OptionsCategory::CONNECTION:
+ usage += HelpMessageGroup("Connection options:");
+ break;
+ case OptionsCategory::ZMQ:
+ usage += HelpMessageGroup("ZeroMQ notification options:");
+ break;
+ case OptionsCategory::DEBUG_TEST:
+ usage += HelpMessageGroup("Debugging/Testing options:");
+ break;
+ case OptionsCategory::NODE_RELAY:
+ usage += HelpMessageGroup("Node relay options:");
+ break;
+ case OptionsCategory::BLOCK_CREATION:
+ usage += HelpMessageGroup("Block creation options:");
+ break;
+ case OptionsCategory::RPC:
+ usage += HelpMessageGroup("RPC server options:");
+ break;
+ case OptionsCategory::WALLET:
+ usage += HelpMessageGroup("Wallet options:");
+ break;
+ case OptionsCategory::WALLET_DEBUG_TEST:
+ if (show_debug) usage += HelpMessageGroup("Wallet debugging/testing options:");
+ break;
+ case OptionsCategory::CHAINPARAMS:
+ usage += HelpMessageGroup("Chain selection options:");
+ break;
+ case OptionsCategory::GUI:
+ usage += HelpMessageGroup("UI Options:");
+ break;
+ case OptionsCategory::COMMANDS:
+ usage += HelpMessageGroup("Commands:");
+ break;
+ case OptionsCategory::REGISTER_COMMANDS:
+ usage += HelpMessageGroup("Register Commands:");
+ break;
+ default:
+ break;
}
- if (show_debug || !arg.second.second) {
- usage += HelpMessageOpt(arg.first.second, arg.second.first);
+
+ // When we get to the hidden options, stop
+ if (arg_map.first == OptionsCategory::HIDDEN) break;
+
+ for (const auto& arg : arg_map.second) {
+ if (show_debug || !arg.second.m_debug_only) {
+ std::string name;
+ if (arg.second.m_help_param.empty()) {
+ name = arg.first;
+ } else {
+ name = arg.first + arg.second.m_help_param;
+ }
+ usage += HelpMessageOpt(name, arg.second.m_help_text);
+ }
}
}
return usage;
@@ -747,26 +810,64 @@ fs::path GetConfigFile(const std::string& confPath)
return AbsPathForConfigVal(fs::path(confPath), false);
}
-void ArgsManager::ReadConfigStream(std::istream& stream)
+static std::string TrimString(const std::string& str, const std::string& pattern)
+{
+ std::string::size_type front = str.find_first_not_of(pattern);
+ if (front == std::string::npos) {
+ return std::string();
+ }
+ std::string::size_type end = str.find_last_not_of(pattern);
+ return str.substr(front, end - front + 1);
+}
+
+static std::vector<std::pair<std::string, std::string>> GetConfigOptions(std::istream& stream)
+{
+ std::vector<std::pair<std::string, std::string>> options;
+ std::string str, prefix;
+ std::string::size_type pos;
+ while (std::getline(stream, str)) {
+ if ((pos = str.find('#')) != std::string::npos) {
+ str = str.substr(0, pos);
+ }
+ const static std::string pattern = " \t\r\n";
+ str = TrimString(str, pattern);
+ if (!str.empty()) {
+ if (*str.begin() == '[' && *str.rbegin() == ']') {
+ prefix = str.substr(1, str.size() - 2) + '.';
+ } else if ((pos = str.find('=')) != std::string::npos) {
+ std::string name = prefix + TrimString(str.substr(0, pos), pattern);
+ std::string value = TrimString(str.substr(pos + 1), pattern);
+ options.emplace_back(name, value);
+ }
+ }
+ }
+ return options;
+}
+
+bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys)
{
LOCK(cs_args);
- std::set<std::string> setOptions;
- setOptions.insert("*");
+ for (const std::pair<std::string, std::string>& option : GetConfigOptions(stream)) {
+ std::string strKey = std::string("-") + option.first;
+ std::string strValue = option.second;
- for (boost::program_options::detail::config_file_iterator it(stream, setOptions), end; it != end; ++it)
- {
- std::string strKey = std::string("-") + it->string_key;
- std::string strValue = it->value[0];
if (InterpretNegatedOption(strKey, strValue)) {
m_config_args[strKey].clear();
} else {
m_config_args[strKey].push_back(strValue);
}
+
+ // Check that the arg is known
+ if (!IsArgKnown(strKey) && !ignore_invalid_keys) {
+ error = strprintf("Invalid configuration value %s", option.first.c_str());
+ return false;
+ }
}
+ return true;
}
-void ArgsManager::ReadConfigFiles()
+bool ArgsManager::ReadConfigFiles(std::string& error, bool ignore_invalid_keys)
{
{
LOCK(cs_args);
@@ -778,35 +879,67 @@ void ArgsManager::ReadConfigFiles()
// ok to not have a config file
if (stream.good()) {
- ReadConfigStream(stream);
+ if (!ReadConfigStream(stream, error, ignore_invalid_keys)) {
+ return false;
+ }
// if there is an -includeconf in the override args, but it is empty, that means the user
// passed '-noincludeconf' on the command line, in which case we should not include anything
if (m_override_args.count("-includeconf") == 0) {
+ std::string chain_id = GetChainName();
std::vector<std::string> includeconf(GetArgs("-includeconf"));
{
// We haven't set m_network yet (that happens in SelectParams()), so manually check
// for network.includeconf args.
- std::vector<std::string> includeconf_net(GetArgs(std::string("-") + GetChainName() + ".includeconf"));
+ std::vector<std::string> includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf"));
includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
}
+ // Remove -includeconf from configuration, so we can warn about recursion
+ // later
+ {
+ LOCK(cs_args);
+ m_config_args.erase("-includeconf");
+ m_config_args.erase(std::string("-") + chain_id + ".includeconf");
+ }
+
for (const std::string& to_include : includeconf) {
fs::ifstream include_config(GetConfigFile(to_include));
if (include_config.good()) {
- ReadConfigStream(include_config);
+ if (!ReadConfigStream(include_config, error, ignore_invalid_keys)) {
+ return false;
+ }
LogPrintf("Included configuration file %s\n", to_include.c_str());
} else {
- fprintf(stderr, "Failed to include configuration file %s\n", to_include.c_str());
+ error = "Failed to include configuration file " + to_include;
+ return false;
+ }
+ }
+
+ // Warn about recursive -includeconf
+ includeconf = GetArgs("-includeconf");
+ {
+ std::vector<std::string> includeconf_net(GetArgs(std::string("-") + chain_id + ".includeconf"));
+ includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
+ std::string chain_id_final = GetChainName();
+ if (chain_id_final != chain_id) {
+ // Also warn about recursive includeconf for the chain that was specified in one of the includeconfs
+ includeconf_net = GetArgs(std::string("-") + chain_id_final + ".includeconf");
+ includeconf.insert(includeconf.end(), includeconf_net.begin(), includeconf_net.end());
}
}
+ for (const std::string& to_include : includeconf) {
+ fprintf(stderr, "warning: -includeconf cannot be used from included files; ignoring -includeconf=%s\n", to_include.c_str());
+ }
}
}
// If datadir is changed in .conf file:
ClearDatadirCache();
if (!fs::is_directory(GetDataDir(false))) {
- throw std::runtime_error(strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str()));
+ error = strprintf("specified data directory \"%s\" does not exist.", gArgs.GetArg("-datadir", "").c_str());
+ return false;
}
+ return true;
}
std::string ArgsManager::GetChainName() const