#include <apt-pkg/version.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/sptr.h>
+#include <apt-pkg/md5.h>
#include <apt-pkg/versionmatch.h>
#include <config.h>
#include "acqprogress.h"
+#include <set>
#include <locale.h>
#include <langinfo.h>
#include <fstream>
#include <errno.h>
#include <regex.h>
#include <sys/wait.h>
+#include <sstream>
/*}}}*/
using namespace std;
and verifies that the system is OK. */
bool CacheFile::CheckDeps(bool AllowBroken)
{
+ bool FixBroken = _config->FindB("APT::Get::Fix-Broken",false);
+
if (_error->PendingError() == true)
return false;
if (pkgApplyStatus(*DCache) == false)
return false;
+ if (_config->FindB("APT::Get::Fix-Policy-Broken",false) == true)
+ {
+ FixBroken = true;
+ if ((DCache->PolicyBrokenCount() > 0))
+ {
+ // upgrade all policy-broken packages with ForceImportantDeps=True
+ for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); I++)
+ if ((*DCache)[I].NowPolicyBroken() == true)
+ DCache->MarkInstall(I,true,0, false, true);
+ }
+ }
+
// Nothing is broken
if (DCache->BrokenCount() == 0 || AllowBroken == true)
return true;
// Attempt to fix broken things
- if (_config->FindB("APT::Get::Fix-Broken",false) == true)
+ if (FixBroken == true)
{
c1out << _("Correcting dependencies...") << flush;
if (pkgFixBroken(*DCache) == false || DCache->BrokenCount() != 0)
cerr << _("Unable to correct missing packages.") << endl;
return _error->Error(_("Aborting install."));
}
-
+
_system->UnLock();
int status_fd = _config->FindI("APT::Status-Fd",-1);
pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd);
else
ExpectedInst++;
- // Install it with autoinstalling enabled.
- if (State.InstBroken() == true && BrokenFix == false)
+ // Install it with autoinstalling enabled (if we not respect the minial
+ // required deps or the policy)
+ if ((State.InstBroken() == true || State.InstPolicyBroken() == true) && BrokenFix == false)
Cache.MarkInstall(Pkg,true);
+
return true;
}
/*}}}*/
for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false;
VF++)
{
- // extra paranioa
- if(VF.File() == NULL)
- continue;
-
/* If this is the status file, and the current version is not the
version in the status file (ie it is not installed, or somesuch)
then it is not a candidate for installation, ever. This weeds
}
// Clean out any old list files
- if (_config->FindB("APT::Get::List-Cleanup",true) == true)
+ if (!Failed && _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 true;
}
/*}}}*/
+// DoAutomaticRemove - Remove all automatic unused packages /*{{{*/
+// ---------------------------------------------------------------------
+/* Remove unused automatic packages */
+bool DoAutomaticRemove(CacheFile &Cache)
+{
+ if(_config->FindI("Debug::pkgAutoRemove",false))
+ std::cout << "DoAutomaticRemove()" << std::endl;
+
+ if (_config->FindB("APT::Get::Remove",true) == false)
+ return _error->Error(_("We are not supposed to delete stuff, can't "
+ "start AutoRemover"));
+
+ {
+ pkgDepCache::ActionGroup group(*Cache);
+
+ // look over the cache to see what can be removed
+ for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg)
+ {
+ if (Cache[Pkg].Garbage)
+ {
+ if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install())
+ fprintf(stdout,"We could delete %s\n", Pkg.Name());
+
+ if(Pkg.CurrentVer() != 0 && Pkg->CurrentState != pkgCache::State::ConfigFiles)
+ Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false));
+ else
+ Cache->MarkKeep(Pkg, false, false);
+ }
+ }
+ }
+
+ // Now see if we destroyed anything
+ if (Cache->BrokenCount() != 0)
+ {
+ c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n"
+ "shouldn't happen. Please file a bug report against apt.") << endl;
+ c1out << endl;
+ c1out << _("The following information may help to resolve the situation:") << endl;
+ c1out << endl;
+ ShowBroken(c1out,Cache,false);
+
+ return _error->Error(_("Internal Error, AutoRemover broke stuff"));
+ }
+ return true;
+}
+
// DoUpgrade - Upgrade all packages /*{{{*/
// ---------------------------------------------------------------------
/* Upgrade all packages without installing new packages or erasing old
return InstallPackages(Cache,true);
}
/*}}}*/
-// DoInstall - Install packages from the command line /*{{{*/
+// DoInstallTask - Install task from the command line /*{{{*/
// ---------------------------------------------------------------------
-/* Install named packages */
-bool DoInstall(CommandLine &CmdL)
+/* Install named task */
+bool TryInstallTask(pkgDepCache &Cache, pkgProblemResolver &Fix,
+ bool BrokenFix,
+ unsigned int& ExpectedInst,
+ const char *taskname)
{
- // Lock the list directory
- FileFd Lock;
- if (_config->FindB("Debug::NoLocking",false) == false)
+ const char *start, *end;
+ pkgCache::PkgIterator Pkg;
+ char buf[64*1024];
+ regex_t Pattern;
+
+ // get the records
+ pkgRecords Recs(Cache);
+
+ // build regexp for the task
+ char S[300];
+ snprintf(S, sizeof(S), "^Task:.*[^a-z]%s[^a-z].*\n", taskname);
+ regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+
+ bool found = false;
+ bool res = true;
+ for (Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
{
- Lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
- if (_error->PendingError() == true)
- return _error->Error(_("Unable to lock the list directory"));
+ pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache);
+ if(ver.end())
+ continue;
+ pkgRecords::Parser &parser = Recs.Lookup(ver.FileList());
+ parser.GetRec(start,end);
+ strncpy(buf, start, end-start);
+ buf[end-start] = 0x0;
+ if (regexec(&Pattern,buf,0,0,0) != 0)
+ continue;
+ res &= TryToInstall(Pkg,Cache,Fix,false,BrokenFix,ExpectedInst);
+ found = true;
}
+ if(!found)
+ _error->Error(_("Couldn't find task %s"),taskname);
+
+ regfree(&Pattern);
+ return res;
+}
+
+// DoInstall - Install packages from the command line /*{{{*/
+// ---------------------------------------------------------------------
+/* Install named packages */
+bool DoInstall(CommandLine &CmdL)
+{
CacheFile Cache;
if (Cache.OpenForInstall() == false ||
Cache.CheckDeps(CmdL.FileSize() != 1) == false)
bool DefRemove = false;
if (strcasecmp(CmdL.FileList[0],"remove") == 0)
DefRemove = true;
+ else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0)
+ {
+ _config->Set("APT::Get::AutomaticRemove", "true");
+ DefRemove = true;
+ }
for (const char **I = CmdL.FileList + 1; *I != 0; I++)
{
bool Remove = DefRemove;
char *VerTag = 0;
bool VerIsRel = false;
+
+ // this is a task!
+ if (Length >= 1 && S[Length - 1] == '^')
+ {
+ S[--Length] = 0;
+ // tasks must always be confirmed
+ ExpectedInst += 1000;
+ // see if we can install it
+ TryInstallTask(Cache, Fix, BrokenFix, ExpectedInst, S);
+ continue;
+ }
+
while (Cache->FindPkg(S).end() == true)
{
// Handle an optional end tag indicating what to do
S[--Length] = 0;
continue;
}
-
+
char *Slash = strchr(S,'=');
if (Slash != 0)
{
return _error->Error(_("Broken packages"));
}
+ if (_config->FindB("APT::Get::AutomaticRemove")) {
+ if (!DoAutomaticRemove(Cache))
+ return false;
+ }
+
/* Print out a list of packages that are going to be installed extra
to what the user asked */
if (Cache->InstCount() != ExpectedInst)
if (*J == 0) {
List += string(I.Name()) + " ";
- VersionsList += string(Cache[I].CandVersion) + "\n";
- }
+ VersionsList += string(Cache[I].CandVersion) + "\n";
+ }
}
ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList);
string SuggestsVersions, RecommendsVersions;
for (unsigned J = 0; J < Cache->Head().PackageCount; J++)
{
- pkgCache::PkgIterator I(Cache,Cache.List[J]);
+ pkgCache::PkgIterator Pkg(Cache,Cache.List[J]);
/* Just look at the ones we want to install */
- if ((*Cache)[I].Install() == false)
+ if ((*Cache)[Pkg].Install() == false)
continue;
- for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++)
- {
- for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; )
- {
- pkgCache::DepIterator Start;
- pkgCache::DepIterator End;
- D.GlobOr(Start,End); // advances D
-
- /*
- * If this is a virtual package, we need to check the list of
- * packages that provide it and see if any of those are
- * installed
- */
-
- bool providedBySomething = false;
- for (pkgCache::PrvIterator Prv = Start.TargetPkg().ProvidesList();
- Prv.end() != true;
- Prv++)
- if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false)
- {
- providedBySomething = true;
- break;
- }
-
- if (providedBySomething) continue;
-
- for(;;)
- {
- /* Skip if package is installed already, or is about to be */
- string target = string(Start.TargetPkg().Name()) + " ";
-
- if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
- || Cache[Start.TargetPkg()].Install())
- break;
-
- /* Skip if we already saw it */
- if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
- break;
-
- if (Start->Type == pkgCache::Dep::Suggests) {
- SuggestsList += target;
- SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
- }
-
- if (Start->Type == pkgCache::Dep::Recommends) {
- RecommendsList += target;
- RecommendsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
- }
-
- if (Start >= End)
- break;
- Start++;
- }
- }
- }
+ // get the recommends/suggests for the candidate ver
+ pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache);
+ for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; )
+ {
+ pkgCache::DepIterator Start;
+ pkgCache::DepIterator End;
+ D.GlobOr(Start,End); // advances D
+
+ // FIXME: we really should display a or-group as a or-group to the user
+ // the problem is that ShowList is incapable of doing this
+ string RecommendsOrList,RecommendsOrVersions;
+ string SuggestsOrList,SuggestsOrVersions;
+ bool foundInstalledInOrGroup = false;
+ for(;;)
+ {
+ /* Skip if package is installed already, or is about to be */
+ string target = string(Start.TargetPkg().Name()) + " ";
+
+ if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install
+ || Cache[Start.TargetPkg()].Install())
+ {
+ foundInstalledInOrGroup=true;
+ break;
+ }
+
+ /* Skip if we already saw it */
+ if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1)
+ {
+ foundInstalledInOrGroup=true;
+ break;
+ }
+
+ // this is a dep on a virtual pkg, check if any package that provides it
+ // should be installed
+ if(Start.TargetPkg().ProvidesList() != 0)
+ {
+ pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList();
+ for (; I.end() == false; I++)
+ {
+ pkgCache::PkgIterator Pkg = I.OwnerPkg();
+ if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() &&
+ Pkg.CurrentVer() != 0)
+ foundInstalledInOrGroup=true;
+ }
+ }
+
+ if (Start->Type == pkgCache::Dep::Suggests)
+ {
+ SuggestsOrList += target;
+ SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+ }
+
+ if (Start->Type == pkgCache::Dep::Recommends)
+ {
+ RecommendsOrList += target;
+ RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n";
+ }
+
+ if (Start >= End)
+ break;
+ Start++;
+ }
+
+ if(foundInstalledInOrGroup == false)
+ {
+ RecommendsList += RecommendsOrList;
+ RecommendsVersions += RecommendsOrVersions;
+ SuggestsList += SuggestsOrList;
+ SuggestsVersions += SuggestsOrVersions;
+ }
+
+ }
}
+
ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions);
ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions);
if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false)
return false;
+ pkgDepCache::ActionGroup group(Cache);
+
// Install everything with the install flag set
pkgCache::PkgIterator I = Cache->PkgBegin();
for (;I.end() != true; I++)
DscFile *Dsc = new DscFile[CmdL.FileSize()];
+ // insert all downloaded uris into this set to avoid downloading them
+ // twice
+ set<string> queued;
// Load the requestd sources into the fetcher
unsigned J = 0;
for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++)
if (_config->FindB("APT::Get::Tar-Only",false) == true &&
I->Type != "tar")
continue;
-
+
+ // don't download the same uri twice (should this be moved to
+ // the fetcher interface itself?)
+ if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end())
+ continue;
+ queued.insert(Last->Index().ArchiveURI(I->Path));
+
+ // check if we have a file with that md5 sum already localy
+ if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path)))
+ {
+ FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly);
+ MD5Summation sum;
+ sum.AddFD(Fd.Fd(), Fd.Size());
+ Fd.Close();
+ if((string)sum.Result() == I->MD5Hash)
+ {
+ ioprintf(c1out,_("Skipping already downloaded file '%s'\n"),
+ flNotDir(I->Path).c_str());
+ continue;
+ }
+ }
+
new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path),
I->MD5Hash,I->Size,
Last->Index().SourceInfo(*Last,*I),Src);
_config->Set("APT::Get::Fix-Broken",false);
_config->Set("APT::Get::Force-Yes",false);
_config->Set("APT::Get::List-Cleanup",true);
+ _config->Set("APT::Get::AutomaticRemove",false);
}
/*}}}*/
// SigWinch - Window size change signal handler /*{{{*/
{0,"remove","APT::Get::Remove",0},
{0,"only-source","APT::Get::Only-Source",0},
{0,"arch-only","APT::Get::Arch-Only",0},
+ {0,"auto-remove","APT::Get::AutomaticRemove",0},
{0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0},
+ {0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean},
+ {0,"fix-policy","APT::Get::Fix-Policy-Broken",0},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}};
{"upgrade",&DoUpgrade},
{"install",&DoInstall},
{"remove",&DoInstall},
+ {"autoremove",&DoInstall},
{"dist-upgrade",&DoDistUpgrade},
{"dselect-upgrade",&DoDSelectUpgrade},
{"build-dep",&DoBuildDep},