X-Git-Url: https://git.hcoop.net/ntk/apt.git/blobdiff_plain/90436124e1957f685673f0926a3cd8edc6d2fcdf..HEAD:/apt-pkg/packagemanager.cc diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index eff92738..249542c6 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -13,7 +13,7 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#include +#include #include #include @@ -24,10 +24,17 @@ #include #include #include +#include +#include +#include +#include -#include +#include +#include +#include #include -#include + +#include /*}}}*/ using namespace std; @@ -215,7 +222,7 @@ bool pkgPackageManager::CreateOrderList() return true; } /*}}}*/ -// PM::DepAlwaysTrue - Returns true if this dep is irrelevent /*{{{*/ +// PM::DepAlwaysTrue - Returns true if this dep is irrelevant /*{{{*/ // --------------------------------------------------------------------- /* The restriction on provides is to eliminate the case when provides are transitioning between valid states [ie exim to smail] */ @@ -243,18 +250,18 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, D->Type != pkgCache::Dep::Obsoletes) continue; - // The package hasnt been changed + // The package hasn't been changed if (List->IsNow(Pkg) == false) continue; - // Ignore self conflicts, ignore conflicts from irrelevent versions + // Ignore self conflicts, ignore conflicts from irrelevant versions if (D.IsIgnorable(Pkg) || D.ParentVer() != D.ParentPkg().CurrentVer()) continue; 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()); } @@ -306,22 +313,45 @@ 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 dependancy 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 - bool PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop); + bool const PkgLoop = List->IsFlag(Pkg,pkgOrderList::Loop); if (Debug) { VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer); @@ -332,116 +362,199 @@ 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; - for (DepIterator D = instVer.DependsList(); - D.end() == false; ) + bool Bad = false, Changed = false; + const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000); + unsigned int i=0; + std::list needConfigure; + do { - // Compute a single dependency element (glob or) - pkgCache::DepIterator Start; - pkgCache::DepIterator End; - D.GlobOr(Start,End); - - if (End->Type == pkgCache::Dep::Depends) - Bad = true; - - // Check for dependanices that have not been unpacked, probably due to loops. - while (End->Type == pkgCache::Dep::Depends) { - PkgIterator DepPkg; - VerIterator InstallVer; - SPtrArray VList = Start.AllTargets(); - - // Check through each version of each package that could satisfy this dependancy - for (Version **I = VList; *I != 0; I++) { - VerIterator Ver(Cache,*I); - DepPkg = Ver.ParentPkg(); - InstallVer = VerIterator(Cache,Cache[DepPkg].InstallVer); - - // Check if the current version of the package is avalible and will satisfy this dependancy - if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && - !List->IsFlag(DepPkg,pkgOrderList::Removed) && DepPkg.State() == PkgIterator::NeedsNothing) + // 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; ) + { + // Compute a single dependency element (glob or) + pkgCache::DepIterator Start, End; + D.GlobOr(Start,End); + + if (End->Type != pkgCache::Dep::Depends) + continue; + Bad = true; + + // 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(); + + for (Version **I = VList; *I != 0; ++I) { - Bad = false; - break; - } - - // Check if the version that is going to be installed will satisfy the dependancy - if (Cache[DepPkg].InstallVer == *I) { - if (List->IsFlag(DepPkg,pkgOrderList::UnPacked)) { - if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop) { - // This dependancy has already been dealt with by another SmartConfigure on Pkg - Bad = false; - break; - } else if (List->IsFlag(Pkg,pkgOrderList::Loop)) { - /* 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 */ - Bad = !SmartConfigure(DepPkg, Depth + 1); - } else { - /* 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 */ - List->Flag(Pkg,pkgOrderList::Loop); - Bad = !SmartConfigure(DepPkg, Depth + 1); - List->RmFlag(Pkg,pkgOrderList::Loop); - } - // If SmartConfigure was succesfull, Bad is false, so break - if (!Bad) break; - } else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { + 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) + { + Bad = false; + 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; - break; } } - } - - /* If the dependany is still not satisfied, try, if possible, unpacking a package to satisfy it */ - if (InstallVer != 0 && Bad) { - if (List->IsNow(DepPkg)) { - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop)) + + 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; + + if (PkgLoop == true) { if (Debug) std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; + Bad = false; } else { - List->Flag(Pkg,pkgOrderList::Loop); if (Debug) - cout << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop" << endl; - SmartUnPack(DepPkg, true, Depth + 1); - List->RmFlag(Pkg,pkgOrderList::Loop); + clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl; + 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; } + + if (Cur == End || Bad == false) + break; } - - if (Start==End) { - if (Bad && Debug && List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - std::clog << OutputInDepth(Depth) << "Could not satisfy " << Start << std::endl; - break; - } else { - Start++; + + if (Bad == false) + continue; + + needConfigure.push_back(Start); + } + if (i++ > max_loops) + 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 + { + Changed = false; + for (std::list::const_iterator D = needConfigure.begin(); D != needConfigure.end(); ++D) + { + // Compute a single dependency element (glob or) without modifying D + pkgCache::DepIterator Start, End; + { + pkgCache::DepIterator Discard = *D; + Discard.GlobOr(Start,End); + } + + if (End->Type != pkgCache::Dep::Depends) + continue; + Bad = true; + + // Search for dependencies which are unpacked but aren't configured yet (maybe 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 version that is going to be installed will satisfy the dependency + if (Cache[DepPkg].InstallVer != *I) + continue; + + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked)) + { + if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop) + { + // This dependency has already been dealt with by another SmartConfigure on Pkg + Bad = false; + break; + } + if (Debug) + std::clog << OutputInDepth(Depth) << "Configure already unpacked " << DepPkg << std::endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; + break; + + } + else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) + { + Bad = false; + break; + } + } + if (Cur == End || Bad == false) + break; } + + + if (Bad == true && Changed == false && Debug == true) + std::clog << OutputInDepth(Depth) << "Could not satisfy " << *D << std::endl; } - } - - if (Bad) { - if (Debug) - _error->Warning(_("Could not configure '%s'. "),Pkg.FullName().c_str()); - return false; - } - + 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) @@ -454,10 +567,12 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) P.end() == false; P = Pkg.Group().NextPkg(P)) { if (Pkg == P || List->IsFlag(P,pkgOrderList::Configured) == true || + List->IsFlag(P,pkgOrderList::UnPacked) == false || 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 @@ -471,29 +586,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 || @@ -510,11 +633,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; } /*}}}*/ @@ -533,7 +659,7 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg) /*}}}*/ // PM::SmartUnPack - Install helper /*{{{*/ // --------------------------------------------------------------------- -/* This puts the system in a state where it can Unpack Pkg, if Pkg is allready +/* This puts the system in a state where it can Unpack Pkg, if Pkg is already unpacked, or when it has been unpacked, if Immediate==true it configures it. */ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg) { @@ -547,219 +673,227 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c clog << OutputInDepth(Depth) << "SmartUnPack " << Pkg.FullName(); VerIterator InstallVer = VerIterator(Cache,Cache[Pkg].InstallVer); if (Pkg.CurrentVer() == 0) - cout << " (install version " << InstallVer.VerStr() << ")"; + clog << " (install version " << InstallVer.VerStr() << ")"; else - cout << " (replace version " << Pkg.CurrentVer().VerStr() << " with " << InstallVer.VerStr() << ")"; + clog << " (replace version " << Pkg.CurrentVer().VerStr() << " with " << InstallVer.VerStr() << ")"; if (PkgLoop) - cout << " (Only Perform PreUnpack Checks)"; - cout << endl; + clog << " (Only Perform PreUnpack Checks)"; + if (Immediate) + clog << " immediately"; + clog << endl; } 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. - It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should + /* 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 dependancy 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), + 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. */ - for (DepIterator D = instVer.DependsList(); - D.end() == 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 { - // Compute a single dependency element (glob or) - pkgCache::DepIterator Start; - pkgCache::DepIterator End; - D.GlobOr(Start,End); - - while (End->Type == pkgCache::Dep::PreDepends) + Changed = false; + for (DepIterator D = instVer.DependsList(); D.end() == false; ) { - if (Debug) - clog << OutputInDepth(Depth) << "PreDepends order for " << Pkg.FullName() << std::endl; + // Compute a single dependency element (glob or) + pkgCache::DepIterator Start, End; + D.GlobOr(Start,End); - // Look for possible ok targets. - SPtrArray VList = Start.AllTargets(); - bool Bad = true; - for (Version **I = VList; *I != 0 && Bad == true; I++) - { - VerIterator Ver(Cache,*I); - PkgIterator Pkg = Ver.ParentPkg(); - - // See if the current version is ok - if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true && - Pkg.State() == PkgIterator::NeedsNothing) + if (End->Type == pkgCache::Dep::PreDepends) + { + bool Bad = true; + if (Debug) + clog << OutputInDepth(Depth) << "PreDepends order for " << Pkg.FullName() << std::endl; + + // Look for easy targets: packages that are already okay + for (DepIterator Cur = Start; Bad == true; ++Cur) { - Bad = false; - if (Debug) - clog << OutputInDepth(Depth) << "Found ok package " << Pkg.FullName() << endl; - continue; - } - } - - // Look for something that could be configured. - for (Version **I = VList; *I != 0 && Bad == true; I++) - { - VerIterator Ver(Cache,*I); - PkgIterator Pkg = Ver.ParentPkg(); - - // Not the install version - if (Cache[Pkg].InstallVer != *I || - (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)) - continue; - - if (List->IsFlag(Pkg,pkgOrderList::Configured)) { - Bad = false; - continue; + SPtrArray VList = Cur.AllTargets(); + for (Version **I = VList; *I != 0; ++I) + { + VerIterator Ver(Cache,*I); + PkgIterator Pkg = Ver.ParentPkg(); + + // See if the current version is ok + if (Pkg.CurrentVer() == Ver && List->IsNow(Pkg) == true && + Pkg.State() == PkgIterator::NeedsNothing) + { + Bad = false; + if (Debug) + clog << OutputInDepth(Depth) << "Found ok package " << Pkg.FullName() << endl; + break; + } + } + if (Cur == End) + break; } - // check if it needs unpack or if if configure is enough - if (!List->IsFlag(Pkg,pkgOrderList::UnPacked)) - { - if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl; - // SmartUnpack with the ImmediateFlag to ensure its really ready - Bad = !SmartUnPack(Pkg, true, Depth + 1); - } else { - if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl; - Bad = !SmartConfigure(Pkg, Depth + 1); - } - } + // Look for something that could be configured. + for (DepIterator Cur = Start; Bad == true && Cur.end() == false; ++Cur) + { + SPtrArray VList = Cur.AllTargets(); + for (Version **I = VList; *I != 0; ++I) + { + VerIterator Ver(Cache,*I); + PkgIterator DepPkg = Ver.ParentPkg(); - /* If this or element did not match then continue on to the - next or element until a matching element is found */ - if (Bad == true) - { - // This triggers if someone make a pre-depends/depend loop. - 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()); - ++Start; - } - else - break; - } - - if (End->Type == pkgCache::Dep::Conflicts || - End->Type == pkgCache::Dep::Obsoletes) - { - /* 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++) - { - VerIterator Ver(Cache,*I); - PkgIterator ConflictPkg = Ver.ParentPkg(); - VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer); - - // See if the current version is conflicting - if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg)) - { - cout << 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)) { - if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0) { - if (Debug) - cout << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl; - List->Flag(Pkg,pkgOrderList::Loop); - SmartUnPack(ConflictPkg,false, Depth + 1); - // 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",ConflictPkg.FullName().c_str()); - } - } else { - if (!List->IsFlag(ConflictPkg,pkgOrderList::Removed)) { - if (Debug) - cout << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.FullName() << " to conflict violation" << endl; - if (EarlyRemove(ConflictPkg) == false) - return _error->Error("Internal Error, Could not early remove %s",ConflictPkg.FullName().c_str()); - } + // Not the install version + if (Cache[DepPkg].InstallVer != *I || + (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing)) + continue; + + if (List->IsFlag(DepPkg,pkgOrderList::Configured)) + { + Bad = false; + break; + } + + // check if it needs unpack or if if configure is enough + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false) + { + if (Debug) + clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl; + if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; + } + else + { + if (Debug) + clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; + } + break; } } + + if (Bad == true) + SomethingBad = true; } - } - - // Check for breaks - if (End->Type == pkgCache::Dep::DpkgBreaks) { - SPtrArray VList = End.AllTargets(); - for (Version **I = VList; *I != 0; I++) + else if (End->Type == pkgCache::Dep::Conflicts || + End->Type == pkgCache::Dep::Obsoletes || + End->Type == pkgCache::Dep::DpkgBreaks) { - VerIterator Ver(Cache,*I); - PkgIterator BrokenPkg = Ver.ParentPkg(); - if (BrokenPkg.CurrentVer() != Ver) + SPtrArray VList = End.AllTargets(); + for (Version **I = VList; *I != 0; ++I) { - if (Debug) - std::clog << OutputInDepth(Depth) << " Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl; - continue; - } + VerIterator Ver(Cache,*I); + PkgIterator ConflictPkg = Ver.ParentPkg(); + if (ConflictPkg.CurrentVer() != Ver) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl; + continue; + } - // Check if it needs to be unpacked - if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false && - List->IsNow(BrokenPkg)) { - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop) { - // This dependancy has already been dealt with by another SmartUnPack on Pkg - break; - } else { - // 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 - VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer); - bool circle = false; - for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D) - { - 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->CurrentVer == 0 || P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V)) - continue; - circle = true; - break; - } - if (circle == true) - break; - } - if (circle == true) + 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; + } + + if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true) + { + if (Debug) + 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 (Debug) - cout << OutputInDepth(Depth) << " Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl; + clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << ConflictPkg << endl; continue; } - else + 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, &End) == false) + return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); + SomethingBad = true; + continue; + } + + if (Cache[ConflictPkg].Delete() == false) + { + if (Debug) + { + clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << End; + if (PkgLoop == true) + clog << " (Looping)"; + clog << std::endl; + } + // 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) { + // but if it fails ignore this failure and look for alternative ways of solving if (Debug) { - cout << OutputInDepth(Depth) << " Unpacking " << BrokenPkg.FullName() << " to avoid " << End; - if (PkgLoop == true) - cout << " (Looping)"; - cout << std::endl; + 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; + } + else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true) + { + if (Debug) + 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) << "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()); } - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - SmartUnPack(BrokenPkg, false, Depth + 1); - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); } + else + _error->MergeWithStack(); } - } else { - // Check if a package needs to be removed - if (Cache[BrokenPkg].Delete() == true && !List->IsFlag(BrokenPkg,pkgOrderList::Configured)) + else { if (Debug) - cout << OutputInDepth(Depth) << " Removing " << BrokenPkg.FullName() << " to avoid " << End << endl; - SmartRemove(BrokenPkg); + 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()); } } } } + 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) @@ -782,7 +916,10 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c This way we avoid that M-A: enabled packages are installed before their older non-M-A enabled packages are replaced by newer versions */ bool const installed = Pkg->CurrentVer != 0; - if (installed == true && Install(Pkg,FileNames[Pkg->ID]) == false) + if (installed == true && + (instVer != Pkg.CurrentVer() || + ((Cache[Pkg].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)) && + Install(Pkg,FileNames[Pkg->ID]) == false) return false; for (PkgIterator P = Pkg.Group().PackageList(); P.end() == false; P = Pkg.Group().NextPkg(P)) @@ -800,6 +937,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c P.end() == false; P = Pkg.Group().NextPkg(P)) { if (P->CurrentVer != 0 || P == Pkg || List->IsFlag(P,pkgOrderList::UnPacked) == true || + List->IsFlag(P,pkgOrderList::Configured) == true || Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer && (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)) continue; @@ -808,13 +946,15 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c } } // packages which are already unpacked don't need to be unpacked again - else if (Pkg.State() != pkgCache::PkgIterator::NeedsConfigure && Install(Pkg,FileNames[Pkg->ID]) == false) + else if ((instVer != Pkg.CurrentVer() || + ((Cache[Pkg].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)) && + Install(Pkg,FileNames[Pkg->ID]) == false) return false; 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); } @@ -850,21 +990,14 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() for (pkgOrderList::iterator I = List->begin(); I != List->end(); ++I) { PkgIterator Pkg(Cache,*I); - + if (List->IsNow(Pkg) == false) { - if (!List->IsFlag(Pkg,pkgOrderList::Configured) && !NoImmConfigure) { - if (SmartConfigure(Pkg, 0) == false && Debug) - _error->Warning("Internal Error, Could not configure %s",Pkg.FullName().c_str()); - // FIXME: The above warning message might need changing - } else { - if (Debug == true) - clog << "Skipping already done " << Pkg.FullName() << endl; - } + if (Debug == true) + clog << "Skipping already done " << Pkg.FullName() << endl; continue; - } - + if (List->IsMissing(Pkg) == true) { if (Debug == true) @@ -898,7 +1031,7 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() DoneSomething = true; if (ImmConfigureAll) { - /* ConfigureAll here to pick up and packages left unconfigured becuase they were unpacked in the + /* ConfigureAll here to pick up and packages left unconfigured because they were unpacked in the "PreUnpack Checks" section */ if (!ConfigureAll()) return Failed; @@ -921,33 +1054,79 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() } return Completed; +} +// PM::DoInstallPostFork - compat /*{{{*/ +// --------------------------------------------------------------------- + /*}}}*/ +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +pkgPackageManager::OrderResult +pkgPackageManager::DoInstallPostFork(int statusFd) +{ + APT::Progress::PackageManager *progress = new + APT::Progress::PackageManagerProgressFd(statusFd); + pkgPackageManager::OrderResult res = DoInstallPostFork(progress); + delete progress; + return res; } /*}}}*/ // PM::DoInstallPostFork - Does install part that happens after the fork /*{{{*/ // --------------------------------------------------------------------- pkgPackageManager::OrderResult -pkgPackageManager::DoInstallPostFork(int statusFd) +pkgPackageManager::DoInstallPostFork(APT::Progress::PackageManager *progress) { - if(statusFd > 0) - // FIXME: use SetCloseExec here once it taught about throwing - // exceptions instead of doing _exit(100) on failure - fcntl(statusFd,F_SETFD,FD_CLOEXEC); - bool goResult = Go(statusFd); - if(goResult == false) - return Failed; - - return Res; + bool goResult = Go(progress); + if(goResult == false) + return Failed; + + return Res; }; +#else +pkgPackageManager::OrderResult +pkgPackageManager::DoInstallPostFork(int statusFd) +{ + bool goResult = Go(statusFd); + if(goResult == false) + return Failed; + + return Res; +} +#endif + /*}}}*/ +// PM::DoInstall - Does the installation /*{{{*/ +// --------------------------------------------------------------------- +/* compat */ +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +pkgPackageManager::OrderResult +pkgPackageManager::DoInstall(int statusFd) +{ + APT::Progress::PackageManager *progress = new + APT::Progress::PackageManagerProgressFd(statusFd); + OrderResult res = DoInstall(progress); + delete progress; + return res; + } +#else +pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) +{ + if(DoInstallPreFork() == Failed) + return Failed; + return DoInstallPostFork(statusFd); +} +#endif + /*}}}*/ // PM::DoInstall - Does the installation /*{{{*/ // --------------------------------------------------------------------- /* This uses the filenames in FileNames and the information in the DepCache to perform the installation of packages.*/ -pkgPackageManager::OrderResult pkgPackageManager::DoInstall(int statusFd) +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +pkgPackageManager::OrderResult +pkgPackageManager::DoInstall(APT::Progress::PackageManager *progress) { if(DoInstallPreFork() == Failed) return Failed; - return DoInstallPostFork(statusFd); + return DoInstallPostFork(progress); } +#endif /*}}}*/