]>
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 usable compressiontypes /*{{{*/
31 // ---------------------------------------------------------------------
32 /* return a vector of compression types in the preferred 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();
50 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
52 // load the order setting into our vector
53 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
54 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
55 o
!= order
.end(); ++o
) {
56 if ((*o
).empty() == true)
58 // ignore types we have no method ready to use
59 std::string
const method
= std::string("Acquire::CompressionTypes::").append(*o
);
60 if (_config
->Exists(method
) == false)
62 // ignore types we have no app ready to use
63 std::string
const app
= _config
->Find(method
);
64 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
65 for (; c
!= compressors
.end(); ++c
)
68 if (c
== compressors
.end())
73 // move again over the option tree to add all missing compression types
74 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
78 for (; Types
!= 0; Types
= Types
->Next
) {
79 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
81 // ignore types we already have in the vector
82 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
84 // ignore types we have no app ready to use
85 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
86 for (; c
!= compressors
.end(); ++c
)
87 if (c
->Name
== Types
->Value
)
89 if (c
== compressors
.end())
91 types
.push_back(Types
->Tag
);
94 // add the special "uncompressed" type
95 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
97 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
98 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
99 types
.push_back("uncompressed");
105 // GetLanguages - Return Vector of Language Codes /*{{{*/
106 // ---------------------------------------------------------------------
107 /* return a vector of language codes in the preferred order.
108 the special word "environment" will be replaced with the long and the short
109 code of the local settings and it will be insured that this will not add
110 duplicates. So in an german local the setting "environment, de_DE, en, de"
111 will result in "de_DE, de, en".
112 The special word "none" is the stopcode for the not-All code vector */
113 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
114 bool const &Cached
, char const ** const Locale
) {
117 // The detection is boring and has a lot of cornercases,
118 // so we cache the results to calculated it only once.
119 std::vector
<string
> static allCodes
;
120 std::vector
<string
> static codes
;
122 // we have something in the cache
123 if (codes
.empty() == false || allCodes
.empty() == false) {
124 if (Cached
== true) {
125 if(All
== true && allCodes
.empty() == false)
135 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
136 // so they will be all included in the Cache.
137 std::vector
<string
> builtin
;
138 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
140 builtin
.push_back("none");
141 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
142 string
const name
= SubstVar(Ent
->d_name
, "%5f", "_");
143 size_t const foundDash
= name
.rfind("-");
144 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
145 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
146 foundDash
<= foundUnderscore
||
147 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
149 string
const c
= name
.substr(foundDash
+1);
150 if (unlikely(c
.empty() == true) || c
== "en")
152 // Skip unusual files, like backups or that alike
153 string::const_iterator s
= c
.begin();
154 for (;s
!= c
.end(); ++s
) {
155 if (isalpha(*s
) == 0 && *s
!= '_')
160 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
162 builtin
.push_back(c
);
167 // FIXME: Remove support for the old APT::Acquire::Translation
168 // it was undocumented and so it should be not very widthly used
169 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
170 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
171 // TRANSLATORS: the two %s are APT configuration options
172 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
173 "APT::Acquire::Translation", "Acquire::Languages");
174 if (oldAcquire
!= "none")
175 codes
.push_back(oldAcquire
);
176 codes
.push_back("en");
178 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
179 b
!= builtin
.end(); ++b
)
180 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
181 allCodes
.push_back(*b
);
188 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
189 // we extract both, a long and a short code and then we will
190 // check if we actually need both (rare) or if the short is enough
191 string
const envMsg
= string(Locale
== 0 ? std::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
192 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
193 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
195 string
const envLong
= envMsg
.substr(0,lenLong
);
196 string
const envShort
= envLong
.substr(0,lenShort
);
198 // It is very likely we will need the environment codes later,
199 // so let us generate them now from LC_MESSAGES and LANGUAGE
200 std::vector
<string
> environment
;
201 if (envShort
!= "C") {
202 // take care of LC_MESSAGES
203 if (envLong
!= envShort
)
204 environment
.push_back(envLong
);
205 environment
.push_back(envShort
);
206 // take care of LANGUAGE
207 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
208 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
209 if (envLang
.empty() == false) {
210 std::vector
<string
> env
= VectorizeString(envLang
,':');
211 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
212 for (std::vector
<string
>::const_iterator e
= env
.begin();
213 e
!= env
.end() && addedLangs
< 3; ++e
) {
214 if (unlikely(e
->empty() == true) || *e
== "en")
216 if (*e
== envLong
|| *e
== envShort
)
218 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
221 environment
.push_back(*e
);
225 // cornercase: LANG=C, so we use only "en" Translation
226 environment
.push_back("en");
229 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages", "environment,en");
230 // the configs define the order, so add the environment
231 // then needed and ensure the codes are not listed twice.
232 bool noneSeen
= false;
233 for (std::vector
<string
>::const_iterator l
= lang
.begin();
234 l
!= lang
.end(); ++l
) {
235 if (*l
== "environment") {
236 for (std::vector
<string
>::const_iterator e
= environment
.begin();
237 e
!= environment
.end(); ++e
) {
238 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
240 if (noneSeen
== false)
242 allCodes
.push_back(*e
);
245 } else if (*l
== "none") {
248 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
251 if (noneSeen
== false)
253 allCodes
.push_back(*l
);
256 if (allCodes
.empty() == false) {
257 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
258 b
!= builtin
.end(); ++b
)
259 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
260 allCodes
.push_back(*b
);
263 allCodes
.push_back("none");
272 // checkLanguage - are we interested in the given Language? /*{{{*/
273 bool const Configuration::checkLanguage(std::string Lang
, bool const All
) {
274 // the empty Language is always interesting as it is the original
275 if (Lang
.empty() == true)
277 // filenames are encoded, so undo this
278 Lang
= SubstVar(Lang
, "%5f", "_");
279 std::vector
<std::string
> const langs
= getLanguages(All
, true);
280 return (std::find(langs
.begin(), langs
.end(), Lang
) != langs
.end());
283 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
284 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
287 std::vector
<string
> static archs
;
288 if (likely(Cached
== true) && archs
.empty() == false)
291 string
const arch
= _config
->Find("APT::Architecture");
292 archs
= _config
->FindVector("APT::Architectures");
294 if (unlikely(arch
.empty() == true))
297 // FIXME: It is a bit unclean to have debian specific code here…
298 if (archs
.empty() == true) {
299 archs
.push_back(arch
);
301 // Generate the base argument list for dpkg
302 std::vector
<const char *> Args
;
303 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
305 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
306 size_t dpkgChrootLen
= dpkgChrootDir
.length();
307 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
308 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
310 Tmp
= Tmp
.substr(dpkgChrootLen
);
313 Args
.push_back(Tmp
.c_str());
315 // Stick in any custom dpkg options
316 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
319 for (; Opts
!= 0; Opts
= Opts
->Next
)
321 if (Opts
->Value
.empty() == true)
323 Args
.push_back(Opts
->Value
.c_str());
327 Args
.push_back("--print-foreign-architectures");
328 Args
.push_back(NULL
);
330 int external
[2] = {-1, -1};
331 if (pipe(external
) != 0)
333 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
337 pid_t dpkgMultiArch
= ExecFork();
338 if (dpkgMultiArch
== 0) {
340 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
341 int const nullfd
= open("/dev/null", O_RDONLY
);
342 dup2(nullfd
, STDIN_FILENO
);
343 dup2(external
[1], STDOUT_FILENO
);
344 dup2(nullfd
, STDERR_FILENO
);
345 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0 && chdir("/") != 0)
346 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
347 execvp(Args
[0], (char**) &Args
[0]);
348 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
353 FILE *dpkg
= fdopen(external
[0], "r");
356 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
357 char* arch
= strtok(buf
, " ");
358 while (arch
!= NULL
) {
359 for (; isspace(*arch
) != 0; ++arch
);
360 if (arch
[0] != '\0') {
361 char const* archend
= arch
;
362 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
363 string
a(arch
, (archend
- arch
));
364 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
367 arch
= strtok(NULL
, " ");
372 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
376 if (archs
.empty() == true ||
377 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
378 archs
.insert(archs
.begin(), arch
);
380 // erase duplicates and empty strings
381 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
382 a
!= archs
.rend(); ++a
) {
383 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
384 archs
.erase(a
.base()-1);
385 if (a
== archs
.rend())
392 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
393 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
396 std::vector
<std::string
> const archs
= getArchitectures(true);
397 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
400 // setDefaultConfigurationForCompressors /*{{{*/
401 void Configuration::setDefaultConfigurationForCompressors() {
402 // Set default application paths to check for optional compression types
403 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
404 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
405 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
406 _config
->Set("Dir::Bin::lzma", _config
->FindFile("Dir::Bin::xz"));
407 _config
->Set("APT::Compressor::lzma::Binary", "xz");
408 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
409 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
410 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
412 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
413 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
414 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
417 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
418 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
419 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
420 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
422 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
423 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
424 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
429 // getCompressors - Return Vector of usbale compressors /*{{{*/
430 // ---------------------------------------------------------------------
431 /* return a vector of compressors used by apt-ftparchive in the
432 multicompress functionality or to detect data.tar files */
433 std::vector
<APT::Configuration::Compressor
>
434 const Configuration::getCompressors(bool const Cached
) {
435 static std::vector
<APT::Configuration::Compressor
> compressors
;
436 if (compressors
.empty() == false) {
443 setDefaultConfigurationForCompressors();
445 compressors
.push_back(Compressor(".", "", "", NULL
, NULL
, 1));
446 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
447 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
450 compressors
.push_back(Compressor("gzip",".gz","false", NULL
, NULL
, 2));
452 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
453 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
456 compressors
.push_back(Compressor("bzip2",".bz2","false", NULL
, NULL
, 3));
458 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
459 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
460 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
461 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
463 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
464 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
465 c
!= comp
.end(); ++c
) {
466 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
468 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
474 // getCompressorExtensions - supported data.tar extensions /*{{{*/
475 // ---------------------------------------------------------------------
477 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
478 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
479 std::vector
<std::string
> ext
;
480 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
481 c
!= compressors
.end(); ++c
)
482 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
483 ext
.push_back(c
->Extension
);
487 // Compressor constructor /*{{{*/
488 // ---------------------------------------------------------------------
490 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
492 char const *compressArg
, char const *uncompressArg
,
493 unsigned short const cost
) {
494 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
495 Name
= _config
->Find(std::string(config
).append("Name"), name
);
496 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
497 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
498 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
499 std::string
const compConf
= std::string(config
).append("CompressArg");
500 if (_config
->Exists(compConf
) == true)
501 CompressArgs
= _config
->FindVector(compConf
);
502 else if (compressArg
!= NULL
)
503 CompressArgs
.push_back(compressArg
);
504 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
505 if (_config
->Exists(uncompConf
) == true)
506 UncompressArgs
= _config
->FindVector(uncompConf
);
507 else if (uncompressArg
!= NULL
)
508 UncompressArgs
.push_back(uncompressArg
);