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