From 486d190d3c66bb7271509dc002f8ec9e9eb0166c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Wed, 10 Jul 2013 13:06:05 +0200 Subject: 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. --- apt-pkg/depcache.cc | 53 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) (limited to 'apt-pkg/depcache.cc') 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 @@ -864,6 +864,11 @@ bool pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, dpkg holds are enforced by the private IsModeChangeOk */ 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) { @@ -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; } /*}}}*/ -- cgit v1.2.3 From 096bd9f59750f6bea754d3a05e240c9eea0f6b53 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Thu, 1 Aug 2013 13:19:43 +0200 Subject: prefer native arch over higher priority for providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rational from the buglog: > The problem here is that the Priority field in one of the Packages files > is incorrect due to a mishap with reprepro configuration, […] the > amd64 version is Priority: standard but the arm64 version is Priority: > optional (and has a stray "optional: interpreters" field). > […] > However, Priority is a rather weak property of a package because it's > typically applied via overrides, and it's easy for maintainers of > third-party repositories to misconfigure them so that overrides aren't > applied correctly. It shouldn't be ranked ahead of choosing packages > from the native architecture. In this case, I have no user-mode > emulation for arm64 set up, so choosing m4:arm64 simply won't work. This effectly makes the priority the least interesting data point in chosing a provider, which is in line with the other checks we have already order above priority in the past and also has a certain appeal by the soft irony it provides. Closes: #718482 --- apt-pkg/depcache.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apt-pkg/depcache.cc') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 2c6eb43bf..978a893f7 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1007,9 +1007,6 @@ struct CompareProviders { else if ((B->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) return true; } - // higher priority seems like a good idea - if (AV->Priority != BV->Priority) - return AV->Priority > BV->Priority; // prefer native architecture if (strcmp(A.Arch(), B.Arch()) != 0) { @@ -1024,6 +1021,9 @@ struct CompareProviders { else if (*a == B.Arch()) return true; } + // higher priority seems like a good idea + if (AV->Priority != BV->Priority) + return AV->Priority > BV->Priority; // unable to decide… return A->ID < B->ID; } -- cgit v1.2.3 From 8fa042ca39dcb39d544f015f4a924c5dbc10ad2c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Mon, 30 Sep 2013 18:51:40 +0200 Subject: don't consider holds for autoremoval MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't remove packages which are held back by the user with a hold, so marking them (or its dependencies) as garbage will lead our autoremover into madness – and given that the package is important enough that the user has held it back it can't be garbage (at least at the moment), so even if a front-end wants to use the info just for information display its a good idea to not consider it garbage for them. Closes: 724995 --- apt-pkg/depcache.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'apt-pkg/depcache.cc') diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 978a893f7..a06789cdf 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -896,6 +896,7 @@ char const* PrintMode(char const mode) case pkgDepCache::ModeInstall: return "Install"; case pkgDepCache::ModeKeep: return "Keep"; case pkgDepCache::ModeDelete: return "Delete"; + case pkgDepCache::ModeGarbage: return "Garbage"; default: return "UNKNOWN"; } } @@ -1726,8 +1727,6 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) follow_recommends = MarkFollowsRecommends(); follow_suggests = MarkFollowsSuggests(); - - // do the mark part, this is the core bit of the algorithm for(PkgIterator p = PkgBegin(); !p.end(); ++p) { @@ -1738,7 +1737,9 @@ bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc) // be nice even then a required package violates the policy (#583517) // and do the full mark process also for required packages (p.CurrentVer().end() != true && - p.CurrentVer()->Priority == pkgCache::State::Required)) + p.CurrentVer()->Priority == pkgCache::State::Required) || + // packages which can't be changed (like holds) can't be garbage + (IsModeChangeOk(ModeGarbage, p, 0, false) == false)) { // the package is installed (and set to keep) if(PkgState[p->ID].Keep() && !p.CurrentVer().end()) -- cgit v1.2.3