#include <apti18n.h>
/*}}}*/
+extern char **environ;
+
using namespace std;
APT_PURE static string AptHistoryRequestingUser() /*{{{*/
bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
{
bool result = true;
- static bool interrupted = false;
Configuration::Item const *Opts = _config->Tree(Cnf);
if (Opts == 0 || Opts->Child == 0)
Opts = Opts->Child;
sighandler_t old_sigpipe = signal(SIGPIPE, SIG_IGN);
- sighandler_t old_sigint = signal(SIGINT, [](int signum){
- interrupted = true;
- });
+ sighandler_t old_sigint = signal(SIGINT, SIG_IGN);
+ sighandler_t old_sigquit = signal(SIGQUIT, SIG_IGN);
unsigned int Count = 1;
for (; Opts != 0; Opts = Opts->Next, Count++)
}
signal(SIGINT, old_sigint);
signal(SIGPIPE, old_sigpipe);
-
- if (interrupted)
- result = _error->Error("Interrupted");
+ signal(SIGQUIT, old_sigquit);
return result;
}
* through to human readable (and i10n-able)
* names and calculates a percentage for each step.
*/
-bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+static bool ItemIsEssential(pkgDPkgPM::Item const &I)
+{
+ static auto const cachegen = _config->Find("pkgCacheGen::Essential");
+ if (cachegen == "none" || cachegen == "native")
+ return true;
+ if (unlikely(I.Pkg.end()))
+ return true;
+ return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
+}
+bool pkgDPkgPM::ExpandPendingCalls(std::vector<Item> &List, pkgDepCache &Cache)
{
- // we remove the last configures (and after that removes) from the list here
- // as they will be covered by the pending calls, so explicit calls are busy work
- decltype(List)::const_iterator::difference_type explicitIdx =
- std::distance(List.cbegin(),
- _config->FindB("Dpkg::ExplicitLastConfigure", false) ? List.cend() :
- std::find_if_not(
- std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }),
- List.crend(), [](Item const &i) { return i.Op == Item::Remove || i.Op == Item::Purge; }).base());
-
- // explicitely remove everything for hookscripts and progress building
{
std::unordered_set<decltype(pkgCache::Package::ID)> alreadyRemoved;
for (auto && I : List)
if (I.Op == Item::Remove || I.Op == Item::Purge)
alreadyRemoved.insert(I.Pkg->ID);
- decltype(List) AppendList;
+ std::remove_reference<decltype(List)>::type AppendList;
for (auto Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
if (Cache[Pkg].Delete() && alreadyRemoved.insert(Pkg->ID).second == true)
AppendList.emplace_back(Cache[Pkg].Purge() ? Item::Purge : Item::Remove, Pkg);
std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
}
-
- // explicitely configure everything for hookscripts and progress building
{
std::unordered_set<decltype(pkgCache::Package::ID)> alreadyConfigured;
for (auto && I : List)
if (I.Op == Item::Configure)
alreadyConfigured.insert(I.Pkg->ID);
- decltype(List) AppendList;
+ std::remove_reference<decltype(List)>::type AppendList;
for (auto && I : List)
if (I.Op == Item::Install && alreadyConfigured.insert(I.Pkg->ID).second == true)
AppendList.emplace_back(Item::Configure, I.Pkg);
AppendList.emplace_back(Item::Configure, Pkg);
std::move(AppendList.begin(), AppendList.end(), std::back_inserter(List));
}
+ return true;
+}
+bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
+{
+ // explicitely remove&configure everything for hookscripts and progress building
+ // we need them only temporarily through, so keep the length and erase afterwards
+ decltype(List)::const_iterator::difference_type explicitIdx =
+ std::distance(List.cbegin(), List.cend());
+ ExpandPendingCalls(List, Cache);
- auto const ItemIsEssential = [](pkgDPkgPM::Item const &I) {
- static auto const cachegen = _config->Find("pkgCacheGen::Essential");
- if (cachegen == "none" || cachegen == "native")
- return true;
- if (unlikely(I.Pkg.end()))
- return true;
- return (I.Pkg->Flags & pkgCache::Flag::Essential) != 0;
- };
-
- auto const StripAlreadyDoneFromPending = [&](APT::VersionVector & Pending) {
+ /* if dpkg told us that it has already done everything to the package we wanted it to do,
+ we shouldn't ask it for "more" later. That can e.g. happen if packages without conffiles
+ are purged as they will have pass through the purge states on remove already */
+ auto const StripAlreadyDoneFrom = [&](APT::VersionVector & Pending) {
Pending.erase(std::remove_if(Pending.begin(), Pending.end(), [&](pkgCache::VerIterator const &Ver) {
auto const PN = Ver.ParentPkg().FullName();
- return PackageOps[PN].size() <= PackageOpsDone[PN];
+ auto const POD = PackageOpsDone.find(PN);
+ if (POD == PackageOpsDone.end())
+ return false;
+ return PackageOps[PN].size() <= POD->second;
}), Pending.end());
};
if (I.Op == Item::Remove || I.Op == Item::Purge)
toBeRemoved[I.Pkg->ID] = false;
- if (std::find(toBeRemoved.begin(), toBeRemoved.end(), true) != toBeRemoved.end())
+ bool const RemovePending = std::find(toBeRemoved.begin(), toBeRemoved.end(), true) != toBeRemoved.end();
+ bool const PurgePending = approvedStates.Purge().empty() == false;
+ if (RemovePending != false || PurgePending != false)
+ List.emplace_back(Item::ConfigurePending, pkgCache::PkgIterator());
+ if (RemovePending)
List.emplace_back(Item::RemovePending, pkgCache::PkgIterator());
- if (approvedStates.Purge().empty() == false)
+ if (PurgePending)
List.emplace_back(Item::PurgePending, pkgCache::PkgIterator());
// support subpressing of triggers processing for special
unsigned long const Op = I->Op;
if (NoTriggers == true && I->Op != Item::TriggersPending &&
- I->Op != Item::ConfigurePending)
+ (I->Op != Item::ConfigurePending || std::next(I) != List.end()))
{
ADDARGC("--no-triggers");
}
{
if (I->File[0] != '/')
return _error->Error("Internal Error, Pathname to install is not absolute '%s'",I->File.c_str());
- auto const file = flNotDir(I->File);
+ auto file = flNotDir(I->File);
+ if (flExtension(file) != "deb")
+ file.append(".deb");
std::string linkpath;
if (dpkg_recursive_install_numbered)
strprintf(linkpath, "%s/%.*lu-%s", tmpdir_to_free, p, n, file.c_str());
else if (I->Op == Item::RemovePending)
{
++I;
- StripAlreadyDoneFromPending(approvedStates.Remove());
+ StripAlreadyDoneFrom(approvedStates.Remove());
if (approvedStates.Remove().empty())
continue;
}
++I;
// explicit removes of packages without conffiles passthrough the purge states instantly, too.
// Setting these non-installed packages up for purging generates 'unknown pkg' warnings from dpkg
- StripAlreadyDoneFromPending(approvedStates.Purge());
+ StripAlreadyDoneFrom(approvedStates.Purge());
if (approvedStates.Purge().empty())
continue;
std::remove_reference<decltype(approvedStates.Remove())>::type approvedRemoves;
if (d->dpkg_error.empty() == false)
{
// no point in reseting packages we already completed removal for
- StripAlreadyDoneFromPending(approvedStates.Remove());
- StripAlreadyDoneFromPending(approvedStates.Purge());
+ StripAlreadyDoneFrom(approvedStates.Remove());
+ StripAlreadyDoneFrom(approvedStates.Purge());
APT::StateChanges undo;
auto && undoRem = approvedStates.Remove();
std::move(undoRem.begin(), undoRem.end(), std::back_inserter(undo.Install()));
if (undo.Save(false) == false)
_error->Error("Couldn't revert dpkg selection for approved remove/purge after an error was encountered!");
}
+
+ StripAlreadyDoneFrom(currentStates.Remove());
+ StripAlreadyDoneFrom(currentStates.Purge());
if (currentStates.Save(false) == false)
_error->Error("Couldn't restore dpkg selection states which were present before this interaction!");