]> git.saurik.com Git - apt.git/blame - apt-pkg/aptconfiguration.cc
imbue datetime parsing with C.UTF-8 locale
[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
124e6916 38 _config->CndSet("Dir::Bin::gzip", "/bin/gzip");
3809194b
DK
39 _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
40 _config->CndSet("Dir::Bin::xz", "/usr/bin/xz");
0179cfa8 41 _config->CndSet("Dir::Bin::lz4", "/usr/bin/lz4");
90f2a7a0
DK
42 if (FileExists(_config->Find("Dir::Bin::xz")) == true) {
43 _config->Set("Dir::Bin::lzma", _config->Find("Dir::Bin::xz"));
3809194b
DK
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");
1a3296c0 47 _config->Set("APT::Compressor::lzma::CompressArg::", "-6");
3809194b
DK
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=");
1a3296c0 57 _config->Set("APT::Compressor::lzma::CompressArg::", "-6");
3809194b
DK
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 }
124e6916
DK
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");
3809194b
DK
70}
71 /*}}}*/
1e3f4083 72// getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
e878aedb 73// ---------------------------------------------------------------------
1e3f4083 74/* return a vector of compression types in the preferred order. */
e878aedb
DK
75std::vector<std::string>
76const 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
858fd39f 85 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
e878aedb 86
8bd02d8b
DK
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();
f7f0d6c7 90 o != order.end(); ++o) {
8bd02d8b
DK
91 if ((*o).empty() == true)
92 continue;
93 // ignore types we have no method ready to use
79b207bc
DK
94 std::string const method = std::string("Acquire::CompressionTypes::").append(*o);
95 if (_config->Exists(method) == false)
8bd02d8b
DK
96 continue;
97 // ignore types we have no app ready to use
79b207bc 98 std::string const app = _config->Find(method);
8dd562a8
DK
99 if (std::find_if(compressors.begin(), compressors.end(), [&app](APT::Configuration::Compressor const &c) {
100 return c.Name == app;
101 }) == compressors.end())
858fd39f 102 continue;
8bd02d8b 103 types.push_back(*o);
e878aedb
DK
104 }
105
8bd02d8b 106 // move again over the option tree to add all missing compression types
e878aedb
DK
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) {
8bd02d8b
DK
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
8dd562a8
DK
118 if (std::find_if(compressors.begin(), compressors.end(), [&Types](APT::Configuration::Compressor const &c) {
119 return c.Name == Types->Value;
120 }) == compressors.end())
858fd39f 121 continue;
e878aedb
DK
122 types.push_back(Types->Tag);
123 }
124
5d885723
DK
125 // add the special "uncompressed" type
126 if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
127 {
90f2a7a0 128 std::string const uncompr = _config->Find("Dir::Bin::uncompressed", "");
5d885723
DK
129 if (uncompr.empty() == true || FileExists(uncompr) == true)
130 types.push_back("uncompressed");
131 }
132
e878aedb
DK
133 return types;
134}
135 /*}}}*/
45df0ad2
DK
136// GetLanguages - Return Vector of Language Codes /*{{{*/
137// ---------------------------------------------------------------------
1e3f4083 138/* return a vector of language codes in the preferred order.
45df0ad2
DK
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 */
144std::vector<std::string> const Configuration::getLanguages(bool const &All,
d7cf5923 145 bool const &Cached, char const ** const Locale) {
45df0ad2
DK
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
3f2d77b5
DK
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());
62d8a765 170 if (D != NULL) {
3f2d77b5
DK
171 builtin.push_back("none");
172 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
527df5a2 173 string const name = SubstVar(Ent->d_name, "%5f", "_");
3f2d77b5 174 size_t const foundDash = name.rfind("-");
7cb28948 175 size_t const foundUnderscore = name.rfind("_", foundDash);
3f2d77b5
DK
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) {
7cb28948 186 if (isalpha(*s) == 0 && *s != '_')
3f2d77b5
DK
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 }
62d8a765 195 closedir(D);
3f2d77b5
DK
196 }
197
45df0ad2
DK
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") {
9f9717fa
DK
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");
45df0ad2
DK
205 if (oldAcquire != "none")
206 codes.push_back(oldAcquire);
3f2d77b5 207 codes.push_back("en");
d7cf5923 208 allCodes = codes;
3f2d77b5
DK
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;
45df0ad2
DK
217 }
218
ab53c018
DK
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
f8043f21 222 string const envMsg = string(Locale == 0 ? ::setlocale(LC_MESSAGES, NULL) : *Locale);
ab53c018
DK
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,
d7cf5923
DK
230 // so let us generate them now from LC_MESSAGES and LANGUAGE
231 std::vector<string> environment;
eb3947c6
DK
232 if (envShort != "C") {
233 // take care of LC_MESSAGES
ab53c018 234 if (envLong != envShort)
eb3947c6
DK
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())
d7cf5923 250 continue;
eb3947c6
DK
251 ++addedLangs;
252 environment.push_back(*e);
d7cf5923 253 }
d7cf5923 254 }
eb3947c6 255 } else {
a5414e56 256 // cornercase: LANG=C, so we use only "en" Translation
eb3947c6 257 environment.push_back("en");
d7cf5923
DK
258 }
259
a5414e56 260 std::vector<string> const lang = _config->FindVector("Acquire::Languages", "environment,en");
45df0ad2
DK
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();
f7f0d6c7 265 l != lang.end(); ++l) {
45df0ad2 266 if (*l == "environment") {
d7cf5923
DK
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;
45df0ad2 271 if (noneSeen == false)
d7cf5923
DK
272 codes.push_back(*e);
273 allCodes.push_back(*e);
45df0ad2
DK
274 }
275 continue;
276 } else if (*l == "none") {
277 noneSeen = true;
278 continue;
d7cf5923 279 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
45df0ad2
DK
280 continue;
281
282 if (noneSeen == false)
283 codes.push_back(*l);
284 allCodes.push_back(*l);
285 }
3f2d77b5 286
a5414e56
DK
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 }
3f2d77b5 296
45df0ad2
DK
297 if (All == true)
298 return allCodes;
299 else
300 return codes;
301}
302 /*}}}*/
c45233ea 303// checkLanguage - are we interested in the given Language? /*{{{*/
d64e130a 304bool Configuration::checkLanguage(std::string Lang, bool const All) {
c45233ea
DK
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 /*}}}*/
1e3f4083 314// getArchitectures - Return Vector of preferred Architectures /*{{{*/
5dd4c8b8
DK
315std::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
3152f4aa 322 string const arch = _config->Find("APT::Architecture");
8aec002f
DK
323 archs = _config->FindVector("APT::Architectures");
324
825db890
DK
325 if (archs.empty() == true)
326 archs = _system->ArchitecturesSupported();
8aec002f 327
5dd4c8b8
DK
328 if (archs.empty() == true ||
329 std::find(archs.begin(), archs.end(), arch) == archs.end())
bd9d81e3 330 archs.insert(archs.begin(), arch);
3152f4aa
DK
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
5dd4c8b8
DK
341 return archs;
342}
343 /*}}}*/
344// checkArchitecture - are we interested in the given Architecture? /*{{{*/
d64e130a 345bool Configuration::checkArchitecture(std::string const &Arch) {
5dd4c8b8
DK
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 /*}}}*/
ce7f128c 352// getCompressors - Return Vector of usealbe compressors /*{{{*/
03bef784
DK
353// ---------------------------------------------------------------------
354/* return a vector of compressors used by apt-ftparchive in the
355 multicompress functionality or to detect data.tar files */
356std::vector<APT::Configuration::Compressor>
357const 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
59f1f42b 368 compressors.push_back(Compressor(".", "", "", NULL, NULL, 0));
90f2a7a0 369 if (_config->Exists("Dir::Bin::lz4") == false || FileExists(_config->Find("Dir::Bin::lz4")) == true)
e3fbd54c
JAK
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
90f2a7a0 375 if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->Find("Dir::Bin::gzip")) == true)
59f1f42b 376 compressors.push_back(Compressor("gzip",".gz","gzip","-6n","-d",100));
8dd623db
DK
377#ifdef HAVE_ZLIB
378 else
59f1f42b 379 compressors.push_back(Compressor("gzip",".gz","false", NULL, NULL, 100));
c4997486 380#endif
90f2a7a0 381 if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->Find("Dir::Bin::xz")) == true)
59f1f42b 382 compressors.push_back(Compressor("xz",".xz","xz","-6","-d",200));
7f350a37
DK
383#ifdef HAVE_LZMA
384 else
59f1f42b 385 compressors.push_back(Compressor("xz",".xz","false", NULL, NULL, 200));
e93b4028 386#endif
90f2a7a0 387 if (_config->Exists("Dir::Bin::bzip2") == false || FileExists(_config->Find("Dir::Bin::bzip2")) == true)
59f1f42b 388 compressors.push_back(Compressor("bzip2",".bz2","bzip2","-6","-d",300));
e93b4028
DK
389#ifdef HAVE_BZ2
390 else
59f1f42b 391 compressors.push_back(Compressor("bzip2",".bz2","false", NULL, NULL, 300));
7f350a37 392#endif
90f2a7a0 393 if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->Find("Dir::Bin::lzma")) == true)
59f1f42b 394 compressors.push_back(Compressor("lzma",".lzma","lzma","-6","-d",400));
7f350a37
DK
395#ifdef HAVE_LZMA
396 else
59f1f42b 397 compressors.push_back(Compressor("lzma",".lzma","false", NULL, NULL, 400));
7f350a37 398#endif
03bef784 399
124e6916
DK
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; }))
03bef784 404 continue;
124e6916 405 compressors.push_back(Compressor(c.c_str(), std::string(".").append(c).c_str(), c.c_str(), nullptr, nullptr, 1000));
03bef784
DK
406 }
407
408 return compressors;
409}
410 /*}}}*/
b0e1a43f
DK
411// getCompressorExtensions - supported data.tar extensions /*{{{*/
412// ---------------------------------------------------------------------
413/* */
414std::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 /*}}}*/
03bef784
DK
424// Compressor constructor /*{{{*/
425// ---------------------------------------------------------------------
426/* */
427Configuration::Compressor::Compressor(char const *name, char const *extension,
428 char const *binary,
429 char const *compressArg, char const *uncompressArg,
430 unsigned short const cost) {
2024154c 431 std::string const config = std::string("APT::Compressor::").append(name).append("::");
03bef784
DK
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 /*}}}*/
ce7f128c
DK
448// getBuildProfiles - return a vector of enabled build profiles /*{{{*/
449std::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}
461std::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;
7a223b93 467 for (++p; p != profiles.end(); ++p)
ce7f128c
DK
468 list.append(",").append(*p);
469 return list;
470}
471 /*}}}*/
e878aedb 472}