00001
00002
00003
00004
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
00039
00040
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
00061
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
00101
00102
00103
00104
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
00125
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
00163
00164
00165 PoolImpl & PoolMember::myPool()
00166 {
00167 static PoolImpl _global;
00168 return _global;
00169 }
00170
00172
00173
00174
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
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
00195 _pool->nscallback = &nsCallback;
00196 _pool->nscallbackdata = (void*)this;
00197 }
00198
00200
00201
00202
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();
00220 _availableLocalesPtr.reset();
00221 _multiversionListPtr.reset();
00222
00223
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
00243
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
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, false );
00274 eraseRepoInfo( repo_r );
00275 if ( isSystemRepo( repo_r ) )
00276 {
00277
00278 _onSystemByUserListPtr.reset();
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 );
00295 _postRepoAdd( repo_r );
00296 return 0;
00297 }
00298
00299 void PoolImpl::_postRepoAdd( ::_Repo * repo_r )
00300 {
00301 if ( ! isSystemRepo( repo_r ) )
00302 {
00303
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
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
00323 if ( ! blockBegin )
00324 blockBegin = i;
00325 ++blockSize;
00326 }
00327 else if ( blockSize )
00328 {
00329
00330 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, false );
00331 blockBegin = blockSize = 0;
00332 }
00333 }
00334 if ( blockSize )
00335 {
00336
00337 ::repo_free_solvable_block( repo_r, blockBegin, blockSize, false );
00338 blockBegin = blockSize = 0;
00339 }
00340 }
00341 else
00342 {
00343
00344 _onSystemByUserListPtr.reset();
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
00362
00363 if ( repo->priority != int(-info_r.priority()) )
00364 {
00365 repo->priority = -info_r.priority();
00366 dirty = true;
00367 }
00368
00369
00370
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
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
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
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;
00472 }
00473 }
00474 }
00475
00476 const LocaleSet & PoolImpl::getAvailableLocales() const
00477 {
00478 if ( !_availableLocalesPtr )
00479 {
00480
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
00551
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
00557 if ( *ch < '1' || '9' < *ch )
00558 continue;
00559 const char * sep1 = ::strchr( ch, '|' );
00560 if ( !sep1 )
00561 continue;
00562 ++sep1;
00563
00564 bool installs = true;
00565 if ( ::strncmp( sep1, "install|", 8 ) )
00566 {
00567 if ( ::strncmp( sep1, "remove |", 8 ) )
00568 continue;
00569 else
00570 installs = false;
00571 }
00572 sep1 += 8;
00573
00574 const char * sep2 = ::strchr( sep1, '|' );
00575 if ( !sep2 || sep1 == sep2 )
00576 continue;
00577 (*in)[sep2-ch] = '\0';
00578 IdString pkg( sep1 );
00579
00580 if ( !installs )
00581 {
00582 onSystemByUserList.erase( pkg );
00583 continue;
00584 }
00585
00586 if ( (sep1 = ::strchr( sep2+1, '|' ))
00587 && (sep1 = ::strchr( sep1+1, '|' ))
00588 && (sep2 = ::strchr( sep1+1, '|' )) )
00589 {
00590 (*in)[sep2-ch] = '\0';
00591 if ( ::strchr( sep1+1, '@' ) )
00592 {
00593
00594 onSystemByUserList.insert( pkg );
00595 continue;
00596 }
00597 }
00598 }
00599 MIL << "onSystemByUserList found: " << onSystemByUserList.size() << endl;
00600 }
00601
00603 }
00606 }
00609 }