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