]>
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::xz","xz");
78 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
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 if (std::find_if(compressors
.begin(), compressors
.end(), [&app
](APT::Configuration::Compressor
const &c
) {
99 }) == compressors
.end())
104 // move again over the option tree to add all missing compression types
105 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
107 Types
= Types
->Child
;
109 for (; Types
!= 0; Types
= Types
->Next
) {
110 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
112 // ignore types we already have in the vector
113 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
115 // ignore types we have no app ready to use
116 if (std::find_if(compressors
.begin(), compressors
.end(), [&Types
](APT::Configuration::Compressor
const &c
) {
117 return c
.Name
== Types
->Value
;
118 }) == compressors
.end())
120 types
.push_back(Types
->Tag
);
123 // add the special "uncompressed" type
124 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
126 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
127 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
128 types
.push_back("uncompressed");
134 // GetLanguages - Return Vector of Language Codes /*{{{*/
135 // ---------------------------------------------------------------------
136 /* return a vector of language codes in the preferred order.
137 the special word "environment" will be replaced with the long and the short
138 code of the local settings and it will be insured that this will not add
139 duplicates. So in an german local the setting "environment, de_DE, en, de"
140 will result in "de_DE, de, en".
141 The special word "none" is the stopcode for the not-All code vector */
142 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
143 bool const &Cached
, char const ** const Locale
) {
146 // The detection is boring and has a lot of cornercases,
147 // so we cache the results to calculated it only once.
148 std::vector
<string
> static allCodes
;
149 std::vector
<string
> static codes
;
151 // we have something in the cache
152 if (codes
.empty() == false || allCodes
.empty() == false) {
153 if (Cached
== true) {
154 if(All
== true && allCodes
.empty() == false)
164 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
165 // so they will be all included in the Cache.
166 std::vector
<string
> builtin
;
167 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
169 builtin
.push_back("none");
170 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
171 string
const name
= SubstVar(Ent
->d_name
, "%5f", "_");
172 size_t const foundDash
= name
.rfind("-");
173 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
174 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
175 foundDash
<= foundUnderscore
||
176 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
178 string
const c
= name
.substr(foundDash
+1);
179 if (unlikely(c
.empty() == true) || c
== "en")
181 // Skip unusual files, like backups or that alike
182 string::const_iterator s
= c
.begin();
183 for (;s
!= c
.end(); ++s
) {
184 if (isalpha(*s
) == 0 && *s
!= '_')
189 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
191 builtin
.push_back(c
);
196 // FIXME: Remove support for the old APT::Acquire::Translation
197 // it was undocumented and so it should be not very widthly used
198 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
199 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
200 // TRANSLATORS: the two %s are APT configuration options
201 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
202 "APT::Acquire::Translation", "Acquire::Languages");
203 if (oldAcquire
!= "none")
204 codes
.push_back(oldAcquire
);
205 codes
.push_back("en");
207 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
208 b
!= builtin
.end(); ++b
)
209 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
210 allCodes
.push_back(*b
);
217 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
218 // we extract both, a long and a short code and then we will
219 // check if we actually need both (rare) or if the short is enough
220 string
const envMsg
= string(Locale
== 0 ? ::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
221 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
222 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
224 string
const envLong
= envMsg
.substr(0,lenLong
);
225 string
const envShort
= envLong
.substr(0,lenShort
);
227 // It is very likely we will need the environment codes later,
228 // so let us generate them now from LC_MESSAGES and LANGUAGE
229 std::vector
<string
> environment
;
230 if (envShort
!= "C") {
231 // take care of LC_MESSAGES
232 if (envLong
!= envShort
)
233 environment
.push_back(envLong
);
234 environment
.push_back(envShort
);
235 // take care of LANGUAGE
236 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
237 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
238 if (envLang
.empty() == false) {
239 std::vector
<string
> env
= VectorizeString(envLang
,':');
240 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
241 for (std::vector
<string
>::const_iterator e
= env
.begin();
242 e
!= env
.end() && addedLangs
< 3; ++e
) {
243 if (unlikely(e
->empty() == true) || *e
== "en")
245 if (*e
== envLong
|| *e
== envShort
)
247 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
250 environment
.push_back(*e
);
254 // cornercase: LANG=C, so we use only "en" Translation
255 environment
.push_back("en");
258 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages", "environment,en");
259 // the configs define the order, so add the environment
260 // then needed and ensure the codes are not listed twice.
261 bool noneSeen
= false;
262 for (std::vector
<string
>::const_iterator l
= lang
.begin();
263 l
!= lang
.end(); ++l
) {
264 if (*l
== "environment") {
265 for (std::vector
<string
>::const_iterator e
= environment
.begin();
266 e
!= environment
.end(); ++e
) {
267 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
269 if (noneSeen
== false)
271 allCodes
.push_back(*e
);
274 } else if (*l
== "none") {
277 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
280 if (noneSeen
== false)
282 allCodes
.push_back(*l
);
285 if (allCodes
.empty() == false) {
286 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
287 b
!= builtin
.end(); ++b
)
288 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
289 allCodes
.push_back(*b
);
292 allCodes
.push_back("none");
301 // checkLanguage - are we interested in the given Language? /*{{{*/
302 bool Configuration::checkLanguage(std::string Lang
, bool const All
) {
303 // the empty Language is always interesting as it is the original
304 if (Lang
.empty() == true)
306 // filenames are encoded, so undo this
307 Lang
= SubstVar(Lang
, "%5f", "_");
308 std::vector
<std::string
> const langs
= getLanguages(All
, true);
309 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
312 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
313 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
316 std::vector
<string
> static archs
;
317 if (likely(Cached
== true) && archs
.empty() == false)
320 string
const arch
= _config
->Find("APT::Architecture");
321 archs
= _config
->FindVector("APT::Architectures");
323 if (unlikely(arch
.empty() == true))
326 // FIXME: It is a bit unclean to have debian specific code here…
327 if (archs
.empty() == true) {
328 archs
.push_back(arch
);
330 // Generate the base argument list for dpkg
331 std::vector
<const char *> Args
;
332 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
334 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
335 size_t dpkgChrootLen
= dpkgChrootDir
.length();
336 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
337 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
339 Tmp
= Tmp
.substr(dpkgChrootLen
);
342 Args
.push_back(Tmp
.c_str());
344 // Stick in any custom dpkg options
345 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
348 for (; Opts
!= 0; Opts
= Opts
->Next
)
350 if (Opts
->Value
.empty() == true)
352 Args
.push_back(Opts
->Value
.c_str());
356 Args
.push_back("--print-foreign-architectures");
357 Args
.push_back(NULL
);
359 int external
[2] = {-1, -1};
360 if (pipe(external
) != 0)
362 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
366 pid_t dpkgMultiArch
= ExecFork();
367 if (dpkgMultiArch
== 0) {
369 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
370 int const nullfd
= open("/dev/null", O_RDONLY
);
371 dup2(nullfd
, STDIN_FILENO
);
372 dup2(external
[1], STDOUT_FILENO
);
373 dup2(nullfd
, STDERR_FILENO
);
374 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
375 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
376 execvp(Args
[0], (char**) &Args
[0]);
377 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
382 FILE *dpkg
= fdopen(external
[0], "r");
386 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
387 char* arch
= strtok_r(buf
, " ", &tok_buf
);
388 while (arch
!= NULL
) {
389 for (; isspace(*arch
) != 0; ++arch
);
390 if (arch
[0] != '\0') {
391 char const* archend
= arch
;
392 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
393 string
a(arch
, (archend
- arch
));
394 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
397 arch
= strtok_r(NULL
, " ", &tok_buf
);
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 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 // getCompressors - Return Vector of usealbe compressors /*{{{*/
431 // ---------------------------------------------------------------------
432 /* return a vector of compressors used by apt-ftparchive in the
433 multicompress functionality or to detect data.tar files */
434 std::vector
<APT::Configuration::Compressor
>
435 const Configuration::getCompressors(bool const Cached
) {
436 static std::vector
<APT::Configuration::Compressor
> compressors
;
437 if (compressors
.empty() == false) {
444 setDefaultConfigurationForCompressors();
446 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
447 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
448 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
451 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
453 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
454 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",3));
457 compressors
.push_back(Compressor("xz",".xz","false", NULL
, NULL
, 3));
459 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
460 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",4));
463 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 4));
465 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
466 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
469 compressors
.push_back(Compressor("lzma",".lzma","false", NULL
, NULL
, 5));
472 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
473 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
474 c
!= comp
.end(); ++c
) {
475 if (c
->empty() || *c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
477 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
483 // getCompressorExtensions - supported data.tar extensions /*{{{*/
484 // ---------------------------------------------------------------------
486 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
487 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
488 std::vector
<std::string
> ext
;
489 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
490 c
!= compressors
.end(); ++c
)
491 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
492 ext
.push_back(c
->Extension
);
496 // Compressor constructor /*{{{*/
497 // ---------------------------------------------------------------------
499 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
501 char const *compressArg
, char const *uncompressArg
,
502 unsigned short const cost
) {
503 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
504 Name
= _config
->Find(std::string(config
).append("Name"), name
);
505 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
506 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
507 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
508 std::string
const compConf
= std::string(config
).append("CompressArg");
509 if (_config
->Exists(compConf
) == true)
510 CompressArgs
= _config
->FindVector(compConf
);
511 else if (compressArg
!= NULL
)
512 CompressArgs
.push_back(compressArg
);
513 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
514 if (_config
->Exists(uncompConf
) == true)
515 UncompressArgs
= _config
->FindVector(uncompConf
);
516 else if (uncompressArg
!= NULL
)
517 UncompressArgs
.push_back(uncompressArg
);
520 // getBuildProfiles - return a vector of enabled build profiles /*{{{*/
521 std::vector
<std::string
> const Configuration::getBuildProfiles() {
522 // order is: override value (~= commandline), environment variable, list (~= config file)
523 std::string profiles_env
= getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
524 if (profiles_env
.empty() == false) {
525 profiles_env
= SubstVar(profiles_env
, " ", ",");
526 std::string
const bp
= _config
->Find("APT::Build-Profiles");
527 _config
->Clear("APT::Build-Profiles");
528 if (bp
.empty() == false)
529 _config
->Set("APT::Build-Profiles", bp
);
531 return _config
->FindVector("APT::Build-Profiles", profiles_env
);
533 std::string
const Configuration::getBuildProfilesString() {
534 std::vector
<std::string
> profiles
= getBuildProfiles();
535 if (profiles
.empty() == true)
537 std::vector
<std::string
>::const_iterator p
= profiles
.begin();
538 std::string list
= *p
;
539 for (++p
; p
!= profiles
.end(); ++p
)
540 list
.append(",").append(*p
);