summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorDavid Kalnischkies <david@kalnischkies.de>2022-04-26 21:33:16 +0200
committerDavid Kalnischkies <david@kalnischkies.de>2024-11-22 12:40:10 +0000
commiteb1e6fc4973a844adbea0297c6425b00f64e8b7b (patch)
tree31270ecd34ce63559e39941f06148cb21c854880 /apt-pkg
parent370e024224b8116840173201d51c0c2a170e0e93 (diff)
Rewrite hidden config option checker for more patterns
The previous version allowed only foo::*::bar as a pattern, now you can have as many starred parts as you want allowing for a finer control instead of hardcoding specific common star-values or giving up with **. It also adds a new INVALID type for an option to mark options which should not be used, but are covered by a pattern which would normally allow it. Our tests are more or less the only users of this hidden feature making this change not very risky even through it has no dedicated test itself.
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/acquire.cc2
-rw-r--r--apt-pkg/contrib/configuration.cc115
2 files changed, 76 insertions, 41 deletions
diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc
index f367e4310..07f64cc69 100644
--- a/apt-pkg/acquire.cc
+++ b/apt-pkg/acquire.cc
@@ -524,7 +524,7 @@ pkgAcquire::MethodConfig *pkgAcquire::GetConfig(string Access)
Configs = Conf;
/* if a method uses DownloadLimit, we switch to SingleInstance mode */
- if(_config->FindI("Acquire::"+Access+"::Dl-Limit",0) > 0)
+ if (not Conf->SingleInstance && _config->FindI("Acquire::" + Access + "::Dl-Limit", 0) > 0)
Conf->SingleInstance = true;
return Conf;
diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc
index c9b2dc0cc..fff10fb17 100644
--- a/apt-pkg/contrib/configuration.cc
+++ b/apt-pkg/contrib/configuration.cc
@@ -55,12 +55,14 @@ Configuration *_config = new Configuration;
but a Cnf-member – but that would need ABI breaks and stuff and for now
that really is an apt-dev-only tool, so it isn't that bad that it is
unusable and allaround a bit strange */
-enum class APT_HIDDEN ConfigType { UNDEFINED, INT, BOOL, STRING, STRING_OR_BOOL, STRING_OR_LIST, FILE, DIR, LIST, PROGRAM_PATH = FILE };
+enum class APT_HIDDEN ConfigType { INVALID, UNDEFINED, INT, BOOL, STRING, STRING_OR_BOOL, STRING_OR_LIST, FILE, DIR, LIST, PROGRAM_PATH = FILE };
APT_HIDDEN std::unordered_map<std::string, ConfigType> apt_known_config {};
+APT_HIDDEN std::vector<std::pair<std::string, ConfigType>> apt_known_config_patterns {};
static std::string getConfigTypeString(ConfigType const type) /*{{{*/
{
switch (type)
{
+ case ConfigType::INVALID: return "INVALID";
case ConfigType::UNDEFINED: return "UNDEFINED";
case ConfigType::INT: return "INT";
case ConfigType::BOOL: return "BOOL";
@@ -94,6 +96,8 @@ static ConfigType getConfigType(std::string const &type) /*{{{*/
return ConfigType::STRING_OR_LIST;
else if (type == "<PROGRAM_PATH>")
return ConfigType::PROGRAM_PATH;
+ else if (type == "<INVALID>")
+ return ConfigType::INVALID;
return ConfigType::UNDEFINED;
}
/*}}}*/
@@ -101,59 +105,86 @@ static ConfigType getConfigType(std::string const &type) /*{{{*/
static void checkFindConfigOptionTypeInternal(std::string name, ConfigType const type)
{
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
- auto known = apt_known_config.find(name);
- if (known == apt_known_config.cend())
+ bool found = false;
+ ConfigType expectedType = ConfigType::INVALID;
+ if (auto const known = apt_known_config.find(name); known != apt_known_config.cend())
{
- auto const rcolon = name.rfind(':');
- if (rcolon != std::string::npos)
+ found = true;
+ expectedType = known->second;
+ }
+ else
+ for (auto const &known : apt_known_config_patterns)
{
- known = apt_known_config.find(name.substr(0, rcolon) + ":*");
- if (known == apt_known_config.cend())
+ std::string_view n{name};
+ std::string_view k{known.first};
+ do
{
- auto const parts = StringSplit(name, "::");
- size_t psize = parts.size();
- if (psize > 1)
+ if (auto star = k.find('*'); star != std::string_view::npos)
{
- for (size_t max = psize; max != 1; --max)
- {
- std::ostringstream os;
- std::copy(parts.begin(), parts.begin() + max, std::ostream_iterator<std::string>(os, "::"));
- os << "**";
- known = apt_known_config.find(os.str());
- if (known != apt_known_config.cend() && known->second == ConfigType::UNDEFINED)
- return;
- }
- for (size_t max = psize - 1; max != 1; --max)
- {
- std::ostringstream os;
- std::copy(parts.begin(), parts.begin() + max - 1, std::ostream_iterator<std::string>(os, "::"));
- os << "*::";
- std::copy(parts.begin() + max + 1, parts.end() - 1, std::ostream_iterator<std::string>(os, "::"));
- os << *(parts.end() - 1);
- known = apt_known_config.find(os.str());
- if (known != apt_known_config.cend())
- break;
- }
+ if (auto nextstar = star + 1; k.length() > nextstar && k[nextstar] == '*')
+ star -= 3;
+ if (n.compare(0, star, k, 0, star) != 0)
+ break;
+ n.remove_prefix(star);
+ k.remove_prefix(star + 1);
}
- }
+ else if (k == n)
+ {
+ n = {};
+ break;
+ }
+ else
+ break;
+
+ if (k.empty())
+ {
+ if (n.find("::") == std::string_view::npos)
+ n = {};
+ break;
+ }
+ if (k == "::**")
+ {
+ if (known.second == ConfigType::UNDEFINED)
+ return;
+ n = {};
+ break;
+ }
+ if (k.compare(0, 2, "::") == 0)
+ {
+ auto const colons = n.find("::");
+ if (colons == std::string_view::npos)
+ break;
+ n.remove_prefix(colons);
+ }
+ else
+ break;
+ } while (not n.empty());
+ if (not n.empty())
+ continue;
+ found = true;
+ expectedType = known.second;
+ break;
}
- }
- if (known == apt_known_config.cend())
+
+ if (not found)
_error->Warning("Using unknown config option »%s« of type %s",
name.c_str(), getConfigTypeString(type).c_str());
- else if (known->second != type)
+ else if (expectedType != type)
{
- if (known->second == ConfigType::DIR && type == ConfigType::FILE)
+ if (expectedType == ConfigType::INVALID)
+ _error->Warning("Using invalid config option »%s« as a type %s",
+ name.c_str(), getConfigTypeString(type).c_str());
+ if (expectedType == ConfigType::DIR && type == ConfigType::FILE)
; // implementation detail
- else if (type == ConfigType::STRING && (known->second == ConfigType::FILE || known->second == ConfigType::DIR))
+ else if (type == ConfigType::STRING && (expectedType == ConfigType::FILE || expectedType == ConfigType::DIR))
; // TODO: that might be an error or not, we will figure this out later
- else if (known->second == ConfigType::STRING_OR_BOOL && (type == ConfigType::BOOL || type == ConfigType::STRING))
+ else if (expectedType == ConfigType::STRING_OR_BOOL && (type == ConfigType::BOOL || type == ConfigType::STRING))
;
- else if (known->second == ConfigType::STRING_OR_LIST && (type == ConfigType::LIST || type == ConfigType::STRING))
+ else if (expectedType == ConfigType::STRING_OR_LIST && (type == ConfigType::LIST || type == ConfigType::STRING))
;
else
_error->Warning("Using config option »%s« of type %s as a type %s",
- name.c_str(), getConfigTypeString(known->second).c_str(), getConfigTypeString(type).c_str());
+ name.c_str(), getConfigTypeString(expectedType).c_str(), getConfigTypeString(type).c_str());
}
}
static void checkFindConfigOptionType(char const * const name, ConfigType const type)
@@ -166,6 +197,7 @@ static void checkFindConfigOptionType(char const * const name, ConfigType const
static bool LoadConfigurationIndex(std::string const &filename) /*{{{*/
{
apt_known_config.clear();
+ apt_known_config_patterns.clear();
if (filename.empty())
return true;
Configuration Idx;
@@ -181,7 +213,10 @@ static bool LoadConfigurationIndex(std::string const &filename) /*{{{*/
{
std::string fulltag = Top->FullTag();
std::transform(fulltag.begin(), fulltag.end(), fulltag.begin(), ::tolower);
- apt_known_config.emplace(std::move(fulltag), getConfigType(Top->Value));
+ if (fulltag.find("::*") == std::string::npos)
+ apt_known_config.emplace(std::move(fulltag), getConfigType(Top->Value));
+ else
+ apt_known_config_patterns.emplace_back(std::move(fulltag), getConfigType(Top->Value));
}
if (Top->Child != nullptr)