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