From b58f28d4c4a06ef0a67cf3b6fe57aa08e7bc6b7e Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 7 May 2014 21:39:53 +0200 Subject: fix some compile errors in the now enabled #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13) --- apt-pkg/packagemanager.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 5d6bc6bd2..0ec9f3309 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 71e7a0f3a432828e5bd5498297051aa37e7f0a59 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 16 May 2014 17:28:11 +0200 Subject: consistently fail if Smart* packagemanager actions fail These failure conditions come with an error message attached and the conditions aren't workaroundable (otherwise this would have been done instead of returning failure), so not erroring out here means that we execute dpkg later on with a known not-working ordering adding insult (our own error messages at the end) to injury (dpkg failure). --- apt-pkg/packagemanager.cc | 85 ++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 46 deletions(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 5d6bc6bd2..56f5c59c9 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -396,12 +396,11 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl; if (PkgLoop == false) List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(DepPkg, true, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - } + if (SmartUnPack(DepPkg, true, Depth + 1) == false) + return false; + Bad = false; + if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) + Changed = true; if (PkgLoop == false) List->RmFlag(Pkg,pkgOrderList::Loop); if (Bad == false) @@ -469,17 +468,14 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) package and it will remove the loop flag */ if (PkgLoop == false) List->Flag(Pkg,pkgOrderList::Loop); - if (SmartConfigure(DepPkg, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - } + if (SmartConfigure(DepPkg, Depth + 1) == false) + return false; + Bad = false; + if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) + Changed = true; if (PkgLoop == false) List->RmFlag(Pkg,pkgOrderList::Loop); - // If SmartConfigure was succesfull, Bad is false, so break - if (Bad == false) - break; + break; } else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { @@ -499,11 +495,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); - if (Bad) { - if (Debug) - _error->Warning(_("Could not configure '%s'. "),Pkg.FullName().c_str()); - return false; - } + if (Bad == true) + return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str()); if (PkgLoop) return true; @@ -527,7 +520,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer && (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)) continue; - SmartConfigure(P, (Depth +1)); + if (SmartConfigure(P, (Depth +1)) == false) + return false; } // Sanity Check @@ -702,25 +696,23 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (Debug) clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl; // SmartUnpack with the ImmediateFlag to ensure its really ready - if (SmartUnPack(Pkg, true, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; - } + if (SmartUnPack(Pkg, true, Depth + 1) == false) + return false; + Bad = false; + if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) + Changed = true; + break; } else { if (Debug) clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl; - if (SmartConfigure(Pkg, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; - } + if (SmartConfigure(Pkg, Depth + 1) == false) + return false; + Bad = false; + if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) + Changed = true; + break; } } } @@ -759,11 +751,12 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0) { if (Debug) - clog << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl; + clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl; List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(ConflictPkg,false, Depth + 1) == true) - if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) - Changed = true; + if (SmartUnPack(ConflictPkg,false, Depth + 1) == false) + return false; + if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) + Changed = true; // Remove loop to allow it to be used later if needed List->RmFlag(Pkg,pkgOrderList::Loop); } @@ -773,7 +766,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c else if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == false) { if (Debug) - clog << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.FullName() << " to conflict violation" << endl; + clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl; if (EarlyRemove(ConflictPkg) == false) return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); } @@ -845,11 +838,10 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c } if (PkgLoop == false) List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(BrokenPkg, false, Depth + 1) == true) - { - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false) - Changed = true; - } + if (SmartUnPack(BrokenPkg, false, Depth + 1) == false) + return false; + if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false) + Changed = true; if (PkgLoop == false) List->RmFlag(Pkg,pkgOrderList::Loop); } @@ -860,7 +852,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c { if (Debug) clog << OutputInDepth(Depth) << " Removing " << BrokenPkg.FullName() << " to avoid " << End << endl; - SmartRemove(BrokenPkg); + if (SmartRemove(BrokenPkg) == false) + return false; } } } -- cgit v1.2.3 From 0eb4af9d3d0c524c7afdc684238aa263ac287449 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sat, 17 May 2014 12:37:13 +0200 Subject: fix tight loop detection and temporary removes As outlined in #748355 apt segfaulted if it encountered a loop between a package pre-depending on a package conflicting with the previous as it ended up in an endless loop trying to unpack 'the other package'. In this specific case as an essential package is involved a lot of force needs to be applied, but can also be caused by 'normal' tight loops and highlights a problem in how we handle breaks which we want to avoid. The fix comes in multiple entangled changes: 1. All Smart* calls are guarded with loop detection. Some already had it, some had parts of it, some did it incorrect, and some didn't even try. 2. temporary removes to avoid a loop (which is done if a loop is detected) prevent the unpack of this looping package (we tried to unpack it to avoid the conflict/breaks, but due to a loop we couldn't, so we remove/deconfigure it instead which means we can't unpack it now) 3. handle conflicts and breaks very similar instead of duplicating most of the code. The only remaining difference is, as it should: deconfigure is enough for breaks, for conflicts we need the big hammer --- apt-pkg/packagemanager.cc | 327 ++++++++++++++++++++++------------------------ 1 file changed, 156 insertions(+), 171 deletions(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 56f5c59c9..393f836f7 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -261,7 +261,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false) continue; - if (EarlyRemove(D.ParentPkg()) == false) + if (EarlyRemove(D.ParentPkg(), &D) == false) return _error->Error("Reverse conflicts early remove for package '%s' failed", Pkg.FullName().c_str()); } @@ -313,18 +313,41 @@ bool pkgPackageManager::ConfigureAll() return true; } /*}}}*/ +// PM::NonLoopingSmart - helper to avoid loops while calling Smart methods /*{{{*/ +// ----------------------------------------------------------------------- +/* ensures that a loop of the form A depends B, B depends A (and similar) + is not leading us down into infinite recursion segfault land */ +bool pkgPackageManager::NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg, + pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop, + bool * const Bad, bool * const Changed) +{ + if (PkgLoop == false) + List->Flag(Pkg,pkgOrderList::Loop); + bool success = false; + switch(action) + { + case UNPACK_IMMEDIATE: success = SmartUnPack(DepPkg, true, Depth + 1); break; + case UNPACK: success = SmartUnPack(DepPkg, false, Depth + 1); break; + case CONFIGURE: success = SmartConfigure(DepPkg, Depth + 1); break; + } + if (PkgLoop == false) + List->RmFlag(Pkg,pkgOrderList::Loop); + + if (success == false) + return false; + + if (Bad != NULL) + *Bad = false; + if (Changed != NULL && List->IsFlag(DepPkg,pkgOrderList::Loop) == false) + *Changed = true; + return true; +} + /*}}}*/ // PM::SmartConfigure - Perform immediate configuration of the pkg /*{{{*/ // --------------------------------------------------------------------- /* This function tries to put the system in a state where Pkg can be configured. - This involves checking each of Pkg's dependanies and unpacking and - configuring packages where needed. - - Note on failure: This method can fail, without causing any problems. - This can happen when using Immediate-Configure-All, SmartUnPack may call - SmartConfigure, it may fail because of a complex dependency situation, but - a error will only be reported if ConfigureAll fails. This is why some of the - messages this function reports on failure (return false;) as just warnings - only shown when debuging*/ + This involves checking each of Pkg's dependencies and unpacking and + configuring packages where needed. */ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) { // If this is true, only check and correct and dependencies without the Loop flag @@ -339,9 +362,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) } VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); - - /* Because of the ordered list, most dependencies should be unpacked, - however if there is a loop (A depends on B, B depends on A) this will not + + /* Because of the ordered list, most dependencies should be unpacked, + however if there is a loop (A depends on B, B depends on A) this will not be the case, so check for dependencies before configuring. */ bool Bad = false, Changed = false; const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000); @@ -388,24 +411,15 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (Debug) std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; Bad = false; - break; } else { if (Debug) clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl; - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(DepPkg, true, Depth + 1) == false) + if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) return false; - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); - if (Bad == false) - break; } + break; } if (Cur == End || Bad == false) @@ -460,22 +474,12 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) Bad = false; break; } - /* Check for a loop to prevent one forming - If A depends on B and B depends on A, SmartConfigure will - just hop between them if this is not checked. Dont remove the - loop flag after finishing however as loop is already set. - This means that there is another SmartConfigure call for this - package and it will remove the loop flag */ - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartConfigure(DepPkg, Depth + 1) == false) + if (Debug) + std::clog << OutputInDepth(Depth) << "Configure already unpacked " << DepPkg << std::endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) return false; - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); break; + } else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { @@ -494,16 +498,16 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (i++ > max_loops) return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); - + if (Bad == true) return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str()); - + if (PkgLoop) return true; static std::string const conf = _config->Find("PackageManager::Configure","all"); static bool const ConfigurePkgs = (conf == "all" || conf == "smart"); - if (List->IsFlag(Pkg,pkgOrderList::Configured)) + if (List->IsFlag(Pkg,pkgOrderList::Configured)) return _error->Error("Internal configure error on '%s'.", Pkg.FullName().c_str()); if (ConfigurePkgs == true && Configure(Pkg) == false) @@ -535,29 +539,37 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) // --------------------------------------------------------------------- /* This is called to deal with conflicts arising from unpacking */ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) +{ + return EarlyRemove(Pkg, NULL); +} +bool pkgPackageManager::EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep) { if (List->IsNow(Pkg) == false) return true; - + // Already removed it if (List->IsFlag(Pkg,pkgOrderList::Removed) == true) return true; - + // Woops, it will not be re-installed! if (List->IsFlag(Pkg,pkgOrderList::InList) == false) return false; + // these breaks on M-A:same packages can be dealt with. They 'loop' by design + if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks && Dep->IsMultiArchImplicit() == true) + return true; + // Essential packages get special treatment bool IsEssential = false; if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 || (Pkg->Flags & pkgCache::Flag::Important) != 0) IsEssential = true; - /* Check for packages that are the dependents of essential packages and + /* Check for packages that are the dependents of essential packages and promote them too */ if (Pkg->CurrentVer != 0) { - for (DepIterator D = Pkg.RevDependsList(); D.end() == false && + for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false && IsEssential == false; ++D) if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends) if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 || @@ -574,11 +586,14 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) "but if you really want to do it, activate the " "APT::Force-LoopBreak option."),Pkg.FullName().c_str()); } - + // dpkg will auto-deconfigure it, no need for the big remove hammer + else if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks) + return true; + bool Res = SmartRemove(Pkg); if (Cache[Pkg].Delete() == false) List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States); - + return Res; } /*}}}*/ @@ -623,13 +638,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); - /* PreUnpack Checks: This loop checks and attempts to rectify and problems that would prevent the package being unpacked. + /* PreUnpack Checks: This loop checks and attempts to rectify any problems that would prevent the package being unpacked. It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with - complex dependency structures, trying to configure some packages while breaking the loops can complicate things . + complex dependency structures, trying to configure some packages while breaking the loops can complicate things. This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured), or by the ConfigureAll call at the end of the for loop in OrderInstall. */ - bool Changed = false; + bool SomethingBad = false, Changed = false; + bool couldBeTemporaryRemoved = Depth != 0 && List->IsFlag(Pkg,pkgOrderList::Removed) == false; const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000); unsigned int i = 0; do @@ -677,183 +693,142 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c for (Version **I = VList; *I != 0; ++I) { VerIterator Ver(Cache,*I); - PkgIterator Pkg = Ver.ParentPkg(); + PkgIterator DepPkg = Ver.ParentPkg(); // Not the install version - if (Cache[Pkg].InstallVer != *I || - (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)) + if (Cache[DepPkg].InstallVer != *I || + (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing)) continue; - if (List->IsFlag(Pkg,pkgOrderList::Configured)) + if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { Bad = false; break; } // check if it needs unpack or if if configure is enough - if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false) + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false) { if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl; - // SmartUnpack with the ImmediateFlag to ensure its really ready - if (SmartUnPack(Pkg, true, Depth + 1) == false) + clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl; + if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) return false; - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; } else { if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl; - if (SmartConfigure(Pkg, Depth + 1) == false) + clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) return false; - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; } + break; } } if (Bad == true) - { - if (Start == End) - return _error->Error("Couldn't configure pre-depend %s for %s, " - "probably a dependency cycle.", - End.TargetPkg().FullName().c_str(),Pkg.FullName().c_str()); - } - else - continue; + SomethingBad = true; } else if (End->Type == pkgCache::Dep::Conflicts || - End->Type == pkgCache::Dep::Obsoletes) + End->Type == pkgCache::Dep::Obsoletes || + End->Type == pkgCache::Dep::DpkgBreaks) { - /* Look for conflicts. Two packages that are both in the install - state cannot conflict so we don't check.. */ SPtrArray VList = End.AllTargets(); - for (Version **I = VList; *I != 0; I++) + for (Version **I = VList; *I != 0; ++I) { VerIterator Ver(Cache,*I); PkgIterator ConflictPkg = Ver.ParentPkg(); - VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer); + if (ConflictPkg.CurrentVer() != Ver) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl; + continue; + } + + if (List->IsNow(ConflictPkg) == false) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Ignore already dealt-with version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl; + continue; + } - // See if the current version is conflicting - if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg)) + if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true) { if (Debug) - clog << OutputInDepth(Depth) << Pkg.FullName() << " conflicts with " << ConflictPkg.FullName() << endl; - /* If a loop is not present or has not yet been detected, attempt to unpack packages - to resolve this conflict. If there is a loop present, remove packages to resolve this conflict */ - if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) + clog << OutputInDepth(Depth) << "Ignoring " << End << " as " << ConflictPkg.FullName() << "was temporarily removed" << endl; + continue; + } + + if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) && PkgLoop) + { + if (End->Type == pkgCache::Dep::DpkgBreaks && End.IsMultiArchImplicit() == true) { - if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0) - { - if (Debug) - clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl; - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(ConflictPkg,false, Depth + 1) == false) - return false; - if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) - Changed = true; - // Remove loop to allow it to be used later if needed - List->RmFlag(Pkg,pkgOrderList::Loop); - } - else if (EarlyRemove(ConflictPkg) == false) - return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str()); + if (Debug) + clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << ConflictPkg << endl; + continue; } - else if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == false) + if (Debug) { - if (Debug) + if (End->Type == pkgCache::Dep::DpkgBreaks) + clog << OutputInDepth(Depth) << "Because of breaks knot, deconfigure " << ConflictPkg.FullName() << " temporarily" << endl; + else clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl; - if (EarlyRemove(ConflictPkg) == false) - return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); } - } - } - } - else if (End->Type == pkgCache::Dep::DpkgBreaks) - { - SPtrArray VList = End.AllTargets(); - for (Version **I = VList; *I != 0; ++I) - { - VerIterator Ver(Cache,*I); - PkgIterator BrokenPkg = Ver.ParentPkg(); - if (BrokenPkg.CurrentVer() != Ver) - { - if (Debug) - std::clog << OutputInDepth(Depth) << " Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl; + if (EarlyRemove(ConflictPkg, &End) == false) + return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); + SomethingBad = true; continue; } - // Check if it needs to be unpacked - if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false && - List->IsNow(BrokenPkg)) + if (Cache[ConflictPkg].Delete() == false) { - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop) + if (Debug) { - // This dependency has already been dealt with by another SmartUnPack on Pkg - break; + clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << End; + if (PkgLoop == true) + clog << " (Looping)"; + clog << std::endl; } - else + // we would like to avoid temporary removals and all that at best via a simple unpack + _error->PushToStack(); + if (NonLoopingSmart(UNPACK, Pkg, ConflictPkg, Depth, PkgLoop, NULL, &Changed) == false) { - // Found a break, so see if we can unpack the package to avoid it - // but do not set loop if another SmartUnPack already deals with it - // Also, avoid it if the package we would unpack pre-depends on this one - VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer); - bool circle = false; - for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D) + // but if it fails ignore this failure and look for alternative ways of solving + if (Debug) { - if (D->Type != pkgCache::Dep::PreDepends) - continue; - SPtrArray VL = D.AllTargets(); - for (Version **I = VL; *I != 0; ++I) - { - VerIterator V(Cache,*I); - PkgIterator P = V.ParentPkg(); - // we are checking for installation as an easy 'protection' against or-groups and (unchosen) providers - if (P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V)) - continue; - circle = true; - break; - } - if (circle == true) - break; + clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << std::endl; + _error->DumpErrors(std::clog); + } + _error->RevertToStack(); + // ignorance can only happen if a) one of the offenders is already gone + if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true) + { + if (Debug) + clog << OutputInDepth(Depth) << "But " << ConflictPkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl; } - if (circle == true) + else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true) { if (Debug) - clog << OutputInDepth(Depth) << " Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl; - continue; + clog << OutputInDepth(Depth) << "But " << Pkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl; } + // or b) we can make one go (removal or dpkg auto-deconfigure) else { if (Debug) - { - clog << OutputInDepth(Depth) << " Unpacking " << BrokenPkg.FullName() << " to avoid " << End; - if (PkgLoop == true) - clog << " (Looping)"; - clog << std::endl; - } - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(BrokenPkg, false, Depth + 1) == false) - return false; - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false) - Changed = true; - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); + clog << OutputInDepth(Depth) << "So temprorary remove/deconfigure " << ConflictPkg.FullName() << " to satisfy " << End << endl; + if (EarlyRemove(ConflictPkg, &End) == false) + return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); } } + else + _error->MergeWithStack(); } - // Check if a package needs to be removed - else if (Cache[BrokenPkg].Delete() == true && List->IsFlag(BrokenPkg,pkgOrderList::Configured) == false) + else { if (Debug) - clog << OutputInDepth(Depth) << " Removing " << BrokenPkg.FullName() << " to avoid " << End << endl; - if (SmartRemove(BrokenPkg) == false) - return false; + clog << OutputInDepth(Depth) << "Removing " << ConflictPkg.FullName() << " now to avoid " << End << endl; + // no earlyremove() here as user has already agreed to the permanent removal + if (SmartRemove(Pkg) == false) + return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str()); } } } @@ -861,7 +836,17 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (i++ > max_loops) return _error->Error("Internal error: APT::pkgPackageManager::MaxLoopCount reached in SmartConfigure for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); - + + if (SomethingBad == true) + return _error->Error("Couldn't configure %s, probably a dependency cycle.", Pkg.FullName().c_str()); + + if (couldBeTemporaryRemoved == true && List->IsFlag(Pkg,pkgOrderList::Removed) == true) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Prevent unpack as " << Pkg << " is currently temporarily removed" << std::endl; + return true; + } + // Check for reverse conflicts. if (CheckRConflicts(Pkg,Pkg.RevDependsList(), instVer.VerStr()) == false) @@ -922,7 +907,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (Immediate == true) { // Perform immedate configuration of the package. if (SmartConfigure(Pkg, Depth + 1) == false) - _error->Warning(_("Could not perform immediate configuration on '%s'. " + _error->Error(_("Could not perform immediate configuration on '%s'. " "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),2); } -- cgit v1.2.3 From 2f58969150b0daec1de407f61385ccf5b2065aa3 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Tue, 29 Jul 2014 15:01:13 +0200 Subject: Fix SmartConfigure to ignore ordering of packages that are already valid With the change of SmartConfigure() in git commit 42d51f the ordering code was trying to re-order dependencies, even when at this point in time this was not needed. Now it will first check all targets of the given dependency and only if there is not a good one try to reorder and unpack/configure as needed. Closes: LP: #1347721 --- apt-pkg/packagemanager.cc | 49 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 393f836f7..249542c68 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -372,6 +372,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) std::list needConfigure; do { + // Check each dependency and see if anything needs to be done + // so that it can be configured Changed = false; for (DepIterator D = instVer.DependsList(); D.end() == false; ) { @@ -383,7 +385,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) continue; Bad = true; - // Check for dependencies that have not been unpacked, probably due to loops. + // the first pass checks if we its all good, i.e. if we have + // to do anything at all for (DepIterator Cur = Start; true; ++Cur) { SPtrArray VList = Cur.AllTargets(); @@ -402,6 +405,47 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) break; } + // Check if the version that is going to be installed will satisfy the dependency + if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false) + continue; + + if (PkgLoop == true) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; + Bad = false; + } + } + + if (Cur == End || Bad == false) + break; + } + + // this dependency is in a good state, so we can stop + if (Bad == false) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Found ok dep " << D.TargetPkg() << std::endl; + continue; + } + + // Check for dependencies that have not been unpacked, + // probably due to loops. + for (DepIterator Cur = Start; true; ++Cur) + { + SPtrArray VList = Cur.AllTargets(); + + for (Version **I = VList; *I != 0; ++I) + { + VerIterator Ver(Cache,*I); + PkgIterator DepPkg = Ver.ParentPkg(); + + // Check if the current version of the package is available and will satisfy this dependency + if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && + List->IsFlag(DepPkg,pkgOrderList::Removed) == false && + DepPkg.State() == PkgIterator::NeedsNothing) + continue; + // Check if the version that is going to be installed will satisfy the dependency if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false) continue; @@ -419,6 +463,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) return false; } + // at this point we either unpacked a Dep or we are in a loop, + // no need to unpack a second one break; } @@ -435,6 +481,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (1) for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); + // now go over anything that needs configuring Bad = false, Changed = false, i = 0; do { -- cgit v1.2.3 From bf3ad91fdf4967fe107e08a6887f9ed51f4f5eea Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 26 Sep 2014 22:55:56 +0200 Subject: =?UTF-8?q?fix:=20warning:=20extra=20=E2=80=98;=E2=80=99=20[-Wpeda?= =?UTF-8?q?ntic]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-By: gcc -Wpedantic Git-Dch: Ignore --- apt-pkg/packagemanager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index e4cd1dc3b..101912f9d 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -1080,7 +1080,7 @@ pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress) return Failed; return Res; -}; +} #else pkgPackageManager::OrderResult pkgPackageManager::DoInstallPostFork(int statusFd) -- cgit v1.2.3 From 1df24acfdb8ba1cd8bbbaa166f170dda480ce41e Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 19 Oct 2014 14:14:37 +0200 Subject: check for failure message in testsuccess/failure These functions check the exit code of the command, but for apt commands we can go further and require an error message for non-zero exits and none for zero exits. Git-Dch: Ignore --- apt-pkg/packagemanager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 101912f9d..2247d04db 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -843,7 +843,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c // but if it fails ignore this failure and look for alternative ways of solving if (Debug) { - clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << std::endl; + clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << " ignoring:" << std::endl; _error->DumpErrors(std::clog); } _error->RevertToStack(); -- cgit v1.2.3 From ccf6bdb3efc54165c76b42aae94c498a36acbe1b Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Fri, 7 Nov 2014 14:20:36 +0100 Subject: use a abi version check similar to the gcc check Git-Dch: Ignore --- apt-pkg/packagemanager.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 2247d04db..ba48c53cc 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -1059,7 +1059,7 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() // PM::DoInstallPostFork - compat /*{{{*/ // --------------------------------------------------------------------- /*}}}*/ -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +#if APT_PKG_ABI >= 413 pkgPackageManager::OrderResult pkgPackageManager::DoInstallPostFork(int statusFd) { @@ -1096,7 +1096,7 @@ pkgPackageManager::DoInstallPostFork(int statusFd) // PM::DoInstall - Does the installation /*{{{*/ // --------------------------------------------------------------------- /* compat */ -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +#if APT_PKG_ABI >= 413 pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) { @@ -1120,7 +1120,7 @@ pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) // --------------------------------------------------------------------- /* This uses the filenames in FileNames and the information in the DepCache to perform the installation of packages.*/ -#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +#if APT_PKG_ABI >= 413 pkgPackageManager::OrderResult pkgPackageManager::DoInstall(APT::Progress::PackageManager *progress) { -- cgit v1.2.3 From 4e6a7e260eb713318b1b5019a72073050242ac3c Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 25 Nov 2014 10:50:58 +0100 Subject: properly handle already reinstall pkgs in ordering The bugreport itself describes the case of the ordering code detecting a loop where none is present, but the testcase finds also cases in which there is actually a loop and we fail to realize it. --reinstall can be considered an interactive command through and it usually doesn't encounter such "hard" problems (= looping essentials), so this is less serious than it sounds at first. Closes: 770291 --- apt-pkg/packagemanager.cc | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'apt-pkg/packagemanager.cc') diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index ba48c53cc..d137dc75a 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -400,7 +400,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) // Check if the current version of the package is available and will satisfy this dependency if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && List->IsFlag(DepPkg,pkgOrderList::Removed) == false && - DepPkg.State() == PkgIterator::NeedsNothing) + DepPkg.State() == PkgIterator::NeedsNothing && + (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall) { Bad = false; break; @@ -413,8 +414,13 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (PkgLoop == true) { if (Debug) - std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; - Bad = false; + std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure"; + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked)) + Bad = false; + else if (Debug) + std::clog << ", but it isn't unpacked yet"; + if (Debug) + std::clog << std::endl; } } @@ -426,7 +432,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (Bad == false) { if (Debug) - std::clog << OutputInDepth(Depth) << "Found ok dep " << D.TargetPkg() << std::endl; + std::clog << OutputInDepth(Depth) << "Found ok dep " << Start.TargetPkg() << std::endl; continue; } @@ -444,7 +450,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) // Check if the current version of the package is available and will satisfy this dependency if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && List->IsFlag(DepPkg,pkgOrderList::Removed) == false && - DepPkg.State() == PkgIterator::NeedsNothing) + DepPkg.State() == PkgIterator::NeedsNothing && + (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall) continue; // Check if the version that is going to be installed will satisfy the dependency @@ -454,8 +461,13 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (PkgLoop == true) { if (Debug) - std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; - Bad = false; + std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure"; + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked)) + Bad = false; + else if (Debug) + std::clog << ", but it isn't unpacked yet"; + if (Debug) + std::clog << std::endl; } else { @@ -722,7 +734,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c // See if the current version is ok if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true && - Pkg.State() == PkgIterator::NeedsNothing) + Pkg.State() == PkgIterator::NeedsNothing && + (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall) { Bad = false; if (Debug) @@ -744,8 +757,11 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c PkgIterator DepPkg = Ver.ParentPkg(); // Not the install version - if (Cache[DepPkg].InstallVer != *I || - (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing)) + if (Cache[DepPkg].InstallVer != *I) + continue; + + if (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing && + (Cache[DepPkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall) continue; if (List->IsFlag(DepPkg,pkgOrderList::Configured)) @@ -757,6 +773,16 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c // check if it needs unpack or if if configure is enough if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false) { + // two packages pre-depending on each other can't be handled sanely + if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop) + { + // this isn't an error as there is potential for something else to satisfy it + // (like a provides or an or-group member) + if (Debug) + clog << OutputInDepth(Depth) << "Unpack loop detected between " << DepPkg.FullName() << " and " << Pkg.FullName() << endl; + continue; + } + if (Debug) clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl; if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) -- cgit v1.2.3