]> git.saurik.com Git - apt.git/blame - apt-pkg/aptconfiguration.cc
prevent C++ locale number formatting in text APIs (try 2)
[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
29b8e6b9
DK
368 std::vector<std::string> CompressorsDone;
369# define APT_ADD_COMPRESSOR(NAME, EXT, BINARY, ARG, DEARG, COST) \
370 { CompressorsDone.push_back(NAME); compressors.emplace_back(NAME, EXT, BINARY, ARG, DEARG, COST); }
371 APT_ADD_COMPRESSOR(".", "", "", nullptr, nullptr, 0)
90f2a7a0 372 if (_config->Exists("Dir::Bin::lz4") == false || FileExists(_config->Find("Dir::Bin::lz4")) == true)
29b8e6b9 373 APT_ADD_COMPRESSOR("lz4",".lz4","lz4","-1","-d",50)
e3fbd54c
JAK
374#ifdef HAVE_LZ4
375 else
29b8e6b9 376 APT_ADD_COMPRESSOR("lz4",".lz4","false", nullptr, nullptr, 50)
e3fbd54c 377#endif
90f2a7a0 378 if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->Find("Dir::Bin::gzip")) == true)
29b8e6b9 379 APT_ADD_COMPRESSOR("gzip",".gz","gzip","-6n","-d",100)
8dd623db
DK
380#ifdef HAVE_ZLIB
381 else
29b8e6b9 382 APT_ADD_COMPRESSOR("gzip",".gz","false", nullptr, nullptr, 100)
c4997486 383#endif
90f2a7a0 384 if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->Find("Dir::Bin::xz")) == true)
29b8e6b9 385 APT_ADD_COMPRESSOR("xz",".xz","xz","-6","-d",200)
7f350a37
DK
386#ifdef HAVE_LZMA
387 else
29b8e6b9 388 APT_ADD_COMPRESSOR("xz",".xz","false", nullptr, nullptr, 200)
e93b4028 389#endif
90f2a7a0 390 if (_config->Exists("Dir::Bin::bzip2") == false || FileExists(_config->Find("Dir::Bin::bzip2")) == true)
29b8e6b9 391 APT_ADD_COMPRESSOR("bzip2",".bz2","bzip2","-6","-d",300)
e93b4028
DK
392#ifdef HAVE_BZ2
393 else
29b8e6b9 394 APT_ADD_COMPRESSOR("bzip2",".bz2","false", nullptr, nullptr, 300)
7f350a37 395#endif
90f2a7a0 396 if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->Find("Dir::Bin::lzma")) == true)
29b8e6b9 397 APT_ADD_COMPRESSOR("lzma",".lzma","lzma","-6","-d",400)
7f350a37
DK
398#ifdef HAVE_LZMA
399 else
29b8e6b9 400 APT_ADD_COMPRESSOR("lzma",".lzma","false", nullptr, nullptr, 400)
7f350a37 401#endif
03bef784 402
124e6916
DK
403 std::vector<std::string> const comp = _config->FindVector("APT::Compressor", "", true);
404 for (auto const &c: comp)
405 {
29b8e6b9 406 if (c.empty() || std::find(CompressorsDone.begin(), CompressorsDone.end(), c) != CompressorsDone.end())
03bef784 407 continue;
124e6916 408 compressors.push_back(Compressor(c.c_str(), std::string(".").append(c).c_str(), c.c_str(), nullptr, nullptr, 1000));
03bef784
DK
409 }
410
411 return compressors;
412}
413 /*}}}*/
b0e1a43f
DK
414// getCompressorExtensions - supported data.tar extensions /*{{{*/
415// ---------------------------------------------------------------------
416/* */
417std::vector<std::string> const Configuration::getCompressorExtensions() {
418 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
419 std::vector<std::string> ext;
420 for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressors.begin();
421 c != compressors.end(); ++c)
422 if (c->Extension.empty() == false && c->Extension != ".")
423 ext.push_back(c->Extension);
424 return ext;
425}
426 /*}}}*/
03bef784
DK
427// Compressor constructor /*{{{*/
428// ---------------------------------------------------------------------
429/* */
430Configuration::Compressor::Compressor(char const *name, char const *extension,
431 char const *binary,
432 char const *compressArg, char const *uncompressArg,
433 unsigned short const cost) {
2024154c 434 std::string const config = std::string("APT::Compressor::").append(name).append("::");
03bef784
DK
435 Name = _config->Find(std::string(config).append("Name"), name);
436 Extension = _config->Find(std::string(config).append("Extension"), extension);
437 Binary = _config->Find(std::string(config).append("Binary"), binary);
438 Cost = _config->FindI(std::string(config).append("Cost"), cost);
439 std::string const compConf = std::string(config).append("CompressArg");
440 if (_config->Exists(compConf) == true)
441 CompressArgs = _config->FindVector(compConf);
442 else if (compressArg != NULL)
443 CompressArgs.push_back(compressArg);
444 std::string const uncompConf = std::string(config).append("UncompressArg");
445 if (_config->Exists(uncompConf) == true)
446 UncompressArgs = _config->FindVector(uncompConf);
447 else if (uncompressArg != NULL)
448 UncompressArgs.push_back(uncompressArg);
449}
450 /*}}}*/
ce7f128c
DK
451// getBuildProfiles - return a vector of enabled build profiles /*{{{*/
452std::vector<std::string> const Configuration::getBuildProfiles() {
453 // order is: override value (~= commandline), environment variable, list (~= config file)
454 std::string profiles_env = getenv("DEB_BUILD_PROFILES") == 0 ? "" : getenv("DEB_BUILD_PROFILES");
455 if (profiles_env.empty() == false) {
456 profiles_env = SubstVar(profiles_env, " ", ",");
457 std::string const bp = _config->Find("APT::Build-Profiles");
458 _config->Clear("APT::Build-Profiles");
459 if (bp.empty() == false)
460 _config->Set("APT::Build-Profiles", bp);
461 }
462 return _config->FindVector("APT::Build-Profiles", profiles_env);
463}
464std::string const Configuration::getBuildProfilesString() {
465 std::vector<std::string> profiles = getBuildProfiles();
466 if (profiles.empty() == true)
467 return "";
468 std::vector<std::string>::const_iterator p = profiles.begin();
469 std::string list = *p;
7a223b93 470 for (++p; p != profiles.end(); ++p)
ce7f128c
DK
471 list.append(",").append(*p);
472 return list;
473}
474 /*}}}*/
e878aedb 475}