+// -*- mode: cpp; mode: fold -*-
+// Description /*{{{*/
+// $Id: apt-get.cc,v 1.91 1999/11/28 01:03:28 jgg Exp $
+/* ######################################################################
+
+ apt-get - Cover for dpkg
+
+ This is an allout cover for dpkg implementing a safer front end. It is
+ based largely on libapt-pkg.
+
+ The syntax is different,
+ apt-get [opt] command [things]
+ Where command is:
+ update - Resyncronize the package files from their sources
+ upgrade - Smart-Download the newest versions of all packages
+ dselect-upgrade - Follows dselect's changes to the Status: field
+ and installes new and removes old packages
+ dist-upgrade - Powerfull upgrader designed to handle the issues with
+ a new distribution.
+ install - Download and install a given package (by name, not by .deb)
+ check - Update the package cache and check for broken packages
+ clean - Erase the .debs downloaded to /var/cache/apt/archives and
+ the partial dir too
+
+ ##################################################################### */
+ /*}}}*/
+// Include Files /*{{{*/
#include <apt-pkg/error.h>
#include <apt-pkg/cmndline.h>
#include <apt-pkg/init.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
+#include <regex.h>
#include <sys/wait.h>
/*}}}*/
// 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() << (Now?" is installed":" is to be 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 << (Now?"it is not installed":"it is not going to be 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)
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)
{
c1out << SizeToStr(DebBytes) << 'B';
c1out << " of archives. After unpacking ";
+
+ // Size delta
+ if (Cache->UsrSize() >= 0)
+ c1out << SizeToStr(Cache->UsrSize()) << "B will be used." << endl;
+ else
+ c1out << SizeToStr(-1*Cache->UsrSize()) << "B will be freed." << endl;
+
+ if (_error->PendingError() == true)
+ return false;
// Check for enough free space
struct statfs Buf;
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)
- c1out << SizeToStr(Cache->UsrSize()) << "B will be used." << endl;
- else
- c1out << SizeToStr(-1*Cache->UsrSize()) << "B will be freed." << endl;
-
- if (_error->PendingError() == true)
- return false;
// Fail safe check
if (_config->FindI("quiet",0) >= 2 ||
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;
}
}
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)
{
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, 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 /*{{{*/
// ---------------------------------------------------------------------
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,_config->FindB("APT::Get::Purge",false));
- 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
/* */
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/");
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;
{'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},
{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}};