X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/b829fb2602a506a01cb2b3fd371e975784d4377c..cc4800145b408de0b4afef88f4489a541024e75a:/apt-pkg/packagemanager.cc

diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index 698c8606f..5d6bc6bd2 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -13,7 +13,7 @@
    ##################################################################### */
 									/*}}}*/
 // Include Files							/*{{{*/
-#include<config.h>
+#include <config.h>
 
 #include <apt-pkg/packagemanager.h>
 #include <apt-pkg/orderlist.h>
@@ -24,10 +24,17 @@
 #include <apt-pkg/algorithms.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/sptr.h>
+#include <apt-pkg/macros.h>
+#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/cacheiterators.h>
+#include <apt-pkg/strutl.h>
+
+#include <stddef.h>
+#include <list>
+#include <string>
+#include <iostream>
 
 #include <apti18n.h>
-#include <iostream>
-#include <fcntl.h>
 									/*}}}*/
 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,11 +250,11 @@ 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;
       
@@ -314,7 +321,7 @@ bool pkgPackageManager::ConfigureAll()
    
    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
+   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*/
@@ -337,7 +344,11 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
       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;
-   do {
+   const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
+   unsigned int i=0;
+   std::list<DepIterator> needConfigure;
+   do
+   {
       Changed = false;
       for (DepIterator D = instVer.DependsList(); D.end() == false; )
       {
@@ -349,7 +360,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	    continue;
 	 Bad = true;
 
-	 // Search for dependencies which are unpacked but aren't configured yet (maybe loops)
+	 // Check for dependencies that have not been unpacked, probably due to loops.
 	 for (DepIterator Cur = Start; true; ++Cur)
 	 {
 	    SPtrArray<Version *> VList = Cur.AllTargets();
@@ -369,51 +380,66 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	       }
 
 	       // Check if the version that is going to be installed will satisfy the dependency
-	       if (Cache[DepPkg].InstallVer != *I)
+	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
 		  continue;
 
-	       if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
+	       if (PkgLoop == true)
 	       {
-		  if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
-		  {
-		    // This dependency has already been dealt with by another SmartConfigure on Pkg
-		    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 (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 (SmartConfigure(DepPkg, Depth + 1) == true)
+		  if (SmartUnPack(DepPkg, true, Depth + 1) == true)
 		  {
 		     Bad = false;
 		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-			Changed = true;
+		        Changed = true;
 		  }
 		  if (PkgLoop == false)
-		    List->RmFlag(Pkg,pkgOrderList::Loop);
-		  // If SmartConfigure was succesfull, Bad is false, so break
+		     List->RmFlag(Pkg,pkgOrderList::Loop);
 		  if (Bad == false)
 		     break;
 	       }
-	       else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
-	       {
-		  Bad = false;
-		  break;
-	       }
 	    }
-	    if (Cur == End)
+
+	    if (Cur == End || Bad == false)
 	       break;
-         }
+	 }
 
 	 if (Bad == false)
 	    continue;
 
-	 // Check for dependencies that have not been unpacked, probably due to loops.
+	 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);
+
+   Bad = false, Changed = false, i = 0;
+   do
+   {
+      Changed = false;
+      for (std::list<DepIterator>::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<Version *> VList = Cur.AllTargets();
@@ -424,42 +450,53 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth)
 	       PkgIterator DepPkg = Ver.ParentPkg();
 
 	       // Check if the version that is going to be installed will satisfy the dependency
-	       if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false)
+	       if (Cache[DepPkg].InstallVer != *I)
 		  continue;
 
-	       if (PkgLoop == true)
-	       {
-		  if (Debug)
-		     std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl;
-	          Bad = false;
-		  break;
-	       }
-	       else
+	       if (List->IsFlag(DepPkg,pkgOrderList::UnPacked))
 	       {
-		  if (Debug)
-		     clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl;
+		  if (List->IsFlag(DepPkg,pkgOrderList::Loop) && PkgLoop)
+		  {
+		    // This dependency has already been dealt with by another SmartConfigure on Pkg
+		    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 (SmartUnPack(DepPkg, true, Depth + 1) == true)
+		  if (SmartConfigure(DepPkg, Depth + 1) == true)
 		  {
 		     Bad = false;
 		     if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false)
-		        Changed = true;
+			Changed = true;
 		  }
 		  if (PkgLoop == false)
-		     List->RmFlag(Pkg,pkgOrderList::Loop);
+		    List->RmFlag(Pkg,pkgOrderList::Loop);
+		  // If SmartConfigure was succesfull, Bad is false, so break
 		  if (Bad == false)
 		     break;
 	       }
+	       else if (List->IsFlag(DepPkg,pkgOrderList::Configured))
+	       {
+		  Bad = false;
+		  break;
+	       }
 	    }
-
-	    if (Cur == End)
+	    if (Cur == End || Bad == false)
 	       break;
-	 }
+         }
+
 
 	 if (Bad == true && Changed == false && Debug == true)
-	    std::clog << OutputInDepth(Depth) << "Could not satisfy " << Start << std::endl;
+	    std::clog << OutputInDepth(Depth) << "Could not satisfy " << *D << std::endl;
       }
+      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) {
@@ -486,6 +523,7 @@ 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;
@@ -565,7 +603,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)
 {
@@ -584,6 +622,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
         clog << " (replace version " << Pkg.CurrentVer().VerStr() << " with " << InstallVer.VerStr() << ")";
       if (PkgLoop)
         clog << " (Only Perform PreUnpack Checks)";
+      if (Immediate)
+	 clog << " immediately";
       clog << endl;
    }
 
@@ -592,11 +632,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
    /* 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
       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 .
+      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;
-   do {
+   const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000);
+   unsigned int i = 0;
+   do 
+   {
       Changed = false;
       for (DepIterator D = instVer.DependsList(); D.end() == false; )
       {
@@ -613,7 +656,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 	    // Look for easy targets: packages that are already okay
 	    for (DepIterator Cur = Start; Bad == true; ++Cur)
 	    {
-	       SPtrArray<Version *> VList = Start.AllTargets();
+	       SPtrArray<Version *> VList = Cur.AllTargets();
 	       for (Version **I = VList; *I != 0; ++I)
 	       {
 		  VerIterator Ver(Cache,*I);
@@ -634,9 +677,9 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 	    }
 
 	    // Look for something that could be configured.
-	    for (DepIterator Cur = Start; Bad == true; ++Cur)
+	    for (DepIterator Cur = Start; Bad == true && Cur.end() == false; ++Cur)
 	    {
-	       SPtrArray<Version *> VList = Start.AllTargets();
+	       SPtrArray<Version *> VList = Cur.AllTargets();
 	       for (Version **I = VList; *I != 0; ++I)
 	       {
 		  VerIterator Ver(Cache,*I);
@@ -707,7 +750,8 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 	       // See if the current version is conflicting
 	       if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg))
 	       {
-		  clog << OutputInDepth(Depth) << Pkg.FullName() << " conflicts with " << ConflictPkg.FullName() << endl;
+		  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)
@@ -756,7 +800,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 	       {
 		  if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop)
 		  {
-		     // This dependancy has already been dealt with by another SmartUnPack on Pkg
+		     // This dependency has already been dealt with by another SmartUnPack on Pkg
 		     break;
 		  }
 		  else
@@ -776,7 +820,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c
 			   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))
+			   if (P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V))
 			      continue;
 			   circle = true;
 			   break;
@@ -821,6 +865,8 @@ 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);
    
    // Check for reverse conflicts.
@@ -845,7 +891,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))
@@ -863,6 +912,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;
@@ -871,7 +921,9 @@ 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) {
@@ -913,21 +965,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)
@@ -961,7 +1006,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; 
@@ -984,33 +1029,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
 									/*}}}*/