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