]> git.saurik.com Git - apt.git/blobdiff - cmdline/apt-get.cc
* Space check is supressed if --print-uris is given. Cl...
[apt.git] / cmdline / apt-get.cc
index dc1e89ae5621f026c3e690bc090f9c7761620fe7..4558f7cf3ff070c46c1d9370527cf705e81fadf0 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: apt-get.cc,v 1.68 1999/07/09 04:11:34 jgg Exp $
+// $Id: apt-get.cc,v 1.96 2000/05/10 06:03:01 jgg Exp $
 /* ######################################################################
    
    apt-get - Cover for dpkg
 #include <termios.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <sys/vfs.h>
+#include <sys/statvfs.h>
 #include <signal.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <errno.h>
+#include <regex.h>
 #include <sys/wait.h>
                                                                        /*}}}*/
 
@@ -61,6 +62,31 @@ ostream c2out;
 ofstream devnull("/dev/null");
 unsigned int ScreenWidth = 80;
 
+// class CacheFile - Cover class for some dependency cache functions   /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+class CacheFile : public pkgCacheFile
+{
+   static pkgCache *SortCache;
+   static int NameComp(const void *a,const void *b);
+   
+   public:
+   pkgCache::Package **List;
+   
+   void Sort();
+   bool CheckDeps(bool AllowBroken = false);
+   bool Open(bool WithLock = true) 
+   {
+      OpTextProgress Prog(*_config);
+      if (pkgCacheFile::Open(Prog,WithLock) == false)
+        return false;
+      Sort();
+      return true;
+   };
+   CacheFile() : List(0) {};
+};
+                                                                       /*}}}*/
+
 // YnPrompt - Yes No Prompt.                                           /*{{{*/
 // ---------------------------------------------------------------------
 /* Returns true on a Yes.*/
@@ -129,18 +155,19 @@ bool ShowList(ostream &out,string Title,string List)
 /* This prints out the names of all the packages that are broken along
    with the name of each each broken dependency and a quite version 
    description. */
-void ShowBroken(ostream &out,pkgDepCache &Cache)
+void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
 {
    out << "Sorry, but the following packages have unmet dependencies:" << endl;
-   pkgCache::PkgIterator I = Cache.PkgBegin();
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      
       if (Cache[I].InstBroken() == false)
          continue;
          
       // Print out each package and the failed dependencies
       out <<"  " <<  I.Name() << ":";
-      int Indent = strlen(I.Name()) + 3;
+      unsigned Indent = strlen(I.Name()) + 3;
       bool First = true;
       if (Cache[I].InstVerIter(Cache).end() == true)
       {
@@ -155,47 +182,65 @@ void ShowBroken(ostream &out,pkgDepCache &Cache)
         pkgCache::DepIterator End;
         D.GlobOr(Start,End);
 
-        if (Cache.IsImportantDep(End) == false || 
+        if (Cache->IsImportantDep(End) == false || 
             (Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
            continue;
-        
-        if (First == false)
-           for (int J = 0; J != Indent; J++)
-              out << ' ';
-        First = false;
 
-        out << ' ' << End.DepType() << ": " << End.TargetPkg().Name();
-        
-        // Show a quick summary of the version requirements
-        if (End.TargetVer() != 0)
-           out << " (" << End.CompType() << " " << End.TargetVer() << 
-           ")";
-        
-        /* Show a summary of the target package if possible. In the case
-         of virtual packages we show nothing */
-        
-        pkgCache::PkgIterator Targ = End.TargetPkg();
-        if (Targ->ProvidesList == 0)
+        bool FirstOr = true;
+        while (1)
         {
-           out << " but ";
-           pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
-           if (Ver.end() == false)
-              out << Ver.VerStr() << " is installed";
+           if (First == false)
+              for (unsigned J = 0; J != Indent; J++)
+                 out << ' ';
+           First = false;
+
+           if (FirstOr == false)
+           {
+              for (unsigned J = 0; J != strlen(End.DepType()) + 3; J++)
+                 out << ' ';
+           }
            else
+              out << ' ' << End.DepType() << ": ";
+           FirstOr = false;
+           
+           out << Start.TargetPkg().Name();
+        
+           // Show a quick summary of the version requirements
+           if (Start.TargetVer() != 0)
+              out << " (" << Start.CompType() << " " << Start.TargetVer() << 
+              ")";
+           
+           /* Show a summary of the target package if possible. In the case
+              of virtual packages we show nothing */    
+           pkgCache::PkgIterator Targ = Start.TargetPkg();
+           if (Targ->ProvidesList == 0)
            {
-              if (Cache[Targ].CandidateVerIter(Cache).end() == true)
+              out << " but ";
+              pkgCache::VerIterator Ver = Cache[Targ].InstVerIter(Cache);
+              if (Ver.end() == false)
+                 out << Ver.VerStr() << (Now?" is installed":" is to be installed");
+              else
               {
-                 if (Targ->ProvidesList == 0)
-                    out << "it is not installable";
+                 if (Cache[Targ].CandidateVerIter(Cache).end() == true)
+                 {
+                    if (Targ->ProvidesList == 0)
+                       out << "it is not installable";
+                    else
+                       out << "it is a virtual package";
+                 }               
                  else
-                    out << "it is a virtual package";
-              }                  
-              else
-                 out << "it is not installed";
-           }          
-        }
-        
-        out << endl;
+                    out << (Now?"it is not installed":"it is not going to be installed");
+              }               
+           }
+           
+           if (Start != End)
+              cout << " or";
+           out << endl;
+           
+           if (Start == End)
+              break;
+           Start++;
+        }       
       }            
    }   
 }
@@ -203,32 +248,35 @@ void ShowBroken(ostream &out,pkgDepCache &Cache)
 // ShowNew - Show packages to newly install                            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void ShowNew(ostream &out,pkgDepCache &Dep)
+void ShowNew(ostream &out,CacheFile &Cache)
 {
    /* Print out a list of packages that are going to be removed extra
       to what the user asked */
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   for (;I.end() != true; I++)
-      if (Dep[I].NewInstall() == true)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
+   {
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      if (Cache[I].NewInstall() == true)
         List += string(I.Name()) + " ";
+   }
+   
    ShowList(out,"The following NEW packages will be installed:",List);
 }
                                                                        /*}}}*/
 // ShowDel - Show packages to delete                                   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void ShowDel(ostream &out,pkgDepCache &Dep)
+void ShowDel(ostream &out,CacheFile &Cache)
 {
    /* Print out a list of packages that are going to be removed extra
       to what the user asked */
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {
-      if (Dep[I].Delete() == true)
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      if (Cache[I].Delete() == true)
       {
-        if ((Dep[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
+        if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge)
            List += string(I.Name()) + "* ";
         else
            List += string(I.Name()) + " ";
@@ -241,15 +289,16 @@ void ShowDel(ostream &out,pkgDepCache &Dep)
 // ShowKept - Show kept packages                                       /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void ShowKept(ostream &out,pkgDepCache &Dep)
+void ShowKept(ostream &out,CacheFile &Cache)
 {
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {    
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      
       // Not interesting
-      if (Dep[I].Upgrade() == true || Dep[I].Upgradable() == false ||
-         I->CurrentVer == 0 || Dep[I].Delete() == true)
+      if (Cache[I].Upgrade() == true || Cache[I].Upgradable() == false ||
+         I->CurrentVer == 0 || Cache[I].Delete() == true)
         continue;
       
       List += string(I.Name()) + " ";
@@ -260,14 +309,15 @@ void ShowKept(ostream &out,pkgDepCache &Dep)
 // ShowUpgraded - Show upgraded packages                               /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void ShowUpgraded(ostream &out,pkgDepCache &Dep)
+void ShowUpgraded(ostream &out,CacheFile &Cache)
 {
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      
       // Not interesting
-      if (Dep[I].Upgrade() == false || Dep[I].NewInstall() == true)
+      if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true)
         continue;
       
       List += string(I.Name()) + " ";
@@ -278,13 +328,13 @@ void ShowUpgraded(ostream &out,pkgDepCache &Dep)
 // ShowHold - Show held but changed packages                           /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool ShowHold(ostream &out,pkgDepCache &Dep)
+bool ShowHold(ostream &out,CacheFile &Cache)
 {
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {
-      if (Dep[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
+      if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() &&
          I->SelectedState == pkgCache::State::Hold)
         List += string(I.Name()) + " ";
    }
@@ -297,21 +347,21 @@ bool ShowHold(ostream &out,pkgDepCache &Dep)
 /* This prints out a warning message that is not to be ignored. It shows
    all essential packages and their dependents that are to be removed. 
    It is insanely risky to remove the dependents of an essential package! */
-bool ShowEssential(ostream &out,pkgDepCache &Dep)
+bool ShowEssential(ostream &out,CacheFile &Cache)
 {
-   pkgCache::PkgIterator I = Dep.PkgBegin();
    string List;
-   bool *Added = new bool[Dep.HeaderP->PackageCount];
-   for (unsigned int I = 0; I != Dep.HeaderP->PackageCount; I++)
+   bool *Added = new bool[Cache->HeaderP->PackageCount];
+   for (unsigned int I = 0; I != Cache->HeaderP->PackageCount; I++)
       Added[I] = false;
    
-   for (;I.end() != true; I++)
+   for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
    {
+      pkgCache::PkgIterator I(Cache,Cache.List[J]);
       if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential)
         continue;
       
       // The essential package is being removed
-      if (Dep[I].Delete() == true)
+      if (Cache[I].Delete() == true)
       {
         if (Added[I->ID] == false)
         {
@@ -332,7 +382,7 @@ bool ShowEssential(ostream &out,pkgDepCache &Dep)
            continue;
         
         pkgCache::PkgIterator P = D.SmartTargetPkg();
-        if (Dep[P].Delete() == true)
+        if (Cache[P].Delete() == true)
         {
            if (Added[P->ID] == true)
               continue;
@@ -358,6 +408,7 @@ void Stats(ostream &out,pkgDepCache &Dep)
 {
    unsigned long Upgrade = 0;
    unsigned long Install = 0;
+   unsigned long ReInstall = 0;
    for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++)
    {
       if (Dep[I].NewInstall() == true)
@@ -365,11 +416,15 @@ void Stats(ostream &out,pkgDepCache &Dep)
       else
         if (Dep[I].Upgrade() == true)
            Upgrade++;
+      if (Dep[I].Delete() == false && (Dep[I].iFlags & pkgDepCache::ReInstall) == pkgDepCache::ReInstall)
+        ReInstall++;
    }   
 
    out << Upgrade << " packages upgraded, " << 
-      Install << " newly installed, " <<
-      Dep.DelCount() << " to remove and " << 
+      Install << " newly installed, ";
+   if (ReInstall != 0)
+      out << ReInstall << " reinstalled, ";
+   out << Dep.DelCount() << " to remove and " << 
       Dep.KeepCount() << " not upgraded." << endl;
 
    if (Dep.BadCount() != 0)
@@ -377,20 +432,36 @@ void Stats(ostream &out,pkgDepCache &Dep)
 }
                                                                        /*}}}*/
 
-// class CacheFile - Cover class for some dependency cache functions   /*{{{*/
+// CacheFile::NameComp - QSort compare by name                         /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-class CacheFile : public pkgCacheFile
+pkgCache *CacheFile::SortCache = 0;
+int CacheFile::NameComp(const void *a,const void *b)
 {
-   public:
+   if (*(pkgCache::Package **)a == 0 || *(pkgCache::Package **)b == 0)
+      return *(pkgCache::Package **)a - *(pkgCache::Package **)b;
    
-   bool CheckDeps(bool AllowBroken = false);
-   bool Open(bool WithLock = true) 
-   {
-      OpTextProgress Prog(*_config); 
-      return pkgCacheFile::Open(Prog,WithLock);
-   };
-};
+   const pkgCache::Package &A = **(pkgCache::Package **)a;
+   const pkgCache::Package &B = **(pkgCache::Package **)b;
+
+   return strcmp(SortCache->StrP + A.Name,SortCache->StrP + B.Name);
+}
+                                                                       /*}}}*/
+// CacheFile::Sort - Sort by name                                      /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void CacheFile::Sort()
+{
+   delete [] List;
+   List = new pkgCache::Package *[Cache->Head().PackageCount];
+   memset(List,0,sizeof(*List)*Cache->Head().PackageCount);
+   pkgCache::PkgIterator I = Cache->PkgBegin();
+   for (;I.end() != true; I++)
+      List[I->ID] = I;
+
+   SortCache = *this;
+   qsort(List,Cache->Head().PackageCount,sizeof(*List),NameComp);
+}
                                                                        /*}}}*/
 // CacheFile::Open - Open the cache file                               /*{{{*/
 // ---------------------------------------------------------------------
@@ -420,7 +491,7 @@ bool CacheFile::CheckDeps(bool AllowBroken)
       if (pkgFixBroken(*Cache) == false || Cache->BrokenCount() != 0)
       {
         c1out << " failed." << endl;
-        ShowBroken(c1out,*this);
+        ShowBroken(c1out,*this,true);
 
         return _error->Error("Unable to correct dependencies");
       }
@@ -432,7 +503,7 @@ bool CacheFile::CheckDeps(bool AllowBroken)
    else
    {
       c1out << "You might want to run `apt-get -f install' to correct these." << endl;
-      ShowBroken(c1out,*this);
+      ShowBroken(c1out,*this,true);
 
       return _error->Error("Unmet dependencies. Try using -f.");
    }
@@ -445,13 +516,17 @@ bool CacheFile::CheckDeps(bool AllowBroken)
 // ---------------------------------------------------------------------
 /* This displays the informative messages describing what is going to 
    happen and then calls the download routines */
-bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey = true)
+bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,
+                    bool Saftey = true)
 {
    if (_config->FindB("APT::Get::Purge",false) == true)
    {
       pkgCache::PkgIterator I = Cache->PkgBegin();
       for (; I.end() == false; I++)
-        Cache[I].iFlags |= pkgDepCache::Purge;
+      {
+        if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete)
+           Cache->MarkDelete(I,true);
+      }
    }
    
    bool Fail = false;
@@ -472,14 +547,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
    // Sanity check
    if (Cache->BrokenCount() != 0)
    {
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
       return _error->Error("Internal Error, InstallPackages was called with broken packages!");
    }
 
-   if (Cache->DelCount() == 0 && Cache->InstCount() == 0 && 
+   if (Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
        Cache->BadCount() == 0)
       return true;
 
+   // No remove flag
+   if (Cache->DelCount() != 0 && _config->FindB("APT::Get::No-Remove",false) == true)
+      return _error->Error("Packages need to be removed but No Remove was specified.");
+       
    // Run the simulator ..
    if (_config->FindB("APT::Get::Simulate") == true)
    {
@@ -530,16 +609,6 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
       c0out << DebBytes << ',' << Cache->DebSize() << endl;
       c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl;
    }
-
-   // Check for enough free space
-   struct statfs Buf;
-   string OutputDir = _config->FindDir("Dir::Cache::Archives");
-   if (statfs(OutputDir.c_str(),&Buf) != 0)
-      return _error->Errno("statfs","Couldn't determine free space in %s",
-                          OutputDir.c_str());
-   if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
-      return _error->Error("Sorry, you don't have enough free space in %s",
-                          OutputDir.c_str());
    
    // Number of bytes
    c1out << "Need to get ";
@@ -559,6 +628,20 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
    if (_error->PendingError() == true)
       return false;
 
+   /* Check for enough free space, but only if we are actually going to
+      download */
+   if (_config->FindB("APT::Get::Print-URIs") == false)
+   {
+      struct statvfs Buf;
+      string OutputDir = _config->FindDir("Dir::Cache::Archives");
+      if (statvfs(OutputDir.c_str(),&Buf) != 0)
+        return _error->Errno("statvfs","Couldn't determine free space in %s",
+                             OutputDir.c_str());
+      if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
+        return _error->Error("Sorry, you don't have enough free space in %s to hold all the .debs.",
+                             OutputDir.c_str());
+   }
+   
    // Fail safe check
    if (_config->FindI("quiet",0) >= 2 ||
        _config->FindB("APT::Get::Assume-Yes",false) == true)
@@ -569,6 +652,9 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
 
    if (Essential == true && Saftey == true)
    {
+      if (_config->FindB("APT::Get::Trivial-Only",false) == true)
+        return _error->Error("Trivial Only specified but this is not a trivial operation.");
+      
       c2out << "You are about to do something potentially harmful" << endl;
       c2out << "To continue type in the phrase 'Yes, I understand this may be bad'" << endl;
       c2out << " ?] " << flush;
@@ -579,10 +665,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
       }     
    }
    else
-   {
+   {      
       // Prompt to continue
       if (Ask == true || Fail == true)
       {            
+        if (_config->FindB("APT::Get::Trivial-Only",false) == true)
+           return _error->Error("Trivial Only specified but this is not a trivial operation.");
+        
         if (_config->FindI("quiet",0) < 2 &&
             _config->FindB("APT::Get::Assume-Yes",false) == false)
         {
@@ -610,32 +699,60 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
    // Run it
    while (1)
    {
-      if (_config->FindB("APT::Get::No-Download",false) == false)
-        if( Fetcher.Run() == pkgAcquire::Failed)
-           return false;
+      bool Transient = false;
+      if (_config->FindB("APT::Get::No-Download",false) == true)
+      {
+        for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();)
+        {
+           if ((*I)->Local == true)
+           {
+              I++;
+              continue;
+           }
+
+           // Close the item and check if it was found in cache
+           (*I)->Finished();
+           if ((*I)->Complete == false)
+              Transient = true;
+           
+           // Clear it out of the fetch list
+           delete *I;
+           I = Fetcher.ItemsBegin();
+        }       
+      }
+      
+      if (Fetcher.Run() == pkgAcquire::Failed)
+        return false;
       
       // Print out errors
       bool Failed = false;
-      bool Transient = false;
       for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
       {
         if ((*I)->Status == pkgAcquire::Item::StatDone &&
             (*I)->Complete == true)
            continue;
         
-        (*I)->Finished();
-        
         if ((*I)->Status == pkgAcquire::Item::StatIdle)
         {
            Transient = true;
            // Failed = true;
            continue;
         }
-        
+
         cerr << "Failed to fetch " << (*I)->DescURI() << endl;
         cerr << "  " << (*I)->ErrorText << endl;
         Failed = true;
       }
+
+      /* If we are in no download mode and missing files and there were
+         'failures' then the user must specify -m. Furthermore, there 
+         is no such thing as a transient error in no-download mode! */
+      if (Transient == true &&
+         _config->FindB("APT::Get::No-Download",false) == true)
+      {
+        Transient = false;
+        Failed = true;
+      }
       
       if (_config->FindB("APT::Get::Download-Only",false) == true)
       {
@@ -646,12 +763,6 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
       
       if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false)
       {
-        /*if (Transient == true)
-        {
-           c2out << "Upgrading with disk swapping is not supported in this version." << endl;
-           c2out << "Try running multiple times with --fix-missing" << endl;
-        }*/
-        
         return _error->Error("Unable to fetch some archives, maybe try with --fix-missing?");
       }
       
@@ -664,7 +775,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
         cerr << "Unable to correct missing packages." << endl;
         return _error->Error("Aborting Install.");
       }
-      
+                
       Cache.ReleaseLock();
       pkgPackageManager::OrderResult Res = PM.DoInstall();
       if (Res == pkgPackageManager::Failed || _error->PendingError() == true)
@@ -679,6 +790,124 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
    }   
 }
                                                                        /*}}}*/
+// TryToInstall - Try to install a single package                      /*{{{*/
+// ---------------------------------------------------------------------
+/* This used to be inlined in DoInstall, but with the advent of regex package
+   name matching it was split out.. */
+bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
+                 pkgProblemResolver &Fix,bool Remove,bool BrokenFix,
+                 unsigned int &ExpectedInst,bool AllowFail = true)
+{
+   /* This is a pure virtual package and there is a single available 
+      provides */
+   if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0 &&
+       Pkg.ProvidesList()->NextProvides == 0)
+   {
+      pkgCache::PkgIterator Tmp = Pkg.ProvidesList().OwnerPkg();
+      c1out << "Note, selecting " << Tmp.Name() << " instead of " << Pkg.Name() << endl;
+      Pkg = Tmp;
+   }
+   
+   // Handle the no-upgrade case
+   if (_config->FindB("APT::Get::no-upgrade",false) == true &&
+       Pkg->CurrentVer != 0)
+   {
+      if (AllowFail == true)
+        c1out << "Skipping " << Pkg.Name() << ", it is already installed and no-upgrade is set." << endl;
+      return true;
+   }
+   
+   // Check if there is something at all to install
+   pkgDepCache::StateCache &State = Cache[Pkg];
+   if (Remove == true && Pkg->CurrentVer == 0)
+   {
+      if (AllowFail == false)
+        return false;
+      return _error->Error("Package %s is not installed",Pkg.Name());
+   }
+   
+   if (State.CandidateVer == 0 && Remove == false)
+   {
+      if (AllowFail == false)
+        return false;
+      
+      if (Pkg->ProvidesList != 0)
+      {
+        c1out << "Package " << Pkg.Name() << " is a virtual package provided by:" << endl;
+        
+        pkgCache::PrvIterator I = Pkg.ProvidesList();
+        for (; I.end() == false; I++)
+        {
+           pkgCache::PkgIterator Pkg = I.OwnerPkg();
+           
+           if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer())
+           {
+              if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
+                 c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() <<
+                 " [Installed]"<< endl;
+              else
+                 c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl;
+           }      
+        }
+        c1out << "You should explicitly select one to install." << endl;
+      }
+      else
+      {
+        c1out << "Package " << Pkg.Name() << " has no available version, but exists in the database." << endl;
+        c1out << "This typically means that the package was mentioned in a dependency and " << endl;
+        c1out << "never uploaded, has been obsoleted or is not available with the contents " << endl;
+        c1out << "of sources.list" << endl;
+        
+        string List;
+        pkgCache::DepIterator Dep = Pkg.RevDependsList();
+        for (; Dep.end() == false; Dep++)
+        {
+           if (Dep->Type != pkgCache::Dep::Replaces)
+              continue;
+           List += string(Dep.ParentPkg().Name()) + " ";
+        }          
+        ShowList(c1out,"However the following packages replace it:",List);
+      }
+      
+      _error->Error("Package %s has no installation candidate",Pkg.Name());
+      return false;
+   }
+
+   Fix.Clear(Pkg);
+   Fix.Protect(Pkg);   
+   if (Remove == true)
+   {
+      Fix.Remove(Pkg);
+      Cache.MarkDelete(Pkg,_config->FindB("APT::Get::Purge",false));
+      return true;
+   }
+   
+   // Install it
+   Cache.MarkInstall(Pkg,false);
+   if (State.Install() == false)
+   {
+      if (_config->FindB("APT::Get::ReInstall",false) == true)
+      {
+        if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false)
+           c1out << "Sorry, re-installation of " << Pkg.Name() << " is not possible, it cannot be downloaded" << endl;
+        else
+           Cache.SetReInstall(Pkg,true);
+      }      
+      else
+      {
+        if (AllowFail == true)
+           c1out << "Sorry, " << Pkg.Name() << " is already the newest version"  << endl;
+      }      
+   }   
+   else
+      ExpectedInst++;
+   
+   // Install it with autoinstalling enabled.
+   if (State.InstBroken() == true && BrokenFix == false)
+      Cache.MarkInstall(Pkg,true);
+   return true;
+}
+                                                                       /*}}}*/
 
 // DoUpdate - Update the package lists                                 /*{{{*/
 // ---------------------------------------------------------------------
@@ -716,16 +945,34 @@ bool DoUpdate(CommandLine &)
    if (Fetcher.Run() == pkgAcquire::Failed)
       return false;
 
+   bool Failed = false;
+   for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+   {
+      if ((*I)->Status == pkgAcquire::Item::StatDone)
+        continue;
+
+      (*I)->Finished();
+      
+      cerr << "Failed to fetch " << (*I)->DescURI() << endl;
+      cerr << "  " << (*I)->ErrorText << endl;
+      Failed = true;
+   }
+   
    // Clean out any old list files
-   if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
-       Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
-      return false;
+   if (_config->FindB("APT::Get::List-Cleanup",true) == true)
+   {
+      if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
+         Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
+        return false;
+   }
    
    // Prepare the cache.   
    CacheFile Cache;
    if (Cache.Open() == false)
       return false;
    
+   if (Failed == true)
+      return _error->Error("Some index files failed to download, they have been ignored, or old ones used instead.");
    return true;
 }
                                                                        /*}}}*/
@@ -742,7 +989,7 @@ bool DoUpgrade(CommandLine &CmdL)
    // Do the upgrade
    if (pkgAllUpgrade(Cache) == false)
    {
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
       return _error->Error("Internal Error, AllUpgrade broke stuff");
    }
    
@@ -805,78 +1052,44 @@ bool DoInstall(CommandLine &CmdL)
       pkgCache::PkgIterator Pkg = Cache->FindPkg(S);
       Packages++;
       if (Pkg.end() == true)
-        return _error->Error("Couldn't find package %s",S);
-      
-      // Handle the no-upgrade case
-      if (_config->FindB("APT::Get::no-upgrade",false) == true &&
-         Pkg->CurrentVer != 0)
-      {
-        c1out << "Skipping " << Pkg.Name() << ", it is already installed and no-upgrade is set." << endl;
-        continue;
-      }
-      
-      // Check if there is something new to install
-      pkgDepCache::StateCache &State = (*Cache)[Pkg];
-      if (State.CandidateVer == 0)
       {
-        if (Pkg->ProvidesList != 0)
-        {
-           c1out << "Package " << S << " is a virtual package provided by:" << endl;
-
-           pkgCache::PrvIterator I = Pkg.ProvidesList();
-           for (; I.end() == false; I++)
-           {
-              pkgCache::PkgIterator Pkg = I.OwnerPkg();
-              
-              if ((*Cache)[Pkg].CandidateVerIter(*Cache) == I.OwnerVer())
-              {
-                 if ((*Cache)[Pkg].Install() == true && (*Cache)[Pkg].NewInstall() == false)
-                    c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() <<
-                    " [Installed]"<< endl;
-                 else
-                    c1out << "  " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl;
-              }      
-           }
-           c1out << "You should explicly select one to install." << endl;
-        }
-        else
+        // Check if the name is a regex
+        const char *I;
+        for (I = S; *I != 0; I++)
+           if (*I == '.' || *I == '?' || *I == '*')
+              break;
+        if (*I == 0)
+           return _error->Error("Couldn't find package %s",S);
+
+        // Regexs must always be confirmed
+        ExpectedInst += 1000;
+        
+        // Compile the regex pattern
+        regex_t Pattern;
+        if (regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE | 
+                    REG_NOSUB) != 0)
+           return _error->Error("Regex compilation error");
+        
+        // Run over the matches
+        bool Hit = false;
+        for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++)
         {
-           c1out << "Package " << S << " has no available version, but exists in the database." << endl;
-           c1out << "This typically means that the package was mentioned in a dependency and " << endl;
-           c1out << "never uploaded, or that it is an obsolete package." << endl;
+           if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0)
+              continue;
            
-           string List;
-           pkgCache::DepIterator Dep = Pkg.RevDependsList();
-           for (; Dep.end() == false; Dep++)
-           {
-              if (Dep->Type != pkgCache::Dep::Replaces)
-                 continue;
-              List += string(Dep.ParentPkg().Name()) + " ";
-           }       
-           ShowList(c1out,"However the following packages replace it:",List);
+           Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,
+                               ExpectedInst,false);
         }
+        regfree(&Pattern);
         
-        return _error->Error("Package %s has no installation candidate",S);
-      }
-      
-      Fix.Protect(Pkg);
-      if (Remove == true)
-      {
-        Fix.Remove(Pkg);
-        Cache->MarkDelete(Pkg);
-        continue;
+        if (Hit == false)
+           return _error->Error("Couldn't find package %s",S);
       }
-      
-      // Install it
-      Cache->MarkInstall(Pkg,false);
-      if (State.Install() == false)
-        c1out << "Sorry, " << S << " is already the newest version"  << endl;
       else
-        ExpectedInst++;
-
-      // Install it with autoinstalling enabled.
-      if (State.InstBroken() == true && BrokenFix == false)
-        Cache->MarkInstall(Pkg,true);
+      {
+        if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false)
+           return false;
+      }      
    }
 
    /* If we are in the Broken fixing mode we do not attempt to fix the
@@ -885,7 +1098,7 @@ bool DoInstall(CommandLine &CmdL)
    if (BrokenFix == true && Cache->BrokenCount() != 0)
    {
       c1out << "You might want to run `apt-get -f install' to correct these:" << endl;
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
 
       return _error->Error("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).");
    }
@@ -912,7 +1125,7 @@ bool DoInstall(CommandLine &CmdL)
 
       c1out << "The following information may help to resolve the situation:" << endl;
       c1out << endl;
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
       return _error->Error("Sorry, broken packages");
    }   
    
@@ -921,9 +1134,9 @@ bool DoInstall(CommandLine &CmdL)
    if (Cache->InstCount() != ExpectedInst)
    {
       string List;
-      pkgCache::PkgIterator I = Cache->PkgBegin();
-      for (;I.end() != true; I++)
+      for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
       {
+        pkgCache::PkgIterator I(Cache,Cache.List[J]);
         if ((*Cache)[I].Install() == false)
            continue;
 
@@ -959,7 +1172,7 @@ bool DoDistUpgrade(CommandLine &CmdL)
    if (pkgDistUpgrade(*Cache) == false)
    {
       c0out << "Failed" << endl;
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
       return false;
    }
    
@@ -1003,9 +1216,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
       // Remove packages 
       if (I->SelectedState == pkgCache::State::DeInstall ||
          I->SelectedState == pkgCache::State::Purge)
-        Cache->MarkDelete(I);
-      if (I->SelectedState == pkgCache::State::Purge)
-        Cache[I].iFlags |= pkgDepCache::Purge;
+        Cache->MarkDelete(I,I->SelectedState == pkgCache::State::Purge);
    }
 
    /* Resolve any problems that dselect created, allupgrade cannot handle
@@ -1029,7 +1240,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    
       if (Fix.Resolve() == false)
       {
-        ShowBroken(c1out,Cache);
+        ShowBroken(c1out,Cache,false);
         return _error->Error("Internal Error, problem resolver broke stuff");
       }
    }
@@ -1037,7 +1248,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
    // Now upgrade everything
    if (pkgAllUpgrade(Cache) == false)
    {
-      ShowBroken(c1out,Cache);
+      ShowBroken(c1out,Cache,false);
       return _error->Error("Internal Error, problem resolver broke stuff");
    }
    
@@ -1049,6 +1260,22 @@ bool DoDSelectUpgrade(CommandLine &CmdL)
 /* */
 bool DoClean(CommandLine &CmdL)
 {
+   if (_config->FindB("APT::Get::Simulate") == true)
+   {
+      cout << "Del " << _config->FindDir("Dir::Cache::archives") << "* " <<
+        _config->FindDir("Dir::Cache::archives") << "partial/*" << endl;
+      return true;
+   }
+   
+   // Lock the archive directory
+   FileFd Lock;
+   if (_config->FindB("Debug::NoLocking",false) == false)
+   {
+      Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
+      if (_error->PendingError() == true)
+        return _error->Error("Unable to lock the download directory");
+   }
+   
    pkgAcquire Fetcher;
    Fetcher.Clean(_config->FindDir("Dir::Cache::archives"));
    Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/");
@@ -1073,6 +1300,15 @@ class LogCleaner : public pkgArchiveCleaner
 
 bool DoAutoClean(CommandLine &CmdL)
 {
+   // Lock the archive directory
+   FileFd Lock;
+   if (_config->FindB("Debug::NoLocking",false) == false)
+   {
+      Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
+      if (_error->PendingError() == true)
+        return _error->Error("Unable to lock the download directory");
+   }
+   
    CacheFile Cache;
    if (Cache.Open() == false)
       return false;
@@ -1213,6 +1449,16 @@ bool DoSource(CommandLine &CmdL)
         if (I->Path.find(".diff.gz") != string::npos)
            Comp = "diff";
         
+        // Diff only mode only fetches .diff files
+        if (_config->FindB("APT::Get::Diff-Only",false) == true &&
+            Comp != "diff")
+           continue;
+        
+        // Tar only mode only fetches .tar files
+        if (_config->FindB("APT::Get::Tar-Only",false) == true &&
+            Comp != "tar")
+           continue;
+        
         new pkgAcqFile(&Fetcher,Last->Source()->ArchiveURI(I->Path),
                        I->MD5Hash,I->Size,Last->Source()->SourceInfo(Src,
                        Last->Version(),Comp),Src);
@@ -1225,10 +1471,10 @@ bool DoSource(CommandLine &CmdL)
    unsigned long DebBytes = Fetcher.TotalNeeded();
 
    // Check for enough free space
-   struct statfs Buf;
+   struct statvfs Buf;
    string OutputDir = ".";
-   if (statfs(OutputDir.c_str(),&Buf) != 0)
-      return _error->Errno("statfs","Couldn't determine free space in %s",
+   if (statvfs(OutputDir.c_str(),&Buf) != 0)
+      return _error->Errno("statvfs","Couldn't determine free space in %s",
                           OutputDir.c_str());
    if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize)
       return _error->Error("Sorry, you don't have enough free space in %s",
@@ -1290,6 +1536,12 @@ bool DoSource(CommandLine &CmdL)
       {
         string Dir = Dsc[I].Package + '-' + pkgBaseVersion(Dsc[I].Version.c_str());
         
+        // Diff only mode only fetches .diff files
+        if (_config->FindB("APT::Get::Diff-Only",false) == true ||
+            _config->FindB("APT::Get::Tar-Only",false) == true ||
+            Dsc[I].Dsc.empty() == true)
+           continue;
+
         // See if the package is already unpacked
         struct stat Stat;
         if (stat(Dir.c_str(),&Stat) == 0 &&
@@ -1407,6 +1659,7 @@ void GetInitialize()
    _config->Set("APT::Get::Assume-Yes",false);
    _config->Set("APT::Get::Fix-Broken",false);
    _config->Set("APT::Get::Force-Yes",false);
+   _config->Set("APT::Get::APT::Get::No-List-Cleanup",true);
 }
                                                                        /*}}}*/
 // SigWinch - Window size change signal handler                                /*{{{*/
@@ -1434,11 +1687,11 @@ int main(int argc,const char *argv[])
       {'d',"download-only","APT::Get::Download-Only",0},
       {'b',"compile","APT::Get::Compile",0},
       {'b',"build","APT::Get::Compile",0},
-      {'s',"simulate","APT::Get::Simulate",0},      
-      {'s',"just-print","APT::Get::Simulate",0},      
-      {'s',"recon","APT::Get::Simulate",0},      
-      {'s',"no-act","APT::Get::Simulate",0},      
-      {'y',"yes","APT::Get::Assume-Yes",0},      
+      {'s',"simulate","APT::Get::Simulate",0},
+      {'s',"just-print","APT::Get::Simulate",0},
+      {'s',"recon","APT::Get::Simulate",0},
+      {'s',"no-act","APT::Get::Simulate",0},
+      {'y',"yes","APT::Get::Assume-Yes",0},
       {'y',"assume-yes","APT::Get::Assume-Yes",0},      
       {'f',"fix-broken","APT::Get::Fix-Broken",0},
       {'u',"show-upgraded","APT::Get::Show-Upgraded",0},
@@ -1449,7 +1702,13 @@ int main(int argc,const char *argv[])
       {0,"no-upgrade","APT::Get::no-upgrade",0},
       {0,"force-yes","APT::Get::force-yes",0},
       {0,"print-uris","APT::Get::Print-URIs",0},
+      {0,"diff-only","APT::Get::Diff-Only",0},
+      {0,"tar-only","APT::Get::tar-Only",0},
       {0,"purge","APT::Get::Purge",0},
+      {0,"list-cleanup","APT::Get::List-Cleanup",0},
+      {0,"reinstall","APT::Get::ReInstall",0},
+      {0,"trivial-only","APT::Get::Trivial-Only",0},
+      {0,"no-remove","APT::Get::No-Remove",0},
       {'c',"config-file",0,CommandLine::ConfigFile},
       {'o',"option",0,CommandLine::ArbItem},
       {0,0,0,0}};
@@ -1480,11 +1739,11 @@ int main(int argc,const char *argv[])
        _config->FindB("version") == true ||
        CmdL.FileSize() == 0)
       return ShowHelp(CmdL);
-
+   
    // Deal with stdout not being a tty
    if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
       _config->Set("quiet","1");
-   
+
    // Setup the output streams
    c0out.rdbuf(cout.rdbuf());
    c1out.rdbuf(cout.rdbuf());