00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <iostream>
00013 #include <sstream>
00014 #include <string>
00015 #include <list>
00016 #include <set>
00017
00018 #include "zypp/base/Logger.h"
00019 #include "zypp/base/Exception.h"
00020 #include "zypp/base/Iterator.h"
00021 #include "zypp/base/Gettext.h"
00022 #include "zypp/PoolItem.h"
00023 #include "zypp/Resolvable.h"
00024 #include "zypp/ResObject.h"
00025 #include "zypp/Package.h"
00026 #include "zypp/Pattern.h"
00027 #include "zypp/Selection.h"
00028 #include "zypp/Script.h"
00029 #include "zypp/Message.h"
00030 #include "zypp/Source.h"
00031 #include "zypp/Url.h"
00032
00033 #include "zypp/CapMatchHelper.h"
00034 #include "zypp/ResFilters.h"
00035 #include "zypp/target/CommitLog.h"
00036 #include "zypp/target/TargetImpl.h"
00037 #include "zypp/target/TargetCallbackReceiver.h"
00038 #include "zypp/target/rpm/librpmDb.h"
00039 #include "zypp/target/CommitPackageCache.h"
00040
00041 #include "zypp/pool/GetResolvablesToInsDel.h"
00042 #include "zypp/solver/detail/Helper.h"
00043 #include "zypp/source/PackageProvider.h"
00044
00045 using namespace std;
00046 using namespace zypp;
00047 using namespace zypp::resfilter;
00048 using zypp::solver::detail::Helper;
00049
00051 namespace zypp
00052 {
00053
00054 namespace target
00055 {
00056
00058 namespace
00059 {
00060 void ExecuteScriptHelper( Script::constPtr script_r, bool do_r )
00061 {
00062 MIL << "Execute script " << script_r << endl;
00063 if ( ! script_r )
00064 {
00065 INT << "NULL Script passed." << endl;
00066 return;
00067 }
00068
00069 Pathname path;
00070 if ( do_r )
00071 {
00072 path = script_r->do_script();
00073 }
00074 else
00075 {
00076 if ( script_r->undo_available() )
00077 {
00078 path = script_r->undo_script();
00079 }
00080 else
00081 {
00082 DBG << "No undo script for " << script_r << endl;
00083 return;
00084 }
00085 }
00086
00087
00088 callback::SendReport<ScriptResolvableReport> report;
00089 report->start( script_r, path,
00090 (do_r ? ScriptResolvableReport::DO
00091 : ScriptResolvableReport::UNDO ) );
00092
00093 PathInfo pi( path );
00094 if ( ! pi.isFile() )
00095 {
00096 std::ostringstream err;
00097 err << "Script is not a file: " << pi.fileType() << " " << path;
00098 report->problem( err.str() );
00099 ZYPP_THROW(Exception(err.str()));
00100 }
00101
00102 filesystem::chmod( path, S_IRUSR|S_IXUSR );
00103 ExternalProgram prog( path.asString(), ExternalProgram::Stderr_To_Stdout, false, -1, true );
00104 for ( std::string output = prog.receiveLine(); output.length(); output = prog.receiveLine() )
00105 {
00106 if ( ! report->progress( ScriptResolvableReport::OUTPUT, output ) )
00107 {
00108 WAR << "User request to abort script." << endl;
00109 prog.kill();
00110 }
00111 }
00112
00113 int exitCode = prog.close();
00114 if ( exitCode != 0 )
00115 {
00116 std::ostringstream err;
00117 err << "Script failed with exit code " << exitCode;
00118 report->problem( err.str() );
00119 ZYPP_THROW(Exception(err.str()));
00120 }
00121
00122 report->finish();
00123 return;
00124 }
00125
00126 inline void ExecuteDoScript( const Script::constPtr & script_r )
00127 {
00128 ExecuteScriptHelper( script_r, true );
00129 }
00130
00131 inline void ExecuteUndoScript( const Script::constPtr & script_r )
00132 {
00133 ExecuteScriptHelper( script_r, false );
00134 }
00136 }
00138
00140 namespace
00141 {
00142
00144 struct StorageRemoveObsoleted
00145 {
00146 StorageRemoveObsoleted( storage::PersistentStorage & storage_r,
00147 const PoolItem & byPoolitem_r )
00148 : _storage( storage_r )
00149 , _byPoolitem( byPoolitem_r )
00150 {}
00151
00152 bool operator()( const PoolItem & poolitem_r ) const
00153 {
00154 if ( ! poolitem_r.status().isInstalled() )
00155 return true;
00156
00157 if ( isKind<Package>(poolitem_r.resolvable()) )
00158 {
00159 ERR << "Ignore unsupported Package/non-Package obsolete: "
00160 << _byPoolitem << " obsoletes " << poolitem_r << endl;
00161 return true;
00162 }
00163
00164 try
00165 {
00166 _storage.deleteObject( poolitem_r.resolvable() );
00167 MIL<< "Obsoleted: " << poolitem_r << " (by " << _byPoolitem << ")" << endl;
00168 }
00169 catch ( Exception & excpt_r )
00170 {
00171 ZYPP_CAUGHT( excpt_r );
00172 WAR << "Failed obsolete: " << poolitem_r << " (by " << _byPoolitem << ")" << endl;
00173 }
00174
00175 return true;
00176 }
00177
00178 private:
00179 storage::PersistentStorage & _storage;
00180 const PoolItem _byPoolitem;
00181 };
00182
00188 void obsoleteMatchesFromStorage( storage::PersistentStorage & storage_r,
00189 const ResPool & pool_r,
00190 const PoolItem & byPoolitem_r )
00191 {
00192 forEachPoolItemMatchedBy( pool_r, byPoolitem_r, Dep::OBSOLETES,
00193 OncePerPoolItem( StorageRemoveObsoleted( storage_r,
00194 byPoolitem_r ) ) );
00195 }
00196
00198 }
00200
00202 struct QueryInstalledEditionHelper
00203 {
00204 bool operator()( const std::string & name_r,
00205 const Edition & ed_r,
00206 const Arch & arch_r ) const
00207 {
00208 rpm::librpmDb::db_const_iterator it;
00209 for ( it.findByName( name_r ); *it; ++it )
00210 {
00211 if ( arch_r == it->tag_arch()
00212 && ( ed_r == Edition::noedition || ed_r == it->tag_edition() ) )
00213 {
00214 return true;
00215 }
00216 }
00217 return false;
00218 }
00219 };
00220
00223 static ManagedFile sourceProvidePackage( const PoolItem & pi )
00224 {
00225
00226
00227 source::PackageProviderPolicy packageProviderPolicy;
00228 packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper() );
00229
00230 Package::constPtr p = asKind<Package>(pi.resolvable());
00231 source::PackageProvider pkgProvider( p, packageProviderPolicy );
00232 return pkgProvider.providePackage();
00233 }
00234
00236
00237 IMPL_PTR_TYPE(TargetImpl);
00238
00239 TargetImpl_Ptr TargetImpl::_nullimpl;
00240
00242 TargetImpl_Ptr TargetImpl::nullimpl()
00243 {
00244 if (_nullimpl == 0)
00245 _nullimpl = new TargetImpl;
00246 return _nullimpl;
00247 }
00248
00250
00251
00252
00253
00254 TargetImpl::TargetImpl(const Pathname & root_r)
00255 : _root(root_r), _storage_enabled(false)
00256 {
00257 _rpm.initDatabase(root_r);
00258 MIL << "Initialized target on " << _root << endl;
00259 }
00260
00262
00263
00264
00265
00266 TargetImpl::~TargetImpl()
00267 {
00268 _rpm.closeDatabase();
00269 MIL << "Targets closed" << endl;
00270 }
00271
00272 bool TargetImpl::isStorageEnabled() const
00273 {
00274 return _storage_enabled;
00275 }
00276
00277
00278 void TargetImpl::enableStorage(const Pathname &root_r)
00279 {
00280 _storage.init(root_r);
00281 _storage_enabled = true;
00282 }
00283
00284 Pathname TargetImpl::root() const
00285 {
00286 return _root;
00287 }
00288
00289 void TargetImpl::loadKindResolvables( const Resolvable::Kind kind )
00290 {
00291
00292 if ( _resstore_loaded[kind] )
00293 return;
00294
00295 if ( kind == ResTraits<zypp::Package>::kind )
00296 {
00297 std::list<Package::Ptr> packages = _rpm.getPackages();
00298 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
00299 it != packages.end();
00300 it++)
00301 {
00302 _store.insert(*it);
00303 }
00304 _resstore_loaded[kind] = true;
00305 }
00306 else
00307 {
00308 if ( isStorageEnabled() )
00309 {
00310
00311 std::list<ResObject::Ptr> resolvables = _storage.storedObjects(kind);
00312 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
00313 it != resolvables.end();
00314 it++)
00315 {
00316 _store.insert(*it);
00317 }
00318 }
00319 else
00320 {
00321 WAR << "storage target not enabled" << std::endl;
00322 }
00323 _resstore_loaded[kind] = true;
00324 }
00325 }
00326
00327 ResStore::resfilter_const_iterator TargetImpl::byKindBegin( const ResObject::Kind & kind_r ) const
00328 {
00329 TargetImpl *ptr = const_cast<TargetImpl *>(this);
00330 ptr->loadKindResolvables(kind_r);
00331 resfilter::ResFilter filter = ByKind(kind_r);
00332 return make_filter_iterator( filter, _store.begin(), _store.end() );
00333 }
00334
00335 ResStore::resfilter_const_iterator TargetImpl::byKindEnd( const ResObject::Kind & kind_r ) const
00336 {
00337 TargetImpl *ptr = const_cast<TargetImpl *>(this);
00338 ptr->loadKindResolvables(kind_r);
00339 resfilter::ResFilter filter = ByKind(kind_r);
00340 return make_filter_iterator( filter, _store.end(), _store.end() );
00341 }
00342
00343 const ResStore & TargetImpl::resolvables()
00344 {
00345 loadKindResolvables( ResTraits<zypp::Patch>::kind );
00346 loadKindResolvables( ResTraits<zypp::Selection>::kind );
00347 loadKindResolvables( ResTraits<zypp::Pattern>::kind );
00348 loadKindResolvables( ResTraits<zypp::Product>::kind );
00349 loadKindResolvables( ResTraits<zypp::Language>::kind );
00350 loadKindResolvables( ResTraits<zypp::Package>::kind );
00351 return _store;
00352 }
00353
00354 void TargetImpl::reset()
00355 {
00356
00357 _store.clear();
00358 _resstore_loaded[ResTraits<zypp::Patch>::kind] = false;
00359 _resstore_loaded[ResTraits<zypp::Selection>::kind] = false;
00360 _resstore_loaded[ResTraits<zypp::Pattern>::kind] = false;
00361 _resstore_loaded[ResTraits<zypp::Product>::kind] = false;
00362 _resstore_loaded[ResTraits<zypp::Language>::kind] = false;
00363 _resstore_loaded[ResTraits<zypp::Package>::kind] = false;
00364 }
00365
00366 ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
00367 {
00368
00369
00370
00371 ZYppCommitPolicy policy_r( policy_rX );
00372 if ( policy_r.restrictToMedia() > 1 )
00373 policy_r.allMedia();
00374
00375
00376 MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
00377 ZYppCommitResult result;
00378
00379 TargetImpl::PoolItemList to_uninstall;
00380 TargetImpl::PoolItemList to_install;
00381 TargetImpl::PoolItemList to_srcinstall;
00382 {
00383
00384 pool::GetResolvablesToInsDel
00385 collect( pool_r, policy_r.restrictToMedia() ? pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR
00386 : pool::GetResolvablesToInsDel::ORDER_BY_SOURCE );
00387 MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00388 to_uninstall.swap( collect._toDelete );
00389 to_install.swap( collect._toInstall );
00390 to_srcinstall.swap( collect._toSrcinstall );
00391 }
00392
00393 if ( policy_r.restrictToMedia() )
00394 {
00395 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
00396 }
00397
00398 commit (to_uninstall, policy_r, pool_r );
00399
00400 if (policy_r.restrictToMedia() == 0)
00401 {
00402 result._remaining = commit( to_install, policy_r, pool_r );
00403 result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
00404 }
00405 else
00406 {
00407 TargetImpl::PoolItemList current_install;
00408 TargetImpl::PoolItemList current_srcinstall;
00409
00410
00411
00412 bool hitUnwantedMedia = false;
00413 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
00414 {
00415 ResObject::constPtr res( it->resolvable() );
00416
00417 if ( hitUnwantedMedia
00418 || ( res->sourceMediaNr() && res->sourceMediaNr() != policy_r.restrictToMedia() ) )
00419 {
00420 hitUnwantedMedia = true;
00421 result._remaining.push_back( *it );
00422 }
00423 else
00424 {
00425 current_install.push_back( *it );
00426 }
00427 }
00428
00429 TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
00430 result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
00431
00432 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
00433 {
00434 Resolvable::constPtr res( it->resolvable() );
00435 Package::constPtr pkg( asKind<Package>(res) );
00436 if (pkg && policy_r.restrictToMedia() != pkg->sourceMediaNr())
00437 {
00438 XXX << "Package " << *pkg << ", wrong media " << pkg->sourceMediaNr() << endl;
00439 result._srcremaining.push_back( *it );
00440 }
00441 else
00442 {
00443 current_srcinstall.push_back( *it );
00444 }
00445 }
00446 bad = commit( current_srcinstall, policy_r, pool_r );
00447 result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
00448 }
00449
00450
00451 result._result = (to_install.size() - result._remaining.size());
00452 return result;
00453 }
00454
00455
00456 TargetImpl::PoolItemList
00457 TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
00458 const ZYppCommitPolicy & policy_r,
00459 const ResPool & pool_r )
00460 {
00461 TargetImpl::PoolItemList remaining;
00462
00463 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
00464
00465 bool abort = false;
00466
00467
00468 Source_Ref lastUsedSource;
00469
00470
00471 CommitPackageCache packageCache( items_r.begin(), items_r.end(),
00472 root() / "tmp", sourceProvidePackage );
00473
00474 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
00475 {
00476 if (isKind<Package>(it->resolvable()))
00477 {
00478 Package::constPtr p = asKind<Package>(it->resolvable());
00479 if (it->status().isToBeInstalled())
00480 {
00481 ManagedFile localfile;
00482 try
00483 {
00484 localfile = packageCache.get( it );
00485 }
00486 catch ( const source::SkipRequestedException & e )
00487 {
00488 ZYPP_CAUGHT( e );
00489 WAR << "Skipping package " << p << " in commit" << endl;
00490 continue;
00491 }
00492
00493 lastUsedSource = p->source();
00494
00495 #warning Exception handling
00496
00497 RpmInstallPackageReceiver progress( it->resolvable() );
00498 progress.connect();
00499 bool success = true;
00500 unsigned flags = 0;
00501 if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
00502 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00503 if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
00504
00505 try
00506 {
00507 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
00508 rpm().installPackage( localfile, flags );
00509
00510 if ( progress.aborted() )
00511 {
00512 WAR << "commit aborted by the user" << endl;
00513 progress.disconnect();
00514 abort = true;
00515 break;
00516 }
00517
00518 }
00519 catch (Exception & excpt_r)
00520 {
00521 ZYPP_CAUGHT(excpt_r);
00522 WAR << "Install failed, retrying with --nodeps" << endl;
00523 if (policy_r.dryRun())
00524 {
00525 WAR << "dry run failed" << endl;
00526 progress.disconnect();
00527 break;
00528 }
00529
00530 try
00531 {
00532 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
00533 flags |= rpm::RpmDb::RPMINST_NODEPS;
00534 rpm().installPackage( localfile, flags );
00535
00536 if ( progress.aborted() )
00537 {
00538 WAR << "commit aborted by the user" << endl;
00539 abort = true;
00540 progress.disconnect();
00541 break;
00542 }
00543 }
00544 catch (Exception & excpt_r)
00545 {
00546 ZYPP_CAUGHT(excpt_r);
00547 WAR << "Install failed again, retrying with --force --nodeps" << endl;
00548
00549 try
00550 {
00551 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
00552 flags |= rpm::RpmDb::RPMINST_FORCE;
00553 rpm().installPackage( localfile, flags );
00554 }
00555 catch (Exception & excpt_r)
00556 {
00557 remaining.push_back( *it );
00558 success = false;
00559 ZYPP_CAUGHT(excpt_r);
00560 }
00561
00562 if ( progress.aborted() )
00563 {
00564 WAR << "commit aborted by the user" << endl;
00565 abort = true;
00566 progress.disconnect();
00567 break;
00568 }
00569 }
00570 }
00571 if (success
00572 && !policy_r.dryRun())
00573 {
00574 it->status().resetTransact( ResStatus::USER );
00575 }
00576 progress.disconnect();
00577 p->source().releaseFile( p->location(), p->sourceMediaNr() );
00578 }
00579 else
00580 {
00581 bool success = true;
00582
00583 RpmRemovePackageReceiver progress( it->resolvable() );
00584 progress.connect();
00585 unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
00586 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00587 try
00588 {
00589 rpm().removePackage( p, flags );
00590 }
00591 catch (Exception & excpt_r)
00592 {
00593 WAR << "removal of " << p << " failed";
00594 success = false;
00595 ZYPP_CAUGHT( excpt_r );
00596 }
00597 if (success
00598 && !policy_r.dryRun())
00599 {
00600 it->status().resetTransact( ResStatus::USER );
00601 }
00602 progress.disconnect();
00603 }
00604 }
00605 else if (!policy_r.dryRun())
00606 {
00607 if ( isStorageEnabled() )
00608 {
00609 if (it->status().isToBeInstalled())
00610 {
00611
00612 obsoleteMatchesFromStorage( _storage, pool_r, *it );
00613
00614 bool success = false;
00615 try
00616 {
00617 if (isKind<Message>(it->resolvable()))
00618 {
00619 Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
00620 std::string text = m->text().asString();
00621
00622 callback::SendReport<target::MessageResolvableReport> report;
00623
00624 report->show( m );
00625
00626 MIL << "Displaying the text '" << text << "'" << endl;
00627 }
00628 else if (isKind<Script>(it->resolvable()))
00629 {
00630 ExecuteDoScript( asKind<Script>(it->resolvable()) );
00631 }
00632 else if (!isKind<Atom>(it->resolvable()))
00633 {
00634
00635 if (true)
00636 {
00637
00638
00639 #warning REMOVE ALL OLD VERSIONS AND NOT JUST ONE
00640 PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it);
00641 if (old)
00642 {
00643 _storage.deleteObject(old.resolvable());
00644 }
00645 }
00646 _storage.storeObject(it->resolvable());
00647 }
00648 success = true;
00649 }
00650 catch (Exception & excpt_r)
00651 {
00652 ZYPP_CAUGHT(excpt_r);
00653 WAR << "Install of Resolvable from storage failed" << endl;
00654 }
00655 if (success)
00656 it->status().resetTransact( ResStatus::USER );
00657 }
00658 else
00659 {
00660 bool success = false;
00661 try
00662 {
00663 if (isKind<Atom>(it->resolvable()))
00664 {
00665 DBG << "Uninstalling atom - no-op" << endl;
00666 }
00667 else if (isKind<Message>(it->resolvable()))
00668 {
00669 DBG << "Uninstalling message - no-op" << endl;
00670 }
00671 else if (isKind<Script>(it->resolvable()))
00672 {
00673 ExecuteUndoScript( asKind<Script>(it->resolvable()) );
00674 }
00675 else
00676 {
00677 _storage.deleteObject(it->resolvable());
00678 }
00679 success = true;
00680 }
00681 catch (Exception & excpt_r)
00682 {
00683 ZYPP_CAUGHT(excpt_r);
00684 WAR << "Uninstall of Resolvable from storage failed" << endl;
00685 }
00686 if (success)
00687 it->status().resetTransact( ResStatus::USER );
00688 }
00689 }
00690 else
00691 {
00692 WAR << "storage target disabled" << std::endl;
00693 }
00694
00695 }
00696
00697 }
00698
00699
00700
00701
00702
00703
00704
00705 if (lastUsedSource)
00706 {
00707 lastUsedSource.release();
00708 }
00709
00710 if ( abort )
00711 ZYPP_THROW( TargetAbortedException( N_("Installation has been aborted as directed.") ) );
00712
00713 return remaining;
00714 }
00715
00716 rpm::RpmDb & TargetImpl::rpm()
00717 {
00718 return _rpm;
00719 }
00720
00721 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
00722 {
00723 return _rpm.hasFile(path_str, name_str);
00724 }
00725
00728 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
00729 {
00730 string name = _rpm.whoOwnsFile (path_str);
00731 if (name.empty())
00732 return NULL;
00733
00734 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it)
00735 {
00736 if ((*it)->name() == name)
00737 {
00738 return *it;
00739 }
00740 }
00741 return NULL;
00742 }
00743
00745 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
00746 {
00747 CommitLog::setFname(path_r);
00748 return true;
00749 }
00750
00751 void
00752 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
00753 TargetImpl::PoolItemList & dellist_r,
00754 TargetImpl::PoolItemList & instlist_r,
00755 TargetImpl::PoolItemList & srclist_r ) const
00756 {
00757 pool::GetResolvablesToInsDel collect( pool_r );
00758 MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00759 dellist_r.swap( collect._toDelete );
00760 instlist_r.swap( collect._toInstall );
00761 srclist_r.swap( collect._toSrcinstall );
00762 }
00763
00764 Date TargetImpl::timestamp() const
00765 {
00766 Date ts_rpm;
00767 Date ts_store;
00768
00769 ts_rpm = _rpm.timestamp();
00770
00771 if ( isStorageEnabled() )
00772 ts_store = _storage.timestamp();
00773
00774 if ( ts_rpm > ts_store )
00775 {
00776 return ts_rpm;
00777 }
00778 else if (ts_rpm < ts_store)
00779 {
00780 return ts_store;
00781 }
00782 else
00783 {
00784
00785 if ( ts_rpm != 0 )
00786 return ts_rpm;
00787 else
00788 return Date::now();
00789 }
00790 }
00791
00793 }
00796 }