From e7d4e0cf4f6d79810e4b4e7de505729e759213dd Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 8 Jul 2016 09:40:46 +0200 Subject: select remove/purge packages early on for dpkg Telling dpkg early on that we are going to remove these packages later helps it with auto-deconfiguration decisions and its another area where a planner can ignore the nitty gritty details and let dpkg decide the course of action if there are no special requirements. --- apt-pkg/deb/dpkgpm.cc | 95 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 13 deletions(-) (limited to 'apt-pkg/deb/dpkgpm.cc') diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 38285d14b..bc34e50e0 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1372,6 +1372,50 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) return _error->Error("Couldn't clean the currently selected dpkg states"); } } + APT::StateChanges approvedStates; + if (_config->FindB("dpkg::selection::remove::approved", true)) + { + for (auto && I: List) + if (I.Op == Item::Remove && Cache[I.Pkg].Delete()) + approvedStates.Remove(FindToBeRemovedVersion(I.Pkg)); + else if (I.Op == Item::Purge && Cache[I.Pkg].Purge()) + approvedStates.Purge(FindToBeRemovedVersion(I.Pkg)); + if (approvedStates.Save(false) == false) + { + _error->Error("Couldn't record the approved state changes as dpkg selection states"); + if (currentStates.Save(false) == false) + _error->Error("Couldn't restore dpkg selection states which were present before this interaction!"); + return false; + } + + { + std::vector toBeRemoved(Cache.Head().PackageCount, false); + std::vector toBePurged(Cache.Head().PackageCount, false); + for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg) + if (Cache[Pkg].Purge()) + toBePurged[Pkg->ID] = true; + else if (Cache[Pkg].Delete()) + toBeRemoved[Pkg->ID] = true; + for (auto && I: approvedStates.Remove()) + toBeRemoved[I.ParentPkg()->ID] = false; + for (auto && I: approvedStates.Purge()) + toBePurged[I.ParentPkg()->ID] = false; + if (std::find(toBeRemoved.begin(), toBeRemoved.end(), true) != toBeRemoved.end()) + { + if (ConfigurePending) + List.emplace(std::prev(List.end()), Item::RemovePending, pkgCache::PkgIterator()); + else + List.emplace_back(Item::RemovePending, pkgCache::PkgIterator()); + } + if (std::find(toBePurged.begin(), toBePurged.end(), true) != toBePurged.end()) + { + if (ConfigurePending) + List.emplace(std::prev(List.end()), Item::PurgePending, pkgCache::PkgIterator()); + else + List.emplace_back(Item::PurgePending, pkgCache::PkgIterator()); + } + } + } d->stdin_is_dev_null = false; @@ -1460,6 +1504,16 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) ADDARGC("--pending"); break; + case Item::RemovePending: + ADDARGC("--remove"); + ADDARGC("--pending"); + break; + + case Item::PurgePending: + ADDARGC("--purge"); + ADDARGC("--pending"); + break; + case Item::Install: ADDARGC("--unpack"); ADDARGC("--auto-deconfigure"); @@ -1741,6 +1795,17 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) StopPtyMagic(); CloseLog(); + if (d->dpkg_error.empty() == false) + { + APT::StateChanges undo; + auto && undoRem = approvedStates.Remove(); + std::move(undoRem.begin(), undoRem.end(), std::back_inserter(undo.Remove())); + auto && undoPur = approvedStates.Purge(); + std::move(undoPur.begin(), undoPur.end(), std::back_inserter(undo.Purge())); + approvedStates.clear(); + if (undo.Save(false) == false) + _error->Error("Couldn't revert dpkg selection for approved remove/purge after an error was encountered!"); + } if (currentStates.Save(false) == false) _error->Error("Couldn't restore dpkg selection states which were present before this interaction!"); @@ -1991,20 +2056,24 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) } // log the ordering, see dpkgpm.h and the "Ops" enum there - const char *ops_str[] = { - "Install", - "Configure", - "Remove", - "Purge", - "ConfigurePending", - "TriggersPending", - }; fprintf(report, "AptOrdering:\n"); - for (vector::iterator I = List.begin(); I != List.end(); ++I) - if ((*I).Pkg != NULL) - fprintf(report, " %s: %s\n", (*I).Pkg.Name(), ops_str[(*I).Op]); - else - fprintf(report, " %s: %s\n", "NULL", ops_str[(*I).Op]); + for (auto && I : List) + { + char const * opstr = nullptr; + switch (I.Op) + { + case Item::Install: opstr = "Install"; break; + case Item::Configure: opstr = "Configure"; break; + case Item::Remove: opstr = "Remove"; break; + case Item::Purge: opstr = "Purge"; break; + case Item::ConfigurePending: opstr = "ConfigurePending"; break; + case Item::TriggersPending: opstr = "TriggersPending"; break; + case Item::RemovePending: opstr = "RemovePending"; break; + case Item::PurgePending: opstr = "PurgePending"; break; + } + auto const pkgname = I.Pkg.end() ? "NULL" : I.Pkg.FullName(); + fprintf(report, " %s: %s\n", pkgname.c_str(), opstr); + } // attach dmesg log (to learn about segfaults) if (FileExists("/bin/dmesg")) -- cgit v1.2.3