00001
00002
00003
00004
00005
00006
00007
00008
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014
00015 #include <iostream>
00016 #include <string>
00017 #include <list>
00018 #include <set>
00019
00020 #include "zypp/base/Logger.h"
00021 #include "zypp/base/Exception.h"
00022 #include "zypp/base/Gettext.h"
00023 #include "zypp/PoolItem.h"
00024 #include "zypp/Resolvable.h"
00025 #include "zypp/ResObject.h"
00026 #include "zypp/Package.h"
00027 #include "zypp/Script.h"
00028 #include "zypp/Message.h"
00029 #include "zypp/Source.h"
00030 #include "zypp/Url.h"
00031
00032 #include "zypp/target/TargetImpl.h"
00033 #include "zypp/target/TargetCallbackReceiver.h"
00034
00035 #include "zypp/pool/GetResolvablesToInsDel.h"
00036 #include "zypp/solver/detail/Helper.h"
00037 #include "zypp/source/PackageProvider.h"
00038
00039 using namespace std;
00040 using zypp::solver::detail::Helper;
00041
00042
00044 namespace zypp
00045 {
00046
00047 namespace target
00048 {
00049
00051 struct QueryInstalledEditionHelper
00052 {
00053 QueryInstalledEditionHelper( rpm::RpmDb & rpmdb_r )
00054 : _rpmdb( rpmdb_r )
00055 {}
00056
00057 bool operator()( const std::string & name_r, const Edition & ed_r ) const
00058 {
00059 if ( ed_r == Edition::noedition )
00060 return _rpmdb.hasPackage( name_r );
00061 return _rpmdb.hasPackage( name_r, ed_r );
00062 }
00063 private:
00064 rpm::RpmDb & _rpmdb;
00065 };
00066
00067
00068 IMPL_PTR_TYPE(TargetImpl);
00069
00070 TargetImpl_Ptr TargetImpl::_nullimpl;
00071
00073 TargetImpl_Ptr TargetImpl::nullimpl()
00074 {
00075 if (_nullimpl == 0)
00076 _nullimpl = new TargetImpl;
00077 return _nullimpl;
00078 }
00079
00080
00082
00083
00084
00085
00086 TargetImpl::TargetImpl(const Pathname & root_r)
00087 : _root(root_r)
00088 {
00089 _rpm.initDatabase(root_r);
00090 _storage_enabled = false;
00091 MIL << "Initialized target on " << _root << endl;
00092 }
00093
00095
00096
00097
00098
00099 TargetImpl::~TargetImpl()
00100 {
00101 _rpm.closeDatabase();
00102 MIL << "Targets closed" << endl;
00103 }
00104
00105 bool TargetImpl::isStorageEnabled() const
00106 {
00107 return _storage_enabled;
00108 }
00109
00110
00111 void TargetImpl::enableStorage(const Pathname &root_r)
00112 {
00113 _storage.init(root_r);
00114 _storage_enabled = true;
00115 }
00116
00117 Pathname TargetImpl::root() const
00118 {
00119 return _root;
00120 }
00121
00122 const ResStore & TargetImpl::resolvables()
00123 {
00124 _store.clear();
00125
00126 std::list<Package::Ptr> packages = _rpm.getPackages();
00127 for (std::list<Package::Ptr>::const_iterator it = packages.begin();
00128 it != packages.end();
00129 it++)
00130 {
00131 _store.insert(*it);
00132 }
00133
00134 if ( isStorageEnabled() )
00135 {
00136
00137 std::list<ResObject::Ptr> resolvables = _storage.storedObjects();
00138 for (std::list<ResObject::Ptr>::iterator it = resolvables.begin();
00139 it != resolvables.end();
00140 it++)
00141 {
00142 _store.insert(*it);
00143 }
00144 }
00145 else
00146 {
00147 WAR << "storage target not enabled" << std::endl;
00148 }
00149
00150 return _store;
00151 }
00152
00153
00154
00155 ZYppCommitResult TargetImpl::commit( ResPool pool_r, const ZYppCommitPolicy & policy_rX )
00156 {
00157
00158
00159
00160 ZYppCommitPolicy policy_r( policy_rX );
00161 if ( policy_r.restrictToMedia() > 1 )
00162 policy_r.allMedia();
00163
00164
00165 MIL << "TargetImpl::commit(<pool>, " << policy_r << ")" << endl;
00166 ZYppCommitResult result;
00167 #warning Commit does not provide ZYppCommitResult::_errors
00168
00169 TargetImpl::PoolItemList to_uninstall;
00170 TargetImpl::PoolItemList to_install;
00171 TargetImpl::PoolItemList to_srcinstall;
00172 {
00173
00174 pool::GetResolvablesToInsDel
00175 collect( pool_r, policy_r.restrictToMedia() ? pool::GetResolvablesToInsDel::ORDER_BY_MEDIANR
00176 : pool::GetResolvablesToInsDel::ORDER_BY_SOURCE );
00177 MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00178 to_uninstall.swap( collect._toDelete );
00179 to_install.swap( collect._toInstall );
00180 to_srcinstall.swap( collect._toSrcinstall );
00181 }
00182
00183 if ( policy_r.restrictToMedia() ) {
00184 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
00185 }
00186
00187 commit (to_uninstall, policy_r, pool_r );
00188
00189 if (policy_r.restrictToMedia() == 0) {
00190 result._remaining = commit( to_install, policy_r, pool_r );
00191 result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
00192 }
00193 else
00194 {
00195 TargetImpl::PoolItemList current_install;
00196 TargetImpl::PoolItemList current_srcinstall;
00197
00198
00199
00200 bool hitUnwantedMedia = false;
00201 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
00202 {
00203 ResObject::constPtr res( it->resolvable() );
00204
00205 if ( hitUnwantedMedia
00206 || ( res->sourceMediaNr() && res->sourceMediaNr() != policy_r.restrictToMedia() ) )
00207 {
00208 hitUnwantedMedia = true;
00209 result._remaining.push_back( *it );
00210 }
00211 else
00212 {
00213 current_install.push_back( *it );
00214 }
00215 }
00216
00217 TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
00218 result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
00219
00220 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
00221 {
00222 Resolvable::constPtr res( it->resolvable() );
00223 Package::constPtr pkg( asKind<Package>(res) );
00224 if (pkg && policy_r.restrictToMedia() != pkg->sourceMediaNr())
00225 {
00226 XXX << "Package " << *pkg << ", wrong media " << pkg->sourceMediaNr() << endl;
00227 result._srcremaining.push_back( *it );
00228 }
00229 else {
00230 current_srcinstall.push_back( *it );
00231 }
00232 }
00233 bad = commit( current_srcinstall, policy_r, pool_r );
00234 result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
00235 }
00236
00237
00238 result._result = (to_install.size() - result._remaining.size());
00239 return result;
00240 }
00241
00242
00243 TargetImpl::PoolItemList
00244 TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
00245 const ZYppCommitPolicy & policy_r,
00246 const ResPool & pool_r )
00247 {
00248 TargetImpl::PoolItemList remaining;
00249
00250 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
00251
00252 bool abort = false;
00253
00254
00255 Source_Ref lastUsedSource;
00256
00257
00258
00259 source::PackageProviderPolicy packageProviderPolicy;
00260 packageProviderPolicy.queryInstalledCB( QueryInstalledEditionHelper(_rpm) );
00261
00262
00263 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
00264 {
00265 if (isKind<Package>(it->resolvable()))
00266 {
00267 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
00268 if (it->status().isToBeInstalled())
00269 {
00270 source::ManagedFile localfile;
00271 try {
00272 source::PackageProvider pkgProvider( p, packageProviderPolicy );
00273 localfile = pkgProvider.providePackage();
00274 }
00275 catch( const source::SkipRequestedException & e )
00276 {
00277 ZYPP_CAUGHT( e );
00278 WAR << "Skipping package " << p << " in commit" << endl;
00279 continue;
00280 }
00281
00282 lastUsedSource = p->source();
00283
00284 #warning Exception handling
00285
00286 RpmInstallPackageReceiver progress( it->resolvable() );
00287 progress.connect();
00288 bool success = true;
00289 unsigned flags = 0;
00290 if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
00291 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00292 if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
00293
00294 try {
00295 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
00296 rpm().installPackage( localfile, flags );
00297
00298 if( progress.aborted() )
00299 {
00300 WAR << "commit aborted by the user" << endl;
00301 progress.disconnect();
00302 abort = true;
00303 break;
00304 }
00305
00306 }
00307 catch (Exception & excpt_r) {
00308 ZYPP_CAUGHT(excpt_r);
00309 WAR << "Install failed, retrying with --nodeps" << endl;
00310 if (policy_r.dryRun()) {
00311 WAR << "dry run failed" << endl;
00312 progress.disconnect();
00313 break;
00314 }
00315
00316 try {
00317 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
00318 flags |= rpm::RpmDb::RPMINST_NODEPS;
00319 rpm().installPackage( localfile, flags );
00320
00321 if( progress.aborted() )
00322 {
00323 WAR << "commit aborted by the user" << endl;
00324 abort = true;
00325 progress.disconnect();
00326 break;
00327 }
00328 }
00329 catch (Exception & excpt_r)
00330 {
00331 ZYPP_CAUGHT(excpt_r);
00332 WAR << "Install failed again, retrying with --force --nodeps" << endl;
00333
00334 try {
00335 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
00336 flags |= rpm::RpmDb::RPMINST_FORCE;
00337 rpm().installPackage( localfile, flags );
00338 }
00339 catch (Exception & excpt_r) {
00340 remaining.push_back( *it );
00341 success = false;
00342 ZYPP_CAUGHT(excpt_r);
00343 }
00344
00345 if( progress.aborted() )
00346 {
00347 WAR << "commit aborted by the user" << endl;
00348 abort = true;
00349 progress.disconnect();
00350 break;
00351 }
00352 }
00353 }
00354 if (success
00355 && !policy_r.dryRun())
00356 {
00357 it->status().resetTransact( ResStatus::USER );
00358 }
00359 progress.disconnect();
00360 p->source().releaseFile( p->location(), p->sourceMediaNr() );
00361 }
00362 else
00363 {
00364 bool success = true;
00365
00366 RpmRemovePackageReceiver progress( it->resolvable() );
00367 progress.connect();
00368 unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
00369 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00370 try {
00371 rpm().removePackage( p, flags );
00372 }
00373 catch (Exception & excpt_r) {
00374 WAR << "removal of " << p << " failed";
00375 success = false;
00376 ZYPP_CAUGHT( excpt_r );
00377 }
00378 if (success
00379 && !policy_r.dryRun())
00380 {
00381 it->status().resetTransact( ResStatus::USER );
00382 }
00383 progress.disconnect();
00384 }
00385 }
00386 else if (!policy_r.dryRun())
00387 {
00388 if ( isStorageEnabled() )
00389 {
00390 if (it->status().isToBeInstalled())
00391 {
00392 bool success = false;
00393 try
00394 {
00395 if (isKind<Message>(it->resolvable()))
00396 {
00397 Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
00398 std::string text = m->text().asString();
00399
00400 callback::SendReport<target::MessageResolvableReport> report;
00401
00402 report->show( m );
00403
00404 MIL << "Displaying the text '" << text << "'" << endl;
00405 }
00406 else if (isKind<Script>(it->resolvable()))
00407 {
00408 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00409 Pathname p = s->do_script();
00410 if (p != "" && p != "/")
00411 {
00412 chmod( p.asString().c_str(), S_IRUSR|S_IXUSR );
00413 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00414 if (! prog)
00415 ZYPP_THROW(Exception("Cannot run the script"));
00416 int retval = prog->close();
00417 delete prog;
00418 if (retval != 0)
00419 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00420 }
00421 else
00422 {
00423 ERR << "Do script not defined" << endl;
00424 }
00425 }
00426 else if (!isKind<Atom>(it->resolvable()))
00427 {
00428
00429 if (true)
00430 {
00431
00432
00433 PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it);
00434 if (old)
00435 {
00436 _storage.deleteObject(old.resolvable());
00437 }
00438 }
00439 _storage.storeObject(it->resolvable());
00440 }
00441 success = true;
00442 }
00443 catch (Exception & excpt_r)
00444 {
00445 ZYPP_CAUGHT(excpt_r);
00446 WAR << "Install of Resolvable from storage failed" << endl;
00447 }
00448 if (success)
00449 it->status().resetTransact( ResStatus::USER );
00450 }
00451 else
00452 {
00453 bool success = false;
00454 try
00455 {
00456 if (isKind<Message>(it->resolvable()))
00457 {
00458 DBG << "Uninstalling message - no-op" << endl;
00459 }
00460 else if (isKind<Script>(it->resolvable()))
00461 {
00462 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00463 Pathname p = s->undo_script();
00464 if (! s->undo_available())
00465 {
00466 DBG << "Undo script not available" << endl;
00467 }
00468 if (p != "" && p != "/")
00469 {
00470 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00471 if (! prog)
00472 ZYPP_THROW(Exception("Cannot run the script"));
00473 int retval = prog->close();
00474 delete prog;
00475 if (retval != 0)
00476 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00477 }
00478 else
00479 {
00480 ERR << "Undo script not defined" << endl;
00481 }
00482 }
00483 else
00484 {
00485 _storage.deleteObject(it->resolvable());
00486 }
00487 success = true;
00488 }
00489 catch (Exception & excpt_r)
00490 {
00491 ZYPP_CAUGHT(excpt_r);
00492 WAR << "Uninstall of Resolvable from storage failed" << endl;
00493 }
00494 if (success)
00495 it->status().resetTransact( ResStatus::USER );
00496 }
00497 }
00498 else
00499 {
00500 WAR << "storage target disabled" << std::endl;
00501 }
00502
00503 }
00504
00505 }
00506
00507
00508
00509
00510
00511
00512
00513 if (lastUsedSource) {
00514 lastUsedSource.release();
00515 }
00516
00517 if( abort )
00518 ZYPP_THROW( TargetAbortedException( N_("Target commit aborted by user.") ) );
00519
00520 return remaining;
00521 }
00522
00523 rpm::RpmDb & TargetImpl::rpm()
00524 { return _rpm; }
00525
00526 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
00527 { return _rpm.hasFile(path_str, name_str); }
00528
00531 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
00532 {
00533 string name = _rpm.whoOwnsFile (path_str);
00534 if (name.empty())
00535 return NULL;
00536
00537 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
00538 if ((*it)->name() == name) {
00539 return *it;
00540 }
00541 }
00542 return NULL;
00543 }
00544
00546 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
00547 {
00548 return rpm::RpmDb::setInstallationLogfile(path_r);
00549 }
00550
00551 void
00552 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
00553 TargetImpl::PoolItemList & dellist_r,
00554 TargetImpl::PoolItemList & instlist_r,
00555 TargetImpl::PoolItemList & srclist_r ) const
00556 {
00557 pool::GetResolvablesToInsDel collect( pool_r );
00558 MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00559 dellist_r.swap( collect._toDelete );
00560 instlist_r.swap( collect._toInstall );
00561 srclist_r.swap( collect._toSrcinstall );
00562 }
00563
00565 }
00568 }