]>
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();
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 execv(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 archs
.push_back(string(arch
, (archend
- arch
)));
397 arch
= strtok(NULL
, " ");
402 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
406 if (archs
.empty() == true ||
407 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
408 archs
.insert(archs
.begin(), arch
);
410 // erase duplicates and empty strings
411 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
412 a
!= archs
.rend(); ++a
) {
413 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
414 archs
.erase(a
.base()-1);
415 if (a
== archs
.rend())
422 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
423 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
426 std::vector
<std::string
> const archs
= getArchitectures(true);
427 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
430 // setDefaultConfigurationForCompressors /*{{{*/
431 void Configuration::setDefaultConfigurationForCompressors() {
432 // Set default application paths to check for optional compression types
433 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
434 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
435 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
438 // getCompressors - Return Vector of usbale compressors /*{{{*/
439 // ---------------------------------------------------------------------
440 /* return a vector of compressors used by apt-ftparchive in the
441 multicompress functionality or to detect data.tar files */
442 std::vector
<APT::Configuration::Compressor
>
443 const Configuration::getCompressors(bool const Cached
) {
444 static std::vector
<APT::Configuration::Compressor
> compressors
;
445 if (compressors
.empty() == false) {
452 setDefaultConfigurationForCompressors();
454 compressors
.push_back(Compressor(".", "", "", "", "", 1));
455 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
456 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",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));
459 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
460 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",4));
461 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
462 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",5));
464 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
465 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
466 c
!= comp
.end(); ++c
) {
467 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
469 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
475 // getCompressorExtensions - supported data.tar extensions /*{{{*/
476 // ---------------------------------------------------------------------
478 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
479 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
480 std::vector
<std::string
> ext
;
481 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
482 c
!= compressors
.end(); ++c
)
483 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
484 ext
.push_back(c
->Extension
);
488 // Compressor constructor /*{{{*/
489 // ---------------------------------------------------------------------
491 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
493 char const *compressArg
, char const *uncompressArg
,
494 unsigned short const cost
) {
495 std::string
const config
= std::string("APT:Compressor::").append(name
).append("::");
496 Name
= _config
->Find(std::string(config
).append("Name"), name
);
497 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
498 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
499 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
500 std::string
const compConf
= std::string(config
).append("CompressArg");
501 if (_config
->Exists(compConf
) == true)
502 CompressArgs
= _config
->FindVector(compConf
);
503 else if (compressArg
!= NULL
)
504 CompressArgs
.push_back(compressArg
);
505 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
506 if (_config
->Exists(uncompConf
) == true)
507 UncompressArgs
= _config
->FindVector(uncompConf
);
508 else if (uncompressArg
!= NULL
)
509 UncompressArgs
.push_back(uncompressArg
);