- new History Log, first version (fate #110205)
[platform/upstream/libzypp.git] / zypp / ZConfig.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/ZConfig.cc
10  *
11 */
12 extern "C"
13 {
14 #include <sys/utsname.h>
15 #include <unistd.h>
16 }
17 #include <iostream>
18 #include <fstream>
19 #include "zypp/base/Logger.h"
20 #include "zypp/base/IOStream.h"
21 #include "zypp/base/InputStream.h"
22 #include "zypp/base/String.h"
23
24 #include "zypp/ZConfig.h"
25 #include "zypp/ZYppFactory.h"
26 #include "zypp/PathInfo.h"
27 #include "zypp/parser/IniDict.h"
28
29 using namespace std;
30 using namespace zypp::filesystem;
31 using namespace zypp::parser;
32
33 ///////////////////////////////////////////////////////////////////
34 namespace zypp
35 { /////////////////////////////////////////////////////////////////
36
37   ///////////////////////////////////////////////////////////////////
38   namespace
39   { /////////////////////////////////////////////////////////////////
40
41     /** Determine system architecture evaluating \c uname and \c /proc/cpuinfo.
42     */
43     Arch _autodetectSystemArchitecture()
44     {
45       struct ::utsname buf;
46       if ( ::uname( &buf ) < 0 )
47       {
48         ERR << "Can't determine system architecture" << endl;
49         return Arch_noarch;
50       }
51
52       Arch architecture( buf.machine );
53       MIL << "Uname architecture is '" << buf.machine << "'" << endl;
54
55       // some CPUs report i686 but dont implement cx8 and cmov
56       // check for both flags in /proc/cpuinfo and downgrade
57       // to i586 if either is missing (cf bug #18885)
58       if ( architecture == Arch_i686 )
59       {
60         std::ifstream cpuinfo( "/proc/cpuinfo" );
61         if ( cpuinfo )
62         {
63           for( iostr::EachLine in( cpuinfo ); in; in.next() )
64           {
65             if ( str::hasPrefix( *in, "flags" ) )
66             {
67               if (    in->find( "cx8" ) == std::string::npos
68                    || in->find( "cmov" ) == std::string::npos )
69               {
70                 architecture = Arch_i586;
71                 WAR << "CPU lacks 'cx8' or 'cmov': architecture downgraded to '" << architecture << "'" << endl;
72               }
73               break;
74             }
75           }
76         }
77         else
78         {
79           ERR << "Cant open " << PathInfo("/proc/cpuinfo") << endl;
80         }
81       }
82       return architecture;
83     }
84
85      /** The locale to be used for texts and messages.
86      *
87      * For the encoding to be used the preference is
88      *
89      *    LC_ALL, LC_CTYPE, LANG
90      *
91      * For the language of the messages to be used, the preference is
92      *
93      *    LANGUAGE, LC_ALL, LC_MESSAGES, LANG
94      *
95      * Note that LANGUAGE can contain more than one locale name, it can be
96      * a list of locale names like for example
97      *
98      *    LANGUAGE=ja_JP.UTF-8:de_DE.UTF-8:fr_FR.UTF-8
99
100      * \todo Support dynamic fallbacklists defined by LANGUAGE
101      */
102     Locale _autodetectTextLocale()
103     {
104       Locale ret( "en" );
105       const char * envlist[] = { "LC_ALL", "LC_MESSAGES", "LANG", NULL };
106       for ( const char ** envvar = envlist; *envvar; ++envvar )
107       {
108         const char * envlang = getenv( *envvar );
109         if ( envlang )
110         {
111           std::string envstr( envlang );
112           if ( envstr != "POSIX" && envstr != "C" )
113           {
114             Locale lang( envstr );
115             if ( ! lang.code().empty() )
116             {
117               MIL << "Found " << *envvar << "=" << envstr << endl;
118               ret = lang;
119               break;
120             }
121           }
122         }
123       }
124       MIL << "Default text locale is '" << ret << "'" << endl;
125       return ret;
126     }
127
128    /////////////////////////////////////////////////////////////////
129   } // namespace zypp
130   ///////////////////////////////////////////////////////////////////
131
132   ///////////////////////////////////////////////////////////////////
133   //
134   //    CLASS NAME : ZConfig::Impl
135   //
136   /** ZConfig implementation.
137    * \todo Enrich section and entry definition by some comment
138    * (including the default setting and provide some method to
139    * write this into a sample zypp.conf.
140   */
141   class ZConfig::Impl
142   {
143     public:
144       Impl( const Pathname & override_r = Pathname() )
145         : cfg_arch                      ( defaultSystemArchitecture() )
146         , cfg_textLocale                ( defaultTextLocale() )
147         , repo_add_probe                ( false )
148         , repo_refresh_delay            ( 10 )
149         , download_use_deltarpm         ( true )
150         , solver_onlyRequires           ( false )
151         , apply_locks_file              ( true )
152
153       {
154         MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
155
156         // override_r has higest prio
157         // ZYPP_CONF might override /etc/zypp/zypp.conf
158         Pathname confpath( override_r );
159         if ( confpath.empty() )
160         {
161           const char *env_confpath = getenv( "ZYPP_CONF" );
162           confpath = env_confpath ? env_confpath : "/etc/zypp/zypp.conf";
163         }
164         else
165         {
166           // Inject this into ZConfig. Be shure this is
167           // allocated via new. See: reconfigureZConfig
168           INT << "Reconfigure to " << confpath << endl;
169           ZConfig::instance()._pimpl.reset( this );
170         }
171         if ( PathInfo(confpath).isExist() )
172         {
173           parser::IniDict dict( confpath );
174           //InputStream is(confpath);
175
176           for ( IniDict::section_const_iterator sit = dict.sectionsBegin();
177                 sit != dict.sectionsEnd();
178                 ++sit )
179           {
180             string section(*sit);
181             //MIL << section << endl;
182             for ( IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
183                   it != dict.entriesEnd(*sit);
184                   ++it )
185             {
186               string entry(it->first);
187               string value(it->second);
188               //DBG << (*it).first << "=" << (*it).second << endl;
189               if ( section == "main" )
190               {
191                 if ( entry == "arch" )
192                 {
193                   Arch carch( value );
194                   if ( carch != cfg_arch )
195                   {
196                     WAR << "Overriding system architecture (" << cfg_arch << "): " << carch << endl;
197                     cfg_arch = carch;
198                   }
199                 }
200                 else if ( entry == "cachedir" )
201                 {
202                   cfg_cache_path = Pathname(value);
203                 }
204                 else if ( entry == "metadatadir" )
205                 {
206                   cfg_metadata_path = Pathname(value);
207                 }
208                 else if ( entry == "solvfilesdir" )
209                 {
210                   cfg_solvfiles_path = Pathname(value);
211                 }
212                 else if ( entry == "packagesdir" )
213                 {
214                   cfg_packages_path = Pathname(value);
215                 }
216                 else if ( entry == "configdir" )
217                 {
218                   cfg_config_path = Pathname(value);
219                 }
220                 else if ( entry == "reposdir" )
221                 {
222                   cfg_known_repos_path = Pathname(value);
223                 }
224                 else if ( entry == "repo.add.probe" )
225                 {
226                   repo_add_probe = str::strToBool( value, repo_add_probe );
227                 }
228                 else if ( entry == "repo.refresh.delay" )
229                 {
230                   str::strtonum(value, repo_refresh_delay);
231                 }
232                 else if ( entry == "download.use_deltarpm" )
233                 {
234                   download_use_deltarpm = str::strToBool( value, download_use_deltarpm );
235                 }
236                 else if ( entry == "vendordir" )
237                 {
238                   cfg_vendor_path = Pathname(value);
239                 }
240                 else if ( entry == "productsdir" )
241                 {
242                   cfg_products_path = Pathname(value);
243                 }
244                 else if ( entry == "solver.onlyRequires" )
245                 {
246                   solver_onlyRequires = str::strToBool( value, solver_onlyRequires );
247                 }
248                 else if ( entry == "solver.checkSystemFile" )
249                 {
250                   solver_checkSystemFile = Pathname(value);
251                 }
252                 else if ( entry == "multiversion" )
253                 {
254                   std::list<std::string> multi;
255                   str::split( value, back_inserter(multi), ", \t" );
256                   for ( std::list<string>::const_iterator it = multi.begin();
257                         it != multi.end(); it++) {
258                       multiversion.insert (IdString(*it));
259                   }
260                 }
261                 else if ( entry == "locksfile.path" )
262                 {
263                   locks_file = Pathname(value);
264                 }
265                 else if ( entry == "locksfile.apply" )
266                 {
267                   apply_locks_file = str::strToBool( value, apply_locks_file );
268                 }
269                 else if ( entry == "update.datadir" )
270                 {
271                   update_data_path = Pathname(value);
272                 }
273                 else if ( entry == "update.scriptsdir" )
274                 {
275                   update_scripts_path = Pathname(value);
276                 }
277                 else if ( entry == "update.messagessdir" )
278                 {
279                   update_messages_path = Pathname(value);
280                 }
281                 else if ( entry == "rpm.install.excludedocs" )
282                 {
283                   rpmInstallFlags.setFlag( target::rpm::RPMINST_EXCLUDEDOCS );
284                 }
285                 else if ( entry == "history.logfile" )
286                 {
287                   history_log_path = Pathname(value);
288                 }
289               }
290             }
291           }
292         }
293         else
294         {
295           MIL << confpath << " not found, using defaults instead." << endl;
296         }
297
298         // legacy:
299         if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
300         {
301           Arch carch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
302           if ( carch != cfg_arch )
303           {
304             WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Overriding system architecture (" << cfg_arch << "): " << carch << endl;
305             cfg_arch = carch;
306           }
307         }
308
309         MIL << "ZConfig singleton created." << endl;
310         MIL << "defaultTextLocale: '" << cfg_textLocale << "'" << endl;
311         MIL << "System architecture is '" << cfg_arch << "'" << endl;
312       }
313
314       ~Impl()
315       {}
316
317     public:
318     Arch     cfg_arch;
319     Locale   cfg_textLocale;
320
321     Pathname cfg_cache_path;
322     Pathname cfg_metadata_path;
323     Pathname cfg_solvfiles_path;
324     Pathname cfg_packages_path;
325
326     Pathname cfg_config_path;
327     Pathname cfg_known_repos_path;
328     Pathname cfg_known_services_path;
329     Pathname cfg_vendor_path;
330     Pathname cfg_products_path;
331     Pathname locks_file;
332
333     Pathname update_data_path;
334     Pathname update_scripts_path;
335     Pathname update_messages_path;
336
337     bool repo_add_probe;
338     unsigned repo_refresh_delay;
339
340     bool download_use_deltarpm;
341
342     bool solver_onlyRequires;
343     Pathname solver_checkSystemFile;
344
345     std::set<IdString> multiversion;
346
347     bool apply_locks_file;
348
349     target::rpm::RpmInstFlags rpmInstallFlags;
350     
351     Pathname history_log_path;
352   };
353   ///////////////////////////////////////////////////////////////////
354
355   // Backdoor to redirect ZConfig from within the running
356   // TEST-application. HANDLE WITH CARE!
357   void reconfigureZConfig( const Pathname & override_r )
358   {
359     // ctor puts itself unter smart pointer control.
360     new ZConfig::Impl( override_r );
361   }
362
363   ///////////////////////////////////////////////////////////////////
364   //
365   //    METHOD NAME : ZConfig::instance
366   //    METHOD TYPE : ZConfig &
367   //
368   ZConfig & ZConfig::instance()
369   {
370     static ZConfig _instance; // The singleton
371     return _instance;
372   }
373
374   ///////////////////////////////////////////////////////////////////
375   //
376   //    METHOD NAME : ZConfig::ZConfig
377   //    METHOD TYPE : Ctor
378   //
379   ZConfig::ZConfig()
380   : _pimpl( new Impl )
381   {}
382
383   ///////////////////////////////////////////////////////////////////
384   //
385   //    METHOD NAME : ZConfig::~ZConfig
386   //    METHOD TYPE : Dtor
387   //
388   ZConfig::~ZConfig( )
389   {}
390
391   ///////////////////////////////////////////////////////////////////
392   //
393   // system architecture
394   //
395   ///////////////////////////////////////////////////////////////////
396
397   Arch ZConfig::defaultSystemArchitecture()
398   {
399     static Arch _val( _autodetectSystemArchitecture() );
400     return _val;
401   }
402
403   Arch ZConfig::systemArchitecture() const
404   { return _pimpl->cfg_arch; }
405
406   void ZConfig::setSystemArchitecture( const Arch & arch_r )
407   {
408     if ( arch_r != _pimpl->cfg_arch )
409     {
410       WAR << "Overriding system architecture (" << _pimpl->cfg_arch << "): " << arch_r << endl;
411       _pimpl->cfg_arch = arch_r;
412     }
413   }
414
415   ///////////////////////////////////////////////////////////////////
416   //
417   // text locale
418   //
419   ///////////////////////////////////////////////////////////////////
420
421   Locale ZConfig::defaultTextLocale()
422   {
423     static Locale _val( _autodetectTextLocale() );
424     return _val;
425   }
426
427   Locale ZConfig::textLocale() const
428   { return _pimpl->cfg_textLocale; }
429
430   void ZConfig::setTextLocale( const Locale & locale_r )
431   {
432     if ( locale_r != _pimpl->cfg_textLocale )
433     {
434       WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
435       _pimpl->cfg_textLocale = locale_r;
436     }
437   }
438
439   ///////////////////////////////////////////////////////////////////
440
441   Pathname ZConfig::repoCachePath() const
442   {
443     return ( _pimpl->cfg_cache_path.empty()
444         ? Pathname("/var/cache/zypp") : _pimpl->cfg_cache_path );
445   }
446
447   Pathname ZConfig::repoMetadataPath() const
448   {
449     return ( _pimpl->cfg_metadata_path.empty()
450         ? (repoCachePath()/"raw") : _pimpl->cfg_metadata_path );
451   }
452
453   Pathname ZConfig::repoSolvfilesPath() const
454   {
455     return ( _pimpl->cfg_solvfiles_path.empty()
456         ? (repoCachePath()/"solv") : _pimpl->cfg_solvfiles_path );
457   }
458
459   Pathname ZConfig::repoPackagesPath() const
460   {
461     return ( _pimpl->cfg_packages_path.empty()
462         ? (repoCachePath()/"packages") : _pimpl->cfg_packages_path );
463   }
464
465   ///////////////////////////////////////////////////////////////////
466
467   Pathname ZConfig::configPath() const
468   {
469     return ( _pimpl->cfg_config_path.empty()
470         ? Pathname("/etc/zypp") : _pimpl->cfg_config_path );
471   }
472
473   Pathname ZConfig::knownReposPath() const
474   {
475     return ( _pimpl->cfg_known_repos_path.empty()
476         ? (configPath()/"repos.d") : _pimpl->cfg_known_repos_path );
477   }
478
479   Pathname ZConfig::knownServicesPath() const
480   {
481     return ( _pimpl->cfg_known_services_path.empty()
482         ? (configPath()/"services.d") : _pimpl->cfg_known_repos_path );
483   }
484
485   Pathname ZConfig::vendorPath() const
486   {
487     return ( _pimpl->cfg_vendor_path.empty()
488         ? (configPath()/"vendors.d") : _pimpl->cfg_vendor_path );
489   }
490
491   Pathname ZConfig::productsPath() const
492   {
493     return ( _pimpl->cfg_products_path.empty()
494         ? (configPath()/"products.d") : _pimpl->cfg_products_path );
495   }
496
497   Pathname ZConfig::locksFile() const
498   {
499     return ( _pimpl->locks_file.empty()
500         ? (configPath()/"locks") : _pimpl->locks_file );
501   }
502
503   ///////////////////////////////////////////////////////////////////
504
505   bool ZConfig::repo_add_probe() const
506   {
507     return _pimpl->repo_add_probe;
508   }
509
510   unsigned ZConfig::repo_refresh_delay() const
511   {
512     return _pimpl->repo_refresh_delay;
513   }
514
515   bool ZConfig::download_use_deltarpm() const
516   { return _pimpl->download_use_deltarpm; }
517
518
519   bool ZConfig::solver_onlyRequires() const
520   { return _pimpl->solver_onlyRequires; }
521
522   Pathname ZConfig::solver_checkSystemFile() const
523   { return _pimpl->solver_checkSystemFile; }
524
525
526   std::set<IdString> ZConfig::multiversion() const
527   { return _pimpl->multiversion; }
528
529   void ZConfig::addMultiversion(std::string &name)
530   { _pimpl->multiversion.insert(IdString(name)); }
531
532   bool ZConfig::removeMultiversion(std::string &name)
533   { return _pimpl->multiversion.erase(IdString(name)); }
534
535   bool ZConfig::apply_locks_file() const
536   {
537     return _pimpl->apply_locks_file;
538   }
539
540   Pathname ZConfig::update_dataPath() const
541   {
542     return ( _pimpl->update_data_path.empty()
543         ? Pathname("/var/adm") : _pimpl->update_data_path );
544   }
545
546   Pathname ZConfig::update_messagesPath() const
547   {
548     return ( _pimpl->update_messages_path.empty()
549              ? Pathname(update_dataPath()/"update-messages") : _pimpl->update_messages_path );
550   }
551
552
553   Pathname ZConfig::update_scriptsPath() const
554   {
555     return ( _pimpl->update_scripts_path.empty()
556              ? Pathname(update_dataPath()/"update-scripts") : _pimpl->update_scripts_path );
557   }
558
559   ///////////////////////////////////////////////////////////////////
560
561   target::rpm::RpmInstFlags ZConfig::rpmInstallFlags() const
562   { return _pimpl->rpmInstallFlags; }
563
564
565   Pathname ZConfig::historyLogFile() const
566   {
567     return ( _pimpl->history_log_path.empty() ?
568         Pathname("/var/log/zypp/history") : _pimpl->history_log_path );
569   }
570
571
572   /////////////////////////////////////////////////////////////////
573 } // namespace zypp
574 ///////////////////////////////////////////////////////////////////