]> git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
support comments in debian/control parsing
[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::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::", "-6");
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::", "-6");
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 /*}}}*/
64 // getCompressionTypes - Return Vector of usable compressiontypes /*{{{*/
65 // ---------------------------------------------------------------------
66 /* return a vector of compression types in the preferred order. */
67 std::vector<std::string>
68 const 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
77 // setup the defaults for the compressiontypes => method mapping
78 _config->CndSet("Acquire::CompressionTypes::xz","xz");
79 _config->CndSet("Acquire::CompressionTypes::bz2","bzip2");
80 _config->CndSet("Acquire::CompressionTypes::lzma","lzma");
81 _config->CndSet("Acquire::CompressionTypes::gz","gzip");
82
83 setDefaultConfigurationForCompressors();
84 std::vector<APT::Configuration::Compressor> const compressors = getCompressors();
85
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();
89 o != order.end(); ++o) {
90 if ((*o).empty() == true)
91 continue;
92 // ignore types we have no method ready to use
93 std::string const method = std::string("Acquire::CompressionTypes::").append(*o);
94 if (_config->Exists(method) == false)
95 continue;
96 // ignore types we have no app ready to use
97 std::string const app = _config->Find(method);
98 if (std::find_if(compressors.begin(), compressors.end(), [&app](APT::Configuration::Compressor const &c) {
99 return c.Name == app;
100 }) == compressors.end())
101 continue;
102 types.push_back(*o);
103 }
104
105 // move again over the option tree to add all missing compression types
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) {
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
117 if (std::find_if(compressors.begin(), compressors.end(), [&Types](APT::Configuration::Compressor const &c) {
118 return c.Name == Types->Value;
119 }) == compressors.end())
120 continue;
121 types.push_back(Types->Tag);
122 }
123
124 // add the special "uncompressed" type
125 if (std::find(types.begin(), types.end(), "uncompressed") == types.end())
126 {
127 std::string const uncompr = _config->FindFile("Dir::Bin::uncompressed", "");
128 if (uncompr.empty() == true || FileExists(uncompr) == true)
129 types.push_back("uncompressed");
130 }
131
132 return types;
133 }
134 /*}}}*/
135 // GetLanguages - Return Vector of Language Codes /*{{{*/
136 // ---------------------------------------------------------------------
137 /* return a vector of language codes in the preferred order.
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 */
143 std::vector<std::string> const Configuration::getLanguages(bool const &All,
144 bool const &Cached, char const ** const Locale) {
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
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());
169 if (D != NULL) {
170 builtin.push_back("none");
171 for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
172 string const name = SubstVar(Ent->d_name, "%5f", "_");
173 size_t const foundDash = name.rfind("-");
174 size_t const foundUnderscore = name.rfind("_", foundDash);
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) {
185 if (isalpha(*s) == 0 && *s != '_')
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 }
194 closedir(D);
195 }
196
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") {
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");
204 if (oldAcquire != "none")
205 codes.push_back(oldAcquire);
206 codes.push_back("en");
207 allCodes = codes;
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;
216 }
217
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
221 string const envMsg = string(Locale == 0 ? ::setlocale(LC_MESSAGES, NULL) : *Locale);
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,
229 // so let us generate them now from LC_MESSAGES and LANGUAGE
230 std::vector<string> environment;
231 if (envShort != "C") {
232 // take care of LC_MESSAGES
233 if (envLong != envShort)
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())
249 continue;
250 ++addedLangs;
251 environment.push_back(*e);
252 }
253 }
254 } else {
255 // cornercase: LANG=C, so we use only "en" Translation
256 environment.push_back("en");
257 }
258
259 std::vector<string> const lang = _config->FindVector("Acquire::Languages", "environment,en");
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();
264 l != lang.end(); ++l) {
265 if (*l == "environment") {
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;
270 if (noneSeen == false)
271 codes.push_back(*e);
272 allCodes.push_back(*e);
273 }
274 continue;
275 } else if (*l == "none") {
276 noneSeen = true;
277 continue;
278 } else if (std::find(allCodes.begin(), allCodes.end(), *l) != allCodes.end())
279 continue;
280
281 if (noneSeen == false)
282 codes.push_back(*l);
283 allCodes.push_back(*l);
284 }
285
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 }
295
296 if (All == true)
297 return allCodes;
298 else
299 return codes;
300 }
301 /*}}}*/
302 // checkLanguage - are we interested in the given Language? /*{{{*/
303 bool Configuration::checkLanguage(std::string Lang, bool const All) {
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 /*}}}*/
313 // getArchitectures - Return Vector of preferred Architectures /*{{{*/
314 std::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
321 string const arch = _config->Find("APT::Architecture");
322 archs = _config->FindVector("APT::Architectures");
323
324 if (archs.empty() == true)
325 archs = _system->ArchitecturesSupported();
326
327 if (archs.empty() == true ||
328 std::find(archs.begin(), archs.end(), arch) == archs.end())
329 archs.insert(archs.begin(), arch);
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
340 return archs;
341 }
342 /*}}}*/
343 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
344 bool Configuration::checkArchitecture(std::string const &Arch) {
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 /*}}}*/
351 // getCompressors - Return Vector of usealbe compressors /*{{{*/
352 // ---------------------------------------------------------------------
353 /* return a vector of compressors used by apt-ftparchive in the
354 multicompress functionality or to detect data.tar files */
355 std::vector<APT::Configuration::Compressor>
356 const 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
367 compressors.push_back(Compressor(".", "", "", NULL, NULL, 1));
368 if (_config->Exists("Dir::Bin::gzip") == false || FileExists(_config->FindFile("Dir::Bin::gzip")) == true)
369 compressors.push_back(Compressor("gzip",".gz","gzip","-6n","-d",2));
370 #ifdef HAVE_ZLIB
371 else
372 compressors.push_back(Compressor("gzip",".gz","false", NULL, NULL, 2));
373 #endif
374 if (_config->Exists("Dir::Bin::xz") == false || FileExists(_config->FindFile("Dir::Bin::xz")) == true)
375 compressors.push_back(Compressor("xz",".xz","xz","-6","-d",3));
376 #ifdef HAVE_LZMA
377 else
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","-6","-d",4));
382 #ifdef HAVE_BZ2
383 else
384 compressors.push_back(Compressor("bzip2",".bz2","false", NULL, NULL, 4));
385 #endif
386 if (_config->Exists("Dir::Bin::lzma") == false || FileExists(_config->FindFile("Dir::Bin::lzma")) == true)
387 compressors.push_back(Compressor("lzma",".lzma","lzma","-6","-d",5));
388 #ifdef HAVE_LZMA
389 else
390 compressors.push_back(Compressor("lzma",".lzma","false", NULL, NULL, 5));
391 #endif
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) {
396 if (c->empty() || *c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz")
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 /*}}}*/
404 // getCompressorExtensions - supported data.tar extensions /*{{{*/
405 // ---------------------------------------------------------------------
406 /* */
407 std::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 /*}}}*/
417 // Compressor constructor /*{{{*/
418 // ---------------------------------------------------------------------
419 /* */
420 Configuration::Compressor::Compressor(char const *name, char const *extension,
421 char const *binary,
422 char const *compressArg, char const *uncompressArg,
423 unsigned short const cost) {
424 std::string const config = std::string("APT::Compressor::").append(name).append("::");
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 /*}}}*/
441 // getBuildProfiles - return a vector of enabled build profiles /*{{{*/
442 std::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 }
454 std::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;
460 for (++p; p != profiles.end(); ++p)
461 list.append(",").append(*p);
462 return list;
463 }
464 /*}}}*/
465 }