]> git.saurik.com Git - apt.git/blame - apt-pkg/aptconfiguration.cc
Release 1.2.3
[apt.git] / apt-pkg / aptconfiguration.cc
CommitLineData
e878aedb
DK
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3/* ######################################################################
4
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
7
8 ##################################################################### */
9 /*}}}*/
10// Include Files /*{{{*/
ea542140
DK
11#include <config.h>
12
e878aedb
DK
13#include <apt-pkg/aptconfiguration.h>
14#include <apt-pkg/configuration.h>
9f9717fa 15#include <apt-pkg/error.h>
d7cf5923
DK
16#include <apt-pkg/fileutl.h>
17#include <apt-pkg/macros.h>
18#include <apt-pkg/strutl.h>
825db890 19#include <apt-pkg/pkgsystem.h>
e878aedb 20
3f2d77b5 21#include <dirent.h>
8aec002f 22#include <stdio.h>
b9ed63d3 23#include <fcntl.h>
453b82a3
DK
24#include <ctype.h>
25#include <stddef.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
8bd02d8b 29#include <algorithm>
3f2d77b5
DK
30#include <string>
31#include <vector>
453b82a3 32
e878aedb
DK
33 /*}}}*/
34namespace APT {
3809194b
DK
35// setDefaultConfigurationForCompressors /*{{{*/
36static 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");
0179cfa8 40 _config->CndSet("Dir::Bin::lz4", "/usr/bin/lz4");
3809194b
DK
41 if (FileExists(_config->FindFile("Dir::Bin::xz")) == true) {
42 _config->Set("Dir::Bin::lzma", _config->FindFile("Dir::Bin::xz"));
43 _config->Set("APT::Compressor::lzma::Binary", "xz");
44 if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
45 _config->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
1a3296c0 46 _config->Set("APT::Compressor::lzma::CompressArg::", "-6");
3809194b
DK
47 }
48 if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
49 _config->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
50 _config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
51 }
52 } else {
53 _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
54 if (_config->Exists("APT::Compressor::lzma::CompressArg") == false) {
55 _config->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
1a3296c0 56 _config->Set("APT::Compressor::lzma::CompressArg::", "-6");
3809194b
DK
57 }
58 if (_config->Exists("APT::Compressor::lzma::UncompressArg") == false) {
59 _config->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
60 _config->Set("APT::Compressor::lzma::UncompressArg::", "-d");
61 }
62 }
63}
64 /*}}}*/
1e3f4083 65// getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
e878aedb 66// ---------------------------------------------------------------------
1e3f4083 67/* return a vector of compression types in the preferred order. */
e878aedb
DK
68std::vector<std::string>
69const Configuration::getCompressionTypes(bool const &Cached) {
70 static std::vector<std::string> types;
71 if (types.empty() == false) {
72 if (Cached == true)
73 return types;
74 else
75 types.clear();
76 }
77
8bd02d8b 78 // setup the defaults for the compressiontypes => method mapping
b2430e6d 79 _config->CndSet("Acquire::CompressionTypes::xz","xz");
e93b4028 80 _config->CndSet("Acquire::CompressionTypes::bz2","bzip2");
8bd02d8b
DK
81 _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
82 _config->CndSet("Acquire::CompressionTypes::gz","gzip");
0179cfa8 83 _config->CndSet("Acquire::CompressionTypes::lz4","lz4");
8bd02d8b 84
03bef784 85 setDefaultConfigurationForCompressors();
858fd39f 86 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
e878aedb 87
8bd02d8b
DK
88 // load the order setting into our vector
89 std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order");
90 for (std::vector<std::string>::const_iterator o = order.begin();
f7f0d6c7 91 o != order.end(); ++o) {
8bd02d8b
DK
92 if ((*o).empty() == true)
93 continue;
94 // ignore types we have no method ready to use
79b207bc
DK
95 std::string const method = std::string("Acquire::CompressionTypes::").append(*o);
96 if (_config->Exists(method) == false)
8bd02d8b
DK
97 continue;
98 // ignore types we have no app ready to use
79b207bc 99 std::string const app = _config->Find(method);
8dd562a8
DK
100 if (std::find_if(compressors.begin(), compressors.end(), [&app](APT::Configuration::Compressor const &c) {
101 return c.Name == app;
102 }) == compressors.end())
858fd39f 103 continue;
8bd02d8b 104 types.push_back(*o);
e878aedb
DK
105 }
106
8bd02d8b 107 // move again over the option tree to add all missing compression types
e878aedb
DK
108 ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes");
109 if (Types != 0)
110 Types = Types->Child;
111
112 for (; Types != 0; Types = Types->Next) {
8bd02d8b
DK
113 if (Types->Tag == "Order" || Types->Tag.empty() == true)
114 continue;
115 // ignore types we already have in the vector
116 if (std::find(types.begin(),types.end(),Types->Tag) != types.end())
117 continue;
118 // ignore types we have no app ready to use
8dd562a8
DK
119 if (std::find_if(compressors.begin(), compressors.end(), [&Types](APT::Configuration::Compressor const &c) {
120 return c.Name == Types->Value;
121 }) == compressors.end())
858fd39f 122 continue;
e878aedb
DK
123 types.push_back(Types->Tag);
124 }
125
5d885723
DK
126 // add the special "uncompressed" type
127 if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
128 {
8f3ba4e8 129 std::string const uncompr = _config->FindFile("Dir::Bin::uncompressed", "");
5d885723
DK
130 if (uncompr.empty() == true || FileExists(uncompr) == true)
131 types.push_back("uncompressed");
132 }
133
e878aedb
DK
134 return types;
135}
136 /*}}}*/
45df0ad2
DK
137// GetLanguages - Return Vector of Language Codes /*{{{*/
138// ---------------------------------------------------------------------
1e3f4083 139/* return a vector of language codes in the preferred order.
45df0ad2
DK
140 the special word "environment" will be replaced with the long and the short
141 code of the local settings and it will be insured that this will not add
142 duplicates. So in an german local the setting "environment, de_DE, en, de"
143 will result in "de_DE, de, en".
144 The special word "none" is the stopcode for the not-All code vector */
145std::vector<std::string> const Configuration::getLanguages(bool const &All,
d7cf5923 146 bool const &Cached, char const ** const Locale) {
45df0ad2
DK
147 using std::string;
148
149 // The detection is boring and has a lot of cornercases,
150 // so we cache the results to calculated it only once.
151 std::vector<string> static allCodes;
152 std::vector<string> static codes;
153
154 // we have something in the cache
155 if (codes.empty() == false || allCodes.empty() == false) {
156 if (Cached == true) {
157 if(All == true && allCodes.empty() == false)
158 return allCodes;
159 else
160 return codes;
161 } else {
162 allCodes.clear();
163 codes.clear();
164 }
165 }
166
3f2d77b5
DK
167 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
168 // so they will be all included in the Cache.
169 std::vector<string> builtin;
170 DIR *D = opendir(_config->FindDir("Dir::State::lists").c_str());
62d8a765 171 if (D != NULL) {
3f2d77b5
DK
172 builtin.push_back("none");
173 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
527df5a2 174 string const name = SubstVar(Ent->d_name, "%5f", "_");
3f2d77b5 175 size_t const foundDash = name.rfind("-");
7cb28948 176 size_t const foundUnderscore = name.rfind("_", foundDash);
3f2d77b5
DK
177 if (foundDash == string::npos || foundUnderscore == string::npos ||
178 foundDash <= foundUnderscore ||
179 name.substr(foundUnderscore+1, foundDash-(foundUnderscore+1)) != "Translation")
180 continue;
181 string const c = name.substr(foundDash+1);
182 if (unlikely(c.empty() == true) || c == "en")
183 continue;
184 // Skip unusual files, like backups or that alike
185 string::const_iterator s = c.begin();
186 for (;s != c.end(); ++s) {
7cb28948 187 if (isalpha(*s) == 0 && *s != '_')
3f2d77b5
DK
188 break;
189 }
190 if (s != c.end())
191 continue;
192 if (std::find(builtin.begin(), builtin.end(), c) != builtin.end())
193 continue;
194 builtin.push_back(c);
195 }
62d8a765 196 closedir(D);
3f2d77b5
DK
197 }
198
45df0ad2
DK
199 // FIXME: Remove support for the old APT::Acquire::Translation
200 // it was undocumented and so it should be not very widthly used
201 string const oldAcquire = _config->Find("APT::Acquire::Translation","");
202 if (oldAcquire.empty() == false && oldAcquire != "environment") {
9f9717fa
DK
203 // TRANSLATORS: the two %s are APT configuration options
204 _error->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
205 "APT::Acquire::Translation", "Acquire::Languages");
45df0ad2
DK
206 if (oldAcquire != "none")
207 codes.push_back(oldAcquire);
3f2d77b5 208 codes.push_back("en");
d7cf5923 209 allCodes = codes;
3f2d77b5
DK
210 for (std::vector<string>::const_iterator b = builtin.begin();
211 b != builtin.end(); ++b)
212 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
213 allCodes.push_back(*b);
214 if (All == true)
215 return allCodes;
216 else
217 return codes;
45df0ad2
DK
218 }
219
ab53c018
DK
220 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
221 // we extract both, a long and a short code and then we will
222 // check if we actually need both (rare) or if the short is enough
f8043f21 223 string const envMsg = string(Locale == 0 ? ::setlocale(LC_MESSAGES, NULL) : *Locale);
ab53c018
DK
224 size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
225 size_t const lenLong = (envMsg.find_first_of(".@") != string::npos) ? envMsg.find_first_of(".@") : (lenShort + 3);
226
227 string const envLong = envMsg.substr(0,lenLong);
228 string const envShort = envLong.substr(0,lenShort);
229
230 // It is very likely we will need the environment codes later,
d7cf5923
DK
231 // so let us generate them now from LC_MESSAGES and LANGUAGE
232 std::vector<string> environment;
eb3947c6
DK
233 if (envShort != "C") {
234 // take care of LC_MESSAGES
ab53c018 235 if (envLong != envShort)
eb3947c6
DK
236 environment.push_back(envLong);
237 environment.push_back(envShort);
238 // take care of LANGUAGE
239 const char *language_env = getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
240 string envLang = Locale == 0 ? language_env : *(Locale+1);
241 if (envLang.empty() == false) {
242 std::vector<string> env = VectorizeString(envLang,':');
243 short addedLangs = 0; // add a maximum of 3 fallbacks from the environment
244 for (std::vector<string>::const_iterator e = env.begin();
245 e != env.end() && addedLangs < 3; ++e) {
246 if (unlikely(e->empty() == true) || *e == "en")
247 continue;
248 if (*e == envLong || *e == envShort)
249 continue;
250 if (std::find(environment.begin(), environment.end(), *e) != environment.end())
d7cf5923 251 continue;
eb3947c6
DK
252 ++addedLangs;
253 environment.push_back(*e);
d7cf5923 254 }
d7cf5923 255 }
eb3947c6 256 } else {
a5414e56 257 // cornercase: LANG=C, so we use only "en" Translation
eb3947c6 258 environment.push_back("en");
d7cf5923
DK
259 }
260
a5414e56 261 std::vector<string> const lang = _config->FindVector("Acquire::Languages", "environment,en");
45df0ad2
DK
262 // the configs define the order, so add the environment
263 // then needed and ensure the codes are not listed twice.
264 bool noneSeen = false;
265 for (std::vector<string>::const_iterator l = lang.begin();
f7f0d6c7 266 l != lang.end(); ++l) {
45df0ad2 267 if (*l == "environment") {
d7cf5923
DK
268 for (std::vector<string>::const_iterator e = environment.begin();
269 e != environment.end(); ++e) {
270 if (std::find(allCodes.begin(), allCodes.end(), *e) != allCodes.end())
271 continue;
45df0ad2 272 if (noneSeen == false)
d7cf5923
DK
273 codes.push_back(*e);
274 allCodes.push_back(*e);
45df0ad2
DK
275 }
276 continue;
277 } else if (*l == "none") {
278 noneSeen = true;
279 continue;
d7cf5923 280 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
45df0ad2
DK
281 continue;
282
283 if (noneSeen == false)
284 codes.push_back(*l);
285 allCodes.push_back(*l);
286 }
3f2d77b5 287
a5414e56
DK
288 if (allCodes.empty() == false) {
289 for (std::vector<string>::const_iterator b = builtin.begin();
290 b != builtin.end(); ++b)
291 if (std::find(allCodes.begin(), allCodes.end(), *b) == allCodes.end())
292 allCodes.push_back(*b);
293 } else {
294 // "none" was forced
295 allCodes.push_back("none");
296 }
3f2d77b5 297
45df0ad2
DK
298 if (All == true)
299 return allCodes;
300 else
301 return codes;
302}
303 /*}}}*/
c45233ea 304// checkLanguage - are we interested in the given Language? /*{{{*/
d64e130a 305bool Configuration::checkLanguage(std::string Lang, bool const All) {
c45233ea
DK
306 // the empty Language is always interesting as it is the original
307 if (Lang.empty() == true)
308 return true;
309 // filenames are encoded, so undo this
310 Lang = SubstVar(Lang, "%5f", "_");
311 std::vector<std::string> const langs = getLanguages(All, true);
312 return (std::find(langs.begin(), langs.end(), Lang) != langs.end());
313}
314 /*}}}*/
1e3f4083 315// getArchitectures - Return Vector of preferred Architectures /*{{{*/
5dd4c8b8
DK
316std::vector<std::string> const Configuration::getArchitectures(bool const &Cached) {
317 using std::string;
318
319 std::vector<string> static archs;
320 if (likely(Cached == true) && archs.empty() == false)
321 return archs;
322
3152f4aa 323 string const arch = _config->Find("APT::Architecture");
8aec002f
DK
324 archs = _config->FindVector("APT::Architectures");
325
825db890
DK
326 if (archs.empty() == true)
327 archs = _system->ArchitecturesSupported();
8aec002f 328
5dd4c8b8
DK
329 if (archs.empty() == true ||
330 std::find(archs.begin(), archs.end(), arch) == archs.end())
bd9d81e3 331 archs.insert(archs.begin(), arch);
3152f4aa
DK
332
333 // erase duplicates and empty strings
334 for (std::vector<string>::reverse_iterator a = archs.rbegin();
335 a != archs.rend(); ++a) {
336 if (a->empty() == true || std::find(a + 1, archs.rend(), *a) != archs.rend())
337 archs.erase(a.base()-1);
338 if (a == archs.rend())
339 break;
340 }
341
5dd4c8b8
DK
342 return archs;
343}
344 /*}}}*/
345// checkArchitecture - are we interested in the given Architecture? /*{{{*/
d64e130a 346bool Configuration::checkArchitecture(std::string const &Arch) {
5dd4c8b8
DK
347 if (Arch == "all")
348 return true;
349 std::vector<std::string> const archs = getArchitectures(true);
350 return (std::find(archs.begin(), archs.end(), Arch) != archs.end());
351}
352 /*}}}*/
ce7f128c 353// getCompressors - Return Vector of usealbe compressors /*{{{*/
03bef784
DK
354// ---------------------------------------------------------------------
355/* return a vector of compressors used by apt-ftparchive in the
356 multicompress functionality or to detect data.tar files */
357std::vector<APT::Configuration::Compressor>
358const Configuration::getCompressors(bool const Cached) {
359 static std::vector<APT::Configuration::Compressor> compressors;
360 if (compressors.empty() == false) {
361 if (Cached == true)
362 return compressors;
363 else
364 compressors.clear();
365 }
366
367 setDefaultConfigurationForCompressors();
368
59f1f42b 369 compressors.push_back(Compressor(".", "", "", NULL, NULL, 0));
e3fbd54c
JAK
370 if (_config->Exists("Dir::Bin::lz4") == false || FileExists(_config->FindFile("Dir::Bin::lz4")) == true)
371 compressors.push_back(Compressor("lz4",".lz4","lz4","-1","-d",50));
372#ifdef HAVE_LZ4
373 else
374 compressors.push_back(Compressor("lz4",".lz4","false", NULL, NULL, 50));
375#endif
03bef784 376 if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->FindFile("Dir::Bin::gzip")) == true)
59f1f42b 377 compressors.push_back(Compressor("gzip",".gz","gzip","-6n","-d",100));
8dd623db
DK
378#ifdef HAVE_ZLIB
379 else
59f1f42b 380 compressors.push_back(Compressor("gzip",".gz","false", NULL, NULL, 100));
c4997486 381#endif
03bef784 382 if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->FindFile("Dir::Bin::xz")) == true)
59f1f42b 383 compressors.push_back(Compressor("xz",".xz","xz","-6","-d",200));
7f350a37
DK
384#ifdef HAVE_LZMA
385 else
59f1f42b 386 compressors.push_back(Compressor("xz",".xz","false", NULL, NULL, 200));
e93b4028
DK
387#endif
388 if (_config->Exists("Dir::Bin::bzip2") == false || FileExists(_config->FindFile("Dir::Bin::bzip2")) == true)
59f1f42b 389 compressors.push_back(Compressor("bzip2",".bz2","bzip2","-6","-d",300));
e93b4028
DK
390#ifdef HAVE_BZ2
391 else
59f1f42b 392 compressors.push_back(Compressor("bzip2",".bz2","false", NULL, NULL, 300));
7f350a37 393#endif
2024154c 394 if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->FindFile("Dir::Bin::lzma")) == true)
59f1f42b 395 compressors.push_back(Compressor("lzma",".lzma","lzma","-6","-d",400));
7f350a37
DK
396#ifdef HAVE_LZMA
397 else
59f1f42b 398 compressors.push_back(Compressor("lzma",".lzma","false", NULL, NULL, 400));
7f350a37 399#endif
03bef784
DK
400
401 std::vector<std::string> const comp = _config->FindVector("APT::Compressor");
402 for (std::vector<std::string>::const_iterator c = comp.begin();
403 c != comp.end(); ++c) {
8056a00c 404 if (c->empty() || *c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz")
03bef784
DK
405 continue;
406 compressors.push_back(Compressor(c->c_str(), std::string(".").append(*c).c_str(), c->c_str(), "-9", "-d", 100));
407 }
408
409 return compressors;
410}
411 /*}}}*/
b0e1a43f
DK
412// getCompressorExtensions - supported data.tar extensions /*{{{*/
413// ---------------------------------------------------------------------
414/* */
415std::vector<std::string> const Configuration::getCompressorExtensions() {
416 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
417 std::vector<std::string> ext;
418 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
419 c != compressors.end(); ++c)
420 if (c->Extension.empty() == false && c->Extension != ".")
421 ext.push_back(c->Extension);
422 return ext;
423}
424 /*}}}*/
03bef784
DK
425// Compressor constructor /*{{{*/
426// ---------------------------------------------------------------------
427/* */
428Configuration::Compressor::Compressor(char const *name, char const *extension,
429 char const *binary,
430 char const *compressArg, char const *uncompressArg,
431 unsigned short const cost) {
2024154c 432 std::string const config = std::string("APT::Compressor::").append(name).append("::");
03bef784
DK
433 Name = _config->Find(std::string(config).append("Name"), name);
434 Extension = _config->Find(std::string(config).append("Extension"), extension);
435 Binary = _config->Find(std::string(config).append("Binary"), binary);
436 Cost = _config->FindI(std::string(config).append("Cost"), cost);
437 std::string const compConf = std::string(config).append("CompressArg");
438 if (_config->Exists(compConf) == true)
439 CompressArgs = _config->FindVector(compConf);
440 else if (compressArg != NULL)
441 CompressArgs.push_back(compressArg);
442 std::string const uncompConf = std::string(config).append("UncompressArg");
443 if (_config->Exists(uncompConf) == true)
444 UncompressArgs = _config->FindVector(uncompConf);
445 else if (uncompressArg != NULL)
446 UncompressArgs.push_back(uncompressArg);
447}
448 /*}}}*/
ce7f128c
DK
449// getBuildProfiles - return a vector of enabled build profiles /*{{{*/
450std::vector<std::string> const Configuration::getBuildProfiles() {
451 // order is: override value (~= commandline), environment variable, list (~= config file)
452 std::string profiles_env = getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
453 if (profiles_env.empty() == false) {
454 profiles_env = SubstVar(profiles_env, " ", ",");
455 std::string const bp = _config->Find("APT::Build-Profiles");
456 _config->Clear("APT::Build-Profiles");
457 if (bp.empty() == false)
458 _config->Set("APT::Build-Profiles", bp);
459 }
460 return _config->FindVector("APT::Build-Profiles", profiles_env);
461}
462std::string const Configuration::getBuildProfilesString() {
463 std::vector<std::string> profiles = getBuildProfiles();
464 if (profiles.empty() == true)
465 return "";
466 std::vector<std::string>::const_iterator p = profiles.begin();
467 std::string list = *p;
7a223b93 468 for (++p; p != profiles.end(); ++p)
ce7f128c
DK
469 list.append(",").append(*p);
470 return list;
471}
472 /*}}}*/
e878aedb 473}