]>
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>
20 #include <sys/types.h>
30 // getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/
31 // ---------------------------------------------------------------------
32 /* return a vector of compression types in the prefered order. */
33 std::vector
<std::string
>
34 const Configuration::getCompressionTypes(bool const &Cached
) {
35 static std::vector
<std::string
> types
;
36 if (types
.empty() == false) {
43 // setup the defaults for the compressiontypes => method mapping
44 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
45 _config
->CndSet("Acquire::CompressionTypes::xz","xz");
46 _config
->CndSet("Acquire::CompressionTypes::lzma","lzma");
47 _config
->CndSet("Acquire::CompressionTypes::gz","gzip");
49 setDefaultConfigurationForCompressors();
50 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
52 // accept non-list order as override setting for config settings on commandline
53 std::string
const overrideOrder
= _config
->Find("Acquire::CompressionTypes::Order","");
54 if (overrideOrder
.empty() == false)
55 types
.push_back(overrideOrder
);
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 prefered 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 environment
.push_back("en");
233 // Support settings like Acquire::Languages=none on the command line to
234 // override the configuration settings vector of languages.
235 string
const forceLang
= _config
->Find("Acquire::Languages","");
236 if (forceLang
.empty() == false) {
237 if (forceLang
== "none") {
240 allCodes
.push_back("none");
242 if (forceLang
== "environment")
245 codes
.push_back(forceLang
);
247 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
248 b
!= builtin
.end(); ++b
)
249 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
250 allCodes
.push_back(*b
);
258 // cornercase: LANG=C, so we use only "en" Translation
259 if (envShort
== "C") {
260 allCodes
= codes
= environment
;
261 allCodes
.insert(allCodes
.end(), builtin
.begin(), builtin
.end());
268 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages");
269 // the default setting -> "environment, en"
270 if (lang
.empty() == true) {
272 if (envShort
!= "en")
273 codes
.push_back("en");
275 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
276 b
!= builtin
.end(); ++b
)
277 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
278 allCodes
.push_back(*b
);
285 // the configs define the order, so add the environment
286 // then needed and ensure the codes are not listed twice.
287 bool noneSeen
= false;
288 for (std::vector
<string
>::const_iterator l
= lang
.begin();
289 l
!= lang
.end(); ++l
) {
290 if (*l
== "environment") {
291 for (std::vector
<string
>::const_iterator e
= environment
.begin();
292 e
!= environment
.end(); ++e
) {
293 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
295 if (noneSeen
== false)
297 allCodes
.push_back(*e
);
300 } else if (*l
== "none") {
303 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
306 if (noneSeen
== false)
308 allCodes
.push_back(*l
);
311 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
312 b
!= builtin
.end(); ++b
)
313 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
314 allCodes
.push_back(*b
);
322 // checkLanguage - are we interested in the given Language? /*{{{*/
323 bool const Configuration::checkLanguage(std::string Lang
, bool const All
) {
324 // the empty Language is always interesting as it is the original
325 if (Lang
.empty() == true)
327 // filenames are encoded, so undo this
328 Lang
= SubstVar(Lang
, "%5f", "_");
329 std::vector
<std::string
> const langs
= getLanguages(All
, true);
330 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
333 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
334 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
337 std::vector
<string
> static archs
;
338 if (likely(Cached
== true) && archs
.empty() == false)
341 string
const arch
= _config
->Find("APT::Architecture");
342 archs
= _config
->FindVector("APT::Architectures");
344 if (unlikely(arch
.empty() == true))
347 // FIXME: It is a bit unclean to have debian specific code here…
348 if (archs
.empty() == true) {
349 archs
.push_back(arch
);
351 // Generate the base argument list for dpkg
352 std::vector
<const char *> Args
;
353 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
355 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
356 size_t dpkgChrootLen
= dpkgChrootDir
.length();
357 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
358 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
360 Tmp
= Tmp
.substr(dpkgChrootLen
);
363 Args
.push_back(Tmp
.c_str());
365 // Stick in any custom dpkg options
366 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
369 for (; Opts
!= 0; Opts
= Opts
->Next
)
371 if (Opts
->Value
.empty() == true)
373 Args
.push_back(Opts
->Value
.c_str());
377 Args
.push_back("--print-foreign-architectures");
378 Args
.push_back(NULL
);
380 int external
[2] = {-1, -1};
381 if (pipe(external
) != 0)
383 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
387 pid_t dpkgMultiArch
= ExecFork();
388 if (dpkgMultiArch
== 0) {
390 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
391 int const nullfd
= open("/dev/null", O_RDONLY
);
392 dup2(nullfd
, STDIN_FILENO
);
393 dup2(external
[1], STDOUT_FILENO
);
394 dup2(nullfd
, STDERR_FILENO
);
395 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
396 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
397 execvp(Args
[0], (char**) &Args
[0]);
398 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
403 FILE *dpkg
= fdopen(external
[0], "r");
406 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
407 char* arch
= strtok(buf
, " ");
408 while (arch
!= NULL
) {
409 for (; isspace(*arch
) != 0; ++arch
);
410 if (arch
[0] != '\0') {
411 char const* archend
= arch
;
412 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
413 string
a(arch
, (archend
- arch
));
414 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
417 arch
= strtok(NULL
, " ");
422 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
426 if (archs
.empty() == true ||
427 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
428 archs
.insert(archs
.begin(), arch
);
430 // erase duplicates and empty strings
431 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
432 a
!= archs
.rend(); ++a
) {
433 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
434 archs
.erase(a
.base()-1);
435 if (a
== archs
.rend())
442 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
443 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
446 std::vector
<std::string
> const archs
= getArchitectures(true);
447 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
450 // setDefaultConfigurationForCompressors /*{{{*/
451 void Configuration::setDefaultConfigurationForCompressors() {
452 // Set default application paths to check for optional compression types
453 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
454 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
455 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
456 _config
->Set("Dir::Bin::lzma", _config
->FindFile("Dir::Bin::xz"));
457 _config
->Set("APT::Compressor::lzma::Binary", "xz");
458 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
459 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
460 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
462 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
463 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
464 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
467 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
468 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
469 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
470 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
472 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
473 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
474 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
479 // getCompressors - Return Vector of usbale compressors /*{{{*/
480 // ---------------------------------------------------------------------
481 /* return a vector of compressors used by apt-ftparchive in the
482 multicompress functionality or to detect data.tar files */
483 std::vector
<APT::Configuration::Compressor
>
484 const Configuration::getCompressors(bool const Cached
) {
485 static std::vector
<APT::Configuration::Compressor
> compressors
;
486 if (compressors
.empty() == false) {
493 setDefaultConfigurationForCompressors();
495 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
496 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
497 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
500 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
502 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
503 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
506 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
508 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
509 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
510 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
511 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
513 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
514 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
515 c
!= comp
.end(); ++c
) {
516 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
518 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
524 // getCompressorExtensions - supported data.tar extensions /*{{{*/
525 // ---------------------------------------------------------------------
527 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
528 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
529 std::vector
<std::string
> ext
;
530 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
531 c
!= compressors
.end(); ++c
)
532 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
533 ext
.push_back(c
->Extension
);
537 // Compressor constructor /*{{{*/
538 // ---------------------------------------------------------------------
540 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
542 char const *compressArg
, char const *uncompressArg
,
543 unsigned short const cost
) {
544 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
545 Name
= _config
->Find(std::string(config
).append("Name"), name
);
546 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
547 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
548 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
549 std::string
const compConf
= std::string(config
).append("CompressArg");
550 if (_config
->Exists(compConf
) == true)
551 CompressArgs
= _config
->FindVector(compConf
);
552 else if (compressArg
!= NULL
)
553 CompressArgs
.push_back(compressArg
);
554 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
555 if (_config
->Exists(uncompConf
) == true)
556 UncompressArgs
= _config
->FindVector(uncompConf
);
557 else if (uncompressArg
!= NULL
)
558 UncompressArgs
.push_back(uncompressArg
);