123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- /* ######################################################################
- Provide access methods to various configuration settings,
- setup defaults and returns validate settings.
- ##################################################################### */
- /*}}}*/
- // Include Files /*{{{*/
- #include <config.h>
- #include <apt-pkg/aptconfiguration.h>
- #include <apt-pkg/configuration.h>
- #include <apt-pkg/error.h>
- #include <apt-pkg/fileutl.h>
- #include <apt-pkg/macros.h>
- #include <apt-pkg/strutl.h>
- #include <sys/types.h>
- #include <dirent.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <algorithm>
- #include <string>
- #include <vector>
- /*}}}*/
- namespace APT {
- // getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
- // ---------------------------------------------------------------------
- /* return a vector of compression types in the preferred order. */
- std::vector<std::string>
- const Configuration::getCompressionTypes(bool const &Cached) {
- static std::vector<std::string> types;
- if (types.empty() == false) {
- if (Cached == true)
- return types;
- else
- types.clear();
- }
- // setup the defaults for the compressiontypes => method mapping
- _config->CndSet("Acquire::CompressionTypes::bz2","bzip2");
- _config->CndSet("Acquire::CompressionTypes::xz","xz");
- _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
- _config->CndSet("Acquire::CompressionTypes::gz","gzip");
- setDefaultConfigurationForCompressors();
- std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
- // accept non-list order as override setting for config settings on commandline
- std::string const overrideOrder = _config->Find("Acquire::CompressionTypes::Order","");
- if (overrideOrder.empty() == false)
- types.push_back(overrideOrder);
- // load the order setting into our vector
- std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order");
- for (std::vector<std::string>::const_iterator o = order.begin();
- o != order.end(); ++o) {
- if ((*o).empty() == true)
- continue;
- // ignore types we have no method ready to use
- std::string const method = std::string("Acquire::CompressionTypes::").append(*o);
- if (_config->Exists(method) == false)
- continue;
- // ignore types we have no app ready to use
- std::string const app = _config->Find(method);
- std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
- for (; c != compressors.end(); ++c)
- if (c->Name == app)
- break;
- if (c == compressors.end())
- continue;
- types.push_back(*o);
- }
- // move again over the option tree to add all missing compression types
- ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes");
- if (Types != 0)
- Types = Types->Child;
- for (; Types != 0; Types = Types->Next) {
- if (Types->Tag == "Order" || Types->Tag.empty() == true)
- continue;
- // ignore types we already have in the vector
- if (std::find(types.begin(),types.end(),Types->Tag) != types.end())
- continue;
- // ignore types we have no app ready to use
- std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
- for (; c != compressors.end(); ++c)
- if (c->Name == Types->Value)
- break;
- if (c == compressors.end())
- continue;
- types.push_back(Types->Tag);
- }
- // add the special "uncompressed" type
- if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
- {
- std::string const uncompr = _config->FindFile("Dir::Bin::uncompressed", "");
- if (uncompr.empty() == true || FileExists(uncompr) == true)
- types.push_back("uncompressed");
- }
- return types;
- }
- /*}}}*/
- // GetLanguages - Return Vector of Language Codes /*{{{*/
- // ---------------------------------------------------------------------
- /* return a vector of language codes in the preferred order.
- the special word "environment" will be replaced with the long and the short
- code of the local settings and it will be insured that this will not add
- duplicates. So in an german local the setting "environment, de_DE, en, de"
- will result in "de_DE, de, en".
- The special word "none" is the stopcode for the not-All code vector */
- std::vector<std::string> const Configuration::getLanguages(bool const &All,
- bool const &Cached, char const ** const Locale) {
- using std::string;
- // The detection is boring and has a lot of cornercases,
- // so we cache the results to calculated it only once.
- std::vector<string> static allCodes;
- std::vector<string> static codes;
- // we have something in the cache
- if (codes.empty() == false || allCodes.empty() == false) {
- if (Cached == true) {
- if(All == true && allCodes.empty() == false)
- return allCodes;
- else
- return codes;
- } else {
- allCodes.clear();
- codes.clear();
- }
- }
- // Include all Language codes we have a Translation file for in /var/lib/apt/lists
- // so they will be all included in the Cache.
- std::vector<string> builtin;
- DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str());
- if (D != NULL) {
- builtin.push_back("none");
- for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
- string const name = SubstVar(Ent->d_name, "%5f", "_");
- size_t const foundDash = name.rfind("-");
- size_t const foundUnderscore = name.rfind("_", foundDash);
- if (foundDash == string::npos || foundUnderscore == string::npos ||
- foundDash <= foundUnderscore ||
- name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation")
- continue;
- string const c = name.substr(foundDash+1);
- if (unlikely(c.empty() == true) || c == "en")
- continue;
- // Skip unusual files, like backups or that alike
- string::const_iterator s = c.begin();
- for (;s != c.end(); ++s) {
- if (isalpha(*s) == 0 && *s != '_')
- break;
- }
- if (s != c.end())
- continue;
- if (std::find(builtin.begin(), builtin.end(), c) != builtin.end())
- continue;
- builtin.push_back(c);
- }
- closedir(D);
- }
- // FIXME: Remove support for the old APT::Acquire::Translation
- // it was undocumented and so it should be not very widthly used
- string const oldAcquire = _config->Find("APT::Acquire::Translation","");
- if (oldAcquire.empty() == false && oldAcquire != "environment") {
- // TRANSLATORS: the two %s are APT configuration options
- _error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
- "APT::Acquire::Translation", "Acquire::Languages");
- if (oldAcquire != "none")
- codes.push_back(oldAcquire);
- codes.push_back("en");
- allCodes = codes;
- for (std::vector<string>::const_iterator b = builtin.begin();
- b != builtin.end(); ++b)
- if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
- allCodes.push_back(*b);
- if (All == true)
- return allCodes;
- else
- return codes;
- }
- // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
- // we extract both, a long and a short code and then we will
- // check if we actually need both (rare) or if the short is enough
- string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : *Locale);
- size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
- size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3);
- string const envLong = envMsg.substr(0,lenLong);
- string const envShort = envLong.substr(0,lenShort);
- // It is very likely we will need the environment codes later,
- // so let us generate them now from LC_MESSAGES and LANGUAGE
- std::vector<string> environment;
- if (envShort != "C") {
- // take care of LC_MESSAGES
- if (envLong != envShort)
- environment.push_back(envLong);
- environment.push_back(envShort);
- // take care of LANGUAGE
- const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
- string envLang = Locale == 0 ? language_env : *(Locale+1);
- if (envLang.empty() == false) {
- std::vector<string> env = VectorizeString(envLang,':');
- short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
- for (std::vector<string>::const_iterator e = env.begin();
- e != env.end() && addedLangs < 3; ++e) {
- if (unlikely(e->empty() == true) || *e == "en")
- continue;
- if (*e == envLong || *e == envShort)
- continue;
- if (std::find(environment.begin(), environment.end(), *e) != environment.end())
- continue;
- ++addedLangs;
- environment.push_back(*e);
- }
- }
- } else {
- environment.push_back("en");
- }
- // Support settings like Acquire::Languages=none on the command line to
- // override the configuration settings vector of languages.
- string const forceLang = _config->Find("Acquire::Languages","");
- if (forceLang.empty() == false) {
- if (forceLang == "none") {
- codes.clear();
- allCodes.clear();
- allCodes.push_back("none");
- } else {
- if (forceLang == "environment")
- codes = environment;
- else
- codes.push_back(forceLang);
- allCodes = codes;
- for (std::vector<string>::const_iterator b = builtin.begin();
- b != builtin.end(); ++b)
- if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
- allCodes.push_back(*b);
- }
- if (All == true)
- return allCodes;
- else
- return codes;
- }
- // cornercase: LANG=C, so we use only "en" Translation
- if (envShort == "C") {
- allCodes = codes = environment;
- allCodes.insert(allCodes.end(), builtin.begin(), builtin.end());
- if (All == true)
- return allCodes;
- else
- return codes;
- }
- std::vector<string> const lang = _config->FindVector("Acquire::Languages");
- // the default setting -> "environment, en"
- if (lang.empty() == true) {
- codes = environment;
- if (envShort != "en")
- codes.push_back("en");
- allCodes = codes;
- for (std::vector<string>::const_iterator b = builtin.begin();
- b != builtin.end(); ++b)
- if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
- allCodes.push_back(*b);
- if (All == true)
- return allCodes;
- else
- return codes;
- }
- // the configs define the order, so add the environment
- // then needed and ensure the codes are not listed twice.
- bool noneSeen = false;
- for (std::vector<string>::const_iterator l = lang.begin();
- l != lang.end(); ++l) {
- if (*l == "environment") {
- for (std::vector<string>::const_iterator e = environment.begin();
- e != environment.end(); ++e) {
- if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end())
- continue;
- if (noneSeen == false)
- codes.push_back(*e);
- allCodes.push_back(*e);
- }
- continue;
- } else if (*l == "none") {
- noneSeen = true;
- continue;
- } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
- continue;
- if (noneSeen == false)
- codes.push_back(*l);
- allCodes.push_back(*l);
- }
- for (std::vector<string>::const_iterator b = builtin.begin();
- b != builtin.end(); ++b)
- if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
- allCodes.push_back(*b);
- if (All == true)
- return allCodes;
- else
- return codes;
- }
- /*}}}*/
- // checkLanguage - are we interested in the given Language? /*{{{*/
- bool const Configuration::checkLanguage(std::string Lang, bool const All) {
- // the empty Language is always interesting as it is the original
- if (Lang.empty() == true)
- return true;
- // filenames are encoded, so undo this
- Lang = SubstVar(Lang, "%5f", "_");
- std::vector<std::string> const langs = getLanguages(All, true);
- return (std::find(langs.begin(), langs.end(), Lang) != langs.end());
- }
- /*}}}*/
- // getArchitectures - Return Vector of preferred Architectures /*{{{*/
- std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
- using std::string;
- std::vector<string> static archs;
- if (likely(Cached == true) && archs.empty() == false)
- return archs;
- string const arch = _config->Find("APT::Architecture");
- archs = _config->FindVector("APT::Architectures");
- if (unlikely(arch.empty() == true))
- return archs;
- // FIXME: It is a bit unclean to have debian specific code here…
- if (archs.empty() == true) {
- archs.push_back(arch);
- // Generate the base argument list for dpkg
- std::vector<const char *> Args;
- string Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
- {
- string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/");
- size_t dpkgChrootLen = dpkgChrootDir.length();
- if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) {
- if (dpkgChrootDir[dpkgChrootLen - 1] == '/')
- --dpkgChrootLen;
- Tmp = Tmp.substr(dpkgChrootLen);
- }
- }
- Args.push_back(Tmp.c_str());
- // Stick in any custom dpkg options
- ::Configuration::Item const *Opts = _config->Tree("DPkg::Options");
- if (Opts != 0) {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- Args.push_back(Opts->Value.c_str());
- }
- }
- Args.push_back("--print-foreign-architectures");
- Args.push_back(NULL);
- int external[2] = {-1, -1};
- if (pipe(external) != 0)
- {
- _error->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
- return archs;
- }
- pid_t dpkgMultiArch = ExecFork();
- if (dpkgMultiArch == 0) {
- close(external[0]);
- std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory");
- int const nullfd = open("/dev/null", O_RDONLY);
- dup2(nullfd, STDIN_FILENO);
- dup2(external[1], STDOUT_FILENO);
- dup2(nullfd, STDERR_FILENO);
- if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0)
- _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir.c_str());
- execvp(Args[0], (char**) &Args[0]);
- _error->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
- _exit(100);
- }
- close(external[1]);
- FILE *dpkg = fdopen(external[0], "r");
- if(dpkg != NULL) {
- char buf[1024];
- while (fgets(buf, sizeof(buf), dpkg) != NULL) {
- char* arch = strtok(buf, " ");
- while (arch != NULL) {
- for (; isspace(*arch) != 0; ++arch);
- if (arch[0] != '\0') {
- char const* archend = arch;
- for (; isspace(*archend) == 0 && *archend != '\0'; ++archend);
- string a(arch, (archend - arch));
- if (std::find(archs.begin(), archs.end(), a) == archs.end())
- archs.push_back(a);
- }
- arch = strtok(NULL, " ");
- }
- }
- fclose(dpkg);
- }
- ExecWait(dpkgMultiArch, "dpkg --print-foreign-architectures", true);
- return archs;
- }
- if (archs.empty() == true ||
- std::find(archs.begin(), archs.end(), arch) == archs.end())
- archs.insert(archs.begin(), arch);
- // erase duplicates and empty strings
- for (std::vector<string>::reverse_iterator a = archs.rbegin();
- a != archs.rend(); ++a) {
- if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
- archs.erase(a.base()-1);
- if (a == archs.rend())
- break;
- }
- return archs;
- }
- /*}}}*/
- // checkArchitecture - are we interested in the given Architecture? /*{{{*/
- bool const Configuration::checkArchitecture(std::string const &Arch) {
- if (Arch == "all")
- return true;
- std::vector<std::string> const archs = getArchitectures(true);
- return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
- }
- /*}}}*/
- // setDefaultConfigurationForCompressors /*{{{*/
- void Configuration::setDefaultConfigurationForCompressors() {
- // Set default application paths to check for optional compression types
- _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
- _config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
- if (FileExists(_config->FindFile("Dir::Bin::xz")) == true) {
- _config->Set("Dir::Bin::lzma", _config->FindFile("Dir::Bin::xz"));
- _config->Set("APT::Compressor::lzma::Binary", "xz");
- if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
- _config->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
- _config->Set("APT::Compressor::lzma::CompressArg::", "-9");
- }
- if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
- _config->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
- _config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
- }
- } else {
- _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
- if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
- _config->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
- _config->Set("APT::Compressor::lzma::CompressArg::", "-9");
- }
- if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
- _config->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
- _config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
- }
- }
- }
- /*}}}*/
- // getCompressors - Return Vector of usbale compressors /*{{{*/
- // ---------------------------------------------------------------------
- /* return a vector of compressors used by apt-ftparchive in the
- multicompress functionality or to detect data.tar files */
- std::vector<APT::Configuration::Compressor>
- const Configuration::getCompressors(bool const Cached) {
- static std::vector<APT::Configuration::Compressor> compressors;
- if (compressors.empty() == false) {
- if (Cached == true)
- return compressors;
- else
- compressors.clear();
- }
- setDefaultConfigurationForCompressors();
- compressors.push_back(Compressor(".", "", "", NULL, NULL, 1));
- if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->FindFile("Dir::Bin::gzip")) == true)
- compressors.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
- #ifdef HAVE_ZLIB
- else
- compressors.push_back(Compressor("gzip",".gz","false", NULL, NULL, 2));
- #endif
- if (_config->Exists("Dir::Bin::bzip2") == false || FileExists(_config->FindFile("Dir::Bin::bzip2")) == true)
- compressors.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
- #ifdef HAVE_BZ2
- else
- compressors.push_back(Compressor("bzip2",".bz2","false", NULL, NULL, 3));
- #endif
- if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->FindFile("Dir::Bin::xz")) == true)
- compressors.push_back(Compressor("xz",".xz","xz","-6","-d",4));
- if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->FindFile("Dir::Bin::lzma")) == true)
- compressors.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
- std::vector<std::string> const comp = _config->FindVector("APT::Compressor");
- for (std::vector<std::string>::const_iterator c = comp.begin();
- c != comp.end(); ++c) {
- if (*c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz")
- continue;
- compressors.push_back(Compressor(c->c_str(), std::string(".").append(*c).c_str(), c->c_str(), "-9", "-d", 100));
- }
- return compressors;
- }
- /*}}}*/
- // getCompressorExtensions - supported data.tar extensions /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- std::vector<std::string> const Configuration::getCompressorExtensions() {
- std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
- std::vector<std::string> ext;
- for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
- c != compressors.end(); ++c)
- if (c->Extension.empty() == false && c->Extension != ".")
- ext.push_back(c->Extension);
- return ext;
- }
- /*}}}*/
- // Compressor constructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- Configuration::Compressor::Compressor(char const *name, char const *extension,
- char const *binary,
- char const *compressArg, char const *uncompressArg,
- unsigned short const cost) {
- std::string const config = std::string("APT::Compressor::").append(name).append("::");
- Name = _config->Find(std::string(config).append("Name"), name);
- Extension = _config->Find(std::string(config).append("Extension"), extension);
- Binary = _config->Find(std::string(config).append("Binary"), binary);
- Cost = _config->FindI(std::string(config).append("Cost"), cost);
- std::string const compConf = std::string(config).append("CompressArg");
- if (_config->Exists(compConf) == true)
- CompressArgs = _config->FindVector(compConf);
- else if (compressArg != NULL)
- CompressArgs.push_back(compressArg);
- std::string const uncompConf = std::string(config).append("UncompressArg");
- if (_config->Exists(uncompConf) == true)
- UncompressArgs = _config->FindVector(uncompConf);
- else if (uncompressArg != NULL)
- UncompressArgs.push_back(uncompressArg);
- }
- /*}}}*/
- }
|