libzypp 9.41.1
|
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