Merge branch 'master' of git@git.opensuse.org:projects/zypp/libzypp
[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 #undef ZYPP_BASE_LOGGER_LOGGROUP
34 #define ZYPP_BASE_LOGGER_LOGGROUP "zconfig"
35
36 ///////////////////////////////////////////////////////////////////
37 namespace zypp
38 { /////////////////////////////////////////////////////////////////
39
40   ///////////////////////////////////////////////////////////////////
41   namespace
42   { /////////////////////////////////////////////////////////////////
43
44     /** Determine system architecture evaluating \c uname and \c /proc/cpuinfo.
45     */
46     Arch _autodetectSystemArchitecture()
47     {
48       struct ::utsname buf;
49       if ( ::uname( &buf ) < 0 )
50       {
51         ERR << "Can't determine system architecture" << endl;
52         return Arch_noarch;
53       }
54
55       Arch architecture( buf.machine );
56       MIL << "Uname architecture is '" << buf.machine << "'" << endl;
57
58       // some CPUs report i686 but dont implement cx8 and cmov
59       // check for both flags in /proc/cpuinfo and downgrade
60       // to i586 if either is missing (cf bug #18885)
61       if ( architecture == Arch_i686 )
62       {
63         std::ifstream cpuinfo( "/proc/cpuinfo" );
64         if ( cpuinfo )
65         {
66           for( iostr::EachLine in( cpuinfo ); in; in.next() )
67           {
68             if ( str::hasPrefix( *in, "flags" ) )
69             {
70               if (    in->find( "cx8" ) == std::string::npos
71                    || in->find( "cmov" ) == std::string::npos )
72               {
73                 architecture = Arch_i586;
74                 WAR << "CPU lacks 'cx8' or 'cmov': architecture downgraded to '" << architecture << "'" << endl;
75               }
76               break;
77             }
78           }
79         }
80         else
81         {
82           ERR << "Cant open " << PathInfo("/proc/cpuinfo") << endl;
83         }
84       }
85       return architecture;
86     }
87
88      /** The locale to be used for texts and messages.
89      *
90      * For the encoding to be used the preference is
91      *
92      *    LC_ALL, LC_CTYPE, LANG
93      *
94      * For the language of the messages to be used, the preference is
95      *
96      *    LANGUAGE, LC_ALL, LC_MESSAGES, LANG
97      *
98      * Note that LANGUAGE can contain more than one locale name, it can be
99      * a list of locale names like for example
100      *
101      *    LANGUAGE=ja_JP.UTF-8:de_DE.UTF-8:fr_FR.UTF-8
102
103      * \todo Support dynamic fallbacklists defined by LANGUAGE
104      */
105     Locale _autodetectTextLocale()
106     {
107       Locale ret( "en" );
108       const char * envlist[] = { "LC_ALL", "LC_MESSAGES", "LANG", NULL };
109       for ( const char ** envvar = envlist; *envvar; ++envvar )
110       {
111         const char * envlang = getenv( *envvar );
112         if ( envlang )
113         {
114           std::string envstr( envlang );
115           if ( envstr != "POSIX" && envstr != "C" )
116           {
117             Locale lang( envstr );
118             if ( ! lang.code().empty() )
119             {
120               MIL << "Found " << *envvar << "=" << envstr << endl;
121               ret = lang;
122               break;
123             }
124           }
125         }
126       }
127       MIL << "Default text locale is '" << ret << "'" << endl;
128 #warning HACK AROUND BOOST_TEST_CATCH_SYSTEM_ERRORS
129       setenv( "BOOST_TEST_CATCH_SYSTEM_ERRORS", "no", 1 );
130       return ret;
131     }
132
133    /////////////////////////////////////////////////////////////////
134   } // namespace zypp
135   ///////////////////////////////////////////////////////////////////
136
137   /** Mutable option with initial value. */
138   template<class _Tp, _Tp _Initial>
139       struct Option
140       {
141         typedef _Tp value_type;
142
143         Option()
144           : _val( _Initial )
145         {}
146
147         value_type get() const
148         { return _val; }
149
150         void set( const value_type & newval_r )
151         { _val = newval_r; }
152
153         private:
154           value_type _val;
155       };
156
157   /** Mutable option with initial value also remembering a config value. */
158   template<class _Tp, _Tp _Initial>
159       struct DefaultOption : public Option<_Tp,_Initial>
160       {
161         typedef _Tp                  value_type;
162         typedef Option<_Tp,_Initial> option_type;
163
164         void restoreDefault()
165         { this->set( _default.get() ); }
166
167         void restoreDefault( const value_type & newval_r )
168         { setDefault( newval_r ); restoreDefault(); }
169
170         value_type getDefault() const
171         { return _default.get(); }
172
173         void setDefault( const value_type & newval_r )
174         { _default.set( newval_r ); }
175
176         private:
177           option_type _default;
178       };
179
180   ///////////////////////////////////////////////////////////////////
181   //
182   //    CLASS NAME : ZConfig::Impl
183   //
184   /** ZConfig implementation.
185    * \todo Enrich section and entry definition by some comment
186    * (including the default setting and provide some method to
187    * write this into a sample zypp.conf.
188   */
189   class ZConfig::Impl
190   {
191     public:
192       Impl( const Pathname & override_r = Pathname() )
193         : _parsedZyppConf               ( override_r )
194         , cfg_arch                      ( defaultSystemArchitecture() )
195         , cfg_textLocale                ( defaultTextLocale() )
196         , repo_add_probe                ( false )
197         , repo_refresh_delay            ( 10 )
198         , download_use_deltarpm         ( true )
199         , download_use_deltarpm_always  ( false )
200         , download_max_concurrent_connections(2)
201         , download_min_download_speed(0)
202         , download_max_download_speed(0)
203         , download_max_silent_tries(5)
204         , solver_onlyRequires           ( false )
205         , apply_locks_file              ( true )
206
207       {
208         MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
209         // override_r has higest prio
210         // ZYPP_CONF might override /etc/zypp/zypp.conf
211         if ( _parsedZyppConf.empty() )
212         {
213           const char *env_confpath = getenv( "ZYPP_CONF" );
214           _parsedZyppConf = env_confpath ? env_confpath : "/etc/zypp/zypp.conf";
215         }
216         else
217         {
218           // Inject this into ZConfig. Be shure this is
219           // allocated via new. See: reconfigureZConfig
220           INT << "Reconfigure to " << _parsedZyppConf << endl;
221           ZConfig::instance()._pimpl.reset( this );
222         }
223         if ( PathInfo(_parsedZyppConf).isExist() )
224         {
225           parser::IniDict dict( _parsedZyppConf );
226           for ( IniDict::section_const_iterator sit = dict.sectionsBegin();
227                 sit != dict.sectionsEnd();
228                 ++sit )
229           {
230             string section(*sit);
231             //MIL << section << endl;
232             for ( IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
233                   it != dict.entriesEnd(*sit);
234                   ++it )
235             {
236               string entry(it->first);
237               string value(it->second);
238               //DBG << (*it).first << "=" << (*it).second << endl;
239               if ( section == "main" )
240               {
241                 if ( entry == "arch" )
242                 {
243                   Arch carch( value );
244                   if ( carch != cfg_arch )
245                   {
246                     WAR << "Overriding system architecture (" << cfg_arch << "): " << carch << endl;
247                     cfg_arch = carch;
248                   }
249                 }
250                 else if ( entry == "cachedir" )
251                 {
252                   cfg_cache_path = Pathname(value);
253                 }
254                 else if ( entry == "metadatadir" )
255                 {
256                   cfg_metadata_path = Pathname(value);
257                 }
258                 else if ( entry == "solvfilesdir" )
259                 {
260                   cfg_solvfiles_path = Pathname(value);
261                 }
262                 else if ( entry == "packagesdir" )
263                 {
264                   cfg_packages_path = Pathname(value);
265                 }
266                 else if ( entry == "configdir" )
267                 {
268                   cfg_config_path = Pathname(value);
269                 }
270                 else if ( entry == "reposdir" )
271                 {
272                   cfg_known_repos_path = Pathname(value);
273                 }
274                 else if ( entry == "servicesdir" )
275                 {
276                   cfg_known_services_path = Pathname(value);
277                 }
278                 else if ( entry == "repo.add.probe" )
279                 {
280                   repo_add_probe = str::strToBool( value, repo_add_probe );
281                 }
282                 else if ( entry == "repo.refresh.delay" )
283                 {
284                   str::strtonum(value, repo_refresh_delay);
285                 }
286                 else if ( entry == "download.use_deltarpm" )
287                 {
288                   download_use_deltarpm = str::strToBool( value, download_use_deltarpm );
289                 }
290                 else if ( entry == "download.use_deltarpm.always" )
291                 {
292                   download_use_deltarpm_always = str::strToBool( value, download_use_deltarpm_always );
293                 }
294                 else if ( entry == "download.media_preference" )
295                 {
296                   download_media_prefer_download.restoreDefault( str::compareCI( value, "volatile" ) != 0 );
297                 }
298                 else if ( entry == "download.max_concurrent_connections" )
299                 {
300                   str::strtonum(value, download_max_concurrent_connections);
301                 }
302                 else if ( entry == "download.min_download_speed" )
303                 {
304                   str::strtonum(value, download_min_download_speed);
305                 }
306                 else if ( entry == "download.max_download_speed" )
307                 {
308                   str::strtonum(value, download_max_download_speed);
309                 }
310                 else if ( entry == "download.max_silent_tries" )
311                 {
312                   str::strtonum(value, download_max_silent_tries);
313                 }
314                 else if ( entry == "vendordir" )
315                 {
316                   cfg_vendor_path = Pathname(value);
317                 }
318                 else if ( entry == "productsdir" )
319                 {
320                   WAR << "Deprecated entry 'productsdir=': This locations is no longer used or supported." << endl;
321                   cfg_products_path = Pathname(value);
322                 }
323                 else if ( entry == "solver.onlyRequires" )
324                 {
325                   solver_onlyRequires = str::strToBool( value, solver_onlyRequires );
326                 }
327                 else if ( entry == "solver.checkSystemFile" )
328                 {
329                   solver_checkSystemFile = Pathname(value);
330                 }
331                 else if ( entry == "multiversion" )
332                 {
333                   std::list<std::string> multi;
334                   str::split( value, back_inserter(multi), ", \t" );
335                   for ( std::list<string>::const_iterator it = multi.begin();
336                         it != multi.end(); it++) {
337                       multiversion.insert (IdString(*it));
338                   }
339                 }
340                 else if ( entry == "locksfile.path" )
341                 {
342                   locks_file = Pathname(value);
343                 }
344                 else if ( entry == "locksfile.apply" )
345                 {
346                   apply_locks_file = str::strToBool( value, apply_locks_file );
347                 }
348                 else if ( entry == "update.datadir" )
349                 {
350                   update_data_path = Pathname(value);
351                 }
352                 else if ( entry == "update.scriptsdir" )
353                 {
354                   update_scripts_path = Pathname(value);
355                 }
356                 else if ( entry == "update.messagessdir" )
357                 {
358                   update_messages_path = Pathname(value);
359                 }
360                 else if ( entry == "rpm.install.excludedocs" )
361                 {
362                   rpmInstallFlags.setFlag( target::rpm::RPMINST_EXCLUDEDOCS );
363                 }
364                 else if ( entry == "history.logfile" )
365                 {
366                   history_log_path = Pathname(value);
367                 }
368                 else if ( entry == "credentials.global.dir" )
369                 {
370                   credentials_global_dir_path = Pathname(value);
371                 }
372                 else if ( entry == "credentials.global.file" )
373                 {
374                   credentials_global_file_path = Pathname(value);
375                 }
376               }
377             }
378           }
379         }
380         else
381         {
382           MIL << _parsedZyppConf << " not found, using defaults instead." << endl;
383           _parsedZyppConf.extend( " (NOT FOUND)" );
384         }
385
386         // legacy:
387         if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
388         {
389           Arch carch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
390           if ( carch != cfg_arch )
391           {
392             WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Overriding system architecture (" << cfg_arch << "): " << carch << endl;
393             cfg_arch = carch;
394           }
395         }
396         MIL << "ZConfig singleton created." << endl;
397       }
398
399       ~Impl()
400       {}
401
402     public:
403     /** Remember any parsed zypp.conf. */
404     Pathname _parsedZyppConf;
405
406     Arch     cfg_arch;
407     Locale   cfg_textLocale;
408
409     Pathname cfg_cache_path;
410     Pathname cfg_metadata_path;
411     Pathname cfg_solvfiles_path;
412     Pathname cfg_packages_path;
413
414     Pathname cfg_config_path;
415     Pathname cfg_known_repos_path;
416     Pathname cfg_known_services_path;
417     Pathname cfg_vendor_path;
418     Pathname cfg_products_path;
419     Pathname locks_file;
420
421     Pathname update_data_path;
422     Pathname update_scripts_path;
423     Pathname update_messages_path;
424
425     bool repo_add_probe;
426     unsigned repo_refresh_delay;
427
428     bool download_use_deltarpm;
429     bool download_use_deltarpm_always;
430     DefaultOption<bool,true> download_media_prefer_download;
431
432     int download_max_concurrent_connections;
433     int download_min_download_speed;
434     int download_max_download_speed;
435     int download_max_silent_tries;
436
437     bool solver_onlyRequires;
438     Pathname solver_checkSystemFile;
439
440     std::set<IdString> multiversion;
441
442     bool apply_locks_file;
443
444     target::rpm::RpmInstFlags rpmInstallFlags;
445
446     Pathname history_log_path;
447     Pathname credentials_global_dir_path;
448     Pathname credentials_global_file_path;
449   };
450   ///////////////////////////////////////////////////////////////////
451
452   // Backdoor to redirect ZConfig from within the running
453   // TEST-application. HANDLE WITH CARE!
454   void reconfigureZConfig( const Pathname & override_r )
455   {
456     // ctor puts itself unter smart pointer control.
457     new ZConfig::Impl( override_r );
458   }
459
460   ///////////////////////////////////////////////////////////////////
461   //
462   //    METHOD NAME : ZConfig::instance
463   //    METHOD TYPE : ZConfig &
464   //
465   ZConfig & ZConfig::instance()
466   {
467     static ZConfig _instance; // The singleton
468     return _instance;
469   }
470
471   ///////////////////////////////////////////////////////////////////
472   //
473   //    METHOD NAME : ZConfig::ZConfig
474   //    METHOD TYPE : Ctor
475   //
476   ZConfig::ZConfig()
477   : _pimpl( new Impl )
478   {
479     about( MIL);
480   }
481
482   ///////////////////////////////////////////////////////////////////
483   //
484   //    METHOD NAME : ZConfig::~ZConfig
485   //    METHOD TYPE : Dtor
486   //
487   ZConfig::~ZConfig( )
488   {}
489
490   ///////////////////////////////////////////////////////////////////
491   //
492   // system architecture
493   //
494   ///////////////////////////////////////////////////////////////////
495
496   Arch ZConfig::defaultSystemArchitecture()
497   {
498     static Arch _val( _autodetectSystemArchitecture() );
499     return _val;
500   }
501
502   Arch ZConfig::systemArchitecture() const
503   { return _pimpl->cfg_arch; }
504
505   void ZConfig::setSystemArchitecture( const Arch & arch_r )
506   {
507     if ( arch_r != _pimpl->cfg_arch )
508     {
509       WAR << "Overriding system architecture (" << _pimpl->cfg_arch << "): " << arch_r << endl;
510       _pimpl->cfg_arch = arch_r;
511     }
512   }
513
514   ///////////////////////////////////////////////////////////////////
515   //
516   // text locale
517   //
518   ///////////////////////////////////////////////////////////////////
519
520   Locale ZConfig::defaultTextLocale()
521   {
522     static Locale _val( _autodetectTextLocale() );
523     return _val;
524   }
525
526   Locale ZConfig::textLocale() const
527   { return _pimpl->cfg_textLocale; }
528
529   void ZConfig::setTextLocale( const Locale & locale_r )
530   {
531     if ( locale_r != _pimpl->cfg_textLocale )
532     {
533       WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
534       _pimpl->cfg_textLocale = locale_r;
535     }
536   }
537
538   ///////////////////////////////////////////////////////////////////
539
540   Pathname ZConfig::repoCachePath() const
541   {
542     return ( _pimpl->cfg_cache_path.empty()
543         ? Pathname("/var/cache/zypp") : _pimpl->cfg_cache_path );
544   }
545
546   Pathname ZConfig::repoMetadataPath() const
547   {
548     return ( _pimpl->cfg_metadata_path.empty()
549         ? (repoCachePath()/"raw") : _pimpl->cfg_metadata_path );
550   }
551
552   Pathname ZConfig::repoSolvfilesPath() const
553   {
554     return ( _pimpl->cfg_solvfiles_path.empty()
555         ? (repoCachePath()/"solv") : _pimpl->cfg_solvfiles_path );
556   }
557
558   Pathname ZConfig::repoPackagesPath() const
559   {
560     return ( _pimpl->cfg_packages_path.empty()
561         ? (repoCachePath()/"packages") : _pimpl->cfg_packages_path );
562   }
563
564   ///////////////////////////////////////////////////////////////////
565
566   Pathname ZConfig::configPath() const
567   {
568     return ( _pimpl->cfg_config_path.empty()
569         ? Pathname("/etc/zypp") : _pimpl->cfg_config_path );
570   }
571
572   Pathname ZConfig::knownReposPath() const
573   {
574     return ( _pimpl->cfg_known_repos_path.empty()
575         ? (configPath()/"repos.d") : _pimpl->cfg_known_repos_path );
576   }
577
578   Pathname ZConfig::knownServicesPath() const
579   {
580     return ( _pimpl->cfg_known_services_path.empty()
581         ? (configPath()/"services.d") : _pimpl->cfg_known_repos_path );
582   }
583
584   Pathname ZConfig::vendorPath() const
585   {
586     return ( _pimpl->cfg_vendor_path.empty()
587         ? (configPath()/"vendors.d") : _pimpl->cfg_vendor_path );
588   }
589
590   Pathname ZConfig::productsPath() const
591   {
592     return ( _pimpl->cfg_products_path.empty()
593         ? (configPath()/"products.d") : _pimpl->cfg_products_path );
594   }
595
596   Pathname ZConfig::locksFile() const
597   {
598     return ( _pimpl->locks_file.empty()
599         ? (configPath()/"locks") : _pimpl->locks_file );
600   }
601
602   ///////////////////////////////////////////////////////////////////
603
604   bool ZConfig::repo_add_probe() const
605   {
606     return _pimpl->repo_add_probe;
607   }
608
609   unsigned ZConfig::repo_refresh_delay() const
610   {
611     return _pimpl->repo_refresh_delay;
612   }
613
614   bool ZConfig::download_use_deltarpm() const
615   { return _pimpl->download_use_deltarpm; }
616
617   bool ZConfig::download_use_deltarpm_always() const
618   { return download_use_deltarpm() && _pimpl->download_use_deltarpm_always; }
619
620   bool ZConfig::download_media_prefer_download() const
621   { return _pimpl->download_media_prefer_download.get(); }
622
623   void ZConfig::set_download_media_prefer_download( bool yesno_r )
624   { _pimpl->download_media_prefer_download.set( yesno_r ); }
625
626   void ZConfig::set_default_download_media_prefer_download()
627   { _pimpl->download_media_prefer_download.restoreDefault(); }
628
629   long ZConfig::download_max_concurrent_connections() const
630   { return _pimpl->download_max_concurrent_connections; }
631
632   long ZConfig::download_min_download_speed() const
633   { return _pimpl->download_min_download_speed; }
634
635   long ZConfig::download_max_download_speed() const
636   { return _pimpl->download_max_download_speed; }
637
638   long ZConfig::download_max_silent_tries() const
639   { return _pimpl->download_max_silent_tries; }
640
641   bool ZConfig::solver_onlyRequires() const
642   { return _pimpl->solver_onlyRequires; }
643
644   Pathname ZConfig::solver_checkSystemFile() const
645   { return ( _pimpl->solver_checkSystemFile.empty()
646       ? (configPath()/"systemCheck") : _pimpl->solver_checkSystemFile ); }
647
648   std::set<IdString> ZConfig::multiversion() const
649   { return _pimpl->multiversion; }
650
651   void ZConfig::addMultiversion(std::string &name)
652   { _pimpl->multiversion.insert(IdString(name)); }
653
654   bool ZConfig::removeMultiversion(std::string &name)
655   { return _pimpl->multiversion.erase(IdString(name)); }
656
657   bool ZConfig::apply_locks_file() const
658   {
659     return _pimpl->apply_locks_file;
660   }
661
662   Pathname ZConfig::update_dataPath() const
663   {
664     return ( _pimpl->update_data_path.empty()
665         ? Pathname("/var/adm") : _pimpl->update_data_path );
666   }
667
668   Pathname ZConfig::update_messagesPath() const
669   {
670     return ( _pimpl->update_messages_path.empty()
671              ? Pathname(update_dataPath()/"update-messages") : _pimpl->update_messages_path );
672   }
673
674
675   Pathname ZConfig::update_scriptsPath() const
676   {
677     return ( _pimpl->update_scripts_path.empty()
678              ? Pathname(update_dataPath()/"update-scripts") : _pimpl->update_scripts_path );
679   }
680
681   ///////////////////////////////////////////////////////////////////
682
683   target::rpm::RpmInstFlags ZConfig::rpmInstallFlags() const
684   { return _pimpl->rpmInstallFlags; }
685
686
687   Pathname ZConfig::historyLogFile() const
688   {
689     return ( _pimpl->history_log_path.empty() ?
690         Pathname("/var/log/zypp/history") : _pimpl->history_log_path );
691   }
692
693
694   Pathname ZConfig::credentialsGlobalDir() const
695   {
696     return ( _pimpl->credentials_global_dir_path.empty() ?
697         Pathname("/etc/zypp/credentials.d") : _pimpl->credentials_global_dir_path );
698   }
699
700   Pathname ZConfig::credentialsGlobalFile() const
701   {
702     return ( _pimpl->credentials_global_file_path.empty() ?
703         Pathname("/etc/zypp/credentials.cat") : _pimpl->credentials_global_file_path );
704   }
705
706   ///////////////////////////////////////////////////////////////////
707
708   std::ostream & ZConfig::about( std::ostream & str ) const
709   {
710     str << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
711     str << "zypp.conf: '" << _pimpl->_parsedZyppConf << "'" << endl;
712     str << "TextLocale: '" << textLocale() << "' (" << defaultTextLocale() << ")" << endl;
713     str << "SystemArchitecture: '" << systemArchitecture() << "' (" << defaultSystemArchitecture() << ")" << endl;
714     return str;
715   }
716
717   /////////////////////////////////////////////////////////////////
718 } // namespace zypp
719 ///////////////////////////////////////////////////////////////////