89f5a58b302a24ff74f1a05f9a9cba1ba3b4efcf
[platform/upstream/libzypp.git] / zypp / zypp_detail / ZYppImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/zypp_detail/ZYppImpl.cc
10  *
11 */
12
13 #include <sys/utsname.h>
14 #include <unistd.h>
15 #include <iostream>
16 #include <fstream>
17 #include "zypp/TmpPath.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/String.h"
20
21 #include "zypp/zypp_detail/ZYppImpl.h"
22 #include "zypp/solver/detail/Helper.h"
23 #include "zypp/target/TargetImpl.h"
24 #include "zypp/ZYpp.h"
25 #include "zypp/NVRAD.h"
26 #include "zypp/Language.h"
27 #include "zypp/DiskUsageCounter.h"
28 #include "zypp/NameKindProxy.h"
29 #include "zypp/Locks.h"
30
31 using std::endl;
32
33 ///////////////////////////////////////////////////////////////////
34 namespace zypp
35 { /////////////////////////////////////////////////////////////////
36   ///////////////////////////////////////////////////////////////////
37   namespace zypp_detail
38   { /////////////////////////////////////////////////////////////////
39
40     /** The locale to be used for texts and messages.
41      *
42      * For the encoding to be used the preference is
43      *
44      *    LC_ALL, LC_CTYPE, LANG
45      *
46      * For the language of the messages to be used, the preference is
47      *
48      *    LANGUAGE, LC_ALL, LC_MESSAGES, LANG
49      *
50      * Note that LANGUAGE can contain more than one locale name, it can be
51      * a list of locale names like for example
52      *
53      *    LANGUAGE=ja_JP.UTF-8:de_DE.UTF-8:fr_FR.UTF-8
54
55      * \todo Support dynamic fallbacklists defined by LANGUAGE
56      */
57     inline Locale defaultTextLocale()
58     {
59       Locale ret( "en" );
60       const char * envlist[] = { "LC_ALL", "LC_MESSAGES", "LANG", NULL };
61       for ( const char ** envvar = envlist; *envvar; ++envvar )
62         {
63           const char * envlang = getenv( *envvar );
64           if ( envlang )
65             {
66               std::string envstr( envlang );
67               if ( envstr != "POSIX" && envstr != "C" )
68                 {
69                   Locale lang( envlang );
70                   if ( ! lang.code().empty() )
71                     {
72                       ret = lang;
73                       break;
74                     }
75                 }
76             }
77         }
78       return ret;
79     }
80
81     Arch defaultArchitecture()
82     {
83       Arch architecture;
84
85       // detect the true architecture
86       struct utsname buf;
87       if ( uname( &buf ) < 0 )
88         {
89           ERR << "Can't determine system architecture" << endl;
90         }
91       else
92         {
93           architecture = Arch( buf.machine );
94           DBG << "uname architecture is '" << buf.machine << "'" << endl;
95
96           // some CPUs report i686 but dont implement cx8 and cmov
97           // check for both flags in /proc/cpuinfo and downgrade
98           // to i586 if either is missing (cf bug #18885)
99
100           if ( architecture == Arch_i686 )
101             {
102               std::ifstream cpuinfo( "/proc/cpuinfo" );
103               if ( !cpuinfo )
104                 {
105                   ERR << "Cant open /proc/cpuinfo" << endl;
106                 }
107               else
108                 {
109                   char infoline[1024];
110                   while ( cpuinfo.good() )
111                     {
112                       if ( !cpuinfo.getline( infoline, 1024, '\n' ) )
113                         {
114                           if ( cpuinfo.eof() )
115                             break;
116                         }
117                       if ( strncmp( infoline, "flags", 5 ) == 0 )
118                         {
119                           std::string flagsline( infoline );
120                           if ( flagsline.find( "cx8" ) == std::string::npos
121                                || flagsline.find( "cmov" ) == std::string::npos )
122                             {
123                               architecture = Arch_i586;
124                               DBG << "CPU lacks 'cx8' or 'cmov': architecture downgraded to '" << architecture << "'" << endl;
125                             }
126                           break;
127                         } // flags found
128                     } // read proc/cpuinfo
129                 } // proc/cpuinfo opened
130             } // i686 extra flags check
131         }
132
133       if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
134       {
135         architecture = Arch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
136         WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Setting fake system architecture for test purpuses to: '" << architecture << "'" << endl;
137       }
138
139       return architecture;
140     }
141     ///////////////////////////////////////////////////////////////////
142     //
143     //  METHOD NAME : ZYppImpl::ZYppImpl
144     //  METHOD TYPE : Constructor
145     //
146     ZYppImpl::ZYppImpl()
147     : _textLocale( defaultTextLocale() )
148     , _target(0)
149     , _resolver( new Resolver( ResPool::instance()) )
150     , _architecture( defaultArchitecture() )
151     {
152       MIL << "libzypp: " << VERSION << " built " << __DATE__ << " " <<  __TIME__ << endl;
153       MIL << "defaultTextLocale: '" << _textLocale << "'" << endl;
154       MIL << "System architecture is '" << _architecture << "'" << endl;
155
156       MIL << "initializing keyring..." << std::endl;
157       //_keyring = new KeyRing(homePath() + Pathname("/keyring/all"), homePath() + Pathname("/keyring/trusted"));
158       _keyring = new KeyRing(tmpPath());
159     }
160
161     ///////////////////////////////////////////////////////////////////
162     //
163     //  METHOD NAME : ZYppImpl::~ZYppImpl
164     //  METHOD TYPE : Destructor
165     //
166     ZYppImpl::~ZYppImpl()
167     {}
168
169     //------------------------------------------------------------------------
170     // add/remove resolvables
171
172     DiskUsageCounter::MountPointSet ZYppImpl::diskUsage()
173     {
174       if ( ! _disk_usage )
175       {
176         setPartitions( DiskUsageCounter::detectMountPoints() );
177       }
178       return _disk_usage->disk_usage(pool());
179     }
180
181     void ZYppImpl::setPartitions(const DiskUsageCounter::MountPointSet &mp)
182     {
183       _disk_usage.reset(new DiskUsageCounter());
184       _disk_usage->setMountPoints(mp);
185     }
186
187     DiskUsageCounter::MountPointSet ZYppImpl::getPartitions() const
188     {
189       if (_disk_usage)
190         return _disk_usage->getMountPoints();
191       else
192         return DiskUsageCounter::detectMountPoints();
193     }
194
195     //------------------------------------------------------------------------
196     // target
197
198     Target_Ptr ZYppImpl::target() const
199     {
200       if (! _target)
201         ZYPP_THROW(Exception("Target not initialized."));
202       return _target;
203      }
204
205     void ZYppImpl::initializeTarget(const Pathname & root)
206     {
207       MIL << "initTarget( " << root << endl;
208       if (_target) {
209         if (_target->root() == root) {
210             MIL << "Repeated call to initializeTarget()" << endl;
211             return;
212         }
213 #warning NEED SOME NEW WAY TO INDICATE NEDD OF TARGET RELOAD
214 #if 0
215         removeInstalledResolvables( );
216 #endif
217       }
218       _target = new Target( root );
219       _target->enableStorage( root );
220     }
221
222     void ZYppImpl::finishTarget()
223     {
224 #warning NEED SOME NEW WAY TO UNLOAD THE POOL
225 #if 0
226       if (_target)
227         removeInstalledResolvables();
228 #endif
229       _target = 0;
230     }
231
232     //------------------------------------------------------------------------
233     // commit
234
235     /** \todo Remove workflow from target, lot's of it could be done here,
236      * and target used for transact. */
237     ZYppCommitResult ZYppImpl::commit( const ZYppCommitPolicy & policy_r )
238     {
239       if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") )
240       {
241         ZYPP_THROW( Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") );
242       }
243
244       MIL << "Attempt to commit (" << policy_r << ")" << endl;
245       if (! _target)
246         ZYPP_THROW( Exception("Target not initialized.") );
247
248       ZYppCommitResult res = _target->_pimpl->commit( pool(), policy_r );
249
250       if (! policy_r.dryRun() ) {
251         // Tag target data invalid, so they are reloaded on the next call to
252         // target->resolvables(). Actually the target should do this without
253         // foreign help.
254         _target->reset();
255 #warning NEED SOME NEW WAY TO INDICATE NEDD OF TARGET RELOAD
256 #if 0
257         removeInstalledResolvables();
258         if ( policy_r.syncPoolAfterCommit() )
259           {
260             // reload new status from target
261             addResolvables( _target->resolvables(), true );
262           }
263 #endif
264       }
265
266       MIL << "Commit (" << policy_r << ") returned: "
267           << res << endl;
268       return res;
269     }
270
271     void ZYppImpl::installSrcPackage( const SrcPackage_constPtr & srcPackage_r )
272     {
273       if (! _target)
274         ZYPP_THROW( Exception("Target not initialized.") );
275       _target->_pimpl->installSrcPackage( srcPackage_r );
276     }
277
278     //------------------------------------------------------------------------
279     // locales
280
281     /** */
282     void ZYppImpl::setRequestedLocales( const LocaleSet & locales_r )
283     {
284 #warning REIMPLEMENT WITHOUT LANGUAGE RESOLVABLE
285 #if 0
286      ResPool mpool( ResPool::instance() );
287       // assert all requested are available
288       for ( LocaleSet::const_iterator it = locales_r.begin();
289             it != locales_r.end(); ++it )
290         {
291           NameKindProxy select( nameKindProxy<Language>( mpool, it->code() ) );
292           if ( select.installedEmpty() && select.availableEmpty() )
293             _pool.insert( Language::availableInstance( *it ) );
294         }
295
296       // now adjust status
297       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
298             it != mpool.byKindEnd<Language>(); ++it )
299         {
300           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
301           if ( locales_r.find( Locale( (*it)->name() ) ) != locales_r.end() )
302             {
303               // Language is requested
304               if ( select.installedEmpty() )
305                 {
306                   if ( select.availableEmpty() )
307                     {
308                       // no item ==> provide available to install
309                       _pool.insert( Language::availableInstance( Locale((*it)->name()) ) );
310                       select = nameKindProxy<Language>( mpool, (*it)->name() );
311                     }
312                   // available only ==> to install
313                   select.availableBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
314                 }
315               else
316                 {
317                   // installed ==> keep it
318                   select.installedBegin()->status().setTransactValue( ResStatus::KEEP_STATE, ResStatus::USER );
319                   if ( ! select.availableEmpty() )
320                     {
321                       // both items ==> keep
322                       select.availableBegin()->status().resetTransact( ResStatus::USER );
323                     }
324                 }
325             }
326           else
327             {
328               // Language is NOT requested
329               if ( ! select.installedEmpty() )
330                 select.installedBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
331               if ( ! select.availableEmpty() )
332                 select.availableBegin()->status().resetTransact( ResStatus::USER );
333             }
334         }
335 #endif
336     }
337
338     /** */
339     ZYppImpl::LocaleSet ZYppImpl::getAvailableLocales() const
340     {
341       ZYpp::LocaleSet ret;
342 #warning REIMPLEMENT WITHOUT LANGUAGE RESOLVABLE
343 #if 0
344       ResPool mpool( ResPool::instance() );
345       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
346             it != mpool.byKindEnd<Language>(); ++it )
347         {
348           if ( (*it).status().isUninstalled() ) // available!
349             ret.insert( Locale( (*it)->name() ) );
350         }
351 #endif
352       return ret;
353     }
354
355     /** */
356     ZYppImpl::LocaleSet ZYppImpl::getRequestedLocales() const
357     {
358       ZYpp::LocaleSet ret;
359 #warning REIMPLEMENT WITHOUT LANGUAGE RESOLVABLE
360 #if 0
361      ResPool mpool( ResPool::instance() );
362       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
363             it != mpool.byKindEnd<Language>(); ++it )
364         {
365           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
366           if ( ! select.installedEmpty()
367                && select.installedBegin()->status().getTransactValue() != ResStatus::TRANSACT )
368             ret.insert( Locale( (*it)->name() ) );
369           else if ( ! select.availableEmpty()
370                     && select.availableBegin()->status().getTransactValue() == ResStatus::TRANSACT )
371             ret.insert( Locale( (*it)->name() ) );
372         }
373 #endif
374       return ret;
375     }
376
377     void ZYppImpl::availableLocale( const Locale & locale_r )
378     {
379 #warning REIMPLEMENT WITHOUT LANGUAGE RESOLVABLE
380 #if 0
381       _pool.insert( Language::availableInstance( locale_r ) );
382 #endif
383     }
384
385     //------------------------------------------------------------------------
386     // architecture
387
388     void ZYppImpl::setArchitecture( const Arch & arch )
389     {
390         _architecture = arch;
391     }
392
393     //------------------------------------------------------------------------
394     // target store path
395
396     Pathname ZYppImpl::homePath() const
397     { return _home_path.empty() ? Pathname("/var/lib/zypp") : _home_path; }
398
399     void ZYppImpl::setHomePath( const Pathname & path )
400     { _home_path = path; }
401
402     Pathname ZYppImpl::tmpPath() const
403     {
404       static TmpDir zypp_tmp_dir( TmpPath::defaultLocation(), "zypp." );
405       return zypp_tmp_dir.path();
406     }
407
408     int ZYppImpl::applyLocks()
409     {
410       Pathname locksrcPath( "/etc/zypp/locks" );
411       try
412       {
413         Target_Ptr trg( target() );
414         if ( trg )
415           locksrcPath = trg->root() / locksrcPath;
416       }
417       catch ( ... )
418       {
419         // noop: Someone decided to let target() throw if the ptr is NULL ;(
420       }
421
422       int num=0;
423       PathInfo locksrc( locksrcPath );
424       if ( locksrc.isFile() )
425       {
426         MIL << "Reading locks from '" << locksrcPath << "'" << endl;
427         num = zypp::locks::readLocks( pool(), locksrcPath );
428         MIL << num << " items locked." << endl;
429       }
430       else
431       {
432         MIL << "No file '" << locksrcPath << "' to read locks from" << endl;
433       }
434       return num;
435     }
436     /******************************************************************
437      **
438      ** FUNCTION NAME : operator<<
439      ** FUNCTION TYPE : std::ostream &
440     */
441     std::ostream & operator<<( std::ostream & str, const ZYppImpl & obj )
442     {
443       return str << "ZYppImpl";
444     }
445
446     /////////////////////////////////////////////////////////////////
447   } // namespace zypp_detail
448   ///////////////////////////////////////////////////////////////////
449   /////////////////////////////////////////////////////////////////
450 } // namespace zypp
451 ///////////////////////////////////////////////////////////////////