Skip to content

Commit

Permalink
Merge pull request #9659 from zeha/ignore-unknown-settings
Browse files Browse the repository at this point in the history
Ignore unknown settings
  • Loading branch information
Habbie authored Apr 1, 2021
2 parents 7204340 + 6e01be5 commit b665994
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 66 deletions.
15 changes: 15 additions & 0 deletions docs/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,21 @@ or slave settings.

Run within a guardian process. See :ref:`running-guardian`.

.. _setting-ignore-unknown-settings:

``ignore-unknown-settings``
---------------------------

.. versionadded:: 4.5.0

- Setting names, separated by commas
- Default: empty

Names of settings to be ignored while parsing configuration files, if the setting
name is unknown to PowerDNS.

Useful during upgrade testing.

.. _setting-include-dir:

``include-dir``
Expand Down
161 changes: 98 additions & 63 deletions pdns/arguments.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,17 @@

const ArgvMap::param_t::const_iterator ArgvMap::begin()
{
return params.begin();
return d_params.begin();
}

const ArgvMap::param_t::const_iterator ArgvMap::end()
{
return params.end();
return d_params.end();
}

string & ArgvMap::set(const string &var)
{
return params[var];
return d_params[var];
}

void ArgvMap::setDefault(const string &var, const string &value)
Expand All @@ -58,9 +58,9 @@ void ArgvMap::setDefault(const string &var, const string &value)

void ArgvMap::setDefaults()
{
for(map<string,string>::const_iterator i=params.begin();i!=params.end();++i)
if(! defaultmap.count(i->first))
defaultmap.insert(*i);
for (const auto& i: d_params)
if(! defaultmap.count(i.first))
defaultmap.insert(i);
}

bool ArgvMap::mustDo(const string &var)
Expand All @@ -71,8 +71,8 @@ bool ArgvMap::mustDo(const string &var)
vector<string>ArgvMap::list()
{
vector<string> ret;
for(map<string,string>::const_iterator i=params.begin();i!=params.end();++i)
ret.push_back(i->first);
for (const auto& i: d_params)
ret.push_back(i.first);
return ret;
}

Expand Down Expand Up @@ -105,13 +105,13 @@ string & ArgvMap::setSwitch(const string &var, const string &help)

bool ArgvMap::contains(const string &var, const string &val)
{
params_t::const_iterator param = params.find(var);
if(param == params.end() || param->second.empty()) {
const auto& param = d_params.find(var);
if(param == d_params.end() || param->second.empty()) {
return false;
}
vector<string> parts;

stringtok( parts, param->second, ", \t" );
stringtok(parts, param->second, ", \t");
for (const auto& part: parts) {
if (part == val) {
return true;
Expand Down Expand Up @@ -154,6 +154,40 @@ string ArgvMap::helpstring(string prefix)
return help;
}

const string ArgvMap::formatOne(bool running, bool full, const string &var, const string &help, const string& theDefault, const string& current)
{
string out;

if (!running || full) {
out += "#################################\n";
out += "# ";
out += var;
out += "\t";
out += help;
out += "\n#\n";
} else {
if (theDefault == current) {
return "";
}
}

if (! running || theDefault == current) {
out += "# ";
}

if (running) {
out += var + "=" + current + "\n";
if (full) {
out += "\n";
}
} else {
out += var + "=" + theDefault + "\n\n";
}

return out;
}

// If running and full, only changed settings are returned.
string ArgvMap::configstring(bool running, bool full)
{
string help;
Expand All @@ -163,40 +197,28 @@ string ArgvMap::configstring(bool running, bool full)
else
help="# Autogenerated configuration file template\n\n";

// Affects parsing, should come first.
help += formatOne(running, full, "ignore-unknown-settings", helpmap["ignore-unknown-settings"], defaultmap["ignore-unknown-settings"], d_params["ignore-unknown-settings"]);

for(const auto& i: helpmap) {
if(d_typeMap[i.first]=="Command")
if (d_typeMap[i.first] == "Command")
continue;
if (i.first == "ignore-unknown-settings")
continue;

if (! defaultmap.count(i.first)) {
throw ArgException(string("Default for parameter '")+i.first+"' not set");
if (!defaultmap.count(i.first)) {
throw ArgException(string("Default for setting '")+i.first+"' not set");
}

if (!running || full) {
help+="#################################\n";
help+="# ";
help+=i.first;
help+="\t";
help+=i.second;
help+="\n#\n";
} else {
if (defaultmap[i.first] == params[i.first]) {
continue;
}
}

if (! running || defaultmap[i.first] == params[i.first]) {
help+="# ";
}
help += formatOne(running, full, i.first, i.second, defaultmap[i.first], d_params[i.first]);
}

if (running) {
help+=i.first+"="+params[i.first]+"\n";
if (full) {
help+="\n";
}
} else {
help+=i.first+"="+defaultmap[i.first]+"\n\n";
if (running) {
for(const auto& i: d_unknownParams) {
help += formatOne(running, full, i.first, "unknown setting", "", i.second);
}
}

return help;
}

Expand All @@ -205,7 +227,7 @@ const string & ArgvMap::operator[](const string &arg)
if(!parmIsset(arg))
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

return params[arg];
return d_params[arg];
}

mode_t ArgvMap::asMode(const string &arg)
Expand All @@ -217,7 +239,7 @@ mode_t ArgvMap::asMode(const string &arg)
if(!parmIsset(arg))
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

cptr_orig = params[arg].c_str();
cptr_orig = d_params[arg].c_str();
mode = static_cast<mode_t>(strtol(cptr_orig, &cptr_ret, 8));
if (mode == 0 && cptr_ret == cptr_orig)
throw ArgException("'" + arg + string("' contains invalid octal mode"));
Expand All @@ -233,11 +255,11 @@ gid_t ArgvMap::asGid(const string &arg)
if(!parmIsset(arg))
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

cptr_orig = params[arg].c_str();
cptr_orig = d_params[arg].c_str();
gid = static_cast<gid_t>(strtol(cptr_orig, &cptr_ret, 0));
if (gid == 0 && cptr_ret == cptr_orig) {
// try to resolve
struct group *group = getgrnam(params[arg].c_str());
struct group *group = getgrnam(d_params[arg].c_str());
if (group == nullptr)
throw ArgException("'" + arg + string("' contains invalid group"));
gid = group->gr_gid;
Expand All @@ -254,11 +276,11 @@ uid_t ArgvMap::asUid(const string &arg)
if(!parmIsset(arg))
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

cptr_orig = params[arg].c_str();
cptr_orig = d_params[arg].c_str();
uid = static_cast<uid_t>(strtol(cptr_orig, &cptr_ret, 0));
if (uid == 0 && cptr_ret == cptr_orig) {
// try to resolve
struct passwd *pwent = getpwnam(params[arg].c_str());
struct passwd *pwent = getpwnam(d_params[arg].c_str());
if (pwent == nullptr)
throw ArgException("'" + arg + string("' contains invalid group"));
uid = pwent->pw_uid;
Expand All @@ -276,10 +298,10 @@ int ArgvMap::asNum(const string &arg, int def)
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

// use default for empty values
if (params[arg].empty())
if (d_params[arg].empty())
return def;

cptr_orig = params[arg].c_str();
cptr_orig = d_params[arg].c_str();
retval = static_cast<int>(strtol(cptr_orig, &cptr_ret, 0));
if (!retval && cptr_ret == cptr_orig)
throw ArgException("'"+arg+"' value '"+string(cptr_orig) + string( "' is not a valid number"));
Expand All @@ -291,7 +313,7 @@ bool ArgvMap::isEmpty(const string &arg)
{
if(!parmIsset(arg))
return true;
return params[arg].empty();
return d_params[arg].empty();
}

double ArgvMap::asDouble(const string &arg)
Expand All @@ -303,10 +325,10 @@ double ArgvMap::asDouble(const string &arg)
if(!parmIsset(arg))
throw ArgException(string("Undefined but needed argument: '")+arg+"'");

if (params[arg].empty())
if (d_params[arg].empty())
return 0.0;

cptr_orig = params[arg].c_str();
cptr_orig = d_params[arg].c_str();
retval = strtod(cptr_orig, &cptr_ret);

if (retval == 0 && cptr_ret == cptr_orig)
Expand All @@ -317,12 +339,12 @@ double ArgvMap::asDouble(const string &arg)

ArgvMap::ArgvMap()
{

set("ignore-unknown-settings","Configuration settings to ignore if they are unknown")="";
}

bool ArgvMap::parmIsset(const string &var)
{
return (params.find(var)!=params.end());
return d_params.find(var) != d_params.end();
}

void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax)
Expand Down Expand Up @@ -365,23 +387,36 @@ void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax)
{
if(incremental)
{
if(params[var].empty())
if(d_params[var].empty())
{
if(!d_cleared.count(var))
throw ArgException("Incremental parameter '"+var+"' without a parent");
params[var]=val;
throw ArgException("Incremental setting '"+var+"' without a parent");
d_params[var] = val;
}
else
params[var]+=", " + val;
d_params[var] += ", " + val;
}
else
{
params[var]=val;
d_params[var] = val;
d_cleared.insert(var);
}
}
else if(!lax)
throw ArgException("Trying to set unknown parameter '"+var+"'");
else
{
// unknown setting encountered. see if its on the ignore list before throwing.
vector<string> parts;
stringtok(parts, d_params["ignore-unknown-settings"], " ,\t\n\r");
if (find(parts.begin(), parts.end(), var) != parts.end()) {
d_unknownParams[var] = val;
g_log<<Logger::Warning<<"Ignoring unknown setting '"<<var<<"' as requested"<<endl;
return;
}

if (!lax) {
throw ArgException("Trying to set unknown setting '"+var+"'");
}
}
}
}

Expand Down Expand Up @@ -454,7 +489,7 @@ bool ArgvMap::parseFile(const char *fname, const string& arg, bool lax) {

bool ArgvMap::preParseFile(const char *fname, const string &arg, const string& theDefault)
{
params[arg]=theDefault;
d_params[arg] = theDefault;

return parseFile(fname, arg, false);
}
Expand All @@ -475,7 +510,7 @@ bool ArgvMap::file(const char *fname, bool lax, bool included)
}

// handle include here (avoid re-include)
if (!included && !params["include-dir"].empty()) {
if (!included && !d_params["include-dir"].empty()) {
std::vector<std::string> extraConfigs;
gatherIncludes(extraConfigs);
for(const std::string& fn : extraConfigs) {
Expand All @@ -491,13 +526,13 @@ bool ArgvMap::file(const char *fname, bool lax, bool included)

void ArgvMap::gatherIncludes(std::vector<std::string> &extraConfigs) {
extraConfigs.clear();
if (params["include-dir"].empty())
if (d_params["include-dir"].empty())
return; // nothing to do

DIR *dir;
if (!(dir = opendir(params["include-dir"].c_str()))) {
if (!(dir = opendir(d_params["include-dir"].c_str()))) {
int err = errno;
string msg = params["include-dir"] + " is not accessible: " + strerror(err);
string msg = d_params["include-dir"] + " is not accessible: " + strerror(err);
g_log << Logger::Error << msg << std::endl;
throw ArgException(msg);
}
Expand All @@ -508,7 +543,7 @@ void ArgvMap::gatherIncludes(std::vector<std::string> &extraConfigs) {
continue; // skip any dots
if (boost::ends_with(ent->d_name, ".conf")) {
// build name
string name = params["include-dir"] + "/" + ent->d_name; // FIXME: Use some path separator
string name = d_params["include-dir"] + "/" + ent->d_name; // FIXME: Use some path separator
// ensure it's readable file
struct stat st;
if (stat(name.c_str(), &st) || !S_ISREG(st.st_mode)) {
Expand Down
5 changes: 3 additions & 2 deletions pdns/arguments.hh
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,9 @@ public:
void gatherIncludes(std::vector<std::string> &extraConfigs);
private:
void parseOne(const string &unparsed, const string &parseOnly="", bool lax=false);
typedef map<string,string> params_t;
params_t params;
const string formatOne(bool running, bool full, const string &var, const string &help, const string& theDefault, const string& value);
map<string,string> d_params;
map<string,string> d_unknownParams;
map<string,string> helpmap;
map<string,string> defaultmap;
map<string,string> d_typeMap;
Expand Down
2 changes: 1 addition & 1 deletion pdns/misc.hh
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ struct ServiceTuple
};
void parseService(const string &descr, ServiceTuple &st);

template <typename Container>
template<typename Container>
void
stringtok (Container &container, string const &in,
const char * const delimiters = " \t\n")
Expand Down
Loading

0 comments on commit b665994

Please sign in to comment.