]>
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
= Ent
->d_name
;
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
== "environment") {
239 } else if (forceLang
!= "none")
240 codes
.push_back(forceLang
);
241 else //if (forceLang == "none")
244 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
245 b
!= builtin
.end(); ++b
)
246 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
247 allCodes
.push_back(*b
);
254 // cornercase: LANG=C, so we use only "en" Translation
255 if (envShort
== "C") {
256 allCodes
= codes
= environment
;
257 allCodes
.insert(allCodes
.end(), builtin
.begin(), builtin
.end());
264 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages");
265 // the default setting -> "environment, en"
266 if (lang
.empty() == true) {
268 if (envShort
!= "en")
269 codes
.push_back("en");
271 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
272 b
!= builtin
.end(); ++b
)
273 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
274 allCodes
.push_back(*b
);
281 // the configs define the order, so add the environment
282 // then needed and ensure the codes are not listed twice.
283 bool noneSeen
= false;
284 for (std::vector
<string
>::const_iterator l
= lang
.begin();
285 l
!= lang
.end(); ++l
) {
286 if (*l
== "environment") {
287 for (std::vector
<string
>::const_iterator e
= environment
.begin();
288 e
!= environment
.end(); ++e
) {
289 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
291 if (noneSeen
== false)
293 allCodes
.push_back(*e
);
296 } else if (*l
== "none") {
299 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
302 if (noneSeen
== false)
304 allCodes
.push_back(*l
);
307 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
308 b
!= builtin
.end(); ++b
)
309 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
310 allCodes
.push_back(*b
);
318 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
319 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
322 std::vector
<string
> static archs
;
323 if (likely(Cached
== true) && archs
.empty() == false)
326 string
const arch
= _config
->Find("APT::Architecture");
327 archs
= _config
->FindVector("APT::Architectures");
329 if (unlikely(arch
.empty() == true))
332 // FIXME: It is a bit unclean to have debian specific code here…
333 if (archs
.empty() == true) {
334 archs
.push_back(arch
);
336 // Generate the base argument list for dpkg
337 std::vector
<const char *> Args
;
338 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
340 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
341 size_t dpkgChrootLen
= dpkgChrootDir
.length();
342 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
343 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
345 Tmp
= Tmp
.substr(dpkgChrootLen
);
348 Args
.push_back(Tmp
.c_str());
350 // Stick in any custom dpkg options
351 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
354 for (; Opts
!= 0; Opts
= Opts
->Next
)
356 if (Opts
->Value
.empty() == true)
358 Args
.push_back(Opts
->Value
.c_str());
362 Args
.push_back("--print-foreign-architectures");
363 Args
.push_back(NULL
);
365 int external
[2] = {-1, -1};
366 if (pipe(external
) != 0)
368 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
372 pid_t dpkgMultiArch
= ExecFork();
373 if (dpkgMultiArch
== 0) {
375 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
376 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0)
377 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
378 int const nullfd
= open("/dev/null", O_RDONLY
);
379 dup2(nullfd
, STDIN_FILENO
);
380 dup2(external
[1], STDOUT_FILENO
);
381 dup2(nullfd
, STDERR_FILENO
);
382 execvp(Args
[0], (char**) &Args
[0]);
383 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
388 FILE *dpkg
= fdopen(external
[0], "r");
391 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
392 char* arch
= strtok(buf
, " ");
393 while (arch
!= NULL
) {
394 for (; isspace(*arch
) != 0; ++arch
);
395 if (arch
[0] != '\0') {
396 char const* archend
= arch
;
397 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
398 string
a(arch
, (archend
- arch
));
399 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
402 arch
= strtok(NULL
, " ");
407 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
411 if (archs
.empty() == true ||
412 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
413 archs
.insert(archs
.begin(), arch
);
415 // erase duplicates and empty strings
416 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
417 a
!= archs
.rend(); ++a
) {
418 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
419 archs
.erase(a
.base()-1);
420 if (a
== archs
.rend())
427 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
428 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
431 std::vector
<std::string
> const archs
= getArchitectures(true);
432 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
435 // setDefaultConfigurationForCompressors /*{{{*/
436 void Configuration::setDefaultConfigurationForCompressors() {
437 // Set default application paths to check for optional compression types
438 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
439 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
440 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
441 _config
->Clear("Dir::Bin::lzma");
442 _config
->Set("APT::Compressor::lzma::Binary", "xz");
443 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
444 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
445 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
447 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
448 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
449 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
452 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
453 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
454 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
455 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
457 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
458 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
459 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
464 // getCompressors - Return Vector of usbale compressors /*{{{*/
465 // ---------------------------------------------------------------------
466 /* return a vector of compressors used by apt-ftparchive in the
467 multicompress functionality or to detect data.tar files */
468 std::vector
<APT::Configuration::Compressor
>
469 const Configuration::getCompressors(bool const Cached
) {
470 static std::vector
<APT::Configuration::Compressor
> compressors
;
471 if (compressors
.empty() == false) {
478 setDefaultConfigurationForCompressors();
480 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
481 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
482 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
485 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
487 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
488 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
491 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
493 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
494 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
495 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
496 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
498 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
499 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
500 c
!= comp
.end(); ++c
) {
501 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
503 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
509 // getCompressorExtensions - supported data.tar extensions /*{{{*/
510 // ---------------------------------------------------------------------
512 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
513 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
514 std::vector
<std::string
> ext
;
515 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
516 c
!= compressors
.end(); ++c
)
517 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
518 ext
.push_back(c
->Extension
);
522 // Compressor constructor /*{{{*/
523 // ---------------------------------------------------------------------
525 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
527 char const *compressArg
, char const *uncompressArg
,
528 unsigned short const cost
) {
529 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
530 Name
= _config
->Find(std::string(config
).append("Name"), name
);
531 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
532 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
533 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
534 std::string
const compConf
= std::string(config
).append("CompressArg");
535 if (_config
->Exists(compConf
) == true)
536 CompressArgs
= _config
->FindVector(compConf
);
537 else if (compressArg
!= NULL
)
538 CompressArgs
.push_back(compressArg
);
539 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
540 if (_config
->Exists(uncompConf
) == true)
541 UncompressArgs
= _config
->FindVector(uncompConf
);
542 else if (uncompressArg
!= NULL
)
543 UncompressArgs
.push_back(uncompressArg
);