logmessage added
[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/base/Logger.h"
18 #include "zypp/base/String.h"
19
20 #include "zypp/zypp_detail/ZYppImpl.h"
21 #include "zypp/detail/ResImplTraits.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
30 using std::endl;
31
32 ///////////////////////////////////////////////////////////////////
33 namespace zypp
34 { /////////////////////////////////////////////////////////////////
35   ///////////////////////////////////////////////////////////////////
36   namespace zypp_detail
37   { /////////////////////////////////////////////////////////////////
38
39     inline Locale defaultTextLocale()
40     {
41       Locale ret( "en" );
42       const char * envlist[] = { "LC_ALL", "LC_CTYPE", "LANG", NULL };
43       for ( const char ** envvar = envlist; *envvar; ++envvar )
44         {
45           const char * envlang = getenv( *envvar );
46           if ( envlang )
47             {
48               std::string envstr( envlang );
49               if ( envstr != "POSIX" && envstr != "C" )
50                 {
51                   Locale lang( envlang );
52                   if ( lang != Locale::noCode )
53                     {
54                       ret = lang;
55                       break;
56                     }
57                 }
58             }
59         }
60       return ret;
61     }
62
63     Arch defaultArchitecture()
64     {
65       Arch architecture;
66
67       // detect the true architecture
68       struct utsname buf;
69       if ( uname( &buf ) < 0 )
70         {
71           ERR << "Can't determine system architecture" << endl;
72         }
73       else
74         {
75           architecture = Arch( buf.machine );
76           DBG << "uname architecture is '" << buf.machine << "'" << endl;
77
78           // some CPUs report i686 but dont implement cx8 and cmov
79           // check for both flags in /proc/cpuinfo and downgrade
80           // to i586 if either is missing (cf bug #18885)
81
82           if ( architecture == Arch_i686 )
83             {
84               std::ifstream cpuinfo( "/proc/cpuinfo" );
85               if ( !cpuinfo )
86                 {
87                   ERR << "Cant open /proc/cpuinfo" << endl;
88                 }
89               else
90                 {
91                   char infoline[1024];
92                   while ( cpuinfo.good() )
93                     {
94                       if ( !cpuinfo.getline( infoline, 1024, '\n' ) )
95                         {
96                           if ( cpuinfo.eof() )
97                             break;
98                         }
99                       if ( strncmp( infoline, "flags", 5 ) == 0 )
100                         {
101                           std::string flagsline( infoline );
102                           if ( flagsline.find( "cx8" ) == std::string::npos
103                                || flagsline.find( "cmov" ) == std::string::npos )
104                             {
105                               architecture = Arch_i586;
106                               DBG << "CPU lacks 'cx8' or 'cmov': architecture downgraded to '" << architecture << "'" << endl;
107                             }
108                           break;
109                         } // flags found
110                     } // read proc/cpuinfo
111                 } // proc/cpuinfo opened
112             } // i686 extra flags check
113         }
114
115       if ( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) )
116       {
117         architecture = Arch( getenv( "ZYPP_TESTSUITE_FAKE_ARCH" ) );
118         WAR << "ZYPP_TESTSUITE_FAKE_ARCH: Setting fake system architecture for test purpuses to: '" << architecture << "'" << endl;
119       }
120
121       return architecture;
122     }
123     ///////////////////////////////////////////////////////////////////
124     //
125     //  METHOD NAME : ZYppImpl::ZYppImpl
126     //  METHOD TYPE : Constructor
127     //
128     ZYppImpl::ZYppImpl()
129     : _textLocale( defaultTextLocale() )
130     , _pool()
131     , _sourceFeed( _pool )
132     , _target(0)
133     , _resolver( new Resolver(_pool.accessor()) )
134     , _architecture( defaultArchitecture() )
135     , _disk_usage()
136     {
137       MIL << "libzypp: " << VERSION << " $Revision$ built " << __DATE__ << " " <<  __TIME__ << endl;
138       MIL << "defaultTextLocale: '" << _textLocale << "'" << endl;
139       MIL << "System architecture is '" << _architecture << "'" << endl;
140
141       MIL << "initializing keyring..." << std::endl;
142       //_keyring = new KeyRing(homePath() + Pathname("/keyring/all"), homePath() + Pathname("/keyring/trusted"));
143       _keyring = new KeyRing(tmpPath());
144     }
145
146     ///////////////////////////////////////////////////////////////////
147     //
148     //  METHOD NAME : ZYppImpl::~ZYppImpl
149     //  METHOD TYPE : Destructor
150     //
151     ZYppImpl::~ZYppImpl()
152     {}
153
154     //------------------------------------------------------------------------
155     // add/remove resolvables
156
157     void ZYppImpl::addResolvables (const ResStore& store, bool installed)
158     {
159         _pool.insert(store.begin(), store.end(), installed);
160     }
161
162     void ZYppImpl::removeResolvables (const ResStore& store)
163     {
164         for (ResStore::iterator it = store.begin(); it != store.end(); ++it)
165         {
166             _pool.erase(*it);
167         }
168     }
169
170     void ZYppImpl::removeInstalledResolvables ()
171     {
172         for (ResPool::const_iterator it = pool().begin(); it != pool().end();)
173         {
174             ResPool::const_iterator next = it; ++next;
175             if (it->status().isInstalled())
176                 _pool.erase( *it );
177             it = next;
178         }
179     }
180
181     DiskUsageCounter::MountPointSet ZYppImpl::diskUsage()
182     { return _disk_usage.disk_usage(pool()); }
183
184     void ZYppImpl::setPartitions(const DiskUsageCounter::MountPointSet &mp)
185     { _disk_usage.setMountPoints(mp); }
186
187     DiskUsageCounter::MountPointSet ZYppImpl::getPartitions() const
188     { return _disk_usage.getMountPoints(); }
189
190     //------------------------------------------------------------------------
191     // target
192
193     Target_Ptr ZYppImpl::target() const
194     {
195       if (! _target)
196         ZYPP_THROW(Exception("Target not initialized."));
197       return _target;
198      }
199
200     void ZYppImpl::initializeTarget(const Pathname & root)
201     {
202       MIL << "initTarget( " << root << endl;
203       if (_target) {
204         if (_target->root() == root) {
205             MIL << "Repeated call to initializeTarget()" << endl;
206             return;
207         }
208         removeInstalledResolvables( );
209       }
210       _target = new Target( root );
211       _target->enableStorage( root );
212     }
213
214     void ZYppImpl::initTarget(const Pathname & root, bool commit_only)
215     {
216       MIL << "initTarget( " << root << ", " << commit_only << ")" << endl;
217       if (_target) {
218         if (_target->root() == root) {
219           MIL << "Repeated call to initTarget()" << endl;
220           return;
221         }
222         removeInstalledResolvables( );
223       }
224       _target = new Target( root );
225       _target->enableStorage( root );
226       if (!commit_only)
227       {
228         addResolvables( _target->resolvables(), true );
229       }
230     }
231
232
233     void ZYppImpl::finishTarget()
234     {
235       if (_target)
236         removeInstalledResolvables();
237       _target = 0;
238     }
239
240     //------------------------------------------------------------------------
241     // commit
242
243     /** \todo Remove workflow from target, lot's of it could be done here,
244      * and target used for transact. */
245     ZYppCommitResult ZYppImpl::commit( const ZYppCommitPolicy & policy_r )
246     {
247       if ( getenv("ZYPP_TESTSUITE_FAKE_ARCH") )
248       {
249         ZYPP_THROW( Exception("ZYPP_TESTSUITE_FAKE_ARCH set. Commit not allowed and disabled.") );
250       }
251
252       MIL << "Attempt to commit (" << policy_r << ")" << endl;
253       if (! _target)
254         ZYPP_THROW( Exception("Target not initialized.") );
255
256       ZYppCommitResult res = _target->_pimpl->commit( pool(), policy_r );
257
258       if (! policy_r.dryRun() ) {
259         // Tag target data invalid, so they are reloaded on the next call to
260         // target->resolvables(). Actually the target should do this without
261         // foreign help.
262         _target->reset();
263         removeInstalledResolvables();
264         if ( policy_r.syncPoolAfterCommit() )
265           {
266             // reload new status from target
267             addResolvables( _target->resolvables(), true );
268           }
269       }
270
271       MIL << "Commit (" << policy_r << ") returned: "
272           << res << endl;
273       return res;
274     }
275
276
277     //------------------------------------------------------------------------
278     // locales
279
280     /** */
281     void ZYppImpl::setRequestedLocales( const LocaleSet & locales_r )
282     {
283       ResPool mpool( pool() );
284       // assert all requested are available
285       for ( LocaleSet::const_iterator it = locales_r.begin();
286             it != locales_r.end(); ++it )
287         {
288           NameKindProxy select( nameKindProxy<Language>( mpool, it->code() ) );
289           if ( select.installedEmpty() && select.availableEmpty() )
290             _pool.insert( Language::availableInstance( *it ) );
291         }
292
293       // now adjust status
294       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
295             it != mpool.byKindEnd<Language>(); ++it )
296         {
297           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
298           if ( locales_r.find( Locale( (*it)->name() ) ) != locales_r.end() )
299             {
300               // Language is requested
301               if ( select.installedEmpty() )
302                 {
303                   if ( select.availableEmpty() )
304                     {
305                       // no item ==> provide available to install
306                       _pool.insert( Language::availableInstance( Locale((*it)->name()) ) );
307                       select = nameKindProxy<Language>( mpool, (*it)->name() );
308                     }
309                   // available only ==> to install
310                   select.availableBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
311                 }
312               else
313                 {
314                   // installed ==> keep it
315                   select.installedBegin()->status().setTransactValue( ResStatus::KEEP_STATE, ResStatus::USER );
316                   if ( ! select.availableEmpty() )
317                     {
318                       // both items ==> keep
319                       select.availableBegin()->status().resetTransact( ResStatus::USER );
320                     }
321                 }
322             }
323           else
324             {
325               // Language is NOT requested
326               if ( ! select.installedEmpty() )
327                 select.installedBegin()->status().setTransactValue( ResStatus::TRANSACT, ResStatus::USER );
328               if ( ! select.availableEmpty() )
329                 select.availableBegin()->status().resetTransact( ResStatus::USER );
330             }
331         }
332     }
333
334     /** */
335     ZYppImpl::LocaleSet ZYppImpl::getAvailableLocales() const
336     {
337       ZYpp::LocaleSet ret;
338       ResPool mpool( pool() );
339       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
340             it != mpool.byKindEnd<Language>(); ++it )
341         {
342           if ( (*it).status().isUninstalled() ) // available!
343             ret.insert( Locale( (*it)->name() ) );
344         }
345       return ret;
346     }
347
348     /** */
349     ZYppImpl::LocaleSet ZYppImpl::getRequestedLocales() const
350     {
351       ZYpp::LocaleSet ret;
352       ResPool mpool( pool() );
353       for ( ResPool::byKind_iterator it = mpool.byKindBegin<Language>();
354             it != mpool.byKindEnd<Language>(); ++it )
355         {
356           NameKindProxy select( nameKindProxy<Language>( mpool, (*it)->name() ) );
357           if ( ! select.installedEmpty()
358                && select.installedBegin()->status().getTransactValue() != ResStatus::TRANSACT )
359             ret.insert( Locale( (*it)->name() ) );
360           else if ( ! select.availableEmpty()
361                     && select.availableBegin()->status().getTransactValue() == ResStatus::TRANSACT )
362             ret.insert( Locale( (*it)->name() ) );
363         }
364       return ret;
365     }
366
367     void ZYppImpl::availableLocale( const Locale & locale_r )
368     {
369       _pool.insert( Language::availableInstance( locale_r ) );
370     }
371
372     //------------------------------------------------------------------------
373     // architecture
374
375     void ZYppImpl::setArchitecture( const Arch & arch )
376     {
377         _architecture = arch;
378         if (_resolver) _resolver->setArchitecture( arch );
379     }
380
381     //------------------------------------------------------------------------
382     // target store path
383
384     Pathname ZYppImpl::homePath() const
385     { return _home_path.empty() ? Pathname("/var/lib/zypp") : _home_path; }
386
387     void ZYppImpl::setHomePath( const Pathname & path )
388     { _home_path = path; }
389
390     Pathname ZYppImpl::tmpPath() const
391     {
392       static TmpDir zypp_tmp_dir("/var/tmp", "zypp.");
393       return zypp_tmp_dir.path();
394     }
395
396     /******************************************************************
397      **
398      ** FUNCTION NAME : operator<<
399      ** FUNCTION TYPE : std::ostream &
400     */
401     std::ostream & operator<<( std::ostream & str, const ZYppImpl & obj )
402     {
403       return str << "ZYppImpl";
404     }
405
406     /////////////////////////////////////////////////////////////////
407   } // namespace zypp_detail
408   ///////////////////////////////////////////////////////////////////
409   /////////////////////////////////////////////////////////////////
410 } // namespace zypp
411 ///////////////////////////////////////////////////////////////////