libzypp 9.41.1

PoolImpl.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <boost/mpl/int.hpp>
00015 
00016 #include "zypp/base/Easy.h"
00017 #include "zypp/base/LogTools.h"
00018 #include "zypp/base/Gettext.h"
00019 #include "zypp/base/Exception.h"
00020 #include "zypp/base/Measure.h"
00021 #include "zypp/base/WatchFile.h"
00022 #include "zypp/base/Sysconfig.h"
00023 #include "zypp/base/IOStream.h"
00024 
00025 #include "zypp/ZConfig.h"
00026 
00027 #include "zypp/sat/detail/PoolImpl.h"
00028 #include "zypp/sat/Pool.h"
00029 #include "zypp/Capability.h"
00030 #include "zypp/Locale.h"
00031 #include "zypp/PoolItem.h"
00032 
00033 #include "zypp/target/modalias/Modalias.h"
00034 #include "zypp/media/MediaPriority.h"
00035 
00036 extern "C"
00037 {
00038 // Workaround satsolver project not providing a common include
00039 // directory. (the -devel package does, but the git repo doesn't).
00040 // #include <satsolver/repo_helix.h>
00041 void repo_add_helix( ::Repo *repo, FILE *fp, int flags );
00042 }
00043 
00044 using std::endl;
00045 
00046 #undef  ZYPP_BASE_LOGGER_LOGGROUP
00047 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::satpool"
00048 
00049 // ///////////////////////////////////////////////////////////////////
00050 namespace zypp
00051 { 
00052 
00053   namespace sat
00054   { 
00055 
00057     namespace detail
00058     { 
00059 
00060       // MPL checks for satlib constants we redefine to avoid
00061       // includes and defines.
00062       BOOST_MPL_ASSERT_RELATION( noId,                 ==, STRID_NULL );
00063       BOOST_MPL_ASSERT_RELATION( emptyId,              ==, STRID_EMPTY );
00064 
00065       BOOST_MPL_ASSERT_RELATION( noSolvableId,         ==, ID_NULL );
00066       BOOST_MPL_ASSERT_RELATION( systemSolvableId,     ==, SYSTEMSOLVABLE );
00067 
00068       BOOST_MPL_ASSERT_RELATION( solvablePrereqMarker, ==, SOLVABLE_PREREQMARKER );
00069       BOOST_MPL_ASSERT_RELATION( solvableFileMarker,   ==, SOLVABLE_FILEMARKER );
00070 
00071       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_AND,       ==, REL_AND );
00072       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_OR,        ==, REL_OR );
00073       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_WITH,      ==, REL_WITH );
00074       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_NAMESPACE, ==, REL_NAMESPACE );
00075       BOOST_MPL_ASSERT_RELATION( CapDetail::CAP_ARCH,      ==, REL_ARCH );
00076 
00078 
00079       const std::string & PoolImpl::systemRepoAlias()
00080       {
00081         static const std::string _val( "@System" );
00082         return _val;
00083       }
00084 
00085       const Pathname & sysconfigStoragePath()
00086       {
00087         static const Pathname _val( "/etc/sysconfig/storage" );
00088         return _val;
00089       }
00090 
00091 
00093 
00094       static void logSat( struct _Pool *, void *data, int type, const char *logString )
00095       {
00096           if ( type & (SAT_FATAL|SAT_ERROR) ) {
00097             _ERR("satsolver") << logString;
00098           } else if ( type & SAT_DEBUG_STATS ) {
00099             _DBG("satsolver") << logString;
00100           } else {
00101             _MIL("satsolver") << logString;
00102           }
00103       }
00104 
00105       detail::IdType PoolImpl::nsCallback( struct _Pool *, void * data, detail::IdType lhs, detail::IdType rhs )
00106       {
00107         // lhs:    the namespace identifier, e.g. NAMESPACE:MODALIAS
00108         // rhs:    the value, e.g. pci:v0000104Cd0000840[01]sv*sd*bc*sc*i*
00109         // return: 0 if not supportded
00110         //         1 if supported by the system
00111         //        -1  AFAIK it's also possible to return a list of solvables that support it, but don't know how.
00112 
00113         static const detail::IdType RET_unsupported    = 0;
00114         static const detail::IdType RET_systemProperty = 1;
00115         switch ( lhs )
00116         {
00117           case NAMESPACE_LANGUAGE:
00118           {
00119             static IdString en( "en" );
00120             const std::tr1::unordered_set<IdString> & locale2Solver( reinterpret_cast<PoolImpl*>(data)->_locale2Solver );
00121             if ( locale2Solver.empty() )
00122             {
00123               return rhs == en.id() ? RET_systemProperty : RET_unsupported;
00124             }
00125             return locale2Solver.find( IdString(rhs) ) != locale2Solver.end() ? RET_systemProperty : RET_unsupported;
00126           }
00127           break;
00128 
00129           case NAMESPACE_MODALIAS:
00130           {
00131             // modalias strings in capability may be hexencoded because rpm does not allow
00132             // ',', ' ' or other special chars.
00133             return target::Modalias::instance().query( str::hexdecode( IdString(rhs).c_str() ) )
00134                 ? RET_systemProperty
00135               : RET_unsupported;
00136           }
00137           break;
00138 
00139           case NAMESPACE_FILESYSTEM:
00140           {
00141             const std::set<std::string> & requiredFilesystems( reinterpret_cast<PoolImpl*>(data)->requiredFilesystems() );
00142             return requiredFilesystems.find( IdString(rhs).asString() ) != requiredFilesystems.end() ? RET_systemProperty : RET_unsupported;
00143           }
00144           break;
00145 
00146           case NAMESPACE_PRODUCTBUDDY:
00147           {
00148             PoolItem pi( (Solvable(rhs)) );
00149             return( pi ? pi.buddy().id() : noId );
00150           }
00151 
00152           break;
00153         }
00154 
00155         WAR << "Unhandled " << Capability( lhs ) << " vs. " << Capability( rhs ) << endl;
00156         return RET_unsupported;
00157       }
00158 
00160       //
00161       //        METHOD NAME : PoolMember::myPool
00162       //        METHOD TYPE : PoolImpl
00163       //
00164       PoolImpl & PoolMember::myPool()
00165       {
00166         static PoolImpl _global;
00167         return _global;
00168       }
00169 
00171       //
00172       //        METHOD NAME : PoolImpl::PoolImpl
00173       //        METHOD TYPE : Ctor
00174       //
00175       PoolImpl::PoolImpl()
00176       : _pool( ::pool_create() )
00177       {
00178         MIL << "Creating sat-pool." << endl;
00179         if ( ! _pool )
00180         {
00181           ZYPP_THROW( Exception( _("Can not create sat-pool.") ) );
00182         }
00183         // initialialize logging
00184         if ( getenv("ZYPP_LIBSAT_FULLLOG") )
00185           ::pool_setdebuglevel( _pool, 4 );
00186         else if ( getenv("ZYPP_FULLLOG") )
00187           ::pool_setdebuglevel( _pool, 2 );
00188         else
00189           ::pool_setdebugmask(_pool, SAT_DEBUG_JOB|SAT_DEBUG_STATS);
00190 
00191         ::pool_setdebugcallback( _pool, logSat, NULL );
00192 
00193         // set namespace callback
00194         _pool->nscallback = &nsCallback;
00195         _pool->nscallbackdata = (void*)this;
00196         if ( getenv("ZYPP_LIBSAT_ALLOWSELFCONFLICTS") ) // bnc#921997
00197           _pool->allowselfconflicts = 1;
00198       }
00199 
00201       //
00202       //        METHOD NAME : PoolImpl::~PoolImpl
00203       //        METHOD TYPE : Dtor
00204       //
00205       PoolImpl::~PoolImpl()
00206       {
00207         ::pool_free( _pool );
00208       }
00209 
00211 
00212       void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 )
00213       {
00214         if ( a1 )
00215         {
00216           if      ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
00217           else if ( a2 ) MIL << a1 << " " << a2 << endl;
00218           else           MIL << a1 << endl;
00219         }
00220         _serial.setDirty();           // pool content change
00221         _availableLocalesPtr.reset(); // available locales may change
00222         _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec.
00223 
00224         // invaldate dependency/namespace related indices:
00225         depSetDirty();
00226       }
00227 
00228       void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 )
00229       {
00230         if ( a1 )
00231         {
00232           if      ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl;
00233           else if ( a2 ) MIL << a1 << " " << a2 << endl;
00234           else           MIL << a1 << endl;
00235         }
00236         ::pool_freewhatprovides( _pool );
00237       }
00238 
00239       void PoolImpl::prepare() const
00240       {
00241         if ( _watcher.remember( _serial ) )
00242         {
00243           // After repo/solvable add/remove:
00244           // set pool architecture
00245           ::pool_setarch( _pool,  ZConfig::instance().systemArchitecture().asString().c_str() );
00246         }
00247         if ( ! _pool->whatprovides )
00248         {
00249           MIL << "pool_createwhatprovides..." << endl;
00250 
00251           ::pool_addfileprovides( _pool );
00252           ::pool_createwhatprovides( _pool );
00253         }
00254         if ( ! _pool->languages )
00255         {
00256           // initial seting
00257           const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() );
00258         }
00259       }
00260 
00261       void PoolImpl::prepareForSolving() const
00262       {
00263         // additional /etc/sysconfig/storage check:
00264         static WatchFile sysconfigFile( sysconfigStoragePath(), WatchFile::NO_INIT );
00265         if ( sysconfigFile.hasChanged() )
00266         {
00267           _requiredFilesystemsPtr.reset(); // recreated on demand
00268           const_cast<PoolImpl*>(this)->depSetDirty( "/etc/sysconfig/storage change" );
00269         }
00270         // finally prepare as usual:
00271         prepare();
00272       }
00273 
00275 
00276       ::_Repo * PoolImpl::_createRepo( const std::string & name_r )
00277       {
00278         setDirty(__FUNCTION__, name_r.c_str() );
00279         ::_Repo * ret = ::repo_create( _pool, name_r.c_str() );
00280         if ( ret && name_r == systemRepoAlias() )
00281           ::pool_set_installed( _pool, ret );
00282         return ret;
00283       }
00284 
00285       void PoolImpl::_deleteRepo( ::_Repo * repo_r )
00286       {
00287         setDirty(__FUNCTION__, repo_r->name );
00288         ::repo_free( repo_r, /*reuseids*/false );
00289         eraseRepoInfo( repo_r );
00290         if ( isSystemRepo( repo_r ) )
00291         {
00292           // systemRepo added
00293           _onSystemByUserListPtr.reset(); // re-evaluate
00294         }
00295       }
00296 
00297       int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r )
00298       {
00299         setDirty(__FUNCTION__, repo_r->name );
00300         int ret = ::repo_add_solv( repo_r , file_r );
00301         if ( ret == 0 )
00302           _postRepoAdd( repo_r );
00303         return ret;
00304       }
00305 
00306       int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r )
00307       {
00308         setDirty(__FUNCTION__, repo_r->name );
00309         ::repo_add_helix( repo_r , file_r, 0 ); // unfortunately void
00310         _postRepoAdd( repo_r );
00311         return 0;
00312       }
00313 
00314       void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
00315       {
00316         if ( ! isSystemRepo( repo_r ) )
00317         {
00318             // Filter out unwanted archs
00319           std::set<detail::IdType> sysids;
00320           {
00321             Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) );
00322             for_( it, sysarchs.begin(), sysarchs.end() )
00323               sysids.insert( it->id() );
00324 
00325               // unfortunately satsolver treats src/nosrc as architecture:
00326             sysids.insert( ARCH_SRC );
00327             sysids.insert( ARCH_NOSRC );
00328           }
00329 
00330           detail::IdType blockBegin = 0;
00331           unsigned       blockSize  = 0;
00332           for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i )
00333           {
00334               ::_Solvable * s( _pool->solvables + i );
00335               if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() )
00336               {
00337                 // Remember an unwanted arch entry:
00338                 if ( ! blockBegin )
00339                   blockBegin = i;
00340                 ++blockSize;
00341               }
00342               else if ( blockSize )
00343               {
00344                 // Free remembered entries
00345                   ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
00346                   blockBegin = blockSize = 0;
00347               }
00348           }
00349           if ( blockSize )
00350           {
00351               // Free remembered entries
00352               ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false );
00353               blockBegin = blockSize = 0;
00354           }
00355         }
00356         else
00357         {
00358           // systemRepo added
00359           _onSystemByUserListPtr.reset(); // re-evaluate
00360         }
00361       }
00362 
00363       detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r )
00364       {
00365         setDirty(__FUNCTION__, repo_r->name );
00366         return ::repo_add_solvable_block( repo_r, count_r );
00367       }
00368 
00369       void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r )
00370       {
00371         ::_Repo * repo( getRepo( id_r ) );
00372         if ( repo )
00373         {
00374           bool dirty = false;
00375 
00376           // satsolver priority is based on '<', while yum's repoinfo
00377           // uses 1(highest)->99(lowest). Thus we use -info_r.priority.
00378           if ( repo->priority != int(-info_r.priority()) )
00379           {
00380             repo->priority = -info_r.priority();
00381             dirty = true;
00382           }
00383 
00384           // subpriority is used to e.g. prefer http over dvd iff
00385           // both have same priority.
00386           int mediaPriority( media::MediaPriority( info_r.url() ) );
00387           if ( repo->subpriority != mediaPriority )
00388           {
00389             repo->subpriority = mediaPriority;
00390             dirty = true;
00391           }
00392 
00393           if ( dirty )
00394             setDirty(__FUNCTION__, info_r.alias().c_str() );
00395         }
00396         _repoinfos[id_r] = info_r;
00397       }
00398 
00400 
00401       // need on demand and id based Locale
00402       void _locale_hack( const LocaleSet & locales_r,
00403                          std::tr1::unordered_set<IdString> & locale2Solver )
00404       {
00405         std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver );
00406         for_( it, locales_r.begin(),locales_r.end() )
00407         {
00408           for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() )
00409             locale2Solver.insert( IdString( l.code() ) );
00410         }
00411         MIL << "New Solver Locales: " << locale2Solver << endl;
00412       }
00413 
00414       void PoolImpl::setTextLocale( const Locale & locale_r )
00415       {
00416         std::vector<std::string> fallbacklist;
00417         for ( Locale l( locale_r ); l != Locale::noCode; l = l.fallback() )
00418         {
00419           fallbacklist.push_back( l.code() );
00420         }
00421         dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl;
00422 
00423         std::vector<const char *> fallbacklist_cstr;
00424         for_( it, fallbacklist.begin(), fallbacklist.end() )
00425         {
00426           fallbacklist_cstr.push_back( it->c_str() );
00427         }
00428         ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() );
00429       }
00430 
00431       void PoolImpl::setRequestedLocales( const LocaleSet & locales_r )
00432       {
00433         depSetDirty( "setRequestedLocales" );
00434         _requestedLocales = locales_r;
00435         MIL << "New RequestedLocales: " << locales_r << endl;
00436         _locale_hack( _requestedLocales, _locale2Solver );
00437       }
00438 
00439       bool PoolImpl::addRequestedLocale( const Locale & locale_r )
00440       {
00441         if ( _requestedLocales.insert( locale_r ).second )
00442         {
00443           depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
00444           _locale_hack( _requestedLocales, _locale2Solver );
00445           return true;
00446         }
00447         return false;
00448       }
00449 
00450       bool PoolImpl::eraseRequestedLocale( const Locale & locale_r )
00451       {
00452         if ( _requestedLocales.erase( locale_r ) )
00453         {
00454           depSetDirty( "addRequestedLocale", locale_r.code().c_str() );
00455           _locale_hack( _requestedLocales, _locale2Solver );
00456           return true;
00457         }
00458         return false;
00459       }
00460 
00461       static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r )
00462       {
00463         // Collect locales from any 'namespace:language(lang)' dependency
00464         CapDetail detail( cap_r );
00465         if ( detail.kind() == CapDetail::EXPRESSION )
00466         {
00467           switch ( detail.capRel() )
00468           {
00469             case CapDetail::CAP_AND:
00470             case CapDetail::CAP_OR:
00471               // expand
00472               _getLocaleDeps( detail.lhs(), store_r );
00473               _getLocaleDeps( detail.rhs(), store_r );
00474               break;
00475 
00476             case CapDetail::CAP_NAMESPACE:
00477               if ( detail.lhs().id() == NAMESPACE_LANGUAGE )
00478               {
00479                 store_r.insert( detail.rhs().id() );
00480               }
00481               break;
00482 
00483             case CapDetail::REL_NONE:
00484             case CapDetail::CAP_WITH:
00485             case CapDetail::CAP_ARCH:
00486               break; // unwanted
00487           }
00488         }
00489       }
00490 
00491       const LocaleSet & PoolImpl::getAvailableLocales() const
00492       {
00493         if ( !_availableLocalesPtr )
00494         {
00495           // Collect any 'namespace:language(ja)' dependencies
00496           std::tr1::unordered_set<sat::detail::IdType> tmp;
00497           Pool pool( Pool::instance() );
00498           for_( it, pool.solvablesBegin(), pool.solvablesEnd() )
00499           {
00500             Capabilities cap( it->supplements() );
00501             for_( cit, cap.begin(), cap.end() )
00502             {
00503               _getLocaleDeps( *cit, tmp );
00504             }
00505           }
00506 #warning immediately build LocaleSet as soon as Loale is an Id based type
00507           _availableLocalesPtr.reset( new LocaleSet(tmp.size()) );
00508           for_( it, tmp.begin(), tmp.end() )
00509           {
00510             _availableLocalesPtr->insert( Locale( IdString(*it) ) );
00511           }
00512         }
00513         return *_availableLocalesPtr;
00514       }
00515 
00516       void PoolImpl::multiversionListInit() const
00517       {
00518         _multiversionListPtr.reset( new MultiversionList );
00519         MultiversionList & multiversionList( *_multiversionListPtr );
00520 
00521         const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() );
00522         for_( it, multiversionSpec.begin(), multiversionSpec.end() )
00523         {
00524           static const std::string prefix( "provides:" );
00525           if ( str::hasPrefix( *it, prefix ) )
00526           {
00527             WhatProvides provides( Capability( it->c_str() + prefix.size() ) );
00528             if ( provides.empty() )
00529             {
00530               MIL << "Multiversion install not provided (" << *it << ")" << endl;
00531             }
00532             else
00533             {
00534               for_( pit, provides.begin(), provides.end() )
00535               {
00536                 if ( multiversionList.insert( pit->ident() ).second )
00537                   MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl;
00538               }
00539             }
00540           }
00541           else
00542           {
00543             MIL << "Multiversion install " << *it << endl;
00544             multiversionList.insert( IdString( *it ) );
00545           }
00546         }
00547       }
00548 
00549       void PoolImpl::onSystemByUserListInit() const
00550       {
00551         _onSystemByUserListPtr.reset( new OnSystemByUserList );
00552         OnSystemByUserList & onSystemByUserList( *_onSystemByUserListPtr );
00553 
00554         Pathname root( ZConfig::instance().systemRoot() );
00555         if ( root.empty() )
00556         {
00557           MIL << "Target not initialized." << endl;
00558           return;
00559         }
00560         PathInfo pi( root / ZConfig::instance().historyLogFile() );
00561         MIL << "onSystemByUserList from history: " << pi << endl;
00562         if ( ! pi.isFile() )
00563           return;
00564 
00565         // go and parse it: 'who' must constain an '@', then it was installed by user request.
00566         // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0...
00567         std::ifstream infile( pi.path().c_str() );
00568         for( iostr::EachLine in( infile ); in; in.next() )
00569         {
00570           const char * ch( (*in).c_str() );
00571           // start with year
00572           if ( *ch < '1' || '9' < *ch )
00573             continue;
00574           const char * sep1 = ::strchr( ch, '|' );      // | after date
00575           if ( !sep1 )
00576             continue;
00577           ++sep1;
00578           // if logs an install or delete
00579           bool installs = true;
00580           if ( ::strncmp( sep1, "install|", 8 ) )
00581           {
00582             if ( ::strncmp( sep1, "remove |", 8 ) )
00583               continue; // no install and no remove
00584               else
00585                 installs = false; // remove
00586           }
00587           sep1 += 8;                                    // | after what
00588           // get the package name
00589           const char * sep2 = ::strchr( sep1, '|' );    // | after name
00590           if ( !sep2 || sep1 == sep2 )
00591             continue;
00592           (*in)[sep2-ch] = '\0';
00593           IdString pkg( sep1 );
00594           // we're done, if a delete
00595           if ( !installs )
00596           {
00597             onSystemByUserList.erase( pkg );
00598             continue;
00599           }
00600           // now guess whether user installed or not (3rd next field contains 'user@host')
00601           if ( (sep1 = ::strchr( sep2+1, '|' ))         // | after version
00602             && (sep1 = ::strchr( sep1+1, '|' ))         // | after arch
00603             && (sep2 = ::strchr( sep1+1, '|' )) )       // | after who
00604           {
00605             (*in)[sep2-ch] = '\0';
00606             if ( ::strchr( sep1+1, '@' ) )
00607             {
00608               // by user
00609               onSystemByUserList.insert( pkg );
00610               continue;
00611             }
00612           }
00613         }
00614         MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
00615       }
00616 
00617       const std::set<std::string> & PoolImpl::requiredFilesystems() const
00618       {
00619         if ( ! _requiredFilesystemsPtr )
00620         {
00621           _requiredFilesystemsPtr.reset( new std::set<std::string> );
00622           std::set<std::string> & requiredFilesystems( *_requiredFilesystemsPtr );
00623           str::split( base::sysconfig::read( sysconfigStoragePath() )["USED_FS_LIST"],
00624                       std::inserter( requiredFilesystems, requiredFilesystems.end() ) );
00625         }
00626         return *_requiredFilesystemsPtr;
00627       }
00628 
00630     } // namespace detail
00633   } // namespace sat
00636 } // namespace zypp