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 getResolvablesToInsDel( pool_r, to_uninstall, to_install, to_srcinstall );
00166
00167 if ( policy_r.restrictToMedia() ) {
00168 MIL << "Restrict to media number " << policy_r.restrictToMedia() << endl;
00169 }
00170
00171 commit (to_uninstall, policy_r, pool_r );
00172
00173 if (policy_r.restrictToMedia() == 0) {
00174 result._remaining = commit( to_install, policy_r, pool_r );
00175 result._srcremaining = commit( to_srcinstall, policy_r, pool_r );
00176 }
00177 else
00178 {
00179 TargetImpl::PoolItemList current_install;
00180 TargetImpl::PoolItemList current_srcinstall;
00181
00182
00183
00184 bool hitUnwantedMedia = false;
00185 for (TargetImpl::PoolItemList::iterator it = to_install.begin(); it != to_install.end(); ++it)
00186 {
00187 ResObject::constPtr res( it->resolvable() );
00188
00189 if ( hitUnwantedMedia
00190 || ( res->sourceMediaNr() && res->sourceMediaNr() != policy_r.restrictToMedia() ) )
00191 {
00192 hitUnwantedMedia = true;
00193 result._remaining.push_back( *it );
00194 }
00195 else
00196 {
00197 current_install.push_back( *it );
00198 }
00199 }
00200
00201 TargetImpl::PoolItemList bad = commit( current_install, policy_r, pool_r );
00202 result._remaining.insert(result._remaining.end(), bad.begin(), bad.end());
00203
00204 for (TargetImpl::PoolItemList::iterator it = to_srcinstall.begin(); it != to_srcinstall.end(); ++it)
00205 {
00206 Resolvable::constPtr res( it->resolvable() );
00207 Package::constPtr pkg( asKind<Package>(res) );
00208 if (pkg && policy_r.restrictToMedia() != pkg->sourceMediaNr())
00209 {
00210 XXX << "Package " << *pkg << ", wrong media " << pkg->sourceMediaNr() << endl;
00211 result._srcremaining.push_back( *it );
00212 }
00213 else {
00214 current_srcinstall.push_back( *it );
00215 }
00216 }
00217 bad = commit( current_srcinstall, policy_r, pool_r );
00218 result._srcremaining.insert(result._srcremaining.end(), bad.begin(), bad.end());
00219 }
00220
00221
00222 result._result = (to_install.size() - result._remaining.size());
00223 return result;
00224 }
00225
00226
00227 TargetImpl::PoolItemList
00228 TargetImpl::commit( const TargetImpl::PoolItemList & items_r,
00229 const ZYppCommitPolicy & policy_r,
00230 const ResPool & pool_r )
00231 {
00232 TargetImpl::PoolItemList remaining;
00233
00234 MIL << "TargetImpl::commit(<list>" << policy_r << ")" << endl;
00235
00236 bool abort = false;
00237
00238
00239 Source_Ref lastUsedSource;
00240
00241 for (TargetImpl::PoolItemList::const_iterator it = items_r.begin(); it != items_r.end(); it++)
00242 {
00243 if (isKind<Package>(it->resolvable()))
00244 {
00245 Package::constPtr p = dynamic_pointer_cast<const Package>(it->resolvable());
00246 if (it->status().isToBeInstalled())
00247 {
00248 Pathname localfile;
00249 try {
00250 localfile = p->source().providePackage(p);
00251 }
00252 catch( const source::SkipRequestedException & e )
00253 {
00254 ZYPP_CAUGHT( e );
00255 WAR << "Skipping package " << p << " in commit" << endl;
00256 continue;
00257 }
00258
00259 lastUsedSource = p->source();
00260
00261 #warning Exception handling
00262
00263 RpmInstallPackageReceiver progress( it->resolvable() );
00264 progress.connect();
00265 bool success = true;
00266 unsigned flags = 0;
00267 if (p->installOnly()) flags |= rpm::RpmDb::RPMINST_NOUPGRADE;
00268 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00269 if (policy_r.rpmNoSignature()) flags |= rpm::RpmDb::RPMINST_NOSIGNATURE;
00270
00271 try {
00272 progress.tryLevel( target::rpm::InstallResolvableReport::RPM );
00273 rpm().installPackage( localfile, flags );
00274
00275 if( progress.aborted() )
00276 {
00277 WAR << "commit aborted by the user" << endl;
00278 progress.disconnect();
00279 abort = true;
00280 break;
00281 }
00282
00283 }
00284 catch (Exception & excpt_r) {
00285 ZYPP_CAUGHT(excpt_r);
00286 WAR << "Install failed, retrying with --nodeps" << endl;
00287 if (policy_r.dryRun()) {
00288 WAR << "dry run failed" << endl;
00289 progress.disconnect();
00290 break;
00291 }
00292
00293 try {
00294 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS );
00295 flags |= rpm::RpmDb::RPMINST_NODEPS;
00296 rpm().installPackage( localfile, flags );
00297
00298 if( progress.aborted() )
00299 {
00300 WAR << "commit aborted by the user" << endl;
00301 abort = true;
00302 progress.disconnect();
00303 break;
00304 }
00305 }
00306 catch (Exception & excpt_r)
00307 {
00308 ZYPP_CAUGHT(excpt_r);
00309 WAR << "Install failed again, retrying with --force --nodeps" << endl;
00310
00311 try {
00312 progress.tryLevel( target::rpm::InstallResolvableReport::RPM_NODEPS_FORCE );
00313 flags |= rpm::RpmDb::RPMINST_FORCE;
00314 rpm().installPackage( localfile, flags );
00315 }
00316 catch (Exception & excpt_r) {
00317 remaining.push_back( *it );
00318 success = false;
00319 ZYPP_CAUGHT(excpt_r);
00320 }
00321
00322 if( progress.aborted() )
00323 {
00324 WAR << "commit aborted by the user" << endl;
00325 abort = true;
00326 progress.disconnect();
00327 break;
00328 }
00329 }
00330 }
00331 if (success
00332 && !policy_r.dryRun())
00333 {
00334 it->status().resetTransact( ResStatus::USER );
00335 }
00336 progress.disconnect();
00337 p->source().releaseFile( p->location(), p->sourceMediaNr() );
00338 }
00339 else
00340 {
00341 bool success = true;
00342
00343 RpmRemovePackageReceiver progress( it->resolvable() );
00344 progress.connect();
00345 unsigned flags = rpm::RpmDb::RPMINST_NODEPS;
00346 if (policy_r.dryRun()) flags |= rpm::RpmDb::RPMINST_TEST;
00347 try {
00348 rpm().removePackage( p, flags );
00349 }
00350 catch (Exception & excpt_r) {
00351 WAR << "removal of " << p << " failed";
00352 success = false;
00353 ZYPP_CAUGHT( excpt_r );
00354 }
00355 if (success
00356 && !policy_r.dryRun())
00357 {
00358 it->status().resetTransact( ResStatus::USER );
00359 }
00360 progress.disconnect();
00361 }
00362 }
00363 else if (!policy_r.dryRun())
00364 {
00365 if ( isStorageEnabled() )
00366 {
00367 if (it->status().isToBeInstalled())
00368 {
00369 bool success = false;
00370 try
00371 {
00372 if (isKind<Message>(it->resolvable()))
00373 {
00374 Message::constPtr m = dynamic_pointer_cast<const Message>(it->resolvable());
00375 std::string text = m->text().asString();
00376
00377 callback::SendReport<target::MessageResolvableReport> report;
00378
00379 report->show( m );
00380
00381 MIL << "Displaying the text '" << text << "'" << endl;
00382 }
00383 else if (isKind<Script>(it->resolvable()))
00384 {
00385 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00386 Pathname p = s->do_script();
00387 if (p != "" && p != "/")
00388 {
00389 chmod( p.asString().c_str(), S_IRUSR|S_IXUSR );
00390 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00391 if (! prog)
00392 ZYPP_THROW(Exception("Cannot run the script"));
00393 int retval = prog->close();
00394 delete prog;
00395 if (retval != 0)
00396 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00397 }
00398 else
00399 {
00400 ERR << "Do script not defined" << endl;
00401 }
00402 }
00403 else if (!isKind<Atom>(it->resolvable()))
00404 {
00405
00406 if (true)
00407 {
00408
00409
00410 PoolItem_Ref old = Helper::findInstalledItem (pool_r, *it);
00411 if (old)
00412 {
00413 _storage.deleteObject(old.resolvable());
00414 }
00415 }
00416 _storage.storeObject(it->resolvable());
00417 }
00418 success = true;
00419 }
00420 catch (Exception & excpt_r)
00421 {
00422 ZYPP_CAUGHT(excpt_r);
00423 WAR << "Install of Resolvable from storage failed" << endl;
00424 }
00425 if (success)
00426 it->status().resetTransact( ResStatus::USER );
00427 }
00428 else
00429 {
00430 bool success = false;
00431 try
00432 {
00433 if (isKind<Message>(it->resolvable()))
00434 {
00435 DBG << "Uninstalling message - no-op" << endl;
00436 }
00437 else if (isKind<Script>(it->resolvable()))
00438 {
00439 Script::constPtr s = dynamic_pointer_cast<const Script>(it->resolvable());
00440 Pathname p = s->undo_script();
00441 if (! s->undo_available())
00442 {
00443 DBG << "Undo script not available" << endl;
00444 }
00445 if (p != "" && p != "/")
00446 {
00447 ExternalProgram* prog = new ExternalProgram(p.asString(), ExternalProgram::Discard_Stderr, false, -1, true);
00448 if (! prog)
00449 ZYPP_THROW(Exception("Cannot run the script"));
00450 int retval = prog->close();
00451 delete prog;
00452 if (retval != 0)
00453 ZYPP_THROW(Exception("Exit code of script is non-zero"));
00454 }
00455 else
00456 {
00457 ERR << "Undo script not defined" << endl;
00458 }
00459 }
00460 else
00461 {
00462 _storage.deleteObject(it->resolvable());
00463 }
00464 success = true;
00465 }
00466 catch (Exception & excpt_r)
00467 {
00468 ZYPP_CAUGHT(excpt_r);
00469 WAR << "Uninstall of Resolvable from storage failed" << endl;
00470 }
00471 if (success)
00472 it->status().resetTransact( ResStatus::USER );
00473 }
00474 }
00475 else
00476 {
00477 WAR << "storage target disabled" << std::endl;
00478 }
00479
00480 }
00481
00482 }
00483
00484
00485
00486
00487
00488
00489
00490 if (lastUsedSource) {
00491 lastUsedSource.release();
00492 }
00493
00494 if( abort )
00495 ZYPP_THROW( TargetAbortedException( N_("Target commit aborted by user.") ) );
00496
00497 return remaining;
00498 }
00499
00500 rpm::RpmDb & TargetImpl::rpm()
00501 { return _rpm; }
00502
00503 bool TargetImpl::providesFile (const std::string & path_str, const std::string & name_str) const
00504 { return _rpm.hasFile(path_str, name_str); }
00505
00508 ResObject::constPtr TargetImpl::whoOwnsFile (const std::string & path_str) const
00509 {
00510 string name = _rpm.whoOwnsFile (path_str);
00511 if (name.empty())
00512 return NULL;
00513
00514 for (ResStore::const_iterator it = _store.begin(); it != _store.end(); ++it) {
00515 if ((*it)->name() == name) {
00516 return *it;
00517 }
00518 }
00519 return NULL;
00520 }
00521
00523 bool TargetImpl::setInstallationLogfile(const Pathname & path_r)
00524 {
00525 return rpm::RpmDb::setInstallationLogfile(path_r);
00526 }
00527
00528 void
00529 TargetImpl::getResolvablesToInsDel ( const ResPool pool_r,
00530 TargetImpl::PoolItemList & dellist_r,
00531 TargetImpl::PoolItemList & instlist_r,
00532 TargetImpl::PoolItemList & srclist_r ) const
00533 {
00534 pool::GetResolvablesToInsDel collect( pool_r );
00535 MIL << "GetResolvablesToInsDel: " << endl << collect << endl;
00536 dellist_r.swap( collect._toDelete );
00537 instlist_r.swap( collect._toInstall );
00538 srclist_r.swap( collect._toSrcinstall );
00539 }
00540
00542 }
00545 }