- merge Stano's patch to keep downloaded rpms
[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()
145         : cfg_arch                ( defaultSystemArchitecture() )
146         , cfg_textLocale          ( defaultTextLocale() )
147         , repo_add_probe          ( false )
148         , repo_refresh_delay      ( 10 )
149         , download_use_patchrpm   ( true )
150         , download_use_deltarpm   ( true )
151
152       {
153         MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
154
155         // ZYPP_CONF might override /etc/zypp/zypp.conf
156         const char *env_confpath = getenv( "ZYPP_CONF" );
157         Pathname confpath( env_confpath ? env_confpath : "/etc/zypp/zypp.conf" );
158         if ( PathInfo(confpath).isExist() )
159         {
160           parser::IniDict dict( confpath );
161           //InputStream is(confpath);
162
163           for ( IniDict::section_const_iterator sit = dict.sectionsBegin();
164                 sit != dict.sectionsEnd();
165                 ++sit )
166           {
167             string section(*sit);
168             //MIL << section << endl;
169             for ( IniDict::entry_const_iterator it = dict.entriesBegin(*sit);
170                   it != dict.entriesEnd(*sit);
171                   ++it )
172             {
173               string entry(it->first);
174               string value(it->second);
175               //DBG << (*it).first << "=" << (*it).second << endl;
176               if ( section == "main" )
177               {
178                 if ( entry == "arch" )
179                 {
180                   Arch carch( value );
181                   if ( carch != cfg_arch )
182                   {
183                     WAR << "Overriding system architecture (" << cfg_arch << "): " << carch << endl;
184                     cfg_arch = carch;
185                   }
186                 }
187                 else if ( entry == "metadatadir" )
188                 {
189                   cfg_metadata_path = Pathname(value);
190                 }
191                 else if ( entry == "reposdir" )
192                 {
193                   cfg_known_repos_path = Pathname(value);
194                 }
195                 else if ( entry == "cachedir" )
196                 {
197                   cfg_cache_path = Pathname(value);
198                 }
199                 else if ( entry == "repo.add.probe" )
200                 {
201                   repo_add_probe = str::strToBool( value, repo_add_probe );
202                 }
203                 else if ( entry == "repo.refresh.delay" )
204                 {
205                   str::strtonum(value, repo_refresh_delay);
206                 }
207                 else if ( entry == "download.use_patchrpm" )
208                 {
209                   download_use_patchrpm = str::strToBool( value, download_use_patchrpm );
210                 }
211                 else if ( entry == "download.use_deltarpm" )
212                 {
213                   download_use_deltarpm = str::strToBool( value, download_use_deltarpm );
214                 }
215                 else if ( entry == "vendordir" )
216                 {
217                   cfg_vendor_path = Pathname(value);
218                 }
219                 else if ( entry == "packagesdir" )
220                 {
221                   cfg_packages_path = Pathname(value);
222                 }
223               }
224             }
225           }
226         }
227         else
228         {
229           MIL << confpath << " not found, using defaults instead." << endl;
230         }
231
232         // legacy:
233         if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
234         {
235           Arch carch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
236           if ( carch != cfg_arch )
237           {
238             WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Overriding system architecture (" << cfg_arch << "): " << carch << endl;
239             cfg_arch = carch;
240           }
241         }
242
243         MIL << "ZConfig singleton created." << endl;
244         MIL << "defaultTextLocale: '" << cfg_textLocale << "'" << endl;
245         MIL << "System architecture is '" << cfg_arch << "'" << endl;
246       }
247
248       ~Impl()
249       {}
250
251     public:
252     Arch     cfg_arch;
253     Locale   cfg_textLocale;
254
255     Pathname cfg_metadata_path;
256     Pathname cfg_packages_path;
257     Pathname cfg_cache_path;
258     Pathname cfg_known_repos_path;
259     Pathname cfg_vendor_path;
260
261     bool repo_add_probe;
262     unsigned repo_refresh_delay;
263
264     bool download_use_patchrpm;
265     bool download_use_deltarpm;
266
267
268   };
269   ///////////////////////////////////////////////////////////////////
270
271   ///////////////////////////////////////////////////////////////////
272   //
273   //    METHOD NAME : ZConfig::instance
274   //    METHOD TYPE : ZConfig &
275   //
276   ZConfig & ZConfig::instance()
277   {
278     static ZConfig _instance; // The singleton
279     return _instance;
280   }
281
282   ///////////////////////////////////////////////////////////////////
283   //
284   //    METHOD NAME : ZConfig::ZConfig
285   //    METHOD TYPE : Ctor
286   //
287   ZConfig::ZConfig()
288   : _pimpl( new Impl )
289   {}
290
291   ///////////////////////////////////////////////////////////////////
292   //
293   //    METHOD NAME : ZConfig::~ZConfig
294   //    METHOD TYPE : Dtor
295   //
296   ZConfig::~ZConfig( )
297   {}
298
299   ///////////////////////////////////////////////////////////////////
300   //
301   // system architecture
302   //
303   ///////////////////////////////////////////////////////////////////
304
305   Arch ZConfig::defaultSystemArchitecture()
306   {
307     static Arch _val( _autodetectSystemArchitecture() );
308     return _val;
309   }
310
311   Arch ZConfig::systemArchitecture() const
312   { return _pimpl->cfg_arch; }
313
314   void ZConfig::setSystemArchitecture( const Arch & arch_r )
315   {
316     if ( arch_r != _pimpl->cfg_arch )
317     {
318       WAR << "Overriding system architecture (" << _pimpl->cfg_arch << "): " << arch_r << endl;
319       _pimpl->cfg_arch = arch_r;
320     }
321   }
322
323   ///////////////////////////////////////////////////////////////////
324   //
325   // text locale
326   //
327   ///////////////////////////////////////////////////////////////////
328
329   Locale ZConfig::defaultTextLocale()
330   {
331     static Locale _val( _autodetectTextLocale() );
332     return _val;
333   }
334
335   Locale ZConfig::textLocale() const
336   { return _pimpl->cfg_textLocale; }
337
338   void ZConfig::setTextLocale( const Locale & locale_r )
339   {
340     if ( locale_r != _pimpl->cfg_textLocale )
341     {
342       WAR << "Overriding text locale (" << _pimpl->cfg_textLocale << "): " << locale_r << endl;
343       _pimpl->cfg_textLocale = locale_r;
344     }
345   }
346
347   ///////////////////////////////////////////////////////////////////
348
349   Pathname ZConfig::repoMetadataPath() const
350   {
351     return ( _pimpl->cfg_metadata_path.empty()
352         ? Pathname("/var/cache/zypp/raw") : _pimpl->cfg_metadata_path );
353   }
354
355   Pathname ZConfig::repoPackagesPath() const
356   {
357     return ( _pimpl->cfg_packages_path.empty()
358         ? Pathname("/var/cache/zypp/packages") : _pimpl->cfg_packages_path );
359   }
360
361   Pathname ZConfig::repoCachePath() const
362   {
363     return ( _pimpl->cfg_cache_path.empty()
364         ? Pathname("/var/cache/zypp") : _pimpl->cfg_cache_path );
365   }
366
367   Pathname ZConfig::knownReposPath() const
368   {
369     return ( _pimpl->cfg_known_repos_path.empty()
370         ? Pathname("/etc/zypp/repos.d") : _pimpl->cfg_known_repos_path );
371   }
372
373   const std::string & ZConfig::cacheDBSplitJoinSeparator() const
374   {
375     static std::string s("!@$");
376     return s;
377   }
378
379   bool ZConfig::repo_add_probe() const
380   {
381     return _pimpl->repo_add_probe;
382   }
383
384   unsigned ZConfig::repo_refresh_delay() const
385   {
386     return _pimpl->repo_refresh_delay;
387   }
388
389   bool ZConfig::download_use_patchrpm() const
390   { return _pimpl->download_use_patchrpm; }
391
392   bool ZConfig::download_use_deltarpm() const
393   { return _pimpl->download_use_deltarpm; }
394
395   Pathname ZConfig::vendorPath() const
396   {
397     return ( _pimpl->cfg_vendor_path.empty()
398         ? Pathname("/etc/zypp/vendors.d") : _pimpl->cfg_vendor_path );
399   }
400
401   /////////////////////////////////////////////////////////////////
402 } // namespace zypp
403 ///////////////////////////////////////////////////////////////////