]>
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>
35 // setDefaultConfigurationForCompressors /*{{{*/
36 static void setDefaultConfigurationForCompressors() {
37 // Set default application paths to check for optional compression types
38 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
39 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
40 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
41 _config
->Set("Dir::Bin::lzma", _config
->FindFile("Dir::Bin::xz"));
42 _config
->Set("APT::Compressor::lzma::Binary", "xz");
43 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
44 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
45 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
47 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
48 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
49 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
52 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
53 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
54 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
55 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
57 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
58 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
59 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
64 // getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
65 // ---------------------------------------------------------------------
66 /* return a vector of compression types in the preferred order. */
67 std::vector
<std::string
>
68 const Configuration::getCompressionTypes(bool const &Cached
) {
69 static std::vector
<std::string
> types
;
70 if (types
.empty() == false) {
77 // setup the defaults for the compressiontypes => method mapping
78 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
79 _config
->CndSet("Acquire::CompressionTypes::xz","xz");
80 _config
->CndSet("Acquire::CompressionTypes::lzma","lzma");
81 _config
->CndSet("Acquire::CompressionTypes::gz","gzip");
83 setDefaultConfigurationForCompressors();
84 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
86 // load the order setting into our vector
87 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
88 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
89 o
!= order
.end(); ++o
) {
90 if ((*o
).empty() == true)
92 // ignore types we have no method ready to use
93 std::string
const method
= std::string("Acquire::CompressionTypes::").append(*o
);
94 if (_config
->Exists(method
) == false)
96 // ignore types we have no app ready to use
97 std::string
const app
= _config
->Find(method
);
98 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
99 for (; c
!= compressors
.end(); ++c
)
102 if (c
== compressors
.end())
107 // move again over the option tree to add all missing compression types
108 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
110 Types
= Types
->Child
;
112 for (; Types
!= 0; Types
= Types
->Next
) {
113 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
115 // ignore types we already have in the vector
116 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
118 // ignore types we have no app ready to use
119 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
120 for (; c
!= compressors
.end(); ++c
)
121 if (c
->Name
== Types
->Value
)
123 if (c
== compressors
.end())
125 types
.push_back(Types
->Tag
);
128 // add the special "uncompressed" type
129 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
131 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
132 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
133 types
.push_back("uncompressed");
139 // GetLanguages - Return Vector of Language Codes /*{{{*/
140 // ---------------------------------------------------------------------
141 /* return a vector of language codes in the preferred order.
142 the special word "environment" will be replaced with the long and the short
143 code of the local settings and it will be insured that this will not add
144 duplicates. So in an german local the setting "environment, de_DE, en, de"
145 will result in "de_DE, de, en".
146 The special word "none" is the stopcode for the not-All code vector */
147 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
148 bool const &Cached
, char const ** const Locale
) {
151 // The detection is boring and has a lot of cornercases,
152 // so we cache the results to calculated it only once.
153 std::vector
<string
> static allCodes
;
154 std::vector
<string
> static codes
;
156 // we have something in the cache
157 if (codes
.empty() == false || allCodes
.empty() == false) {
158 if (Cached
== true) {
159 if(All
== true && allCodes
.empty() == false)
169 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
170 // so they will be all included in the Cache.
171 std::vector
<string
> builtin
;
172 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
174 builtin
.push_back("none");
175 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
176 string
const name
= SubstVar(Ent
->d_name
, "%5f", "_");
177 size_t const foundDash
= name
.rfind("-");
178 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
179 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
180 foundDash
<= foundUnderscore
||
181 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
183 string
const c
= name
.substr(foundDash
+1);
184 if (unlikely(c
.empty() == true) || c
== "en")
186 // Skip unusual files, like backups or that alike
187 string::const_iterator s
= c
.begin();
188 for (;s
!= c
.end(); ++s
) {
189 if (isalpha(*s
) == 0 && *s
!= '_')
194 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
196 builtin
.push_back(c
);
201 // FIXME: Remove support for the old APT::Acquire::Translation
202 // it was undocumented and so it should be not very widthly used
203 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
204 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
205 // TRANSLATORS: the two %s are APT configuration options
206 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
207 "APT::Acquire::Translation", "Acquire::Languages");
208 if (oldAcquire
!= "none")
209 codes
.push_back(oldAcquire
);
210 codes
.push_back("en");
212 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
213 b
!= builtin
.end(); ++b
)
214 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
215 allCodes
.push_back(*b
);
222 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
223 // we extract both, a long and a short code and then we will
224 // check if we actually need both (rare) or if the short is enough
225 string
const envMsg
= string(Locale
== 0 ? std::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
226 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
227 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
229 string
const envLong
= envMsg
.substr(0,lenLong
);
230 string
const envShort
= envLong
.substr(0,lenShort
);
232 // It is very likely we will need the environment codes later,
233 // so let us generate them now from LC_MESSAGES and LANGUAGE
234 std::vector
<string
> environment
;
235 if (envShort
!= "C") {
236 // take care of LC_MESSAGES
237 if (envLong
!= envShort
)
238 environment
.push_back(envLong
);
239 environment
.push_back(envShort
);
240 // take care of LANGUAGE
241 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
242 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
243 if (envLang
.empty() == false) {
244 std::vector
<string
> env
= VectorizeString(envLang
,':');
245 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
246 for (std::vector
<string
>::const_iterator e
= env
.begin();
247 e
!= env
.end() && addedLangs
< 3; ++e
) {
248 if (unlikely(e
->empty() == true) || *e
== "en")
250 if (*e
== envLong
|| *e
== envShort
)
252 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
255 environment
.push_back(*e
);
259 // cornercase: LANG=C, so we use only "en" Translation
260 environment
.push_back("en");
263 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages", "environment,en");
264 // the configs define the order, so add the environment
265 // then needed and ensure the codes are not listed twice.
266 bool noneSeen
= false;
267 for (std::vector
<string
>::const_iterator l
= lang
.begin();
268 l
!= lang
.end(); ++l
) {
269 if (*l
== "environment") {
270 for (std::vector
<string
>::const_iterator e
= environment
.begin();
271 e
!= environment
.end(); ++e
) {
272 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
274 if (noneSeen
== false)
276 allCodes
.push_back(*e
);
279 } else if (*l
== "none") {
282 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
285 if (noneSeen
== false)
287 allCodes
.push_back(*l
);
290 if (allCodes
.empty() == false) {
291 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
292 b
!= builtin
.end(); ++b
)
293 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
294 allCodes
.push_back(*b
);
297 allCodes
.push_back("none");
306 // checkLanguage - are we interested in the given Language? /*{{{*/
307 bool Configuration::checkLanguage(std::string Lang
, bool const All
) {
308 // the empty Language is always interesting as it is the original
309 if (Lang
.empty() == true)
311 // filenames are encoded, so undo this
312 Lang
= SubstVar(Lang
, "%5f", "_");
313 std::vector
<std::string
> const langs
= getLanguages(All
, true);
314 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
317 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
318 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
321 std::vector
<string
> static archs
;
322 if (likely(Cached
== true) && archs
.empty() == false)
325 string
const arch
= _config
->Find("APT::Architecture");
326 archs
= _config
->FindVector("APT::Architectures");
328 if (unlikely(arch
.empty() == true))
331 // FIXME: It is a bit unclean to have debian specific code here…
332 if (archs
.empty() == true) {
333 archs
.push_back(arch
);
335 // Generate the base argument list for dpkg
336 std::vector
<const char *> Args
;
337 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
339 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
340 size_t dpkgChrootLen
= dpkgChrootDir
.length();
341 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
342 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
344 Tmp
= Tmp
.substr(dpkgChrootLen
);
347 Args
.push_back(Tmp
.c_str());
349 // Stick in any custom dpkg options
350 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
353 for (; Opts
!= 0; Opts
= Opts
->Next
)
355 if (Opts
->Value
.empty() == true)
357 Args
.push_back(Opts
->Value
.c_str());
361 Args
.push_back("--print-foreign-architectures");
362 Args
.push_back(NULL
);
364 int external
[2] = {-1, -1};
365 if (pipe(external
) != 0)
367 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
371 pid_t dpkgMultiArch
= ExecFork();
372 if (dpkgMultiArch
== 0) {
374 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
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 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
380 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
381 execvp(Args
[0], (char**) &Args
[0]);
382 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
387 FILE *dpkg
= fdopen(external
[0], "r");
390 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
391 char* arch
= strtok(buf
, " ");
392 while (arch
!= NULL
) {
393 for (; isspace(*arch
) != 0; ++arch
);
394 if (arch
[0] != '\0') {
395 char const* archend
= arch
;
396 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
397 string
a(arch
, (archend
- arch
));
398 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
401 arch
= strtok(NULL
, " ");
406 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
410 if (archs
.empty() == true ||
411 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
412 archs
.insert(archs
.begin(), arch
);
414 // erase duplicates and empty strings
415 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
416 a
!= archs
.rend(); ++a
) {
417 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
418 archs
.erase(a
.base()-1);
419 if (a
== archs
.rend())
426 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
427 bool Configuration::checkArchitecture(std::string
const &Arch
) {
430 std::vector
<std::string
> const archs
= getArchitectures(true);
431 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
434 // getCompressors - Return Vector of usealbe compressors /*{{{*/
435 // ---------------------------------------------------------------------
436 /* return a vector of compressors used by apt-ftparchive in the
437 multicompress functionality or to detect data.tar files */
438 std::vector
<APT::Configuration::Compressor
>
439 const Configuration::getCompressors(bool const Cached
) {
440 static std::vector
<APT::Configuration::Compressor
> compressors
;
441 if (compressors
.empty() == false) {
448 setDefaultConfigurationForCompressors();
450 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
451 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
452 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
455 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 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));
461 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
463 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
464 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
467 compressors
.push_back(Compressor("xz",".xz","false", NULL
, NULL
, 4));
469 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
470 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
473 compressors
.push_back(Compressor("lzma",".lzma","false", NULL
, NULL
, 5));
476 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
477 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
478 c
!= comp
.end(); ++c
) {
479 if (c
->empty() || *c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
481 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
487 // getCompressorExtensions - supported data.tar extensions /*{{{*/
488 // ---------------------------------------------------------------------
490 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
491 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
492 std::vector
<std::string
> ext
;
493 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
494 c
!= compressors
.end(); ++c
)
495 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
496 ext
.push_back(c
->Extension
);
500 // Compressor constructor /*{{{*/
501 // ---------------------------------------------------------------------
503 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
505 char const *compressArg
, char const *uncompressArg
,
506 unsigned short const cost
) {
507 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
508 Name
= _config
->Find(std::string(config
).append("Name"), name
);
509 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
510 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
511 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
512 std::string
const compConf
= std::string(config
).append("CompressArg");
513 if (_config
->Exists(compConf
) == true)
514 CompressArgs
= _config
->FindVector(compConf
);
515 else if (compressArg
!= NULL
)
516 CompressArgs
.push_back(compressArg
);
517 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
518 if (_config
->Exists(uncompConf
) == true)
519 UncompressArgs
= _config
->FindVector(uncompConf
);
520 else if (uncompressArg
!= NULL
)
521 UncompressArgs
.push_back(uncompressArg
);
524 // getBuildProfiles - return a vector of enabled build profiles /*{{{*/
525 std::vector
<std::string
> const Configuration::getBuildProfiles() {
526 // order is: override value (~= commandline), environment variable, list (~= config file)
527 std::string profiles_env
= getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
528 if (profiles_env
.empty() == false) {
529 profiles_env
= SubstVar(profiles_env
, " ", ",");
530 std::string
const bp
= _config
->Find("APT::Build-Profiles");
531 _config
->Clear("APT::Build-Profiles");
532 if (bp
.empty() == false)
533 _config
->Set("APT::Build-Profiles", bp
);
535 return _config
->FindVector("APT::Build-Profiles", profiles_env
);
537 std::string
const Configuration::getBuildProfilesString() {
538 std::vector
<std::string
> profiles
= getBuildProfiles();
539 if (profiles
.empty() == true)
541 std::vector
<std::string
>::const_iterator p
= profiles
.begin();
542 std::string list
= *p
;
543 for (++p
; p
!= profiles
.end(); ++p
)
544 list
.append(",").append(*p
);