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