Bug fixes
[ntk/apt.git] / cmdline / apt-get.cc
index a30c983..3074435 100644 (file)
@@ -1,6 +1,6 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: apt-get.cc,v 1.83 1999/10/22 05:58:54 jgg Exp $
+// $Id: apt-get.cc,v 1.99 2000/06/05 04:47:30 jgg Exp $
 /* ######################################################################
    
    apt-get - Cover for dpkg
@@ -47,7 +47,7 @@
 #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>
@@ -516,7 +516,8 @@ 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)
    {
@@ -554,6 +555,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
        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)
    {
@@ -613,16 +618,6 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
       c1out << SizeToStr(DebBytes) << 'B';
       
    c1out << " of archives. After unpacking ";
-
-   // 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 to hold all the .debs.",
-                          OutputDir.c_str());
    
    // Size delta
    if (Cache->UsrSize() >= 0)
@@ -633,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)
@@ -643,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;
@@ -653,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)
         {
@@ -684,13 +699,33 @@ 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 &&
@@ -703,16 +738,16 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true,bool Saftey =
            // 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 then there were
+      /* 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 && 
+      if (Transient == true &&
          _config->FindB("APT::Get::No-Download",false) == true)
       {
         Transient = false;
@@ -740,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)
@@ -769,7 +804,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
        Pkg.ProvidesList()->NextProvides == 0)
    {
       pkgCache::PkgIterator Tmp = Pkg.ProvidesList().OwnerPkg();
-      c1out << "Note, installing " << Tmp.Name() << " instead of " << Pkg.Name() << endl;
+      c1out << "Note, selecting " << Tmp.Name() << " instead of " << Pkg.Name() << endl;
       Pkg = Tmp;
    }
    
@@ -784,7 +819,14 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
    
    // Check if there is something at all to install
    pkgDepCache::StateCache &State = Cache[Pkg];
-   if (State.CandidateVer == 0)
+   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;
@@ -813,7 +855,8 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       {
         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, or that it is an obsolete package." << 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();
@@ -829,8 +872,9 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache,
       _error->Error("Package %s has no installation candidate",Pkg.Name());
       return false;
    }
-   
-   Fix.Protect(Pkg);
+
+   Fix.Clear(Pkg);
+   Fix.Protect(Pkg);   
    if (Remove == true)
    {
       Fix.Remove(Pkg);
@@ -915,7 +959,7 @@ bool DoUpdate(CommandLine &)
    }
    
    // Clean out any old list files
-   if (_config->FindB("APT::Get::List-Cleanup",false) == 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)
@@ -1216,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/");
@@ -1231,7 +1291,7 @@ class LogCleaner : public pkgArchiveCleaner
    protected:
    virtual void Erase(const char *File,string Pkg,string Ver,struct stat &St) 
    {
-      cout << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << endl;
+      c1out << "Del " << Pkg << " " << Ver << " [" << SizeToStr(St.st_size) << "B]" << endl;
       
       if (_config->FindB("APT::Get::Simulate") == false)
         unlink(File);      
@@ -1240,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;
@@ -1402,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",
@@ -1469,9 +1538,10 @@ bool DoSource(CommandLine &CmdL)
         
         // Diff only mode only fetches .diff files
         if (_config->FindB("APT::Get::Diff-Only",false) == true ||
-            _config->FindB("APT::Get::Tar-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 &&
@@ -1541,7 +1611,8 @@ bool ShowHelp(CommandLine &CmdL)
       return 100;
        
    cout << "Usage: apt-get [options] command" << endl;
-   cout << "       apt-get [options] install pkg1 [pkg2 ...]" << endl;
+   cout << "       apt-get [options] install|remove pkg1 [pkg2 ...]" << endl;
+   cout << "       apt-get [options] source pkg1 [pkg2 ...]" << endl;
    cout << endl;
    cout << "apt-get is a simple command line interface for downloading and" << endl;
    cout << "installing packages. The most frequently used commands are update" << endl;
@@ -1617,11 +1688,12 @@ 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',"dry-run","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},
@@ -1637,6 +1709,8 @@ int main(int argc,const char *argv[])
       {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}};
@@ -1667,11 +1741,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());