summaryrefslogtreecommitdiff
path: root/apt-pkg/depcache.cc
diff options
context:
space:
mode:
authorDavid Kalnischkies <kalnischkies@gmail.com>2013-07-10 13:06:05 +0200
committerDavid Kalnischkies <kalnischkies@gmail.com>2013-07-11 18:42:54 +0200
commit486d190d3c66bb7271509dc002f8ec9e9eb0166c (patch)
tree171b341a7caa4c82f47ce007ddb41fccb58f6faa /apt-pkg/depcache.cc
parent3d1be93dc4242df2b93de632715a8aa7dd34f96f (diff)
prevent MarkInstall of unsynced Multi-Arch:same siblings
Multi-Arch: same packages can be co-installed, but need to have the same version for all installed packages (aka "siblings"). Otherwise the unsynced versions will fight against each other and the auto-install as wel as the problem resolver will later have to decide between holding the packages or to remove one of the siblings (usually a foreign) taking a bunch of packages (like the entire foreign setup) with them. The idea here is now to be more pro-active: MarkInstall will fail for a package if the siblings aren't synced, so we don't allow a situation in which a resolver has to decide if to hold or to remove-upgrade under the assumption that the remove-upgrade decision is always wrong and doesn't deserve to be explored (expect valid out-of-syncs of course). Thats a pretty bold move to take for a library which is used by different solvers so this check is done in IsInstallOk and can be overridden if front-ends want to.
Diffstat (limited to 'apt-pkg/depcache.cc')
-rw-r--r--apt-pkg/depcache.cc53
1 files changed, 49 insertions, 4 deletions
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index 9f8422fec..2c6eb43bf 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -865,6 +865,11 @@ bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge,
unsigned long Depth, bool FromUser)
{
+ return IsDeleteOkProtectInstallRequests(Pkg, rPurge, Depth, FromUser);
+}
+bool pkgDepCache::IsDeleteOkProtectInstallRequests(PkgIterator const &Pkg,
+ bool const rPurge, unsigned long const Depth, bool const FromUser)
+{
if (FromUser == false && Pkg->CurrentVer == 0)
{
StateCache &P = PkgState[Pkg->ID];
@@ -1047,9 +1052,10 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
return true;
}
- // check if we are allowed to install the package
- if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
- return false;
+ // check if we are allowed to install the package (if we haven't already)
+ if (P.Mode != ModeInstall || P.InstallVer != P.CandidateVer)
+ if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
+ return false;
ActionGroup group(*this);
P.iFlags &= ~AutoKept;
@@ -1271,11 +1277,50 @@ bool pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
/*}}}*/
// DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/
// ---------------------------------------------------------------------
-/* The default implementation does nothing.
+/* The default implementation checks if the installation of an M-A:same
+ package would lead us into a version-screw and if so forbids it.
dpkg holds are enforced by the private IsModeChangeOk */
bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
unsigned long Depth, bool FromUser)
{
+ return IsInstallOkMultiArchSameVersionSynced(Pkg,AutoInst, Depth, FromUser);
+}
+bool pkgDepCache::IsInstallOkMultiArchSameVersionSynced(PkgIterator const &Pkg,
+ bool const AutoInst, unsigned long const Depth, bool const FromUser)
+{
+ if (FromUser == true) // as always: user is always right
+ return true;
+
+ // ignore packages with none-M-A:same candidates
+ VerIterator const CandVer = PkgState[Pkg->ID].CandidateVerIter(*this);
+ if (unlikely(CandVer.end() == true) || CandVer == Pkg.CurrentVer() ||
+ (CandVer->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same)
+ return true;
+
+ GrpIterator const Grp = Pkg.Group();
+ for (PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
+ {
+ // not installed or version synced: fine by definition
+ // (simple string-compare as stuff like '1' == '0:1-0' can't happen here)
+ if (P->CurrentVer == 0 || strcmp(Pkg.CandVersion(), P.CandVersion()) == 0)
+ continue;
+ // packages loosing M-A:same can be out-of-sync
+ VerIterator CV = PkgState[P->ID].CandidateVerIter(*this);
+ if (unlikely(CV.end() == true) ||
+ (CV->MultiArch & pkgCache::Version::Same) != pkgCache::Version::Same)
+ continue;
+
+ // not downloadable means the package is obsolete, so allow out-of-sync
+ if (CV.Downloadable() == false)
+ continue;
+
+ PkgState[Pkg->ID].iFlags |= AutoKept;
+ if (unlikely(DebugMarker == true))
+ std::clog << OutputInDepth(Depth) << "Ignore MarkInstall of " << Pkg
+ << " as its M-A:same siblings are not version-synced" << std::endl;
+ return false;
+ }
+
return true;
}
/*}}}*/