| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830 |
- // -*- mode: cpp; mode: fold -*-
- // Description /*{{{*/
- // $Id: depcache.cc,v 1.25 2001/05/27 05:36:04 jgg Exp $
- /* ######################################################################
- Dependency Cache - Caches Dependency information.
-
- ##################################################################### */
- /*}}}*/
- // Include Files /*{{{*/
- #include <apt-pkg/depcache.h>
- #include <apt-pkg/version.h>
- #include <apt-pkg/error.h>
- #include <apt-pkg/sptr.h>
- #include <apt-pkg/algorithms.h>
- #include <apt-pkg/fileutl.h>
- #include <apt-pkg/strutl.h>
- #include <apt-pkg/configuration.h>
- #include <apt-pkg/aptconfiguration.h>
- #include <apt-pkg/pkgsystem.h>
- #include <apt-pkg/tagfile.h>
- #include <iostream>
- #include <sstream>
- #include <set>
- #include <sys/stat.h>
- #include <apti18n.h>
- /*}}}*/
- // helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/
- static bool
- ConfigValueInSubTree(const char* SubTree, const char *needle)
- {
- Configuration::Item const *Opts;
- Opts = _config->Tree(SubTree);
- if (Opts != 0 && Opts->Child != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- if (strcmp(needle, Opts->Value.c_str()) == 0)
- return true;
- }
- }
- return false;
- }
- /*}}}*/
- pkgDepCache::ActionGroup::ActionGroup(pkgDepCache &cache) : /*{{{*/
- cache(cache), released(false)
- {
- ++cache.group_level;
- }
- void pkgDepCache::ActionGroup::release()
- {
- if(!released)
- {
- if(cache.group_level == 0)
- std::cerr << "W: Unbalanced action groups, expect badness" << std::endl;
- else
- {
- --cache.group_level;
- if(cache.group_level == 0)
- cache.MarkAndSweep();
- }
- released = false;
- }
- }
- pkgDepCache::ActionGroup::~ActionGroup()
- {
- release();
- }
- /*}}}*/
- // DepCache::pkgDepCache - Constructors /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- pkgDepCache::pkgDepCache(pkgCache *pCache,Policy *Plcy) :
- group_level(0), Cache(pCache), PkgState(0), DepState(0)
- {
- DebugMarker = _config->FindB("Debug::pkgDepCache::Marker", false);
- DebugAutoInstall = _config->FindB("Debug::pkgDepCache::AutoInstall", false);
- delLocalPolicy = 0;
- LocalPolicy = Plcy;
- if (LocalPolicy == 0)
- delLocalPolicy = LocalPolicy = new Policy;
- }
- /*}}}*/
- // DepCache::~pkgDepCache - Destructor /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- pkgDepCache::~pkgDepCache()
- {
- delete [] PkgState;
- delete [] DepState;
- delete delLocalPolicy;
- }
- /*}}}*/
- // DepCache::Init - Generate the initial extra structures. /*{{{*/
- // ---------------------------------------------------------------------
- /* This allocats the extension buffers and initializes them. */
- bool pkgDepCache::Init(OpProgress *Prog)
- {
- // Suppress mark updates during this operation (just in case) and
- // run a mark operation when Init terminates.
- ActionGroup actions(*this);
- delete [] PkgState;
- delete [] DepState;
- PkgState = new StateCache[Head().PackageCount];
- DepState = new unsigned char[Head().DependsCount];
- memset(PkgState,0,sizeof(*PkgState)*Head().PackageCount);
- memset(DepState,0,sizeof(*DepState)*Head().DependsCount);
- if (Prog != 0)
- {
- Prog->OverallProgress(0,2*Head().PackageCount,Head().PackageCount,
- _("Building dependency tree"));
- Prog->SubProgress(Head().PackageCount,_("Candidate versions"));
- }
-
- /* Set the current state of everything. In this state all of the
- packages are kept exactly as is. See AllUpgrade */
- int Done = 0;
- for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
- {
- if (Prog != 0 && Done%20 == 0)
- Prog->Progress(Done);
-
- // Find the proper cache slot
- StateCache &State = PkgState[I->ID];
- State.iFlags = 0;
- // Figure out the install version
- State.CandidateVer = GetCandidateVer(I);
- State.InstallVer = I.CurrentVer();
- State.Mode = ModeKeep;
-
- State.Update(I,*this);
- }
-
- if (Prog != 0)
- {
-
- Prog->OverallProgress(Head().PackageCount,2*Head().PackageCount,
- Head().PackageCount,
- _("Building dependency tree"));
- Prog->SubProgress(Head().PackageCount,_("Dependency generation"));
- }
-
- Update(Prog);
- if(Prog != 0)
- Prog->Done();
- return true;
- }
- /*}}}*/
- bool pkgDepCache::readStateFile(OpProgress *Prog) /*{{{*/
- {
- FileFd state_file;
- string const state = _config->FindFile("Dir::State::extended_states");
- if(FileExists(state)) {
- state_file.Open(state, FileFd::ReadOnly);
- int const file_size = state_file.Size();
- if(Prog != NULL)
- Prog->OverallProgress(0, file_size, 1,
- _("Reading state information"));
- pkgTagFile tagfile(&state_file);
- pkgTagSection section;
- int amt = 0;
- bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
- while(tagfile.Step(section)) {
- string const pkgname = section.FindS("Package");
- string pkgarch = section.FindS("Architecture");
- if (pkgarch.empty() == true)
- pkgarch = "any";
- pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
- // Silently ignore unknown packages and packages with no actual version.
- if(pkg.end() == true || pkg->VersionList == 0)
- continue;
- short const reason = section.FindI("Auto-Installed", 0);
- if(reason > 0)
- {
- PkgState[pkg->ID].Flags |= Flag::Auto;
- if (unlikely(debug_autoremove))
- std::clog << "Auto-Installed : " << pkg.FullName() << std::endl;
- if (pkgarch == "any")
- {
- pkgCache::GrpIterator G = pkg.Group();
- for (pkg = G.NextPkg(pkg); pkg.end() != true; pkg = G.NextPkg(pkg))
- if (pkg->VersionList != 0)
- PkgState[pkg->ID].Flags |= Flag::Auto;
- }
- }
- amt += section.size();
- if(Prog != NULL)
- Prog->OverallProgress(amt, file_size, 1,
- _("Reading state information"));
- }
- if(Prog != NULL)
- Prog->OverallProgress(file_size, file_size, 1,
- _("Reading state information"));
- }
- return true;
- }
- /*}}}*/
- bool pkgDepCache::writeStateFile(OpProgress *prog, bool InstalledOnly) /*{{{*/
- {
- bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
-
- if(debug_autoremove)
- std::clog << "pkgDepCache::writeStateFile()" << std::endl;
- FileFd StateFile;
- string const state = _config->FindFile("Dir::State::extended_states");
- // if it does not exist, create a empty one
- if(!FileExists(state))
- {
- StateFile.Open(state, FileFd::WriteEmpty);
- StateFile.Close();
- }
- // open it
- if(!StateFile.Open(state, FileFd::ReadOnly))
- return _error->Error(_("Failed to open StateFile %s"),
- state.c_str());
- FILE *OutFile;
- string const outfile = state + ".tmp";
- if((OutFile = fopen(outfile.c_str(),"w")) == NULL)
- return _error->Error(_("Failed to write temporary StateFile %s"),
- outfile.c_str());
- // first merge with the existing sections
- pkgTagFile tagfile(&StateFile);
- pkgTagSection section;
- std::set<string> pkgs_seen;
- const char *nullreorderlist[] = {0};
- while(tagfile.Step(section)) {
- string const pkgname = section.FindS("Package");
- string pkgarch = section.FindS("Architecture");
- if (pkgarch.empty() == true)
- pkgarch = "native";
- // Silently ignore unknown packages and packages with no actual
- // version.
- pkgCache::PkgIterator pkg = Cache->FindPkg(pkgname, pkgarch);
- if(pkg.end() || pkg.VersionList().end())
- continue;
- StateCache const &P = PkgState[pkg->ID];
- bool newAuto = (P.Flags & Flag::Auto);
- // skip not installed or now-removed ones if requested
- if (InstalledOnly && (
- (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
- (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
- {
- // The section is obsolete if it contains no other tag
- unsigned int const count = section.Count();
- if (count < 2 ||
- (count == 2 && section.Exists("Auto-Installed")) ||
- (count == 3 && section.Exists("Auto-Installed") && section.Exists("Architecture")))
- continue;
- else
- newAuto = false;
- }
- if(_config->FindB("Debug::pkgAutoRemove",false))
- std::clog << "Update existing AutoInstall info: "
- << pkg.FullName() << std::endl;
- TFRewriteData rewrite[3];
- rewrite[0].Tag = "Architecture";
- rewrite[0].Rewrite = pkg.Arch();
- rewrite[0].NewTag = 0;
- rewrite[1].Tag = "Auto-Installed";
- rewrite[1].Rewrite = newAuto ? "1" : "0";
- rewrite[1].NewTag = 0;
- rewrite[2].Tag = 0;
- TFRewrite(OutFile, section, nullreorderlist, rewrite);
- fprintf(OutFile,"\n");
- pkgs_seen.insert(pkg.FullName());
- }
-
- // then write the ones we have not seen yet
- std::ostringstream ostr;
- for(pkgCache::PkgIterator pkg=Cache->PkgBegin(); !pkg.end(); pkg++) {
- StateCache const &P = PkgState[pkg->ID];
- if(P.Flags & Flag::Auto) {
- if (pkgs_seen.find(pkg.FullName()) != pkgs_seen.end()) {
- if(debug_autoremove)
- std::clog << "Skipping already written " << pkg.FullName() << std::endl;
- continue;
- }
- // skip not installed ones if requested
- if (InstalledOnly && (
- (pkg->CurrentVer == 0 && P.Mode != ModeInstall) ||
- (pkg->CurrentVer != 0 && P.Mode == ModeDelete)))
- continue;
- const char* const pkgarch = pkg.Arch();
- if (strcmp(pkgarch, "all") == 0)
- continue;
- if(debug_autoremove)
- std::clog << "Writing new AutoInstall: " << pkg.FullName() << std::endl;
- ostr.str(string(""));
- ostr << "Package: " << pkg.Name()
- << "\nArchitecture: " << pkgarch
- << "\nAuto-Installed: 1\n\n";
- fprintf(OutFile,"%s",ostr.str().c_str());
- }
- }
- fclose(OutFile);
- // move the outfile over the real file and set permissions
- rename(outfile.c_str(), state.c_str());
- chmod(state.c_str(), 0644);
- return true;
- }
- /*}}}*/
- // DepCache::CheckDep - Checks a single dependency /*{{{*/
- // ---------------------------------------------------------------------
- /* This first checks the dependency against the main target package and
- then walks along the package provides list and checks if each provides
- will be installed then checks the provides against the dep. Res will be
- set to the package which was used to satisfy the dep. */
- bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
- {
- Res = Dep.TargetPkg();
- /* Check simple depends. A depends -should- never self match but
- we allow it anyhow because dpkg does. Technically it is a packaging
- bug. Conflicts may never self match */
- if (Dep.TargetPkg() != Dep.ParentPkg() ||
- (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
- {
- PkgIterator Pkg = Dep.TargetPkg();
- // Check the base package
- if (Type == NowVersion && Pkg->CurrentVer != 0)
- if (VS().CheckDep(Pkg.CurrentVer().VerStr(),Dep->CompareOp,
- Dep.TargetVer()) == true)
- return true;
-
- if (Type == InstallVersion && PkgState[Pkg->ID].InstallVer != 0)
- if (VS().CheckDep(PkgState[Pkg->ID].InstVerIter(*this).VerStr(),
- Dep->CompareOp,Dep.TargetVer()) == true)
- return true;
-
- if (Type == CandidateVersion && PkgState[Pkg->ID].CandidateVer != 0)
- if (VS().CheckDep(PkgState[Pkg->ID].CandidateVerIter(*this).VerStr(),
- Dep->CompareOp,Dep.TargetVer()) == true)
- return true;
- }
-
- if (Dep->Type == Dep::Obsoletes)
- return false;
-
- // Check the providing packages
- PrvIterator P = Dep.TargetPkg().ProvidesList();
- PkgIterator Pkg = Dep.ParentPkg();
- for (; P.end() != true; P++)
- {
- /* Provides may never be applied against the same package if it is
- a conflicts. See the comment above. */
- if (P.OwnerPkg() == Pkg &&
- (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
- continue;
-
- // Check if the provides is a hit
- if (Type == NowVersion)
- {
- if (P.OwnerPkg().CurrentVer() != P.OwnerVer())
- continue;
- }
-
- if (Type == InstallVersion)
- {
- StateCache &State = PkgState[P.OwnerPkg()->ID];
- if (State.InstallVer != (Version *)P.OwnerVer())
- continue;
- }
- if (Type == CandidateVersion)
- {
- StateCache &State = PkgState[P.OwnerPkg()->ID];
- if (State.CandidateVer != (Version *)P.OwnerVer())
- continue;
- }
-
- // Compare the versions.
- if (VS().CheckDep(P.ProvideVersion(),Dep->CompareOp,Dep.TargetVer()) == true)
- {
- Res = P.OwnerPkg();
- return true;
- }
- }
-
- return false;
- }
- /*}}}*/
- // DepCache::AddSizes - Add the packages sizes to the counters /*{{{*/
- // ---------------------------------------------------------------------
- /* Call with Mult = -1 to preform the inverse opration */
- void pkgDepCache::AddSizes(const PkgIterator &Pkg,signed long Mult)
- {
- StateCache &P = PkgState[Pkg->ID];
-
- if (Pkg->VersionList == 0)
- return;
-
- if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
- P.Keep() == true)
- return;
-
- // Compute the size data
- if (P.NewInstall() == true)
- {
- iUsrSize += (signed)(Mult*P.InstVerIter(*this)->InstalledSize);
- iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
- return;
- }
-
- // Upgrading
- if (Pkg->CurrentVer != 0 &&
- (P.InstallVer != (Version *)Pkg.CurrentVer() ||
- (P.iFlags & ReInstall) == ReInstall) && P.InstallVer != 0)
- {
- iUsrSize += (signed)(Mult*((signed)P.InstVerIter(*this)->InstalledSize -
- (signed)Pkg.CurrentVer()->InstalledSize));
- iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
- return;
- }
-
- // Reinstall
- if (Pkg.State() == pkgCache::PkgIterator::NeedsUnpack &&
- P.Delete() == false)
- {
- iDownloadSize += (signed)(Mult*P.InstVerIter(*this)->Size);
- return;
- }
-
- // Removing
- if (Pkg->CurrentVer != 0 && P.InstallVer == 0)
- {
- iUsrSize -= (signed)(Mult*Pkg.CurrentVer()->InstalledSize);
- return;
- }
- }
- /*}}}*/
- // DepCache::AddStates - Add the package to the state counter /*{{{*/
- // ---------------------------------------------------------------------
- /* This routine is tricky to use, you must make sure that it is never
- called twice for the same package. This means the Remove/Add section
- should be as short as possible and not encompass any code that will
- calld Remove/Add itself. Remember, dependencies can be circular so
- while processing a dep for Pkg it is possible that Add/Remove
- will be called on Pkg */
- void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
- {
- StateCache &State = PkgState[Pkg->ID];
-
- // The Package is broken (either minimal dep or policy dep)
- if ((State.DepState & DepInstMin) != DepInstMin)
- iBrokenCount += Add;
- if ((State.DepState & DepInstPolicy) != DepInstPolicy)
- iPolicyBrokenCount += Add;
-
- // Bad state
- if (Pkg.State() != PkgIterator::NeedsNothing)
- iBadCount += Add;
-
- // Not installed
- if (Pkg->CurrentVer == 0)
- {
- if (State.Mode == ModeDelete &&
- (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
- iDelCount += Add;
-
- if (State.Mode == ModeInstall)
- iInstCount += Add;
- return;
- }
-
- // Installed, no upgrade
- if (State.Status == 0)
- {
- if (State.Mode == ModeDelete)
- iDelCount += Add;
- else
- if ((State.iFlags & ReInstall) == ReInstall)
- iInstCount += Add;
-
- return;
- }
-
- // Alll 3 are possible
- if (State.Mode == ModeDelete)
- iDelCount += Add;
- if (State.Mode == ModeKeep)
- iKeepCount += Add;
- if (State.Mode == ModeInstall)
- iInstCount += Add;
- }
- /*}}}*/
- // DepCache::BuildGroupOrs - Generate the Or group dep data /*{{{*/
- // ---------------------------------------------------------------------
- /* The or group results are stored in the last item of the or group. This
- allows easy detection of the state of a whole or'd group. */
- void pkgDepCache::BuildGroupOrs(VerIterator const &V)
- {
- unsigned char Group = 0;
-
- for (DepIterator D = V.DependsList(); D.end() != true; D++)
- {
- // Build the dependency state.
- unsigned char &State = DepState[D->ID];
- /* Invert for Conflicts. We have to do this twice to get the
- right sense for a conflicts group */
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
- State = ~State;
-
- // Add to the group if we are within an or..
- State &= 0x7;
- Group |= State;
- State |= Group << 3;
- if ((D->CompareOp & Dep::Or) != Dep::Or)
- Group = 0;
-
- // Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
- State = ~State;
- }
- }
- /*}}}*/
- // DepCache::VersionState - Perform a pass over a dependency list /*{{{*/
- // ---------------------------------------------------------------------
- /* This is used to run over a dependency list and determine the dep
- state of the list, filtering it through both a Min check and a Policy
- check. The return result will have SetMin/SetPolicy low if a check
- fails. It uses the DepState cache for it's computations. */
- unsigned char pkgDepCache::VersionState(DepIterator D,unsigned char Check,
- unsigned char SetMin,
- unsigned char SetPolicy)
- {
- unsigned char Dep = 0xFF;
-
- while (D.end() != true)
- {
- // Compute a single dependency element (glob or)
- DepIterator Start = D;
- unsigned char State = 0;
- for (bool LastOR = true; D.end() == false && LastOR == true; D++)
- {
- State |= DepState[D->ID];
- LastOR = (D->CompareOp & Dep::Or) == Dep::Or;
- }
-
- // Minimum deps that must be satisfied to have a working package
- if (Start.IsCritical() == true)
- if ((State & Check) != Check)
- Dep &= ~SetMin;
-
- // Policy deps that must be satisfied to install the package
- if (IsImportantDep(Start) == true &&
- (State & Check) != Check)
- Dep &= ~SetPolicy;
- }
- return Dep;
- }
- /*}}}*/
- // DepCache::DependencyState - Compute the 3 results for a dep /*{{{*/
- // ---------------------------------------------------------------------
- /* This is the main dependency computation bit. It computes the 3 main
- results for a dependencys, Now, Install and Candidate. Callers must
- invert the result if dealing with conflicts. */
- unsigned char pkgDepCache::DependencyState(DepIterator &D)
- {
- unsigned char State = 0;
-
- if (CheckDep(D,NowVersion) == true)
- State |= DepNow;
- if (CheckDep(D,InstallVersion) == true)
- State |= DepInstall;
- if (CheckDep(D,CandidateVersion) == true)
- State |= DepCVer;
-
- return State;
- }
- /*}}}*/
- // DepCache::UpdateVerState - Compute the Dep member of the state /*{{{*/
- // ---------------------------------------------------------------------
- /* This determines the combined dependency representation of a package
- for its two states now and install. This is done by using the pre-generated
- dependency information. */
- void pkgDepCache::UpdateVerState(PkgIterator Pkg)
- {
- // Empty deps are always true
- StateCache &State = PkgState[Pkg->ID];
- State.DepState = 0xFF;
-
- // Check the Current state
- if (Pkg->CurrentVer != 0)
- {
- DepIterator D = Pkg.CurrentVer().DependsList();
- State.DepState &= VersionState(D,DepNow,DepNowMin,DepNowPolicy);
- }
-
- /* Check the candidate state. We do not compare against the whole as
- a candidate state but check the candidate version against the
- install states */
- if (State.CandidateVer != 0)
- {
- DepIterator D = State.CandidateVerIter(*this).DependsList();
- State.DepState &= VersionState(D,DepInstall,DepCandMin,DepCandPolicy);
- }
-
- // Check target state which can only be current or installed
- if (State.InstallVer != 0)
- {
- DepIterator D = State.InstVerIter(*this).DependsList();
- State.DepState &= VersionState(D,DepInstall,DepInstMin,DepInstPolicy);
- }
- }
- /*}}}*/
- // DepCache::RemovePseudoInstalledPkg - MultiArch helper for Update() /*{{{*/
- // ---------------------------------------------------------------------
- /* We "install" arch all packages for all archs if it is installed. Many
- of these will be broken. This method will look at these broken Pkg and
- "remove" it. */
- bool pkgDepCache::RemovePseudoInstalledPkg(PkgIterator &Pkg, std::set<unsigned long> &recheck) {
- if (unlikely(Pkg->CurrentVer == 0))
- return false;
- VerIterator V = Pkg.CurrentVer();
- if (V->MultiArch != Version::All)
- return false;
- // Never ever kill an "all" package - they have no dependency so they can't be broken
- if (strcmp(Pkg.Arch(),"all") == 0)
- return false;
- unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
- if ((CurDepState & DepInstMin) == DepInstMin) {
- // okay, the package isn't broken, but is the package also required?
- // If it has no real dependencies, no installed rdepends and doesn't
- // provide something of value, we will kill it as not required.
- // These pseudopackages have otherwise interesting effects if they get
- // a new dependency in a newer version…
- for (pkgCache::DepIterator D = V.DependsList();
- D.end() != true; ++D)
- if (D.IsCritical() == true && D.ParentPkg()->Group != Pkg->Group)
- return false;
- for (DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
- {
- if (D.IsCritical() == false)
- continue;
- PkgIterator const P = D.ParentPkg();
- if (P->Group == Pkg->Group)
- continue;
- if (P->CurrentVer != 0)
- return false;
- }
- for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
- for (DepIterator d = Prv.ParentPkg().RevDependsList();
- d.end() != true; ++d)
- {
- PkgIterator const P = d.ParentPkg();
- if (P->CurrentVer != 0 &&
- P->Group != Pkg->Group)
- return false;
- }
- }
- // Dependencies for this arch all package are not statisfied
- // so we installed it only for our convenience: get right of it now.
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
- Pkg->CurrentVer = 0;
- PkgState[Pkg->ID].InstallVer = 0;
- AddStates(Pkg);
- Update(Pkg);
- AddSizes(Pkg);
- // After the remove previously satisfied pseudo pkg could be now
- // no longer satisfied, so we need to recheck the reverse dependencies
- for (DepIterator d = Pkg.RevDependsList(); d.end() != true; ++d)
- {
- PkgIterator const P = d.ParentPkg();
- if (P->CurrentVer != 0)
- recheck.insert(P.Index());
- }
- for (DepIterator d = V.DependsList(); d.end() != true; ++d)
- {
- PkgIterator const P = d.TargetPkg();
- for (PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
- {
- PkgIterator const O = Prv.OwnerPkg();
- if (O->CurrentVer != 0)
- recheck.insert(O.Index());
- }
- if (P->CurrentVer != 0)
- recheck.insert(P.Index());
- }
- for (PrvIterator Prv = V.ProvidesList(); Prv.end() != true; Prv++)
- {
- for (DepIterator d = Prv.ParentPkg().RevDependsList();
- d.end() != true; ++d)
- {
- PkgIterator const P = d.ParentPkg();
- if (P->CurrentVer == 0)
- continue;
- recheck.insert(P.Index());
- }
- }
- return true;
- }
- /*}}}*/
- // DepCache::Update - Figure out all the state information /*{{{*/
- // ---------------------------------------------------------------------
- /* This will figure out the state of all the packages and all the
- dependencies based on the current policy. */
- void pkgDepCache::Update(OpProgress *Prog)
- {
- iUsrSize = 0;
- iDownloadSize = 0;
- iDelCount = 0;
- iInstCount = 0;
- iKeepCount = 0;
- iBrokenCount = 0;
- iBadCount = 0;
- std::set<unsigned long> recheck;
- // Perform the depends pass
- int Done = 0;
- bool const checkMultiArch = APT::Configuration::getArchitectures().size() > 1;
- unsigned long killed = 0;
- for (PkgIterator I = PkgBegin(); I.end() != true; I++,Done++)
- {
- if (Prog != 0 && Done%20 == 0)
- Prog->Progress(Done);
- for (VerIterator V = I.VersionList(); V.end() != true; V++)
- {
- unsigned char Group = 0;
- for (DepIterator D = V.DependsList(); D.end() != true; D++)
- {
- // Build the dependency state.
- unsigned char &State = DepState[D->ID];
- State = DependencyState(D);
- // Add to the group if we are within an or..
- Group |= State;
- State |= Group << 3;
- if ((D->CompareOp & Dep::Or) != Dep::Or)
- Group = 0;
- // Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
- State = ~State;
- }
- }
- // Compute the package dependency state and size additions
- AddSizes(I);
- UpdateVerState(I);
- AddStates(I);
- if (checkMultiArch != true || I->CurrentVer == 0)
- continue;
- VerIterator const V = I.CurrentVer();
- if (V->MultiArch != Version::All)
- continue;
- recheck.insert(I.Index());
- --Done; // no progress if we need to recheck the package
- }
- if (checkMultiArch == true) {
- /* FIXME: recheck breaks proper progress reporting as we don't know
- how many packages we need to recheck. To lower the effect
- a bit we increase with a kill, but we should do something more clever… */
- while(recheck.empty() == false)
- for (std::set<unsigned long>::const_iterator p = recheck.begin();
- p != recheck.end();) {
- if (Prog != 0 && Done%20 == 0)
- Prog->Progress(Done);
- PkgIterator P = PkgIterator(*Cache, Cache->PkgP + *p);
- if (RemovePseudoInstalledPkg(P, recheck) == true) {
- ++killed;
- ++Done;
- }
- recheck.erase(p++);
- }
- /* Okay, we have killed a great amount of pseudopackages -
- we have killed so many that we have now arch "all" packages
- without an installed pseudo package, but we NEED an installed
- pseudo package, so we will search now for a pseudo package
- we can install without breaking everything. */
- for (GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
- {
- PkgIterator P = G.FindPkg("all");
- if (P.end() == true)
- continue;
- if (P->CurrentVer == 0)
- continue;
- bool installed = false;
- for (P = G.FindPkg("any"); P.end() != true; P = G.NextPkg(P))
- {
- if (strcmp(P.Arch(), "all") == 0)
- continue;
- if (P->CurrentVer == 0)
- continue;
- installed = true;
- break;
- }
- if (installed == false)
- recheck.insert(G.Index());
- }
- while (recheck.empty() != true)
- {
- std::set<unsigned long>::const_iterator g = recheck.begin();
- unsigned long const G = *g;
- recheck.erase(g);
- if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
- _error->Warning(_("Internal error, group '%s' has no installable pseudo package"), GrpIterator(*Cache, Cache->GrpP + G).Name());
- }
- }
- if (Prog != 0)
- Prog->Progress(Done);
- readStateFile(Prog);
- }
- /*}}}*/
- // DepCache::ReInstallPseudoForGroup - MultiArch helper for Update() /*{{{*/
- // ---------------------------------------------------------------------
- /* RemovePseudoInstalledPkg() is very successful. It even kills packages
- to an amount that no pseudo package is left, but we need a pseudo package
- for upgrading senarios so we need to reinstall one pseudopackage which
- doesn't break everything. Thankfully we can't have architecture depending
- negative dependencies so this problem is already eliminated */
- bool pkgDepCache::ReInstallPseudoForGroup(pkgCache::PkgIterator const &P, std::set<unsigned long> &recheck)
- {
- if (P->CurrentVer != 0)
- return true;
- // recursive call for packages which provide this package
- for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() != true; ++Prv)
- ReInstallPseudoForGroup(Prv.OwnerPkg(), recheck);
- // check if we actually need to look at this group
- unsigned long const G = P->Group;
- std::set<unsigned long>::const_iterator Pi = recheck.find(G);
- if (Pi == recheck.end())
- return true;
- recheck.erase(Pi); // remove here, so we can't fall into an endless loop
- if (unlikely(ReInstallPseudoForGroup(G, recheck) == false))
- {
- recheck.insert(G);
- return false;
- }
- return true;
- }
- bool pkgDepCache::ReInstallPseudoForGroup(unsigned long const &G, std::set<unsigned long> &recheck)
- {
- std::vector<std::string> static const Archs = APT::Configuration::getArchitectures();
- pkgCache::GrpIterator Grp(*Cache, Cache->GrpP + G);
- if (unlikely(Grp.end() == true))
- return false;
- for (std::vector<std::string>::const_iterator a = Archs.begin();
- a != Archs.end(); ++a)
- {
- pkgCache::PkgIterator P = Grp.FindPkg(*a);
- if (P.end() == true)
- continue;
- pkgCache::VerIterator allV = Grp.FindPkg("all").CurrentVer();
- for (VerIterator V = P.VersionList(); V.end() != true; ++V)
- {
- // search for the same version as the all package
- if (allV->Hash != V->Hash || strcmp(allV.VerStr(),V.VerStr()) != 0)
- continue;
- unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
- // If it is broken, try to install dependencies first before retry
- if ((CurDepState & DepInstMin) != DepInstMin)
- {
- for (pkgCache::DepIterator D = V.DependsList(); D.end() != true; ++D)
- {
- if (D->Type != pkgCache::Dep::PreDepends && D->Type != pkgCache::Dep::Depends)
- continue;
- ReInstallPseudoForGroup(D.TargetPkg(), recheck);
- }
- unsigned char const CurDepState = VersionState(V.DependsList(),DepInstall,DepInstMin,DepInstPolicy);
- // if package ist still broken… try another arch
- if ((CurDepState & DepInstMin) != DepInstMin)
- break;
- }
- // dependencies satisfied: reinstall the package
- RemoveSizes(P);
- RemoveStates(P);
- P->CurrentVer = V.Index();
- PkgState[P->ID].InstallVer = V;
- AddStates(P);
- Update(P);
- AddSizes(P);
- return true;
- }
- }
- return false;
- }
- /*}}}*/
- // DepCache::Update - Update the deps list of a package /*{{{*/
- // ---------------------------------------------------------------------
- /* This is a helper for update that only does the dep portion of the scan.
- It is mainly meant to scan reverse dependencies. */
- void pkgDepCache::Update(DepIterator D)
- {
- // Update the reverse deps
- for (;D.end() != true; D++)
- {
- unsigned char &State = DepState[D->ID];
- State = DependencyState(D);
-
- // Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
- State = ~State;
- RemoveStates(D.ParentPkg());
- BuildGroupOrs(D.ParentVer());
- UpdateVerState(D.ParentPkg());
- AddStates(D.ParentPkg());
- }
- }
- /*}}}*/
- // DepCache::Update - Update the related deps of a package /*{{{*/
- // ---------------------------------------------------------------------
- /* This is called whenever the state of a package changes. It updates
- all cached dependencies related to this package. */
- void pkgDepCache::Update(PkgIterator const &Pkg)
- {
- // Recompute the dep of the package
- RemoveStates(Pkg);
- UpdateVerState(Pkg);
- AddStates(Pkg);
-
- // Update the reverse deps
- Update(Pkg.RevDependsList());
- // Update the provides map for the current ver
- if (Pkg->CurrentVer != 0)
- for (PrvIterator P = Pkg.CurrentVer().ProvidesList();
- P.end() != true; P++)
- Update(P.ParentPkg().RevDependsList());
- // Update the provides map for the candidate ver
- if (PkgState[Pkg->ID].CandidateVer != 0)
- for (PrvIterator P = PkgState[Pkg->ID].CandidateVerIter(*this).ProvidesList();
- P.end() != true; P++)
- Update(P.ParentPkg().RevDependsList());
- }
- /*}}}*/
- // DepCache::MarkKeep - Put the package in the keep state /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgDepCache::MarkKeep(PkgIterator const &Pkg, bool Soft, bool FromUser,
- unsigned long Depth)
- {
- // Simplifies other routines.
- if (Pkg.end() == true)
- return;
- /* Reject an attempt to keep a non-source broken installed package, those
- must be upgraded */
- if (Pkg.State() == PkgIterator::NeedsUnpack &&
- Pkg.CurrentVer().Downloadable() == false)
- return;
-
- /** \todo Can this be moved later in the method? */
- ActionGroup group(*this);
- /* We changed the soft state all the time so the UI is a bit nicer
- to use */
- StateCache &P = PkgState[Pkg->ID];
- if (Soft == true)
- P.iFlags |= AutoKept;
- else
- P.iFlags &= ~AutoKept;
-
- // Check that it is not already kept
- if (P.Mode == ModeKeep)
- return;
- // We dont even try to keep virtual packages..
- if (Pkg->VersionList == 0)
- return;
- #if 0 // reseting the autoflag here means we lose the
- // auto-mark information if a user selects a package for removal
- // but changes his mind then and sets it for keep again
- // - this makes sense as default when all Garbage dependencies
- // are automatically marked for removal (as aptitude does).
- // setting a package for keep then makes it no longer autoinstalled
- // for all other use-case this action is rather suprising
- if(FromUser && !P.Marked)
- P.Flags &= ~Flag::Auto;
- #endif
- if (DebugMarker == true)
- std::clog << OutputInDepth(Depth) << "MarkKeep " << Pkg << " FU=" << FromUser << std::endl;
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
- P.Mode = ModeKeep;
- if (Pkg->CurrentVer == 0)
- P.InstallVer = 0;
- else
- P.InstallVer = Pkg.CurrentVer();
- AddStates(Pkg);
- Update(Pkg);
- AddSizes(Pkg);
- }
- /*}}}*/
- // DepCache::MarkDelete - Put the package in the delete state /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge,
- unsigned long Depth, bool FromUser)
- {
- // Simplifies other routines.
- if (Pkg.end() == true)
- return;
- ActionGroup group(*this);
- // Check that it is not already marked for delete
- StateCache &P = PkgState[Pkg->ID];
- P.iFlags &= ~(AutoKept | Purge);
- if (rPurge == true)
- P.iFlags |= Purge;
-
- if ((P.Mode == ModeDelete || P.InstallVer == 0) &&
- (Pkg.Purge() == true || rPurge == false))
- return;
-
- // We dont even try to delete virtual packages..
- if (Pkg->VersionList == 0)
- return;
- // check if we are allowed to install the package
- if (IsDeleteOk(Pkg,rPurge,Depth,FromUser) == false)
- return;
- if (DebugMarker == true)
- std::clog << OutputInDepth(Depth) << "MarkDelete " << Pkg << " FU=" << FromUser << std::endl;
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
-
- if (Pkg->CurrentVer == 0 && (Pkg.Purge() == true || rPurge == false))
- P.Mode = ModeKeep;
- else
- P.Mode = ModeDelete;
- P.InstallVer = 0;
- AddStates(Pkg);
- Update(Pkg);
- AddSizes(Pkg);
- // if we remove the pseudo package, we also need to remove the "real"
- if (Pkg->CurrentVer != 0 && Pkg.CurrentVer().Pseudo() == true)
- MarkDelete(Pkg.Group().FindPkg("all"), rPurge, Depth+1, FromUser);
- }
- /*}}}*/
- // DepCache::IsDeleteOk - check if it is ok to remove this package /*{{{*/
- // ---------------------------------------------------------------------
- /* The default implementation just honors dpkg hold
- But an application using this library can override this method
- to control the MarkDelete behaviour */
- bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge,
- unsigned long Depth, bool FromUser)
- {
- if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
- {
- if (DebugMarker == true)
- std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl;
- return false;
- }
- return true;
- }
- /*}}}*/
- // DepCache::MarkInstall - Put the package in the install state /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
- unsigned long Depth, bool FromUser,
- bool ForceImportantDeps)
- {
- if (Depth > 100)
- return;
-
- // Simplifies other routines.
- if (Pkg.end() == true)
- return;
-
- ActionGroup group(*this);
- /* Check that it is not already marked for install and that it can be
- installed */
- StateCache &P = PkgState[Pkg->ID];
- P.iFlags &= ~AutoKept;
- if ((P.InstPolicyBroken() == false && P.InstBroken() == false) &&
- (P.Mode == ModeInstall ||
- P.CandidateVer == (Version *)Pkg.CurrentVer()))
- {
- if (P.CandidateVer == (Version *)Pkg.CurrentVer() && P.InstallVer == 0)
- MarkKeep(Pkg, false, FromUser, Depth+1);
- return;
- }
- // See if there is even any possible instalation candidate
- if (P.CandidateVer == 0)
- return;
- // We dont even try to install virtual packages..
- if (Pkg->VersionList == 0)
- return;
- // check if we are allowed to install the package
- if (IsInstallOk(Pkg,AutoInst,Depth,FromUser) == false)
- return;
- /* Target the candidate version and remove the autoflag. We reset the
- autoflag below if this was called recursively. Otherwise the user
- should have the ability to de-auto a package by changing its state */
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
-
- P.Mode = ModeInstall;
- P.InstallVer = P.CandidateVer;
- if(FromUser)
- {
- // Set it to manual if it's a new install or cancelling the
- // removal of a garbage package.
- if(P.Status == 2 || (!Pkg.CurrentVer().end() && !P.Marked))
- P.Flags &= ~Flag::Auto;
- }
- else
- {
- // Set it to auto if this is a new install.
- if(P.Status == 2)
- P.Flags |= Flag::Auto;
- }
- if (P.CandidateVer == (Version *)Pkg.CurrentVer())
- P.Mode = ModeKeep;
-
- AddStates(Pkg);
- Update(Pkg);
- AddSizes(Pkg);
- if (AutoInst == false)
- return;
- if (DebugMarker == true)
- std::clog << OutputInDepth(Depth) << "MarkInstall " << Pkg << " FU=" << FromUser << std::endl;
- DepIterator Dep = P.InstVerIter(*this).DependsList();
- for (; Dep.end() != true;)
- {
- // Grok or groups
- DepIterator Start = Dep;
- bool Result = true;
- unsigned Ors = 0;
- for (bool LastOR = true; Dep.end() == false && LastOR == true; Dep++,Ors++)
- {
- LastOR = (Dep->CompareOp & Dep::Or) == Dep::Or;
- if ((DepState[Dep->ID] & DepInstall) == DepInstall)
- Result = false;
- }
-
- // Dep is satisfied okay.
- if (Result == false)
- continue;
- /* Check if this dep should be consider for install. If it is a user
- defined important dep and we are installed a new package then
- it will be installed. Otherwise we only check for important
- deps that have changed from the installed version
- */
- if (IsImportantDep(Start) == false)
- continue;
-
- /* Check if any ImportantDep() (but not Critical) were added
- * since we installed the package. Also check for deps that
- * were satisfied in the past: for instance, if a version
- * restriction in a Recommends was tightened, upgrading the
- * package should follow that Recommends rather than causing the
- * dependency to be removed. (bug #470115)
- */
- bool isNewImportantDep = false;
- bool isPreviouslySatisfiedImportantDep = false;
- if(!ForceImportantDeps && !Start.IsCritical())
- {
- bool found=false;
- VerIterator instVer = Pkg.CurrentVer();
- if(!instVer.end())
- {
- for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
- {
- //FIXME: deal better with or-groups(?)
- DepIterator LocalStart = D;
- if(IsImportantDep(D) && !D.IsCritical() &&
- Start.TargetPkg() == D.TargetPkg())
- {
- if(!isPreviouslySatisfiedImportantDep)
- {
- DepIterator D2 = D;
- while((D2->CompareOp & Dep::Or) != 0)
- ++D2;
- isPreviouslySatisfiedImportantDep =
- (((*this)[D2] & DepGNow) != 0);
- }
- found=true;
- }
- }
- // this is a new dep if it was not found to be already
- // a important dep of the installed pacakge
- isNewImportantDep = !found;
- }
- }
- if(isNewImportantDep)
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "new important dependency: "
- << Start.TargetPkg().Name() << std::endl;
- if(isPreviouslySatisfiedImportantDep)
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
- << Start.TargetPkg().Name() << std::endl;
- // skip important deps if the package is already installed
- if (Pkg->CurrentVer != 0 && Start.IsCritical() == false
- && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
- && !ForceImportantDeps)
- continue;
-
- /* If we are in an or group locate the first or that can
- succeed. We have already cached this.. */
- for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
- Start++;
- /* This bit is for processing the possibilty of an install/upgrade
- fixing the problem */
- SPtrArray<Version *> List = Start.AllTargets();
- if (Start->Type != Dep::DpkgBreaks &&
- (DepState[Start->ID] & DepCVer) == DepCVer)
- {
- // Right, find the best version to install..
- Version **Cur = List;
- PkgIterator P = Start.TargetPkg();
- PkgIterator InstPkg(*Cache,0);
-
- // See if there are direct matches (at the start of the list)
- for (; *Cur != 0 && (*Cur)->ParentPkg == P.Index(); Cur++)
- {
- PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
- if (PkgState[Pkg->ID].CandidateVer != *Cur)
- continue;
- InstPkg = Pkg;
- break;
- }
- // Select the highest priority providing package
- if (InstPkg.end() == true)
- {
- pkgPrioSortList(*Cache,Cur);
- for (; *Cur != 0; Cur++)
- {
- PkgIterator Pkg(*Cache,Cache->PkgP + (*Cur)->ParentPkg);
- if (PkgState[Pkg->ID].CandidateVer != *Cur)
- continue;
- InstPkg = Pkg;
- break;
- }
- }
-
- if (InstPkg.end() == false)
- {
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "Installing " << InstPkg.Name()
- << " as " << Start.DepType() << " of " << Pkg.Name()
- << std::endl;
- // now check if we should consider it a automatic dependency or not
- if(Pkg.Section() && ConfigValueInSubTree("APT::Never-MarkAuto-Sections", Pkg.Section()))
- {
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "Setting NOT as auto-installed (direct "
- << Start.DepType() << " of pkg in APT::Never-MarkAuto-Sections)" << std::endl;
- MarkInstall(InstPkg,true,Depth + 1, true);
- }
- else
- {
- // mark automatic dependency
- MarkInstall(InstPkg,true,Depth + 1, false, ForceImportantDeps);
- // Set the autoflag, after MarkInstall because MarkInstall unsets it
- if (P->CurrentVer == 0)
- PkgState[InstPkg->ID].Flags |= Flag::Auto;
- }
- }
- continue;
- }
- /* For conflicts we just de-install the package and mark as auto,
- Conflicts may not have or groups. For dpkg's Breaks we try to
- upgrade the package. */
- if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes ||
- Start->Type == Dep::DpkgBreaks)
- {
- for (Version **I = List; *I != 0; I++)
- {
- VerIterator Ver(*this,*I);
- PkgIterator Pkg = Ver.ParentPkg();
- if (Start->Type != Dep::DpkgBreaks)
- MarkDelete(Pkg,false,Depth + 1, false);
- else if (PkgState[Pkg->ID].CandidateVer != *I)
- MarkInstall(Pkg,true,Depth + 1, false, ForceImportantDeps);
- }
- continue;
- }
- }
- }
- /*}}}*/
- // DepCache::IsInstallOk - check if it is ok to install this package /*{{{*/
- // ---------------------------------------------------------------------
- /* The default implementation just honors dpkg hold
- But an application using this library can override this method
- to control the MarkInstall behaviour */
- bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst,
- unsigned long Depth, bool FromUser)
- {
- if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false)
- {
- if (DebugMarker == true)
- std::clog << OutputInDepth(Depth) << "Hold prevents MarkInstall of " << Pkg << " FU=" << FromUser << std::endl;
- return false;
- }
- return true;
- }
- /*}}}*/
- // DepCache::SetReInstall - Set the reinstallation flag /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgDepCache::SetReInstall(PkgIterator const &Pkg,bool To)
- {
- ActionGroup group(*this);
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
-
- StateCache &P = PkgState[Pkg->ID];
- if (To == true)
- P.iFlags |= ReInstall;
- else
- P.iFlags &= ~ReInstall;
-
- AddStates(Pkg);
- AddSizes(Pkg);
- }
- /*}}}*/
- // DepCache::SetCandidateVersion - Change the candidate version /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- void pkgDepCache::SetCandidateVersion(VerIterator TargetVer)
- {
- ActionGroup group(*this);
- pkgCache::PkgIterator Pkg = TargetVer.ParentPkg();
- StateCache &P = PkgState[Pkg->ID];
- RemoveSizes(Pkg);
- RemoveStates(Pkg);
- if (P.CandidateVer == P.InstallVer)
- P.InstallVer = (Version *)TargetVer;
- P.CandidateVer = (Version *)TargetVer;
- P.Update(Pkg,*this);
-
- AddStates(Pkg);
- Update(Pkg);
- AddSizes(Pkg);
- }
- void pkgDepCache::MarkAuto(const PkgIterator &Pkg, bool Auto)
- {
- StateCache &state = PkgState[Pkg->ID];
- ActionGroup group(*this);
- if(Auto)
- state.Flags |= Flag::Auto;
- else
- state.Flags &= ~Flag::Auto;
- }
- /*}}}*/
- // StateCache::Update - Compute the various static display things /*{{{*/
- // ---------------------------------------------------------------------
- /* This is called whenever the Candidate version changes. */
- void pkgDepCache::StateCache::Update(PkgIterator Pkg,pkgCache &Cache)
- {
- // Some info
- VerIterator Ver = CandidateVerIter(Cache);
-
- // Use a null string or the version string
- if (Ver.end() == true)
- CandVersion = "";
- else
- CandVersion = Ver.VerStr();
-
- // Find the current version
- CurVersion = "";
- if (Pkg->CurrentVer != 0)
- CurVersion = Pkg.CurrentVer().VerStr();
-
- // Strip off the epochs for display
- CurVersion = StripEpoch(CurVersion);
- CandVersion = StripEpoch(CandVersion);
-
- // Figure out if its up or down or equal
- Status = Ver.CompareVer(Pkg.CurrentVer());
- if (Pkg->CurrentVer == 0 || Pkg->VersionList == 0 || CandidateVer == 0)
- Status = 2;
- }
- /*}}}*/
- // StateCache::StripEpoch - Remove the epoch specifier from the version /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- const char *pkgDepCache::StateCache::StripEpoch(const char *Ver)
- {
- if (Ver == 0)
- return 0;
- // Strip any epoch
- for (const char *I = Ver; *I != 0; I++)
- if (*I == ':')
- return I + 1;
- return Ver;
- }
- /*}}}*/
- // Policy::GetCandidateVer - Returns the Candidate install version /*{{{*/
- // ---------------------------------------------------------------------
- /* The default just returns the highest available version that is not
- a source and automatic. */
- pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator Pkg)
- {
- /* Not source/not automatic versions cannot be a candidate version
- unless they are already installed */
- VerIterator Last(*(pkgCache *)this,0);
-
- for (VerIterator I = Pkg.VersionList(); I.end() == false; I++)
- {
- if (Pkg.CurrentVer() == I)
- return I;
-
- for (VerFileIterator J = I.FileList(); J.end() == false; J++)
- {
- if ((J.File()->Flags & Flag::NotSource) != 0)
- continue;
- /* Stash the highest version of a not-automatic source, we use it
- if there is nothing better */
- if ((J.File()->Flags & Flag::NotAutomatic) != 0)
- {
- if (Last.end() == true)
- Last = I;
- continue;
- }
- return I;
- }
- }
-
- return Last;
- }
- /*}}}*/
- // Policy::IsImportantDep - True if the dependency is important /*{{{*/
- // ---------------------------------------------------------------------
- /* */
- bool pkgDepCache::Policy::IsImportantDep(DepIterator Dep)
- {
- if(Dep.IsCritical())
- return true;
- else if(Dep->Type == pkgCache::Dep::Recommends)
- {
- if ( _config->FindB("APT::Install-Recommends", false))
- return true;
- // we suport a special mode to only install-recommends for certain
- // sections
- // FIXME: this is a meant as a temporarly solution until the
- // recommends are cleaned up
- const char *sec = Dep.ParentVer().Section();
- if (sec && ConfigValueInSubTree("APT::Install-Recommends-Sections", sec))
- return true;
- }
- else if(Dep->Type == pkgCache::Dep::Suggests)
- return _config->FindB("APT::Install-Suggests", false);
- return false;
- }
- /*}}}*/
- pkgDepCache::DefaultRootSetFunc::DefaultRootSetFunc() /*{{{*/
- : constructedSuccessfully(false)
- {
- Configuration::Item const *Opts;
- Opts = _config->Tree("APT::NeverAutoRemove");
- if (Opts != 0 && Opts->Child != 0)
- {
- Opts = Opts->Child;
- for (; Opts != 0; Opts = Opts->Next)
- {
- if (Opts->Value.empty() == true)
- continue;
- regex_t *p = new regex_t;
- if(regcomp(p,Opts->Value.c_str(),
- REG_EXTENDED | REG_ICASE | REG_NOSUB) != 0)
- {
- regfree(p);
- delete p;
- _error->Error("Regex compilation error for APT::NeverAutoRemove");
- return;
- }
- rootSetRegexp.push_back(p);
- }
- }
- constructedSuccessfully = true;
- }
- /*}}}*/
- pkgDepCache::DefaultRootSetFunc::~DefaultRootSetFunc() /*{{{*/
- {
- for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
- {
- regfree(rootSetRegexp[i]);
- delete rootSetRegexp[i];
- }
- }
- /*}}}*/
- bool pkgDepCache::DefaultRootSetFunc::InRootSet(const pkgCache::PkgIterator &pkg) /*{{{*/
- {
- for(unsigned int i = 0; i < rootSetRegexp.size(); i++)
- if (regexec(rootSetRegexp[i], pkg.Name(), 0, 0, 0) == 0)
- return true;
- return false;
- }
- /*}}}*/
- pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/
- {
- DefaultRootSetFunc *f = new DefaultRootSetFunc;
- if(f->wasConstructedSuccessfully())
- return f;
- else
- {
- delete f;
- return NULL;
- }
- }
- /*}}}*/
- bool pkgDepCache::MarkFollowsRecommends()
- {
- return _config->FindB("APT::AutoRemove::RecommendsImportant", true);
- }
- bool pkgDepCache::MarkFollowsSuggests()
- {
- return _config->FindB("APT::AutoRemove::SuggestsImportant", false);
- }
- // pkgDepCache::MarkRequired - the main mark algorithm /*{{{*/
- bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
- {
- bool follow_recommends;
- bool follow_suggests;
- bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
- // init the states
- for(PkgIterator p = PkgBegin(); !p.end(); ++p)
- {
- PkgState[p->ID].Marked = false;
- PkgState[p->ID].Garbage = false;
- // debug output
- if(debug_autoremove && PkgState[p->ID].Flags & Flag::Auto)
- std::clog << "AutoDep: " << p.FullName() << std::endl;
- }
- // init vars
- follow_recommends = MarkFollowsRecommends();
- follow_suggests = MarkFollowsSuggests();
- // do the mark part, this is the core bit of the algorithm
- for(PkgIterator p = PkgBegin(); !p.end(); ++p)
- {
- if(!(PkgState[p->ID].Flags & Flag::Auto) ||
- (p->Flags & Flag::Essential) ||
- userFunc.InRootSet(p) ||
- // be nice even then a required package violates the policy (#583517)
- // and do the full mark process also for required packages
- (p.CurrentVer().end() != true &&
- p.CurrentVer()->Priority == pkgCache::State::Required))
- {
- // the package is installed (and set to keep)
- if(PkgState[p->ID].Keep() && !p.CurrentVer().end())
- MarkPackage(p, p.CurrentVer(),
- follow_recommends, follow_suggests);
- // the package is to be installed
- else if(PkgState[p->ID].Install())
- MarkPackage(p, PkgState[p->ID].InstVerIter(*this),
- follow_recommends, follow_suggests);
- }
- }
- return true;
- }
- /*}}}*/
- // MarkPackage - mark a single package in Mark-and-Sweep /*{{{*/
- void pkgDepCache::MarkPackage(const pkgCache::PkgIterator &pkg,
- const pkgCache::VerIterator &ver,
- bool const &follow_recommends,
- bool const &follow_suggests)
- {
- pkgDepCache::StateCache &state = PkgState[pkg->ID];
- // if we are marked already we are done
- if(state.Marked)
- return;
- VerIterator const currver = pkg.CurrentVer();
- VerIterator const candver = state.CandidateVerIter(*this);
- VerIterator const instver = state.InstVerIter(*this);
- #if 0
- // If a package was garbage-collected but is now being marked, we
- // should re-select it
- // For cases when a pkg is set to upgrade and this trigger the
- // removal of a no-longer used dependency. if the pkg is set to
- // keep again later it will result in broken deps
- if(state.Delete() && state.RemoveReason = Unused)
- {
- if(ver==candver)
- mark_install(pkg, false, false, NULL);
- else if(ver==pkg.CurrentVer())
- MarkKeep(pkg, false, false);
-
- instver=state.InstVerIter(*this);
- }
- #endif
- // For packages that are not going to be removed, ignore versions
- // other than the InstVer. For packages that are going to be
- // removed, ignore versions other than the current version.
- if(!(ver == instver && !instver.end()) &&
- !(ver == currver && instver.end() && !ver.end()))
- return;
- bool const debug_autoremove = _config->FindB("Debug::pkgAutoRemove", false);
- if(debug_autoremove)
- {
- std::clog << "Marking: " << pkg.FullName();
- if(!ver.end())
- std::clog << " " << ver.VerStr();
- if(!currver.end())
- std::clog << ", Curr=" << currver.VerStr();
- if(!instver.end())
- std::clog << ", Inst=" << instver.VerStr();
- std::clog << std::endl;
- }
- state.Marked=true;
- if(ver.end() == true)
- return;
- // If the version belongs to a Multi-Arch all package
- // we will mark all others in this Group with this version also
- if (ver->MultiArch == pkgCache::Version::All &&
- strcmp(ver.Arch(true), "all") == 0)
- {
- GrpIterator G = pkg.Group();
- const char* const VerStr = ver.VerStr();
- for (PkgIterator P = G.FindPkg("any");
- P.end() != true; P = G.NextPkg(P))
- {
- for (VerIterator V = P.VersionList();
- V.end() != true; ++V)
- {
- if (ver->Hash != V->Hash ||
- strcmp(VerStr, V.VerStr()) != 0)
- continue;
- MarkPackage(P, V, follow_recommends, follow_suggests);
- break;
- }
- }
- }
- for(DepIterator d = ver.DependsList(); !d.end(); ++d)
- {
- if(d->Type == Dep::Depends ||
- d->Type == Dep::PreDepends ||
- (follow_recommends &&
- d->Type == Dep::Recommends) ||
- (follow_suggests &&
- d->Type == Dep::Suggests))
- {
- // Try all versions of this package.
- for(VerIterator V = d.TargetPkg().VersionList();
- !V.end(); ++V)
- {
- if(_system->VS->CheckDep(V.VerStr(), d->CompareOp, d.TargetVer()))
- {
- if(debug_autoremove)
- {
- std::clog << "Following dep: " << d.ParentPkg().FullName()
- << " " << d.ParentVer().VerStr() << " "
- << d.DepType() << " " << d.TargetPkg().FullName();
- if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
- {
- std::clog << " (" << d.CompType() << " "
- << d.TargetVer() << ")";
- }
- std::clog << std::endl;
- }
- MarkPackage(V.ParentPkg(), V,
- follow_recommends, follow_suggests);
- }
- }
- // Now try virtual packages
- for(PrvIterator prv=d.TargetPkg().ProvidesList();
- !prv.end(); ++prv)
- {
- if(_system->VS->CheckDep(prv.ProvideVersion(), d->CompareOp,
- d.TargetVer()))
- {
- if(debug_autoremove)
- {
- std::clog << "Following dep: " << d.ParentPkg().FullName() << " "
- << d.ParentVer().VerStr() << " "
- << d.DepType() << " " << d.TargetPkg().FullName() << " ";
- if((d->CompareOp & ~pkgCache::Dep::Or) != pkgCache::Dep::NoOp)
- {
- std::clog << " (" << d.CompType() << " "
- << d.TargetVer() << ")";
- }
- std::clog << ", provided by "
- << prv.OwnerPkg().FullName() << " "
- << prv.OwnerVer().VerStr()
- << std::endl;
- }
- MarkPackage(prv.OwnerPkg(), prv.OwnerVer(),
- follow_recommends, follow_suggests);
- }
- }
- }
- }
- }
- /*}}}*/
- bool pkgDepCache::Sweep() /*{{{*/
- {
- bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
- // do the sweep
- for(PkgIterator p=PkgBegin(); !p.end(); ++p)
- {
- StateCache &state=PkgState[p->ID];
- // skip required packages
- if (!p.CurrentVer().end() &&
- (p.CurrentVer()->Priority == pkgCache::State::Required))
- continue;
- // if it is not marked and it is installed, it's garbage
- if(!state.Marked && (!p.CurrentVer().end() || state.Install()))
- {
- state.Garbage=true;
- if(debug_autoremove)
- std::clog << "Garbage: " << p.FullName() << std::endl;
- }
- }
- return true;
- }
- /*}}}*/
|