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