]>
git.saurik.com Git - apt.git/blob - apt-pkg/aptconfiguration.cc
f0cd8ebc088502ea0b33fc08fbb76205b978205d
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
5 Provide access methods to various configuration settings,
6 setup defaults and returns validate settings.
8 ##################################################################### */
10 // Include Files /*{{{*/
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>
20 #include <sys/types.h>
30 // getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/
31 // ---------------------------------------------------------------------
32 /* return a vector of compression types in the prefered order. */
33 std::vector
<std::string
>
34 const Configuration::getCompressionTypes(bool const &Cached
) {
35 static std::vector
<std::string
> types
;
36 if (types
.empty() == false) {
43 // setup the defaults for the compressiontypes => method mapping
44 _config
->CndSet("Acquire::CompressionTypes::bz2","bzip2");
45 _config
->CndSet("Acquire::CompressionTypes::xz","xz");
46 _config
->CndSet("Acquire::CompressionTypes::lzma","lzma");
47 _config
->CndSet("Acquire::CompressionTypes::gz","gzip");
49 setDefaultConfigurationForCompressors();
50 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
52 // accept non-list order as override setting for config settings on commandline
53 std::string
const overrideOrder
= _config
->Find("Acquire::CompressionTypes::Order","");
54 if (overrideOrder
.empty() == false)
55 types
.push_back(overrideOrder
);
57 // load the order setting into our vector
58 std::vector
<std::string
> const order
= _config
->FindVector("Acquire::CompressionTypes::Order");
59 for (std::vector
<std::string
>::const_iterator o
= order
.begin();
60 o
!= order
.end(); ++o
) {
61 if ((*o
).empty() == true)
63 // ignore types we have no method ready to use
64 if (_config
->Exists(std::string("Acquire::CompressionTypes::").append(*o
)) == false)
66 // ignore types we have no app ready to use
67 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
68 for (; c
!= compressors
.end(); ++c
)
71 if (c
== compressors
.end())
76 // move again over the option tree to add all missing compression types
77 ::Configuration::Item
const *Types
= _config
->Tree("Acquire::CompressionTypes");
81 for (; Types
!= 0; Types
= Types
->Next
) {
82 if (Types
->Tag
== "Order" || Types
->Tag
.empty() == true)
84 // ignore types we already have in the vector
85 if (std::find(types
.begin(),types
.end(),Types
->Tag
) != types
.end())
87 // ignore types we have no app ready to use
88 std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
89 for (; c
!= compressors
.end(); ++c
)
90 if (c
->Name
== Types
->Value
)
92 if (c
== compressors
.end())
94 types
.push_back(Types
->Tag
);
97 // add the special "uncompressed" type
98 if (std::find(types
.begin(), types
.end(), "uncompressed") == types
.end())
100 std::string
const uncompr
= _config
->FindFile("Dir::Bin::uncompressed", "");
101 if (uncompr
.empty() == true || FileExists(uncompr
) == true)
102 types
.push_back("uncompressed");
108 // GetLanguages - Return Vector of Language Codes /*{{{*/
109 // ---------------------------------------------------------------------
110 /* return a vector of language codes in the prefered order.
111 the special word "environment" will be replaced with the long and the short
112 code of the local settings and it will be insured that this will not add
113 duplicates. So in an german local the setting "environment, de_DE, en, de"
114 will result in "de_DE, de, en".
115 The special word "none" is the stopcode for the not-All code vector */
116 std::vector
<std::string
> const Configuration::getLanguages(bool const &All
,
117 bool const &Cached
, char const ** const Locale
) {
120 // The detection is boring and has a lot of cornercases,
121 // so we cache the results to calculated it only once.
122 std::vector
<string
> static allCodes
;
123 std::vector
<string
> static codes
;
125 // we have something in the cache
126 if (codes
.empty() == false || allCodes
.empty() == false) {
127 if (Cached
== true) {
128 if(All
== true && allCodes
.empty() == false)
138 // Include all Language codes we have a Translation file for in /var/lib/apt/lists
139 // so they will be all included in the Cache.
140 std::vector
<string
> builtin
;
141 DIR *D
= opendir(_config
->FindDir("Dir::State::lists").c_str());
143 builtin
.push_back("none");
144 for (struct dirent
*Ent
= readdir(D
); Ent
!= 0; Ent
= readdir(D
)) {
145 string
const name
= Ent
->d_name
;
146 size_t const foundDash
= name
.rfind("-");
147 size_t const foundUnderscore
= name
.rfind("_", foundDash
);
148 if (foundDash
== string::npos
|| foundUnderscore
== string::npos
||
149 foundDash
<= foundUnderscore
||
150 name
.substr(foundUnderscore
+1, foundDash
-(foundUnderscore
+1)) != "Translation")
152 string
const c
= name
.substr(foundDash
+1);
153 if (unlikely(c
.empty() == true) || c
== "en")
155 // Skip unusual files, like backups or that alike
156 string::const_iterator s
= c
.begin();
157 for (;s
!= c
.end(); ++s
) {
158 if (isalpha(*s
) == 0 && *s
!= '_')
163 if (std::find(builtin
.begin(), builtin
.end(), c
) != builtin
.end())
165 builtin
.push_back(c
);
170 // FIXME: Remove support for the old APT::Acquire::Translation
171 // it was undocumented and so it should be not very widthly used
172 string
const oldAcquire
= _config
->Find("APT::Acquire::Translation","");
173 if (oldAcquire
.empty() == false && oldAcquire
!= "environment") {
174 // TRANSLATORS: the two %s are APT configuration options
175 _error
->Notice("Option '%s' is deprecated. Please use '%s' instead, see 'man 5 apt.conf' for details.",
176 "APT::Acquire::Translation", "Acquire::Languages");
177 if (oldAcquire
!= "none")
178 codes
.push_back(oldAcquire
);
179 codes
.push_back("en");
181 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
182 b
!= builtin
.end(); ++b
)
183 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
184 allCodes
.push_back(*b
);
191 // get the environment language codes: LC_MESSAGES (and later LANGUAGE)
192 // we extract both, a long and a short code and then we will
193 // check if we actually need both (rare) or if the short is enough
194 string
const envMsg
= string(Locale
== 0 ? std::setlocale(LC_MESSAGES
, NULL
) : *Locale
);
195 size_t const lenShort
= (envMsg
.find('_') != string::npos
) ? envMsg
.find('_') : 2;
196 size_t const lenLong
= (envMsg
.find_first_of(".@") != string::npos
) ? envMsg
.find_first_of(".@") : (lenShort
+ 3);
198 string
const envLong
= envMsg
.substr(0,lenLong
);
199 string
const envShort
= envLong
.substr(0,lenShort
);
201 // It is very likely we will need the environment codes later,
202 // so let us generate them now from LC_MESSAGES and LANGUAGE
203 std::vector
<string
> environment
;
204 if (envShort
!= "C") {
205 // take care of LC_MESSAGES
206 if (envLong
!= envShort
)
207 environment
.push_back(envLong
);
208 environment
.push_back(envShort
);
209 // take care of LANGUAGE
210 const char *language_env
= getenv("LANGUAGE") == 0 ? "" : getenv("LANGUAGE");
211 string envLang
= Locale
== 0 ? language_env
: *(Locale
+1);
212 if (envLang
.empty() == false) {
213 std::vector
<string
> env
= VectorizeString(envLang
,':');
214 short addedLangs
= 0; // add a maximum of 3 fallbacks from the environment
215 for (std::vector
<string
>::const_iterator e
= env
.begin();
216 e
!= env
.end() && addedLangs
< 3; ++e
) {
217 if (unlikely(e
->empty() == true) || *e
== "en")
219 if (*e
== envLong
|| *e
== envShort
)
221 if (std::find(environment
.begin(), environment
.end(), *e
) != environment
.end())
224 environment
.push_back(*e
);
228 environment
.push_back("en");
231 // Support settings like Acquire::Languages=none on the command line to
232 // override the configuration settings vector of languages.
233 string
const forceLang
= _config
->Find("Acquire::Languages","");
234 if (forceLang
.empty() == false) {
235 if (forceLang
== "environment") {
237 } else if (forceLang
!= "none")
238 codes
.push_back(forceLang
);
239 else //if (forceLang == "none")
242 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
243 b
!= builtin
.end(); ++b
)
244 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
245 allCodes
.push_back(*b
);
252 // cornercase: LANG=C, so we use only "en" Translation
253 if (envShort
== "C") {
254 allCodes
= codes
= environment
;
255 allCodes
.insert(allCodes
.end(), builtin
.begin(), builtin
.end());
262 std::vector
<string
> const lang
= _config
->FindVector("Acquire::Languages");
263 // the default setting -> "environment, en"
264 if (lang
.empty() == true) {
266 if (envShort
!= "en")
267 codes
.push_back("en");
269 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
270 b
!= builtin
.end(); ++b
)
271 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
272 allCodes
.push_back(*b
);
279 // the configs define the order, so add the environment
280 // then needed and ensure the codes are not listed twice.
281 bool noneSeen
= false;
282 for (std::vector
<string
>::const_iterator l
= lang
.begin();
283 l
!= lang
.end(); ++l
) {
284 if (*l
== "environment") {
285 for (std::vector
<string
>::const_iterator e
= environment
.begin();
286 e
!= environment
.end(); ++e
) {
287 if (std::find(allCodes
.begin(), allCodes
.end(), *e
) != allCodes
.end())
289 if (noneSeen
== false)
291 allCodes
.push_back(*e
);
294 } else if (*l
== "none") {
297 } else if (std::find(allCodes
.begin(), allCodes
.end(), *l
) != allCodes
.end())
300 if (noneSeen
== false)
302 allCodes
.push_back(*l
);
305 for (std::vector
<string
>::const_iterator b
= builtin
.begin();
306 b
!= builtin
.end(); ++b
)
307 if (std::find(allCodes
.begin(), allCodes
.end(), *b
) == allCodes
.end())
308 allCodes
.push_back(*b
);
316 // getArchitectures - Return Vector of prefered Architectures /*{{{*/
317 std::vector
<std::string
> const Configuration::getArchitectures(bool const &Cached
) {
320 std::vector
<string
> static archs
;
321 if (likely(Cached
== true) && archs
.empty() == false)
324 string
const arch
= _config
->Find("APT::Architecture");
325 archs
= _config
->FindVector("APT::Architectures");
327 if (unlikely(arch
.empty() == true))
330 // FIXME: It is a bit unclean to have debian specific code here…
331 if (archs
.empty() == true) {
332 archs
.push_back(arch
);
334 // Generate the base argument list for dpkg
335 std::vector
<const char *> Args
;
336 string Tmp
= _config
->Find("Dir::Bin::dpkg","dpkg");
338 string
const dpkgChrootDir
= _config
->FindDir("DPkg::Chroot-Directory", "/");
339 size_t dpkgChrootLen
= dpkgChrootDir
.length();
340 if (dpkgChrootDir
!= "/" && Tmp
.find(dpkgChrootDir
) == 0) {
341 if (dpkgChrootDir
[dpkgChrootLen
- 1] == '/')
343 Tmp
= Tmp
.substr(dpkgChrootLen
);
346 Args
.push_back(Tmp
.c_str());
348 // Stick in any custom dpkg options
349 ::Configuration::Item
const *Opts
= _config
->Tree("DPkg::Options");
352 for (; Opts
!= 0; Opts
= Opts
->Next
)
354 if (Opts
->Value
.empty() == true)
356 Args
.push_back(Opts
->Value
.c_str());
360 Args
.push_back("--print-foreign-architectures");
361 Args
.push_back(NULL
);
363 int external
[2] = {-1, -1};
364 if (pipe(external
) != 0)
366 _error
->WarningE("getArchitecture", "Can't create IPC pipe for dpkg --print-foreign-architectures");
370 pid_t dpkgMultiArch
= ExecFork();
371 if (dpkgMultiArch
== 0) {
373 std::string
const chrootDir
= _config
->FindDir("DPkg::Chroot-Directory");
374 if (chrootDir
!= "/" && chroot(chrootDir
.c_str()) != 0)
375 _error
->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --print-foreign-architectures", chrootDir
.c_str());
376 int const nullfd
= open("/dev/null", O_RDONLY
);
377 dup2(nullfd
, STDIN_FILENO
);
378 dup2(external
[1], STDOUT_FILENO
);
379 dup2(nullfd
, STDERR_FILENO
);
380 execvp(Args
[0], (char**) &Args
[0]);
381 _error
->WarningE("getArchitecture", "Can't detect foreign architectures supported by dpkg!");
386 FILE *dpkg
= fdopen(external
[0], "r");
389 while (fgets(buf
, sizeof(buf
), dpkg
) != NULL
) {
390 char* arch
= strtok(buf
, " ");
391 while (arch
!= NULL
) {
392 for (; isspace(*arch
) != 0; ++arch
);
393 if (arch
[0] != '\0') {
394 char const* archend
= arch
;
395 for (; isspace(*archend
) == 0 && *archend
!= '\0'; ++archend
);
396 string
a(arch
, (archend
- arch
));
397 if (std::find(archs
.begin(), archs
.end(), a
) == archs
.end())
400 arch
= strtok(NULL
, " ");
405 ExecWait(dpkgMultiArch
, "dpkg --print-foreign-architectures", true);
409 if (archs
.empty() == true ||
410 std::find(archs
.begin(), archs
.end(), arch
) == archs
.end())
411 archs
.insert(archs
.begin(), arch
);
413 // erase duplicates and empty strings
414 for (std::vector
<string
>::reverse_iterator a
= archs
.rbegin();
415 a
!= archs
.rend(); ++a
) {
416 if (a
->empty() == true || std::find(a
+ 1, archs
.rend(), *a
) != archs
.rend())
417 archs
.erase(a
.base()-1);
418 if (a
== archs
.rend())
425 // checkArchitecture - are we interested in the given Architecture? /*{{{*/
426 bool const Configuration::checkArchitecture(std::string
const &Arch
) {
429 std::vector
<std::string
> const archs
= getArchitectures(true);
430 return (std::find(archs
.begin(), archs
.end(), Arch
) != archs
.end());
433 // setDefaultConfigurationForCompressors /*{{{*/
434 void Configuration::setDefaultConfigurationForCompressors() {
435 // Set default application paths to check for optional compression types
436 _config
->CndSet("Dir::Bin::bzip2", "/bin/bzip2");
437 _config
->CndSet("Dir::Bin::xz", "/usr/bin/xz");
438 if (FileExists(_config
->FindFile("Dir::Bin::xz")) == true) {
439 _config
->Clear("Dir::Bin::lzma");
440 _config
->Set("APT::Compressor::lzma::Binary", "xz");
441 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
442 _config
->Set("APT::Compressor::lzma::CompressArg::", "--format=lzma");
443 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
445 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
446 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--format=lzma");
447 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
450 _config
->CndSet("Dir::Bin::lzma", "/usr/bin/lzma");
451 if (_config
->Exists("APT::Compressor::lzma::CompressArg") == false) {
452 _config
->Set("APT::Compressor::lzma::CompressArg::", "--suffix=");
453 _config
->Set("APT::Compressor::lzma::CompressArg::", "-9");
455 if (_config
->Exists("APT::Compressor::lzma::UncompressArg") == false) {
456 _config
->Set("APT::Compressor::lzma::UncompressArg::", "--suffix=");
457 _config
->Set("APT::Compressor::lzma::UncompressArg::", "-d");
462 // getCompressors - Return Vector of usbale compressors /*{{{*/
463 // ---------------------------------------------------------------------
464 /* return a vector of compressors used by apt-ftparchive in the
465 multicompress functionality or to detect data.tar files */
466 std::vector
<APT::Configuration::Compressor
>
467 const Configuration::getCompressors(bool const Cached
) {
468 static std::vector
<APT::Configuration::Compressor
> compressors
;
469 if (compressors
.empty() == false) {
476 setDefaultConfigurationForCompressors();
478 compressors
.push_back(Compressor(".", "", "", "", "", 1));
479 if (_config
->Exists("Dir::Bin::gzip") == false || FileExists(_config
->FindFile("Dir::Bin::gzip")) == true)
480 compressors
.push_back(Compressor("gzip",".gz","gzip","-9n","-d",2));
483 compressors
.push_back(Compressor("gzip",".gz","false", "", "", 2));
485 if (_config
->Exists("Dir::Bin::bzip2") == false || FileExists(_config
->FindFile("Dir::Bin::bzip2")) == true)
486 compressors
.push_back(Compressor("bzip2",".bz2","bzip2","-9","-d",3));
489 compressors
.push_back(Compressor("bzip2",".bz2","false", "", "", 3));
491 if (_config
->Exists("Dir::Bin::xz") == false || FileExists(_config
->FindFile("Dir::Bin::xz")) == true)
492 compressors
.push_back(Compressor("xz",".xz","xz","-6","-d",4));
493 if (_config
->Exists("Dir::Bin::lzma") == false || FileExists(_config
->FindFile("Dir::Bin::lzma")) == true)
494 compressors
.push_back(Compressor("lzma",".lzma","lzma","-9","-d",5));
496 std::vector
<std::string
> const comp
= _config
->FindVector("APT::Compressor");
497 for (std::vector
<std::string
>::const_iterator c
= comp
.begin();
498 c
!= comp
.end(); ++c
) {
499 if (*c
== "." || *c
== "gzip" || *c
== "bzip2" || *c
== "lzma" || *c
== "xz")
501 compressors
.push_back(Compressor(c
->c_str(), std::string(".").append(*c
).c_str(), c
->c_str(), "-9", "-d", 100));
507 // getCompressorExtensions - supported data.tar extensions /*{{{*/
508 // ---------------------------------------------------------------------
510 std::vector
<std::string
> const Configuration::getCompressorExtensions() {
511 std::vector
<APT::Configuration::Compressor
> const compressors
= getCompressors();
512 std::vector
<std::string
> ext
;
513 for (std::vector
<APT::Configuration::Compressor
>::const_iterator c
= compressors
.begin();
514 c
!= compressors
.end(); ++c
)
515 if (c
->Extension
.empty() == false && c
->Extension
!= ".")
516 ext
.push_back(c
->Extension
);
520 // Compressor constructor /*{{{*/
521 // ---------------------------------------------------------------------
523 Configuration::Compressor::Compressor(char const *name
, char const *extension
,
525 char const *compressArg
, char const *uncompressArg
,
526 unsigned short const cost
) {
527 std::string
const config
= std::string("APT::Compressor::").append(name
).append("::");
528 Name
= _config
->Find(std::string(config
).append("Name"), name
);
529 Extension
= _config
->Find(std::string(config
).append("Extension"), extension
);
530 Binary
= _config
->Find(std::string(config
).append("Binary"), binary
);
531 Cost
= _config
->FindI(std::string(config
).append("Cost"), cost
);
532 std::string
const compConf
= std::string(config
).append("CompressArg");
533 if (_config
->Exists(compConf
) == true)
534 CompressArgs
= _config
->FindVector(compConf
);
535 else if (compressArg
!= NULL
)
536 CompressArgs
.push_back(compressArg
);
537 std::string
const uncompConf
= std::string(config
).append("UncompressArg");
538 if (_config
->Exists(uncompConf
) == true)
539 UncompressArgs
= _config
->FindVector(uncompConf
);
540 else if (uncompressArg
!= NULL
)
541 UncompressArgs
.push_back(uncompressArg
);