]>
git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
f00852775bac76ec3645dd51ab77e81617a2a181
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();
51 // accept non-list order as override setting for config settings on commandline
52 std::string
const overrideOrder
= _config
->Find("Acquire::CompressionTypes::Order","");
53 if (overrideOrder
.empty() == false)
54 types
.push_back(overrideOrder
);
56 // load the order setting into our vector
57 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
58 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
59 o
!= order
.end(); ++o
) {
60 if ((*o
).empty() == true)
62 // ignore types we have no method ready to use
63 if (_config
->Exists(std::string("Acquire::CompressionTypes::").append(*o
)) == false)
65 // ignore types we have no app ready to use
66 std::string
const appsetting
= std::string("Dir::Bin::").append(*o
);
67 if (_config
->Exists(appsetting
) == true) {
68 std::string
const app
= _config
->FindFile(appsetting
.c_str(), "");
69 if (app
.empty() == false && FileExists(app
) == false)
75 // move again over the option tree to add all missing compression types
76 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
80 for (; Types
!= 0; Types
= Types
->Next
) {
81 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
83 // ignore types we already have in the vector
84 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
86 // ignore types we have no app ready to use
87 std::string
const appsetting
= std::string("Dir::Bin::").append(Types
->Value
);
88 if (appsetting
.empty() == false && _config
->Exists(appsetting
) == true) {
89 std::string
const app
= _config
->FindFile(appsetting
.c_str(), "");
90 if (app
.empty() == false && FileExists(app
) == false)
93 types
.push_back(Types
->Tag
);
96 // add the special "uncompressed" type
97 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
99 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
100 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
101 types
.push_back("uncompressed");
107 // GetLanguages - Return Vector of Language Codes /*{{{*/
108 // ---------------------------------------------------------------------
109 /* return a vector of language codes in the prefered order.
110 the special word "environment" will be replaced with the long and the short
111 code of the local settings and it will be insured that this will not add
112 duplicates. So in an german local the setting "environment, de_DE, en, de"
113 will result in "de_DE, de, en".
114 The special word "none" is the stopcode for the not-All code vector */
115 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
116 bool const &Cached
, char const ** const Locale
) {
119 // The detection is boring and has a lot of cornercases,
120 // so we cache the results to calculated it only once.
121 std::vector
<string
> static allCodes
;
122 std::vector
<string
> static codes
;
124 // we have something in the cache
125 if (codes
.empty() == false || allCodes
.empty() == false) {
126 if (Cached
== true) {
127 if(All
== true && allCodes
.empty() == false)
137 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
138 // so they will be all included in the Cache.
139 std::vector
<string
> builtin
;
140 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
142 builtin
.push_back("none");
143 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
144 string
const name
= Ent
->d_name
;
145 size_t const foundDash
= name
.rfind("-");
146 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
147 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
148 foundDash
<= foundUnderscore
||
149 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
151 string
const c
= name
.substr(foundDash
+1);
152 if (unlikely(c
.empty() == true) || c
== "en")
154 // Skip unusual files, like backups or that alike
155 string::const_iterator s
= c
.begin();
156 for (;s
!= c
.end(); ++s
) {
157 if (isalpha(*s
) == 0 && *s
!= '_')
162 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
164 builtin
.push_back(c
);
169 // FIXME: Remove support for the old APT::Acquire::Translation
170 // it was undocumented and so it should be not very widthly used
171 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
172 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
173 // TRANSLATORS: the two %s are APT configuration options
174 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
175 "APT::Acquire::Translation", "Acquire::Languages");
176 if (oldAcquire
!= "none")
177 codes
.push_back(oldAcquire
);
178 codes
.push_back("en");
180 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
181 b
!= builtin
.end(); ++b
)
182 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
183 allCodes
.push_back(*b
);
190 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
191 // we extract both, a long and a short code and then we will
192 // check if we actually need both (rare) or if the short is enough
193 string
const envMsg
= string(Locale
== 0 ? std::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
194 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
195 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
197 string
const envLong
= envMsg
.substr(0,lenLong
);
198 string
const envShort
= envLong
.substr(0,lenShort
);
200 // It is very likely we will need the environment codes later,
201 // so let us generate them now from LC_MESSAGES and LANGUAGE
202 std::vector
<string
> environment
;
203 if (envShort
!= "C") {
204 // take care of LC_MESSAGES
205 if (envLong
!= envShort
)
206 environment
.push_back(envLong
);
207 environment
.push_back(envShort
);
208 // take care of LANGUAGE
209 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
210 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
211 if (envLang
.empty() == false) {
212 std::vector
<string
> env
= VectorizeString(envLang
,':');
213 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
214 for (std::vector
<string
>::const_iterator e
= env
.begin();
215 e
!= env
.end() && addedLangs
< 3; ++e
) {
216 if (unlikely(e
->empty() == true) || *e
== "en")
218 if (*e
== envLong
|| *e
== envShort
)
220 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
223 environment
.push_back(*e
);
227 environment
.push_back("en");
230 // Support settings like Acquire::Languages=none on the command line to
231 // override the configuration settings vector of languages.
232 string
const forceLang
= _config
->Find("Acquire::Languages","");
233 if (forceLang
.empty() == false) {
234 if (forceLang
== "environment") {
236 } else if (forceLang
!= "none")
237 codes
.push_back(forceLang
);
238 else //if (forceLang == "none")
241 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
242 b
!= builtin
.end(); ++b
)
243 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
244 allCodes
.push_back(*b
);
251 // cornercase: LANG=C, so we use only "en" Translation
252 if (envShort
== "C") {
253 allCodes
= codes
= environment
;
254 allCodes
.insert(allCodes
.end(), builtin
.begin(), builtin
.end());
261 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages");
262 // the default setting -> "environment, en"
263 if (lang
.empty() == true) {
265 if (envShort
!= "en")
266 codes
.push_back("en");
268 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
269 b
!= builtin
.end(); ++b
)
270 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
271 allCodes
.push_back(*b
);
278 // the configs define the order, so add the environment
279 // then needed and ensure the codes are not listed twice.
280 bool noneSeen
= false;
281 for (std::vector
<string
>::const_iterator l
= lang
.begin();
282 l
!= lang
.end(); ++l
) {
283 if (*l
== "environment") {
284 for (std::vector
<string
>::const_iterator e
= environment
.begin();
285 e
!= environment
.end(); ++e
) {
286 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
288 if (noneSeen
== false)
290 allCodes
.push_back(*e
);
293 } else if (*l
== "none") {
296 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
299 if (noneSeen
== false)
301 allCodes
.push_back(*l
);
304 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
305 b
!= builtin
.end(); ++b
)
306 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
307 allCodes
.push_back(*b
);
315 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
316 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
319 std::vector
<string
> static archs
;
320 if (likely(Cached
== true) && archs
.empty() == false)
323 string
const arch
= _config
->Find("APT::Architecture");
324 archs
= _config
->FindVector("APT::Architectures");
326 if (unlikely(arch
.empty() == true))
329 // FIXME: It is a bit unclean to have debian specific code here…
330 if (archs
.empty() == true) {
331 archs
.push_back(arch
);
333 // Generate the base argument list for dpkg
334 std::vector
<const char *> Args
;
335 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
337 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
338 size_t dpkgChrootLen
= dpkgChrootDir
.length();
339 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
340 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
342 Tmp
= Tmp
.substr(dpkgChrootLen
);
345 Args
.push_back(Tmp
.c_str());
347 // Stick in any custom dpkg options
348 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
351 for (; Opts
!= 0; Opts
= Opts
->Next
)
353 if (Opts
->Value
.empty() == true)
355 Args
.push_back(Opts
->Value
.c_str());
359 Args
.push_back("--print-foreign-architectures");
360 Args
.push_back(NULL
);
362 int external
[2] = {-1, -1};
363 if (pipe(external
) != 0)
365 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
369 pid_t dpkgMultiArch
= ExecFork();
370 if (dpkgMultiArch
== 0) {
372 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
373 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0)
374 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
375 int const nullfd
= open("/dev/null", O_RDONLY
);
376 dup2(nullfd
, STDIN_FILENO
);
377 dup2(external
[1], STDOUT_FILENO
);
378 dup2(nullfd
, STDERR_FILENO
);
379 execvp(Args
[0], (char**) &Args
[0]);
380 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
385 FILE *dpkg
= fdopen(external
[0], "r");
388 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
389 char* arch
= strtok(buf
, " ");
390 while (arch
!= NULL
) {
391 for (; isspace(*arch
) != 0; ++arch
);
392 if (arch
[0] != '\0') {
393 char const* archend
= arch
;
394 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
395 string
a(arch
, (archend
- arch
));
396 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
399 arch
= strtok(NULL
, " ");
404 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
408 if (archs
.empty() == true ||
409 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
410 archs
.insert(archs
.begin(), arch
);
412 // erase duplicates and empty strings
413 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
414 a
!= archs
.rend(); ++a
) {
415 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
416 archs
.erase(a
.base()-1);
417 if (a
== archs
.rend())
424 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
425 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
428 std::vector
<std::string
> const archs
= getArchitectures(true);
429 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
432 // setDefaultConfigurationForCompressors /*{{{*/
433 void Configuration::setDefaultConfigurationForCompressors() {
434 // Set default application paths to check for optional compression types
435 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
436 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
437 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
438 _config
->CndSet("Dir::Bin::lzma", _config
->Find("Dir::Bin::xz"));
439 _config
->Set("APT::Compressor::lzma::Binary", "xz");
440 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
441 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
442 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
444 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
445 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
446 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
449 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
450 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
451 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
452 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
454 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
455 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
456 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
461 // getCompressors - Return Vector of usbale compressors /*{{{*/
462 // ---------------------------------------------------------------------
463 /* return a vector of compressors used by apt-ftparchive in the
464 multicompress functionality or to detect data.tar files */
465 std::vector
<APT::Configuration::Compressor
>
466 const Configuration::getCompressors(bool const Cached
) {
467 static std::vector
<APT::Configuration::Compressor
> compressors
;
468 if (compressors
.empty() == false) {
475 setDefaultConfigurationForCompressors();
477 compressors
.push_back(Compressor(".", "", "", "", "", 1));
478 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
479 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
482 compressors
.push_back(Compressor("gzip",".gz","/bin/false", "", "", 2));
484 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
485 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
486 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
487 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
488 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
489 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
491 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
492 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
493 c
!= comp
.end(); ++c
) {
494 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
496 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
502 // getCompressorExtensions - supported data.tar extensions /*{{{*/
503 // ---------------------------------------------------------------------
505 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
506 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
507 std::vector
<std::string
> ext
;
508 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
509 c
!= compressors
.end(); ++c
)
510 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
511 ext
.push_back(c
->Extension
);
515 // Compressor constructor /*{{{*/
516 // ---------------------------------------------------------------------
518 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
520 char const *compressArg
, char const *uncompressArg
,
521 unsigned short const cost
) {
522 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
523 Name
= _config
->Find(std::string(config
).append("Name"), name
);
524 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
525 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
526 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
527 std::string
const compConf
= std::string(config
).append("CompressArg");
528 if (_config
->Exists(compConf
) == true)
529 CompressArgs
= _config
->FindVector(compConf
);
530 else if (compressArg
!= NULL
)
531 CompressArgs
.push_back(compressArg
);
532 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
533 if (_config
->Exists(uncompConf
) == true)
534 UncompressArgs
= _config
->FindVector(uncompConf
);
535 else if (uncompressArg
!= NULL
)
536 UncompressArgs
.push_back(uncompressArg
);