libzypp
10.5.0
|
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 libsolv project not providing a common include 00039 // directory. (the -devel package does, but the git repo doesn't). 00040 // #include <solv/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 & (SOLV_FATAL|SOLV_ERROR) ) { 00097 _ERR("libsolv") << logString; 00098 } else if ( type & SOLV_DEBUG_STATS ) { 00099 _DBG("libsolv") << logString; 00100 } else { 00101 _MIL("libsolv") << 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_LIBSOLV_FULLLOG") || 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, SOLV_DEBUG_JOB|SOLV_DEBUG_STATS); 00190 00191 ::pool_setdebugcallback( _pool, logSat, NULL ); 00192 00193 // set namespace callback 00194 _pool->nscallback = &nsCallback; 00195 _pool->nscallbackdata = (void*)this; 00196 } 00197 00199 // 00200 // METHOD NAME : PoolImpl::~PoolImpl 00201 // METHOD TYPE : Dtor 00202 // 00203 PoolImpl::~PoolImpl() 00204 { 00205 ::pool_free( _pool ); 00206 } 00207 00209 00210 void PoolImpl::setDirty( const char * a1, const char * a2, const char * a3 ) 00211 { 00212 if ( a1 ) 00213 { 00214 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl; 00215 else if ( a2 ) MIL << a1 << " " << a2 << endl; 00216 else MIL << a1 << endl; 00217 } 00218 _serial.setDirty(); // pool content change 00219 _availableLocalesPtr.reset(); // available locales may change 00220 _multiversionListPtr.reset(); // re-evaluate ZConfig::multiversionSpec. 00221 00222 // invaldate dependency/namespace related indices: 00223 depSetDirty(); 00224 } 00225 00226 void PoolImpl::depSetDirty( const char * a1, const char * a2, const char * a3 ) 00227 { 00228 if ( a1 ) 00229 { 00230 if ( a3 ) MIL << a1 << " " << a2 << " " << a3 << endl; 00231 else if ( a2 ) MIL << a1 << " " << a2 << endl; 00232 else MIL << a1 << endl; 00233 } 00234 ::pool_freewhatprovides( _pool ); 00235 } 00236 00237 void PoolImpl::prepare() const 00238 { 00239 if ( _watcher.remember( _serial ) ) 00240 { 00241 // After repo/solvable add/remove: 00242 // set pool architecture 00243 ::pool_setarch( _pool, ZConfig::instance().systemArchitecture().asString().c_str() ); 00244 } 00245 if ( ! _pool->whatprovides ) 00246 { 00247 MIL << "pool_createwhatprovides..." << endl; 00248 00249 ::pool_addfileprovides( _pool ); 00250 ::pool_createwhatprovides( _pool ); 00251 } 00252 if ( ! _pool->languages ) 00253 { 00254 // initial seting 00255 const_cast<PoolImpl*>(this)->setTextLocale( ZConfig::instance().textLocale() ); 00256 } 00257 } 00258 00259 void PoolImpl::prepareForSolving() const 00260 { 00261 // additional /etc/sysconfig/storage check: 00262 static WatchFile sysconfigFile( sysconfigStoragePath(), WatchFile::NO_INIT ); 00263 if ( sysconfigFile.hasChanged() ) 00264 { 00265 _requiredFilesystemsPtr.reset(); // recreated on demand 00266 const_cast<PoolImpl*>(this)->depSetDirty( "/etc/sysconfig/storage change" ); 00267 } 00268 // finally prepare as usual: 00269 prepare(); 00270 } 00271 00273 00274 ::_Repo * PoolImpl::_createRepo( const std::string & name_r ) 00275 { 00276 setDirty(__FUNCTION__, name_r.c_str() ); 00277 ::_Repo * ret = ::repo_create( _pool, name_r.c_str() ); 00278 if ( ret && name_r == systemRepoAlias() ) 00279 ::pool_set_installed( _pool, ret ); 00280 return ret; 00281 } 00282 00283 void PoolImpl::_deleteRepo( ::_Repo * repo_r ) 00284 { 00285 setDirty(__FUNCTION__, repo_r->name ); 00286 ::repo_free( repo_r, /*reuseids*/false ); 00287 eraseRepoInfo( repo_r ); 00288 if ( isSystemRepo( repo_r ) ) 00289 { 00290 // systemRepo added 00291 _onSystemByUserListPtr.reset(); // re-evaluate 00292 } 00293 } 00294 00295 int PoolImpl::_addSolv( ::_Repo * repo_r, FILE * file_r ) 00296 { 00297 setDirty(__FUNCTION__, repo_r->name ); 00298 int ret = ::repo_add_solv( repo_r , file_r ); 00299 if ( ret == 0 ) 00300 _postRepoAdd( repo_r ); 00301 return ret; 00302 } 00303 00304 int PoolImpl::_addHelix( ::_Repo * repo_r, FILE * file_r ) 00305 { 00306 setDirty(__FUNCTION__, repo_r->name ); 00307 ::repo_add_helix( repo_r , file_r, 0 ); // unfortunately void 00308 _postRepoAdd( repo_r ); 00309 return 0; 00310 } 00311 00312 void PoolImpl::_postRepoAdd( ::_Repo * repo_r ) 00313 { 00314 if ( ! isSystemRepo( repo_r ) ) 00315 { 00316 // Filter out unwanted archs 00317 std::set<detail::IdType> sysids; 00318 { 00319 Arch::CompatSet sysarchs( Arch::compatSet( ZConfig::instance().systemArchitecture() ) ); 00320 for_( it, sysarchs.begin(), sysarchs.end() ) 00321 sysids.insert( it->id() ); 00322 00323 // unfortunately libsolv treats src/nosrc as architecture: 00324 sysids.insert( ARCH_SRC ); 00325 sysids.insert( ARCH_NOSRC ); 00326 } 00327 00328 detail::IdType blockBegin = 0; 00329 unsigned blockSize = 0; 00330 for ( detail::IdType i = repo_r->start; i < repo_r->end; ++i ) 00331 { 00332 ::_Solvable * s( _pool->solvables + i ); 00333 if ( s->repo == repo_r && sysids.find( s->arch ) == sysids.end() ) 00334 { 00335 // Remember an unwanted arch entry: 00336 if ( ! blockBegin ) 00337 blockBegin = i; 00338 ++blockSize; 00339 } 00340 else if ( blockSize ) 00341 { 00342 // Free remembered entries 00343 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false ); 00344 blockBegin = blockSize = 0; 00345 } 00346 } 00347 if ( blockSize ) 00348 { 00349 // Free remembered entries 00350 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, /*reuseids*/false ); 00351 blockBegin = blockSize = 0; 00352 } 00353 } 00354 else 00355 { 00356 // systemRepo added 00357 _onSystemByUserListPtr.reset(); // re-evaluate 00358 } 00359 } 00360 00361 detail::SolvableIdType PoolImpl::_addSolvables( ::_Repo * repo_r, unsigned count_r ) 00362 { 00363 setDirty(__FUNCTION__, repo_r->name ); 00364 return ::repo_add_solvable_block( repo_r, count_r ); 00365 } 00366 00367 void PoolImpl::setRepoInfo( RepoIdType id_r, const RepoInfo & info_r ) 00368 { 00369 ::_Repo * repo( getRepo( id_r ) ); 00370 if ( repo ) 00371 { 00372 bool dirty = false; 00373 00374 // libsolv priority is based on '<', while yum's repoinfo 00375 // uses 1(highest)->99(lowest). Thus we use -info_r.priority. 00376 if ( repo->priority != int(-info_r.priority()) ) 00377 { 00378 repo->priority = -info_r.priority(); 00379 dirty = true; 00380 } 00381 00382 // subpriority is used to e.g. prefer http over dvd iff 00383 // both have same priority. 00384 int mediaPriority( media::MediaPriority( info_r.url() ) ); 00385 if ( repo->subpriority != mediaPriority ) 00386 { 00387 repo->subpriority = mediaPriority; 00388 dirty = true; 00389 } 00390 00391 if ( dirty ) 00392 setDirty(__FUNCTION__, info_r.alias().c_str() ); 00393 } 00394 _repoinfos[id_r] = info_r; 00395 } 00396 00398 00399 // need on demand and id based Locale 00400 void _locale_hack( const LocaleSet & locales_r, 00401 std::tr1::unordered_set<IdString> & locale2Solver ) 00402 { 00403 std::tr1::unordered_set<IdString>( 2*locales_r.size() ).swap( locale2Solver ); 00404 for_( it, locales_r.begin(),locales_r.end() ) 00405 { 00406 for ( Locale l( *it ); l != Locale::noCode; l = l.fallback() ) 00407 locale2Solver.insert( IdString( l.code() ) ); 00408 } 00409 MIL << "New Solver Locales: " << locale2Solver << endl; 00410 } 00411 00412 void PoolImpl::setTextLocale( const Locale & locale_r ) 00413 { 00414 std::vector<std::string> fallbacklist; 00415 for ( Locale l( locale_r ); l != Locale::noCode; l = l.fallback() ) 00416 { 00417 fallbacklist.push_back( l.code() ); 00418 } 00419 dumpRangeLine( MIL << "pool_set_languages: ", fallbacklist.begin(), fallbacklist.end() ) << endl; 00420 00421 std::vector<const char *> fallbacklist_cstr; 00422 for_( it, fallbacklist.begin(), fallbacklist.end() ) 00423 { 00424 fallbacklist_cstr.push_back( it->c_str() ); 00425 } 00426 ::pool_set_languages( _pool, &fallbacklist_cstr.front(), fallbacklist_cstr.size() ); 00427 } 00428 00429 void PoolImpl::setRequestedLocales( const LocaleSet & locales_r ) 00430 { 00431 depSetDirty( "setRequestedLocales" ); 00432 _requestedLocales = locales_r; 00433 MIL << "New RequestedLocales: " << locales_r << endl; 00434 _locale_hack( _requestedLocales, _locale2Solver ); 00435 } 00436 00437 bool PoolImpl::addRequestedLocale( const Locale & locale_r ) 00438 { 00439 if ( _requestedLocales.insert( locale_r ).second ) 00440 { 00441 depSetDirty( "addRequestedLocale", locale_r.code().c_str() ); 00442 _locale_hack( _requestedLocales, _locale2Solver ); 00443 return true; 00444 } 00445 return false; 00446 } 00447 00448 bool PoolImpl::eraseRequestedLocale( const Locale & locale_r ) 00449 { 00450 if ( _requestedLocales.erase( locale_r ) ) 00451 { 00452 depSetDirty( "addRequestedLocale", locale_r.code().c_str() ); 00453 _locale_hack( _requestedLocales, _locale2Solver ); 00454 return true; 00455 } 00456 return false; 00457 } 00458 00459 static void _getLocaleDeps( Capability cap_r, std::tr1::unordered_set<sat::detail::IdType> & store_r ) 00460 { 00461 // Collect locales from any 'namespace:language(lang)' dependency 00462 CapDetail detail( cap_r ); 00463 if ( detail.kind() == CapDetail::EXPRESSION ) 00464 { 00465 switch ( detail.capRel() ) 00466 { 00467 case CapDetail::CAP_AND: 00468 case CapDetail::CAP_OR: 00469 // expand 00470 _getLocaleDeps( detail.lhs(), store_r ); 00471 _getLocaleDeps( detail.rhs(), store_r ); 00472 break; 00473 00474 case CapDetail::CAP_NAMESPACE: 00475 if ( detail.lhs().id() == NAMESPACE_LANGUAGE ) 00476 { 00477 store_r.insert( detail.rhs().id() ); 00478 } 00479 break; 00480 00481 case CapDetail::REL_NONE: 00482 case CapDetail::CAP_WITH: 00483 case CapDetail::CAP_ARCH: 00484 break; // unwanted 00485 } 00486 } 00487 } 00488 00489 const LocaleSet & PoolImpl::getAvailableLocales() const 00490 { 00491 if ( !_availableLocalesPtr ) 00492 { 00493 // Collect any 'namespace:language(ja)' dependencies 00494 std::tr1::unordered_set<sat::detail::IdType> tmp; 00495 Pool pool( Pool::instance() ); 00496 for_( it, pool.solvablesBegin(), pool.solvablesEnd() ) 00497 { 00498 Capabilities cap( it->supplements() ); 00499 for_( cit, cap.begin(), cap.end() ) 00500 { 00501 _getLocaleDeps( *cit, tmp ); 00502 } 00503 } 00504 #warning immediately build LocaleSet as soon as Loale is an Id based type 00505 _availableLocalesPtr.reset( new LocaleSet(tmp.size()) ); 00506 for_( it, tmp.begin(), tmp.end() ) 00507 { 00508 _availableLocalesPtr->insert( Locale( IdString(*it) ) ); 00509 } 00510 } 00511 return *_availableLocalesPtr; 00512 } 00513 00514 void PoolImpl::multiversionListInit() const 00515 { 00516 _multiversionListPtr.reset( new MultiversionList ); 00517 MultiversionList & multiversionList( *_multiversionListPtr ); 00518 00519 const std::set<std::string> & multiversionSpec( ZConfig::instance().multiversionSpec() ); 00520 for_( it, multiversionSpec.begin(), multiversionSpec.end() ) 00521 { 00522 static const std::string prefix( "provides:" ); 00523 if ( str::hasPrefix( *it, prefix ) ) 00524 { 00525 WhatProvides provides( Capability( it->c_str() + prefix.size() ) ); 00526 if ( provides.empty() ) 00527 { 00528 MIL << "Multiversion install not provided (" << *it << ")" << endl; 00529 } 00530 else 00531 { 00532 for_( pit, provides.begin(), provides.end() ) 00533 { 00534 if ( multiversionList.insert( pit->ident() ).second ) 00535 MIL << "Multiversion install " << pit->ident() << " (" << *it << ")" << endl; 00536 } 00537 } 00538 } 00539 else 00540 { 00541 MIL << "Multiversion install " << *it << endl; 00542 multiversionList.insert( IdString( *it ) ); 00543 } 00544 } 00545 } 00546 00547 void PoolImpl::onSystemByUserListInit() const 00548 { 00549 _onSystemByUserListPtr.reset( new OnSystemByUserList ); 00550 OnSystemByUserList & onSystemByUserList( *_onSystemByUserListPtr ); 00551 00552 Pathname root( ZConfig::instance().systemRoot() ); 00553 if ( root.empty() ) 00554 { 00555 MIL << "Target not initialized." << endl; 00556 return; 00557 } 00558 PathInfo pi( root / ZConfig::instance().historyLogFile() ); 00559 MIL << "onSystemByUserList from history: " << pi << endl; 00560 if ( ! pi.isFile() ) 00561 return; 00562 00563 // go and parse it: 'who' must constain an '@', then it was installed by user request. 00564 // 2009-09-29 07:25:19|install|lirc-remotes|0.8.5-3.2|x86_64|root@opensuse|InstallationImage|a204211eb0... 00565 std::ifstream infile( pi.path().c_str() ); 00566 for( iostr::EachLine in( infile ); in; in.next() ) 00567 { 00568 const char * ch( (*in).c_str() ); 00569 // start with year 00570 if ( *ch < '1' || '9' < *ch ) 00571 continue; 00572 const char * sep1 = ::strchr( ch, '|' ); // | after date 00573 if ( !sep1 ) 00574 continue; 00575 ++sep1; 00576 // if logs an install or delete 00577 bool installs = true; 00578 if ( ::strncmp( sep1, "install|", 8 ) ) 00579 { 00580 if ( ::strncmp( sep1, "remove |", 8 ) ) 00581 continue; // no install and no remove 00582 else 00583 installs = false; // remove 00584 } 00585 sep1 += 8; // | after what 00586 // get the package name 00587 const char * sep2 = ::strchr( sep1, '|' ); // | after name 00588 if ( !sep2 || sep1 == sep2 ) 00589 continue; 00590 (*in)[sep2-ch] = '\0'; 00591 IdString pkg( sep1 ); 00592 // we're done, if a delete 00593 if ( !installs ) 00594 { 00595 onSystemByUserList.erase( pkg ); 00596 continue; 00597 } 00598 // now guess whether user installed or not (3rd next field contains 'user@host') 00599 if ( (sep1 = ::strchr( sep2+1, '|' )) // | after version 00600 && (sep1 = ::strchr( sep1+1, '|' )) // | after arch 00601 && (sep2 = ::strchr( sep1+1, '|' )) ) // | after who 00602 { 00603 (*in)[sep2-ch] = '\0'; 00604 if ( ::strchr( sep1+1, '@' ) ) 00605 { 00606 // by user 00607 onSystemByUserList.insert( pkg ); 00608 continue; 00609 } 00610 } 00611 } 00612 MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl; 00613 } 00614 00615 const std::set<std::string> & PoolImpl::requiredFilesystems() const 00616 { 00617 if ( ! _requiredFilesystemsPtr ) 00618 { 00619 _requiredFilesystemsPtr.reset( new std::set<std::string> ); 00620 std::set<std::string> & requiredFilesystems( *_requiredFilesystemsPtr ); 00621 str::split( base::sysconfig::read( sysconfigStoragePath() )["USED_FS_LIST"], 00622 std::inserter( requiredFilesystems, requiredFilesystems.end() ) ); 00623 } 00624 return *_requiredFilesystemsPtr; 00625 } 00626 00628 } // namespace detail 00631 } // namespace sat 00634 } // namespace zypp