]>
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>
34 // setDefaultConfigurationForCompressors /*{{{*/
35 static void setDefaultConfigurationForCompressors() {
36 // Set default application paths to check for optional compression types
37 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
38 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
39 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
40 _config
->Set("Dir::Bin::lzma", _config
->FindFile("Dir::Bin::xz"));
41 _config
->Set("APT::Compressor::lzma::Binary", "xz");
42 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
43 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
44 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
46 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
47 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
48 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
51 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
52 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
53 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
54 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
56 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
57 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
58 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
63 // getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
64 // ---------------------------------------------------------------------
65 /* return a vector of compression types in the preferred order. */
66 std::vector
<std::string
>
67 const Configuration::getCompressionTypes(bool const &Cached
) {
68 static std::vector
<std::string
> types
;
69 if (types
.empty() == false) {
76 // setup the defaults for the compressiontypes => method mapping
77 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
78 _config
->CndSet("Acquire::CompressionTypes::xz","xz");
79 _config
->CndSet("Acquire::CompressionTypes::lzma","lzma");
80 _config
->CndSet("Acquire::CompressionTypes::gz","gzip");
82 setDefaultConfigurationForCompressors();
83 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
85 // load the order setting into our vector
86 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
87 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
88 o
!= order
.end(); ++o
) {
89 if ((*o
).empty() == true)
91 // ignore types we have no method ready to use
92 std::string
const method
= std::string("Acquire::CompressionTypes::").append(*o
);
93 if (_config
->Exists(method
) == false)
95 // ignore types we have no app ready to use
96 std::string
const app
= _config
->Find(method
);
97 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
98 for (; c
!= compressors
.end(); ++c
)
101 if (c
== compressors
.end())
106 // move again over the option tree to add all missing compression types
107 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
109 Types
= Types
->Child
;
111 for (; Types
!= 0; Types
= Types
->Next
) {
112 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
114 // ignore types we already have in the vector
115 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
117 // ignore types we have no app ready to use
118 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
119 for (; c
!= compressors
.end(); ++c
)
120 if (c
->Name
== Types
->Value
)
122 if (c
== compressors
.end())
124 types
.push_back(Types
->Tag
);
127 // add the special "uncompressed" type
128 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
130 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
131 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
132 types
.push_back("uncompressed");
138 // GetLanguages - Return Vector of Language Codes /*{{{*/
139 // ---------------------------------------------------------------------
140 /* return a vector of language codes in the preferred order.
141 the special word "environment" will be replaced with the long and the short
142 code of the local settings and it will be insured that this will not add
143 duplicates. So in an german local the setting "environment, de_DE, en, de"
144 will result in "de_DE, de, en".
145 The special word "none" is the stopcode for the not-All code vector */
146 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
147 bool const &Cached
, char const ** const Locale
) {
150 // The detection is boring and has a lot of cornercases,
151 // so we cache the results to calculated it only once.
152 std::vector
<string
> static allCodes
;
153 std::vector
<string
> static codes
;
155 // we have something in the cache
156 if (codes
.empty() == false || allCodes
.empty() == false) {
157 if (Cached
== true) {
158 if(All
== true && allCodes
.empty() == false)
168 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
169 // so they will be all included in the Cache.
170 std::vector
<string
> builtin
;
171 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
173 builtin
.push_back("none");
174 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
175 string
const name
= SubstVar(Ent
->d_name
, "%5f", "_");
176 size_t const foundDash
= name
.rfind("-");
177 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
178 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
179 foundDash
<= foundUnderscore
||
180 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
182 string
const c
= name
.substr(foundDash
+1);
183 if (unlikely(c
.empty() == true) || c
== "en")
185 // Skip unusual files, like backups or that alike
186 string::const_iterator s
= c
.begin();
187 for (;s
!= c
.end(); ++s
) {
188 if (isalpha(*s
) == 0 && *s
!= '_')
193 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
195 builtin
.push_back(c
);
200 // FIXME: Remove support for the old APT::Acquire::Translation
201 // it was undocumented and so it should be not very widthly used
202 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
203 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
204 // TRANSLATORS: the two %s are APT configuration options
205 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
206 "APT::Acquire::Translation", "Acquire::Languages");
207 if (oldAcquire
!= "none")
208 codes
.push_back(oldAcquire
);
209 codes
.push_back("en");
211 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
212 b
!= builtin
.end(); ++b
)
213 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
214 allCodes
.push_back(*b
);
221 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
222 // we extract both, a long and a short code and then we will
223 // check if we actually need both (rare) or if the short is enough
224 string
const envMsg
= string(Locale
== 0 ? ::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
225 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
226 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
228 string
const envLong
= envMsg
.substr(0,lenLong
);
229 string
const envShort
= envLong
.substr(0,lenShort
);
231 // It is very likely we will need the environment codes later,
232 // so let us generate them now from LC_MESSAGES and LANGUAGE
233 std::vector
<string
> environment
;
234 if (envShort
!= "C") {
235 // take care of LC_MESSAGES
236 if (envLong
!= envShort
)
237 environment
.push_back(envLong
);
238 environment
.push_back(envShort
);
239 // take care of LANGUAGE
240 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
241 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
242 if (envLang
.empty() == false) {
243 std::vector
<string
> env
= VectorizeString(envLang
,':');
244 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
245 for (std::vector
<string
>::const_iterator e
= env
.begin();
246 e
!= env
.end() && addedLangs
< 3; ++e
) {
247 if (unlikely(e
->empty() == true) || *e
== "en")
249 if (*e
== envLong
|| *e
== envShort
)
251 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
254 environment
.push_back(*e
);
258 // cornercase: LANG=C, so we use only "en" Translation
259 environment
.push_back("en");
262 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages", "environment,en");
263 // the configs define the order, so add the environment
264 // then needed and ensure the codes are not listed twice.
265 bool noneSeen
= false;
266 for (std::vector
<string
>::const_iterator l
= lang
.begin();
267 l
!= lang
.end(); ++l
) {
268 if (*l
== "environment") {
269 for (std::vector
<string
>::const_iterator e
= environment
.begin();
270 e
!= environment
.end(); ++e
) {
271 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
273 if (noneSeen
== false)
275 allCodes
.push_back(*e
);
278 } else if (*l
== "none") {
281 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
284 if (noneSeen
== false)
286 allCodes
.push_back(*l
);
289 if (allCodes
.empty() == false) {
290 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
291 b
!= builtin
.end(); ++b
)
292 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
293 allCodes
.push_back(*b
);
296 allCodes
.push_back("none");
305 // checkLanguage - are we interested in the given Language? /*{{{*/
306 bool Configuration::checkLanguage(std::string Lang
, bool const All
) {
307 // the empty Language is always interesting as it is the original
308 if (Lang
.empty() == true)
310 // filenames are encoded, so undo this
311 Lang
= SubstVar(Lang
, "%5f", "_");
312 std::vector
<std::string
> const langs
= getLanguages(All
, true);
313 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
316 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
317 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
320 std::vector
<string
> static archs
;
321 if (likely(Cached
== true) && archs
.empty() == false)
324 string
const arch
= _config
->Find("APT::Architecture");
325 archs
= _config
->FindVector("APT::Architectures");
327 if (unlikely(arch
.empty() == true))
330 // FIXME: It is a bit unclean to have debian specific code here…
331 if (archs
.empty() == true) {
332 archs
.push_back(arch
);
334 // Generate the base argument list for dpkg
335 std::vector
<const char *> Args
;
336 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
338 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
339 size_t dpkgChrootLen
= dpkgChrootDir
.length();
340 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
341 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
343 Tmp
= Tmp
.substr(dpkgChrootLen
);
346 Args
.push_back(Tmp
.c_str());
348 // Stick in any custom dpkg options
349 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
352 for (; Opts
!= 0; Opts
= Opts
->Next
)
354 if (Opts
->Value
.empty() == true)
356 Args
.push_back(Opts
->Value
.c_str());
360 Args
.push_back("--print-foreign-architectures");
361 Args
.push_back(NULL
);
363 int external
[2] = {-1, -1};
364 if (pipe(external
) != 0)
366 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
370 pid_t dpkgMultiArch
= ExecFork();
371 if (dpkgMultiArch
== 0) {
373 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
374 int const nullfd
= open("/dev/null", O_RDONLY
);
375 dup2(nullfd
, STDIN_FILENO
);
376 dup2(external
[1], STDOUT_FILENO
);
377 dup2(nullfd
, STDERR_FILENO
);
378 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
379 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
380 execvp(Args
[0], (char**) &Args
[0]);
381 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
386 FILE *dpkg
= fdopen(external
[0], "r");
389 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
390 char* arch
= strtok(buf
, " ");
391 while (arch
!= NULL
) {
392 for (; isspace(*arch
) != 0; ++arch
);
393 if (arch
[0] != '\0') {
394 char const* archend
= arch
;
395 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
396 string
a(arch
, (archend
- arch
));
397 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
400 arch
= strtok(NULL
, " ");
405 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
409 if (archs
.empty() == true ||
410 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
411 archs
.insert(archs
.begin(), arch
);
413 // erase duplicates and empty strings
414 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
415 a
!= archs
.rend(); ++a
) {
416 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
417 archs
.erase(a
.base()-1);
418 if (a
== archs
.rend())
425 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
426 bool Configuration::checkArchitecture(std::string
const &Arch
) {
429 std::vector
<std::string
> const archs
= getArchitectures(true);
430 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
433 // getCompressors - Return Vector of usealbe compressors /*{{{*/
434 // ---------------------------------------------------------------------
435 /* return a vector of compressors used by apt-ftparchive in the
436 multicompress functionality or to detect data.tar files */
437 std::vector
<APT::Configuration::Compressor
>
438 const Configuration::getCompressors(bool const Cached
) {
439 static std::vector
<APT::Configuration::Compressor
> compressors
;
440 if (compressors
.empty() == false) {
447 setDefaultConfigurationForCompressors();
449 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
450 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
451 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
454 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
456 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
457 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
460 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
462 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
463 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
466 compressors
.push_back(Compressor("xz",".xz","false", NULL
, NULL
, 4));
468 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
469 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
472 compressors
.push_back(Compressor("lzma",".lzma","false", NULL
, NULL
, 5));
475 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
476 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
477 c
!= comp
.end(); ++c
) {
478 if (c
->empty() || *c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
480 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
486 // getCompressorExtensions - supported data.tar extensions /*{{{*/
487 // ---------------------------------------------------------------------
489 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
490 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
491 std::vector
<std::string
> ext
;
492 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
493 c
!= compressors
.end(); ++c
)
494 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
495 ext
.push_back(c
->Extension
);
499 // Compressor constructor /*{{{*/
500 // ---------------------------------------------------------------------
502 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
504 char const *compressArg
, char const *uncompressArg
,
505 unsigned short const cost
) {
506 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
507 Name
= _config
->Find(std::string(config
).append("Name"), name
);
508 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
509 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
510 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
511 std::string
const compConf
= std::string(config
).append("CompressArg");
512 if (_config
->Exists(compConf
) == true)
513 CompressArgs
= _config
->FindVector(compConf
);
514 else if (compressArg
!= NULL
)
515 CompressArgs
.push_back(compressArg
);
516 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
517 if (_config
->Exists(uncompConf
) == true)
518 UncompressArgs
= _config
->FindVector(uncompConf
);
519 else if (uncompressArg
!= NULL
)
520 UncompressArgs
.push_back(uncompressArg
);
523 // getBuildProfiles - return a vector of enabled build profiles /*{{{*/
524 std::vector
<std::string
> const Configuration::getBuildProfiles() {
525 // order is: override value (~= commandline), environment variable, list (~= config file)
526 std::string profiles_env
= getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
527 if (profiles_env
.empty() == false) {
528 profiles_env
= SubstVar(profiles_env
, " ", ",");
529 std::string
const bp
= _config
->Find("APT::Build-Profiles");
530 _config
->Clear("APT::Build-Profiles");
531 if (bp
.empty() == false)
532 _config
->Set("APT::Build-Profiles", bp
);
534 return _config
->FindVector("APT::Build-Profiles", profiles_env
);
536 std::string
const Configuration::getBuildProfilesString() {
537 std::vector
<std::string
> profiles
= getBuildProfiles();
538 if (profiles
.empty() == true)
540 std::vector
<std::string
>::const_iterator p
= profiles
.begin();
541 std::string list
= *p
;
542 for (++p
; p
!= profiles
.end(); ++p
)
543 list
.append(",").append(*p
);