// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: apt-get.cc,v 1.73 1999/09/05 20:27:37 jgg Exp $
+// $Id: apt-get.cc,v 1.84 1999/10/24 06:03:48 jgg Exp $
/* ######################################################################
apt-get - Cover for dpkg
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
+#include <regex.h>
#include <sys/wait.h>
/*}}}*/
/* 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,CacheFile &Cache)
+void ShowBroken(ostream &out,CacheFile &Cache,bool Now)
{
out << "Sorry, but the following packages have unmet dependencies:" << endl;
for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
// 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)
{
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++;
+ }
}
}
}
{
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)
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)
if (pkgFixBroken(*Cache) == false || Cache->BrokenCount() != 0)
{
c1out << " failed." << endl;
- ShowBroken(c1out,*this);
+ ShowBroken(c1out,*this,true);
return _error->Error("Unable to correct dependencies");
}
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.");
}
// 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;
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 ";
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)
while (1)
{
if (_config->FindB("APT::Get::No-Download",false) == false)
- if( Fetcher.Run() == pkgAcquire::Failed)
+ if (Fetcher.Run() == pkgAcquire::Failed)
return false;
// Print out errors
(*I)->Complete == true)
continue;
- (*I)->Finished();
-
if ((*I)->Status == pkgAcquire::Item::StatIdle)
{
Transient = true;
cerr << " " << (*I)->ErrorText << endl;
Failed = true;
}
+
+ /* If we are in no download mode and missing files then 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)
{
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?");
}
}
}
/*}}}*/
+// 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, installing " << 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 (State.CandidateVer == 0)
+ {
+ 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, or that it is an obsolete package." << 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.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 /*{{{*/
// ---------------------------------------------------------------------
(*I)->Finished();
+ cerr << "Failed to fetch " << (*I)->DescURI() << endl;
+ cerr << " " << (*I)->ErrorText << endl;
Failed = true;
}
// Do the upgrade
if (pkgAllUpgrade(Cache) == false)
{
- ShowBroken(c1out,Cache);
+ ShowBroken(c1out,Cache,false);
return _error->Error("Internal Error, AllUpgrade broke stuff");
}
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);
+ if (Hit == false)
+ return _error->Error("Couldn't find package %s",S);
}
-
- Fix.Protect(Pkg);
- if (Remove == true)
- {
- Fix.Remove(Pkg);
- Cache->MarkDelete(Pkg,_config->FindB("APT::Get::Purge",false));
- continue;
- }
-
- // 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
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).");
}
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");
}
if (pkgDistUpgrade(*Cache) == false)
{
c0out << "Failed" << endl;
- ShowBroken(c1out,Cache);
+ ShowBroken(c1out,Cache,false);
return false;
}
if (Fix.Resolve() == false)
{
- ShowBroken(c1out,Cache);
+ ShowBroken(c1out,Cache,false);
return _error->Error("Internal Error, problem resolver broke stuff");
}
}
// Now upgrade everything
if (pkgAllUpgrade(Cache) == false)
{
- ShowBroken(c1out,Cache);
+ ShowBroken(c1out,Cache,false);
return _error->Error("Internal Error, problem resolver broke stuff");
}
/* */
bool DoClean(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");
+ }
+
pkgAcquire Fetcher;
Fetcher.Clean(_config->FindDir("Dir::Cache::archives"));
Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/");
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;
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);
{
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)
+ continue;
+
// See if the package is already unpacked
struct stat Stat;
if (stat(Dir.c_str(),&Stat) == 0 &&
{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},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}};