]>
git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
8 ##################################################################### */
10 // Include Files /*{{{*/
13 #include <apt-pkg/aptconfiguration.h>
14 #include <apt-pkg/configuration.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/macros.h>
18 #include <apt-pkg/strutl.h>
35 // getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
36 // ---------------------------------------------------------------------
37 /* return a vector of compression types in the preferred order. */
38 std::vector
<std::string
>
39 const Configuration::getCompressionTypes(bool const &Cached
) {
40 static std::vector
<std::string
> types
;
41 if (types
.empty() == false) {
48 // setup the defaults for the compressiontypes => method mapping
49 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
50 _config
->CndSet("Acquire::CompressionTypes::xz","xz");
51 _config
->CndSet("Acquire::CompressionTypes::lzma","lzma");
52 _config
->CndSet("Acquire::CompressionTypes::gz","gzip");
54 setDefaultConfigurationForCompressors();
55 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
57 // load the order setting into our vector
58 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
59 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
60 o
!= order
.end(); ++o
) {
61 if ((*o
).empty() == true)
63 // ignore types we have no method ready to use
64 std::string
const method
= std::string("Acquire::CompressionTypes::").append(*o
);
65 if (_config
->Exists(method
) == false)
67 // ignore types we have no app ready to use
68 std::string
const app
= _config
->Find(method
);
69 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
70 for (; c
!= compressors
.end(); ++c
)
73 if (c
== compressors
.end())
78 // move again over the option tree to add all missing compression types
79 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
83 for (; Types
!= 0; Types
= Types
->Next
) {
84 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
86 // ignore types we already have in the vector
87 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
89 // ignore types we have no app ready to use
90 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
91 for (; c
!= compressors
.end(); ++c
)
92 if (c
->Name
== Types
->Value
)
94 if (c
== compressors
.end())
96 types
.push_back(Types
->Tag
);
99 // add the special "uncompressed" type
100 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
102 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
103 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
104 types
.push_back("uncompressed");
110 // GetLanguages - Return Vector of Language Codes /*{{{*/
111 // ---------------------------------------------------------------------
112 /* return a vector of language codes in the preferred order.
113 the special word "environment" will be replaced with the long and the short
114 code of the local settings and it will be insured that this will not add
115 duplicates. So in an german local the setting "environment, de_DE, en, de"
116 will result in "de_DE, de, en".
117 The special word "none" is the stopcode for the not-All code vector */
118 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
119 bool const &Cached
, char const ** const Locale
) {
122 // The detection is boring and has a lot of cornercases,
123 // so we cache the results to calculated it only once.
124 std::vector
<string
> static allCodes
;
125 std::vector
<string
> static codes
;
127 // we have something in the cache
128 if (codes
.empty() == false || allCodes
.empty() == false) {
129 if (Cached
== true) {
130 if(All
== true && allCodes
.empty() == false)
140 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
141 // so they will be all included in the Cache.
142 std::vector
<string
> builtin
;
143 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
145 builtin
.push_back("none");
146 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
147 string
const name
= SubstVar(Ent
->d_name
, "%5f", "_");
148 size_t const foundDash
= name
.rfind("-");
149 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
150 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
151 foundDash
<= foundUnderscore
||
152 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
154 string
const c
= name
.substr(foundDash
+1);
155 if (unlikely(c
.empty() == true) || c
== "en")
157 // Skip unusual files, like backups or that alike
158 string::const_iterator s
= c
.begin();
159 for (;s
!= c
.end(); ++s
) {
160 if (isalpha(*s
) == 0 && *s
!= '_')
165 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
167 builtin
.push_back(c
);
172 // FIXME: Remove support for the old APT::Acquire::Translation
173 // it was undocumented and so it should be not very widthly used
174 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
175 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
176 // TRANSLATORS: the two %s are APT configuration options
177 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
178 "APT::Acquire::Translation", "Acquire::Languages");
179 if (oldAcquire
!= "none")
180 codes
.push_back(oldAcquire
);
181 codes
.push_back("en");
183 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
184 b
!= builtin
.end(); ++b
)
185 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
186 allCodes
.push_back(*b
);
193 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
194 // we extract both, a long and a short code and then we will
195 // check if we actually need both (rare) or if the short is enough
196 string
const envMsg
= string(Locale
== 0 ? std::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
197 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
198 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
200 string
const envLong
= envMsg
.substr(0,lenLong
);
201 string
const envShort
= envLong
.substr(0,lenShort
);
203 // It is very likely we will need the environment codes later,
204 // so let us generate them now from LC_MESSAGES and LANGUAGE
205 std::vector
<string
> environment
;
206 if (envShort
!= "C") {
207 // take care of LC_MESSAGES
208 if (envLong
!= envShort
)
209 environment
.push_back(envLong
);
210 environment
.push_back(envShort
);
211 // take care of LANGUAGE
212 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
213 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
214 if (envLang
.empty() == false) {
215 std::vector
<string
> env
= VectorizeString(envLang
,':');
216 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
217 for (std::vector
<string
>::const_iterator e
= env
.begin();
218 e
!= env
.end() && addedLangs
< 3; ++e
) {
219 if (unlikely(e
->empty() == true) || *e
== "en")
221 if (*e
== envLong
|| *e
== envShort
)
223 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
226 environment
.push_back(*e
);
230 // cornercase: LANG=C, so we use only "en" Translation
231 environment
.push_back("en");
234 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages", "environment,en");
235 // the configs define the order, so add the environment
236 // then needed and ensure the codes are not listed twice.
237 bool noneSeen
= false;
238 for (std::vector
<string
>::const_iterator l
= lang
.begin();
239 l
!= lang
.end(); ++l
) {
240 if (*l
== "environment") {
241 for (std::vector
<string
>::const_iterator e
= environment
.begin();
242 e
!= environment
.end(); ++e
) {
243 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
245 if (noneSeen
== false)
247 allCodes
.push_back(*e
);
250 } else if (*l
== "none") {
253 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
256 if (noneSeen
== false)
258 allCodes
.push_back(*l
);
261 if (allCodes
.empty() == false) {
262 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
263 b
!= builtin
.end(); ++b
)
264 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
265 allCodes
.push_back(*b
);
268 allCodes
.push_back("none");
277 // checkLanguage - are we interested in the given Language? /*{{{*/
278 bool Configuration::checkLanguage(std::string Lang
, bool const All
) {
279 // the empty Language is always interesting as it is the original
280 if (Lang
.empty() == true)
282 // filenames are encoded, so undo this
283 Lang
= SubstVar(Lang
, "%5f", "_");
284 std::vector
<std::string
> const langs
= getLanguages(All
, true);
285 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
288 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
289 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
292 std::vector
<string
> static archs
;
293 if (likely(Cached
== true) && archs
.empty() == false)
296 string
const arch
= _config
->Find("APT::Architecture");
297 archs
= _config
->FindVector("APT::Architectures");
299 if (unlikely(arch
.empty() == true))
302 // FIXME: It is a bit unclean to have debian specific code here…
303 if (archs
.empty() == true) {
304 archs
.push_back(arch
);
306 // Generate the base argument list for dpkg
307 std::vector
<const char *> Args
;
308 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
310 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
311 size_t dpkgChrootLen
= dpkgChrootDir
.length();
312 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
313 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
315 Tmp
= Tmp
.substr(dpkgChrootLen
);
318 Args
.push_back(Tmp
.c_str());
320 // Stick in any custom dpkg options
321 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
324 for (; Opts
!= 0; Opts
= Opts
->Next
)
326 if (Opts
->Value
.empty() == true)
328 Args
.push_back(Opts
->Value
.c_str());
332 Args
.push_back("--print-foreign-architectures");
333 Args
.push_back(NULL
);
335 int external
[2] = {-1, -1};
336 if (pipe(external
) != 0)
338 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
342 pid_t dpkgMultiArch
= ExecFork();
343 if (dpkgMultiArch
== 0) {
345 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
346 int const nullfd
= open("/dev/null", O_RDONLY
);
347 dup2(nullfd
, STDIN_FILENO
);
348 dup2(external
[1], STDOUT_FILENO
);
349 dup2(nullfd
, STDERR_FILENO
);
350 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
351 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
352 execvp(Args
[0], (char**) &Args
[0]);
353 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
358 FILE *dpkg
= fdopen(external
[0], "r");
361 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
362 char* arch
= strtok(buf
, " ");
363 while (arch
!= NULL
) {
364 for (; isspace(*arch
) != 0; ++arch
);
365 if (arch
[0] != '\0') {
366 char const* archend
= arch
;
367 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
368 string
a(arch
, (archend
- arch
));
369 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
372 arch
= strtok(NULL
, " ");
377 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
381 if (archs
.empty() == true ||
382 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
383 archs
.insert(archs
.begin(), arch
);
385 // erase duplicates and empty strings
386 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
387 a
!= archs
.rend(); ++a
) {
388 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
389 archs
.erase(a
.base()-1);
390 if (a
== archs
.rend())
397 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
398 bool Configuration::checkArchitecture(std::string
const &Arch
) {
401 std::vector
<std::string
> const archs
= getArchitectures(true);
402 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
405 // setDefaultConfigurationForCompressors /*{{{*/
406 void Configuration::setDefaultConfigurationForCompressors() {
407 // Set default application paths to check for optional compression types
408 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
409 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
410 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
411 _config
->Set("Dir::Bin::lzma", _config
->FindFile("Dir::Bin::xz"));
412 _config
->Set("APT::Compressor::lzma::Binary", "xz");
413 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
414 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
415 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
417 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
418 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
419 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
422 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
423 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
424 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
425 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
427 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
428 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
429 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
434 // getCompressors - Return Vector of usealbe compressors /*{{{*/
435 // ---------------------------------------------------------------------
436 /* return a vector of compressors used by apt-ftparchive in the
437 multicompress functionality or to detect data.tar files */
438 std::vector
<APT::Configuration::Compressor
>
439 const Configuration::getCompressors(bool const Cached
) {
440 static std::vector
<APT::Configuration::Compressor
> compressors
;
441 if (compressors
.empty() == false) {
448 setDefaultConfigurationForCompressors();
450 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
451 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
452 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
455 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
457 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
458 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
461 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
463 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
464 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
467 compressors
.push_back(Compressor("xz",".xz","false", NULL
, NULL
, 4));
469 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
470 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
473 compressors
.push_back(Compressor("lzma",".lzma","false", NULL
, NULL
, 5));
476 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
477 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
478 c
!= comp
.end(); ++c
) {
479 if (c
->empty() || *c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
481 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
487 // getCompressorExtensions - supported data.tar extensions /*{{{*/
488 // ---------------------------------------------------------------------
490 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
491 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
492 std::vector
<std::string
> ext
;
493 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
494 c
!= compressors
.end(); ++c
)
495 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
496 ext
.push_back(c
->Extension
);
500 // Compressor constructor /*{{{*/
501 // ---------------------------------------------------------------------
503 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
505 char const *compressArg
, char const *uncompressArg
,
506 unsigned short const cost
) {
507 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
508 Name
= _config
->Find(std::string(config
).append("Name"), name
);
509 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
510 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
511 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
512 std::string
const compConf
= std::string(config
).append("CompressArg");
513 if (_config
->Exists(compConf
) == true)
514 CompressArgs
= _config
->FindVector(compConf
);
515 else if (compressArg
!= NULL
)
516 CompressArgs
.push_back(compressArg
);
517 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
518 if (_config
->Exists(uncompConf
) == true)
519 UncompressArgs
= _config
->FindVector(uncompConf
);
520 else if (uncompressArg
!= NULL
)
521 UncompressArgs
.push_back(uncompressArg
);
524 // getBuildProfiles - return a vector of enabled build profiles /*{{{*/
525 std::vector
<std::string
> const Configuration::getBuildProfiles() {
526 // order is: override value (~= commandline), environment variable, list (~= config file)
527 std::string profiles_env
= getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
528 if (profiles_env
.empty() == false) {
529 profiles_env
= SubstVar(profiles_env
, " ", ",");
530 std::string
const bp
= _config
->Find("APT::Build-Profiles");
531 _config
->Clear("APT::Build-Profiles");
532 if (bp
.empty() == false)
533 _config
->Set("APT::Build-Profiles", bp
);
535 return _config
->FindVector("APT::Build-Profiles", profiles_env
);
537 std::string
const Configuration::getBuildProfilesString() {
538 std::vector
<std::string
> profiles
= getBuildProfiles();
539 if (profiles
.empty() == true)
541 std::vector
<std::string
>::const_iterator p
= profiles
.begin();
542 std::string list
= *p
;
543 for (++p
; p
!= profiles
.end(); ++p
)
544 list
.append(",").append(*p
);