diff options
-rw-r--r-- | apt-pkg/algorithms.cc | 270 | ||||
-rw-r--r-- | apt-pkg/algorithms.h | 20 | ||||
-rw-r--r-- | apt-pkg/cacheiterators.h | 5 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.cc | 13 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 6 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.h | 4 | ||||
-rw-r--r-- | apt-pkg/contrib/progress.cc | 32 | ||||
-rw-r--r-- | apt-pkg/contrib/progress.h | 8 | ||||
-rw-r--r-- | apt-pkg/depcache.h | 4 | ||||
-rw-r--r-- | apt-pkg/pkgcache.cc | 14 | ||||
-rw-r--r-- | apt-pkg/pkgcachegen.cc | 8 | ||||
-rw-r--r-- | apt-pkg/tagfile.cc | 13 | ||||
-rw-r--r-- | cmdline/apt-cache.cc | 27 | ||||
-rw-r--r-- | cmdline/apt-get.cc | 764 | ||||
-rw-r--r-- | cmdline/makefile | 4 | ||||
-rw-r--r-- | doc/examples/apt.conf | 47 | ||||
-rw-r--r-- | doc/examples/sources.list | 4 | ||||
-rw-r--r-- | doc/files.sgml | 170 |
18 files changed, 1220 insertions, 193 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index ce0c41efd..2e4ca5c2c 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1,10 +1,16 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: algorithms.cc,v 1.3 1998/07/12 23:58:20 jgg Exp $ +// $Id: algorithms.cc,v 1.4 1998/10/02 04:39:42 jgg Exp $ /* ###################################################################### Algorithms - A set of misc algorithms + The pkgProblemResolver class has become insanely complex and + very sophisticated, it handles every test case I have thrown at it + to my satisfaction. Understanding exactly why all the steps the class + does are required is difficult and changing though not very risky + may result in other cases not working. + ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ @@ -13,6 +19,7 @@ #endif #include <apt-pkg/algorithms.h> #include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> #include <iostream.h> /*}}}*/ @@ -37,7 +44,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) PkgIterator Pkg = Sim.FindPkg(iPkg.Name()); Flags[Pkg->ID] = 1; - cout << "Inst " << Pkg.Name(); + clog << "Inst " << Pkg.Name(); Sim.MarkInstall(Pkg,false); // Look for broken conflicts+predepends. @@ -51,7 +58,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) { if ((Sim[D] & pkgDepCache::DepInstall) == 0) { - cout << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']'; + clog << " [" << I.Name() << " on " << D.TargetPkg().Name() << ']'; if (D->Type == pkgCache::Dep::Conflicts) _error->Error("Fatal, conflicts violated %s",I.Name()); } @@ -61,7 +68,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/) if (Sim.BrokenCount() != 0) ShortBreaks(); else - cout << endl; + clog << endl; return true; } /*}}}*/ @@ -79,7 +86,7 @@ bool pkgSimulate::Configure(PkgIterator iPkg) // Sim.MarkInstall(Pkg,false); if (Sim[Pkg].InstBroken() == true) { - cout << "Conf " << Pkg.Name() << " broken" << endl; + clog << "Conf " << Pkg.Name() << " broken" << endl; Sim.Update(); @@ -91,21 +98,21 @@ bool pkgSimulate::Configure(PkgIterator iPkg) continue; if (D->Type == pkgCache::Dep::Conflicts) - cout << " Conflicts:" << D.TargetPkg().Name(); + clog << " Conflicts:" << D.TargetPkg().Name(); else - cout << " Depends:" << D.TargetPkg().Name(); + clog << " Depends:" << D.TargetPkg().Name(); } - cout << endl; + clog << endl; _error->Error("Conf Broken %s",Pkg.Name()); } else - cout << "Conf " << Pkg.Name(); + clog << "Conf " << Pkg.Name(); if (Sim.BrokenCount() != 0) ShortBreaks(); else - cout << endl; + clog << endl; return true; } @@ -120,12 +127,12 @@ bool pkgSimulate::Remove(PkgIterator iPkg) Flags[Pkg->ID] = 3; Sim.MarkDelete(Pkg); - cout << "Remv " << Pkg.Name(); + clog << "Remv " << Pkg.Name(); if (Sim.BrokenCount() != 0) ShortBreaks(); else - cout << endl; + clog << endl; return true; } @@ -135,18 +142,18 @@ bool pkgSimulate::Remove(PkgIterator iPkg) /* */ void pkgSimulate::ShortBreaks() { - cout << " ["; + clog << " ["; for (PkgIterator I = Sim.PkgBegin(); I.end() == false; I++) { if (Sim[I].InstBroken() == true) { if (Flags[I->ID] == 0) - cout << I.Name() << ' '; + clog << I.Name() << ' '; /* else - cout << I.Name() << "! ";*/ + clog << I.Name() << "! ";*/ } } - cout << ']' << endl; + clog << ']' << endl; } /*}}}*/ // ApplyStatus - Adjust for non-ok packages /*{{{*/ @@ -182,8 +189,8 @@ bool pkgApplyStatus(pkgDepCache &Cache) /*}}}*/ // FixBroken - Fix broken packages /*{{{*/ // --------------------------------------------------------------------- -/* This autoinstalls every broken package and then runs ScoredFix on the - result. */ +/* This autoinstalls every broken package and then runs the problem resolver + on the result. */ bool pkgFixBroken(pkgDepCache &Cache) { // Auto upgrade all broken packages @@ -215,7 +222,7 @@ bool pkgFixBroken(pkgDepCache &Cache) pre-existing package. This creates the initial set of conditions which most likely contain problems because too many things were installed. - ScoredFix is used to resolve the problems. + The problem resolver is used to resolve the problems. */ bool pkgDistUpgrade(pkgDepCache &Cache) { @@ -252,6 +259,34 @@ bool pkgDistUpgrade(pkgDepCache &Cache) return Fix.Resolve(); } /*}}}*/ +// AllUpgrade - Upgrade as many packages as possible /*{{{*/ +// --------------------------------------------------------------------- +/* Right now the system must be consistent before this can be called. + It also will not change packages marked for install, it only tries + to install packages not marked for install */ +bool pkgAllUpgrade(pkgDepCache &Cache) +{ + pkgProblemResolver Fix(Cache); + + if (Cache.BrokenCount() != 0) + return false; + + // Upgrade all installed packages + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) + { + if (Cache[I].Install() == true) + Fix.Protect(I); + + if (I->SelectedState == pkgCache::State::Hold) + continue; + + if (I->CurrentVer != 0 && Cache[I].InstallVer != 0) + Cache.MarkInstall(I,false); + } + + return Fix.ResolveByKeep(); +} + /*}}}*/ // ProblemResolver::pkgProblemResolver - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -265,7 +300,7 @@ pkgProblemResolver::pkgProblemResolver(pkgDepCache &Cache) : Cache(Cache) memset(Flags,0,sizeof(*Flags)*Size); // Set debug to true to see its decision logic - Debug = false; + Debug = _config->FindB("Debug::pkgProblemResolver",false); } /*}}}*/ // ProblemResolver::ScoreSort - Sort the list by score /*{{{*/ @@ -383,11 +418,16 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) { if ((Flags[Pkg->ID] & Upgradable) == 0 || Cache[Pkg].Upgradable() == false) return false; + Flags[Pkg->ID] &= ~Upgradable; bool WasKept = Cache[Pkg].Keep(); Cache.MarkInstall(Pkg,false); + // This must be a virtual package or something like that. + if (Cache[Pkg].InstVerIter(Cache).end() == true) + return false; + // Isolate the problem dependency bool Fail = false; for (pkgCache::DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false;) @@ -415,19 +455,28 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) // Hm, the group is broken.. I have no idea how to handle this if (Start != End) { - cout << "Note, a broken or group was found in " << Pkg.Name() << "." << endl; + clog << "Note, a broken or group was found in " << Pkg.Name() << "." << endl; Fail = true; break; } - + + // Do not change protected packages + PkgIterator P = Start.SmartTargetPkg(); + if ((Flags[P->ID] & Protected) == Protected) + { + if (Debug == true) + clog << " Reinet Failed because of protected " << P.Name() << endl; + Fail = true; + break; + } + // Upgrade the package if the candidate version will fix the problem. if ((Cache[Start] & pkgDepCache::DepCVer) == pkgDepCache::DepCVer) { - PkgIterator P = Start.SmartTargetPkg(); if (DoUpgrade(P) == false) { if (Debug == true) - cout << " Reinst Failed because of " << P.Name() << endl; + clog << " Reinst Failed because of " << P.Name() << endl; Fail = true; break; } @@ -440,7 +489,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) continue; if (Debug == true) - cout << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl; + clog << " Reinst Failed early because of " << Start.TargetPkg().Name() << endl; Fail = true; break; } @@ -457,7 +506,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) } if (Debug == true) - cout << " Re-Instated " << Pkg.Name() << endl; + clog << " Re-Instated " << Pkg.Name() << endl; return true; } /*}}}*/ @@ -477,7 +526,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg) upgrade packages to advoid problems. */ bool pkgProblemResolver::Resolve(bool BrokenFix) { - unsigned long Size = Cache.HeaderP->PackageCount; + unsigned long Size = Cache.HeaderP->PackageCount; // Record which packages are marked for install bool Again = false; @@ -505,7 +554,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) while (Again == true); if (Debug == true) - cout << "Starting" << endl; + clog << "Starting" << endl; MakeScores(); @@ -524,13 +573,13 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Scores[(*K)->ID] != 0) { pkgCache::PkgIterator Pkg(Cache,*K); - cout << Scores[(*K)->ID] << ' ' << Pkg.Name() << + clog << Scores[(*K)->ID] << ' ' << Pkg.Name() << ' ' << (pkgCache::Version *)Pkg.CurrentVer() << ' ' << Cache[Pkg].InstallVer << ' ' << Cache[Pkg].CandidateVer << endl; } */ if (Debug == true) - cout << "Starting 2" << endl; + clog << "Starting 2" << endl; /* Now consider all broken packages. For each broken package we either remove the package or fix it's problem. We do this once, it should @@ -549,13 +598,15 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Cache[I].CandidateVer != Cache[I].InstallVer && I->CurrentVer != 0 && Cache[I].InstallVer != 0 && (Flags[I->ID] & PreInstalled) != 0 && - (Flags[I->ID] & Protected) == 0) + (Flags[I->ID] & Protected) == 0 && + (Flags[I->ID] & ReInstateTried) == 0) { if (Debug == true) - cout << " Try to Re-Instate " << I.Name() << endl; + clog << " Try to Re-Instate " << I.Name() << endl; int OldBreaks = Cache.BrokenCount(); pkgCache::Version *OldVer = Cache[I].InstallVer; - + Flags[I->ID] &= ReInstateTried; + Cache.MarkInstall(I,false); if (Cache[I].InstBroken() == true || OldBreaks < Cache.BrokenCount()) @@ -567,7 +618,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) } else if (Debug == true) - cout << "Re-Instated " << I.Name() << endl; + clog << "Re-Instated " << I.Name() << " (" << OldBreaks << " vs " << Cache.BrokenCount() << ')' << endl; } if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false) @@ -601,13 +652,13 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) // Hm, the group is broken.. I have no idea how to handle this if (Start != End) { - cout << "Note, a broken or group was found in " << I.Name() << "." << endl; + clog << "Note, a broken or group was found in " << I.Name() << "." << endl; Cache.MarkDelete(I); break; } if (Debug == true) - cout << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl; + clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl; /* Conflicts is simple, decide if we should remove this package or the conflicted one */ @@ -619,7 +670,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) pkgCache::PkgIterator Pkg = Ver.ParentPkg(); if (Debug == true) - cout << " Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] << + clog << " Considering " << Pkg.Name() << ' ' << (int)Scores[Pkg->ID] << " as a solution to " << I.Name() << ' ' << (int)Scores[I->ID] << endl; if (Scores[I->ID] <= Scores[Pkg->ID] || ((Cache[End] & pkgDepCache::DepGNow) == 0 && @@ -627,24 +678,24 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) { if ((Flags[I->ID] & Protected) != 0) continue; - + // See if a keep will do Cache.MarkKeep(I); if (Cache[I].InstBroken() == false) { if (Debug == true) - cout << " Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl; + clog << " Holding Back " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl; } else { if (BrokenFix == false || DoUpgrade(I) == false) { if (Debug == true) - cout << " Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl; + clog << " Removing " << I.Name() << " rather than change " << End.TargetPkg().Name() << endl; Cache.MarkDelete(I); if (Counter > 1) Scores[I->ID] = Scores[Pkg->ID]; - } + } } Change = true; @@ -660,6 +711,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) LEnd->Pkg = Pkg; LEnd->Dep = End; LEnd++; + if (End->Type != pkgCache::Dep::Conflicts) break; } @@ -672,12 +724,12 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (Cache[I].InstBroken() == false) { if (Debug == true) - cout << " Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl; + clog << " Holding Back " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl; } else { if (Debug == true) - cout << " Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl; + clog << " Removing " << I.Name() << " because I can't find " << End.TargetPkg().Name() << endl; Cache.MarkDelete(I); } @@ -700,14 +752,14 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) if (J->Dep->Type == pkgCache::Dep::Conflicts) { if (Debug == true) - cout << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl; + clog << " Fixing " << I.Name() << " via remove of " << J->Pkg.Name() << endl; Cache.MarkDelete(J->Pkg); } } else { if (Debug == true) - cout << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl; + clog << " Fixing " << I.Name() << " via keep of " << J->Pkg.Name() << endl; Cache.MarkKeep(J->Pkg); } @@ -718,13 +770,137 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) } if (Debug == true) - cout << "Done" << endl; + clog << "Done" << endl; delete [] Scores; delete [] PList; if (Cache.BrokenCount() != 0) - return _error->Error("Internal error, ScoredFix generated breaks."); + return _error->Error("Internal error, pkgProblemResolver::Resolve generated breaks."); + + return true; +} + /*}}}*/ +// ProblemResolver::ResolveByKeep - Resolve problems using keep /*{{{*/ +// --------------------------------------------------------------------- +/* This is the work horse of the soft upgrade routine. It is very gental + in that it does not install or remove any packages. It is assumed that the + system was non-broken previously. */ +bool pkgProblemResolver::ResolveByKeep() +{ + unsigned long Size = Cache.HeaderP->PackageCount; + + if (Debug == true) + clog << "Entering ResolveByKeep" << endl; + + MakeScores(); + + /* We have to order the packages so that the broken fixing pass + operates from highest score to lowest. This prevents problems when + high score packages cause the removal of lower score packages that + would cause the removal of even lower score packages. */ + pkgCache::Package **PList = new pkgCache::Package *[Size]; + pkgCache::Package **PEnd = PList; + for (pkgCache::PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) + *PEnd++ = I; + This = this; + qsort(PList,PEnd - PList,sizeof(*PList),&ScoreSort); + + // Consider each broken package + pkgCache::Package **LastStop = 0; + for (pkgCache::Package **K = PList; K != PEnd; K++) + { + pkgCache::PkgIterator I(Cache,*K); + + if (Cache[I].InstallVer == 0 || Cache[I].InstBroken() == false) + continue; + + /* Keep the package. If this works then great, otherwise we have + to be significantly more agressive and manipulate its dependencies */ + if ((Flags[I->ID] & Protected) == 0) + { + if (Debug == true) + clog << "Keeping package " << I.Name() << endl; + Cache.MarkKeep(I); + if (Cache[I].InstBroken() == false) + { + K = PList; + continue; + } + } + + // Isolate the problem dependencies + for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;) + { + // Compute a single dependency element (glob or) + pkgCache::DepIterator Start = D; + pkgCache::DepIterator End = D; + unsigned char State = 0; + for (bool LastOR = true; D.end() == false && LastOR == true; D++) + { + State |= Cache[D]; + LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or; + if (LastOR == true) + End = D; + } + + // We only worry about critical deps. + if (End.IsCritical() != true) + continue; + + // Dep is ok + if ((Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall) + continue; + + // Hm, the group is broken.. I have no idea how to handle this + if (Start != End) + { + clog << "Note, a broken or group was found in " << I.Name() << "." << endl; + if ((Flags[I->ID] & Protected) == 0) + Cache.MarkKeep(I); + break; + } + + if (Debug == true) + clog << "Package " << I.Name() << " has broken dep on " << End.TargetPkg().Name() << endl; + + // Look at all the possible provides on this package + pkgCache::Version **VList = End.AllTargets(); + bool Done = false; + for (pkgCache::Version **V = VList; *V != 0; V++) + { + pkgCache::VerIterator Ver(Cache,*V); + pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + + // It is not keepable + if (Cache[Pkg].InstallVer == 0 || + Pkg->CurrentVer == 0) + continue; + + if ((Flags[I->ID] & Protected) == 0) + { + if (Debug == true) + clog << " Keeping Package " << Pkg.Name() << " due to dep" << endl; + Cache.MarkKeep(Pkg); + } + + if (Cache[I].InstBroken() == false) + break; + } + + if (Cache[I].InstBroken() == false) + break; + } + + if (Cache[I].InstBroken() == true) + continue; + + // Restart again. + if (K == LastStop) + return _error->Error("Internal Error, pkgProblemResolver::ResolveByKeep is looping on package %s.",I.Name()); + LastStop = K; + K = PList; + } return true; } diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h index d17a42447..0379357c2 100644 --- a/apt-pkg/algorithms.h +++ b/apt-pkg/algorithms.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: algorithms.h,v 1.3 1998/07/19 21:24:11 jgg Exp $ +// $Id: algorithms.h,v 1.4 1998/10/02 04:39:43 jgg Exp $ /* ###################################################################### Algorithms - A set of misc algorithms @@ -16,7 +16,15 @@ field in the status file. It is important to get proper crash recovery. pkgFixBroken corrects a broken system so that it is in a sane state. + + pkgAllUpgrade attempts to upgade as many packages as possible but + without installing new packages. + The problem resolver class contains a number of complex algorithms + to try to best-guess an upgrade state. It solves the problem of + maximizing the number of install state packages while having no broken + packages. + ##################################################################### */ /*}}}*/ // Header section: pkglib @@ -60,7 +68,7 @@ class pkgProblemResolver typedef pkgCache::Package Package; enum Flags {Protected = (1 << 0), PreInstalled = (1 << 1), - Upgradable = (1 << 2)}; + Upgradable = (1 << 2), ReInstateTried = (1 << 3)}; signed short *Scores; unsigned char *Flags; bool Debug; @@ -81,13 +89,19 @@ class pkgProblemResolver public: inline void Protect(pkgCache::PkgIterator Pkg) {Flags[Pkg->ID] |= Protected;}; + + // Try to intelligently resolve problems by installing and removing packages bool Resolve(bool BrokenFix = false); - + + // Try to resolve problems only by using keep + bool ResolveByKeep(); + pkgProblemResolver(pkgDepCache &Cache); }; bool pkgDistUpgrade(pkgDepCache &Cache); bool pkgApplyStatus(pkgDepCache &Cache); bool pkgFixBroken(pkgDepCache &Cache); +bool pkgAllUpgrade(pkgDepCache &Cache); #endif diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h index 390c923b9..7cdc197a2 100644 --- a/apt-pkg/cacheiterators.h +++ b/apt-pkg/cacheiterators.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cacheiterators.h,v 1.6 1998/07/12 23:58:23 jgg Exp $ +// $Id: cacheiterators.h,v 1.7 1998/10/02 04:39:44 jgg Exp $ /* ###################################################################### Cache Iterators - Iterators for navigating the cache structure @@ -173,7 +173,8 @@ class pkgCache::DepIterator bool IsCritical(); Version **AllTargets(); bool SmartTargetPkg(PkgIterator &Result); - + const char *CompType(); + inline DepIterator(pkgCache &Owner,Dependency *Trg,Version * = 0) : Dep(Trg), Type(DepVer), Owner(&Owner) { diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index b12fed6be..433b92244 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: configuration.cc,v 1.5 1998/09/26 05:34:26 jgg Exp $ +// $Id: configuration.cc,v 1.6 1998/10/02 04:39:49 jgg Exp $ /* ###################################################################### Configuration Class @@ -105,6 +105,7 @@ string Configuration::Find(const char *Name,const char *Default) // Configuration::FindDir - Find a directory /*{{{*/ // --------------------------------------------------------------------- /* Directories are stored as the base dir in the Parent node and the + sub directory in sub nodes */ string Configuration::FindDir(const char *Name,const char *Default = 0) { @@ -117,8 +118,16 @@ string Configuration::FindDir(const char *Name,const char *Default = 0) return Default; } + // Absolute path if (Itm->Value[0] == '/' || Itm->Parent == 0) return Itm->Value; + + // ./ is also considered absolute as is anything with ~ in it + if (Itm->Value[0] != 0 && + ((Itm->Value[0] == '.' && Itm->Value[1] == '/') || + (Itm->Value[0] == '~' && Itm->Value[1] == '/'))) + return Itm->Value; + if (Itm->Parent->Value.end()[-1] == '/') return Itm->Parent->Value + Itm->Value; else @@ -167,7 +176,7 @@ bool Configuration::FindB(const char *Name,bool Default) strcasecmp(Itm->Value.c_str(),"true") == 0 || strcasecmp(Itm->Value.c_str(),"with") == 0 || strcasecmp(Itm->Value.c_str(),"enable") == 0) - return false; + return true; return Default; } diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index d18f7853e..60b9f8b75 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: fileutl.cc,v 1.7 1998/08/26 04:52:26 jgg Exp $ +// $Id: fileutl.cc,v 1.8 1998/10/02 04:39:50 jgg Exp $ /* ###################################################################### File Utilities @@ -140,6 +140,10 @@ FileFd::FileFd(string FileName,OpenMode Mode, unsigned long Perms) case WriteExists: iFd = open(FileName.c_str(),O_RDWR); break; + + case WriteAny: + iFd = open(FileName.c_str(),O_RDWR | O_CREAT,Perms); + break; // Dont use this in public directories case LockEmpty: diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index a99d5fee6..c468c95d3 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: fileutl.h,v 1.5 1998/08/26 04:52:27 jgg Exp $ +// $Id: fileutl.h,v 1.6 1998/10/02 04:39:52 jgg Exp $ /* ###################################################################### File Utilities @@ -38,7 +38,7 @@ class FileFd string FileName; public: - enum OpenMode {ReadOnly,WriteEmpty,WriteExists,LockEmpty}; + enum OpenMode {ReadOnly,WriteEmpty,WriteExists,WriteAny,LockEmpty}; bool Read(void *To,unsigned long Size); bool Write(void *From,unsigned long Size); diff --git a/apt-pkg/contrib/progress.cc b/apt-pkg/contrib/progress.cc index 9a29c4b66..0f2218f3c 100644 --- a/apt-pkg/contrib/progress.cc +++ b/apt-pkg/contrib/progress.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: progress.cc,v 1.7 1998/09/07 05:28:38 jgg Exp $ +// $Id: progress.cc,v 1.8 1998/10/02 04:39:53 jgg Exp $ /* ###################################################################### OpProgress - Operation Progress @@ -13,6 +13,7 @@ #endif #include <apt-pkg/progress.h> #include <apt-pkg/error.h> +#include <apt-pkg/configuration.h> #include <stdio.h> /*}}}*/ @@ -108,6 +109,18 @@ bool OpProgress::CheckChange(float Interval) return true; } /*}}}*/ +// OpTextProgress::OpTextProgress - Constructor /*{{{*/ +// --------------------------------------------------------------------- +/* */ +OpTextProgress::OpTextProgress(Configuration &Config) : + NoUpdate(false), NoDisplay(false), LastLen(0) +{ + if (Config.FindI("quiet",0) >= 1) + NoUpdate = true; + if (Config.FindI("quiet",0) >= 2) + NoDisplay = true; +}; + /*}}}*/ // OpTextProgress::Done - Clean up the display /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -123,7 +136,13 @@ void OpTextProgress::Done() Write(S); cout << endl; OldOp = string(); - } + } + + if (NoUpdate == true && NoDisplay == false && OldOp.empty() == false) + { + OldOp = string(); + cout << endl; + } } /*}}}*/ // OpTextProgress::Update - Simple text spinner /*{{{*/ @@ -139,7 +158,14 @@ void OpTextProgress::Update() { if (MajorChange == false) return; - cout << Op << endl; + if (NoDisplay == false) + { + if (OldOp.empty() == false) + cout << endl; + OldOp = "a"; + cout << Op << "..." << flush; + } + return; } diff --git a/apt-pkg/contrib/progress.h b/apt-pkg/contrib/progress.h index 554cb16ea..094c4b016 100644 --- a/apt-pkg/contrib/progress.h +++ b/apt-pkg/contrib/progress.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: progress.h,v 1.3 1998/08/26 04:52:29 jgg Exp $ +// $Id: progress.h,v 1.4 1998/10/02 04:39:54 jgg Exp $ /* ###################################################################### OpProgress - Operation Progress @@ -29,6 +29,7 @@ #include <string> #include <sys/time.h> +class Configuration; class OpProgress { unsigned long Current; @@ -72,6 +73,7 @@ class OpTextProgress : public OpProgress string OldOp; bool NoUpdate; + bool NoDisplay; unsigned long LastLen; virtual void Update(); void Write(const char *S); @@ -80,7 +82,9 @@ class OpTextProgress : public OpProgress virtual void Done(); - OpTextProgress(bool NoUpdate = false) : NoUpdate(NoUpdate), LastLen(0) {}; + OpTextProgress(bool NoUpdate = false) : NoUpdate(NoUpdate), + NoDisplay(false), LastLen(0) {}; + OpTextProgress(Configuration &Config); virtual ~OpTextProgress() {Done();}; }; diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h index 8d90a529f..bd64ee5a2 100644 --- a/apt-pkg/depcache.h +++ b/apt-pkg/depcache.h @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: depcache.h,v 1.4 1998/09/07 05:28:35 jgg Exp $ +// $Id: depcache.h,v 1.5 1998/10/02 04:39:45 jgg Exp $ /* ###################################################################### DepCache - Dependency Extension data for the cache @@ -94,7 +94,7 @@ class pkgDepCache : public pkgCache inline bool Delete() const {return Mode == ModeDelete;}; inline bool Keep() const {return Mode == ModeKeep;}; inline bool Upgrade() const {return Status > 0 && Mode == ModeInstall;}; - inline bool Upgradable() const {return Status == 1;}; + inline bool Upgradable() const {return Status >= 1;}; inline bool Downgrade() const {return Status < 0;}; inline bool Held() const {return Status != 0 && Keep();}; inline bool NowBroken() const {return (DepState & DepNowMin) != DepNowMin;}; diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 02b28fa47..2e62f2ea4 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcache.cc,v 1.8 1998/07/19 04:22:00 jgg Exp $ +// $Id: pkgcache.cc,v 1.9 1998/10/02 04:39:46 jgg Exp $ /* ###################################################################### Package Cache - Accessor code for the cache @@ -336,6 +336,18 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() return Res; } /*}}}*/ +// DepIterator::CompType - Return a string describing the compare type /*{{{*/ +// --------------------------------------------------------------------- +/* This returns a string representation of the dependency compare + type */ +const char *pkgCache::DepIterator::CompType() +{ + const char *Ops[] = {"","<=",">=","<",">","=","!="}; + if ((Dep->CompareOp & 0xF) < sizeof(Ops)) + return Ops[Dep->CompareOp & 0xF]; + return ""; +} + /*}}}*/ // VerIterator::CompareVer - Fast version compare for same pkgs /*{{{*/ // --------------------------------------------------------------------- /* This just looks over the version list to see if B is listed before A. In diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 6b3bfa3c5..567628ef5 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: pkgcachegen.cc,v 1.17 1998/09/26 05:34:23 jgg Exp $ +// $Id: pkgcachegen.cc,v 1.18 1998/10/02 04:39:47 jgg Exp $ /* ###################################################################### Package Cache Generator - Generator for the cache structure. @@ -413,7 +413,7 @@ bool pkgSrcCacheCheck(pkgSourceList &List) } MMap Map(CacheF,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map.Size() == 0) { _error->Discard(); return false; @@ -474,7 +474,7 @@ bool pkgPkgCacheCheck(string CacheFile) } MMap Map(CacheF,MMap::Public | MMap::ReadOnly); - if (_error->PendingError() == true) + if (_error->PendingError() == true || Map.Size() == 0) { _error->Discard(); return false; @@ -565,7 +565,7 @@ bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress) string CacheFile = _config->FindDir("Dir::Cache::pkgcache"); bool SrcOk = pkgSrcCacheCheck(List); - bool PkgOk = pkgPkgCacheCheck(CacheFile); + bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile); // Rebuild the source and package caches if (SrcOk == false) diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index f6855f17a..50d669977 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: tagfile.cc,v 1.10 1998/07/19 04:42:10 jgg Exp $ +// $Id: tagfile.cc,v 1.11 1998/10/02 04:39:48 jgg Exp $ /* ###################################################################### Fast scanner for RFC-822 type header information @@ -45,7 +45,10 @@ bool pkgTagFile::Step(pkgTagSection &Tag) return false; if (Tag.Scan(Start,End - Start) == false) + { + cout << string(Start,End-Start) << endl; return _error->Error("Unable to parse package file"); + } } Start += Tag.size(); iOffset += Tag.size(); @@ -125,13 +128,16 @@ bool pkgTagSection::Scan(const char *Start,unsigned long MaxLength) { if (Stop[-1] != '\n') continue; + + // Skip line feeds + for (; Stop[0] == '\r' && Stop < End; Stop++); + if (Stop[0] == '\n') { // Extra one at the end to simplify find Indexes[TagCount] = Stop - Section; - for (; Stop[0] == '\n' && Stop < End; Stop++); + for (; (Stop[0] == '\n' || Stop[0] == '\r') && Stop < End; Stop++); return true; - break; } if (isspace(Stop[0]) == 0) @@ -167,6 +173,7 @@ bool pkgTagSection::Find(const char *Tag,const char *&Start, End = Section + Indexes[I+1]; for (; (isspace(*Start) != 0 || *Start == ':') && Start < End; Start++); for (; isspace(End[-1]) != 0 && End > Start; End--); + return true; } Start = End = 0; diff --git a/cmdline/apt-cache.cc b/cmdline/apt-cache.cc index a4f34c61a..c4a6c7a42 100644 --- a/cmdline/apt-cache.cc +++ b/cmdline/apt-cache.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: apt-cache.cc,v 1.8 1998/09/26 05:34:29 jgg Exp $ +// $Id: apt-cache.cc,v 1.9 1998/10/02 04:39:55 jgg Exp $ /* ###################################################################### apt-cache - Manages the cache files @@ -222,7 +222,7 @@ bool DoAdd(CommandLine &CmdL) return _error->Error("You must give at least one file name"); // Open the cache - FileFd CacheF(_config->FindDir("Dir::Cache::srcpkgcache"),FileFd::ReadOnly); + FileFd CacheF(_config->FindDir("Dir::Cache::srcpkgcache"),FileFd::WriteAny); if (_error->PendingError() == true) return false; @@ -230,7 +230,7 @@ bool DoAdd(CommandLine &CmdL) if (_error->PendingError() == true) return false; - OpTextProgress Progress; + OpTextProgress Progress(*_config); pkgCacheGenerator Gen(Map,Progress); if (_error->PendingError() == true) return false; @@ -264,10 +264,11 @@ bool DoAdd(CommandLine &CmdL) /* */ bool GenCaches() { - OpTextProgress Progress; + OpTextProgress Progress(*_config); + pkgSourceList List; List.ReadMainList(); - return pkgMakeStatusCache(List,Progress); + return pkgMakeStatusCache(List,Progress); } /*}}}*/ // ShowHelp - Show a help screen /*{{{*/ @@ -280,7 +281,7 @@ int ShowHelp() cout << "Usage: apt-cache [options] command" << endl; cout << " apt-cache [options] add file1 [file1 ...]" << endl; - cout << " apt-cache [options] showpkg pkg2 [pkg2 ...]" << endl; + cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl; cout << endl; cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl; cout << "cache files stored in " << _config->FindDir("Dir::Cache") << endl; @@ -305,6 +306,15 @@ int ShowHelp() return 100; } /*}}}*/ +// CacheInitialize - Initialize things for apt-cache /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void CacheInitialize() +{ + _config->Set("quiet",0); + _config->Set("help",false); +} + /*}}}*/ int main(int argc,const char *argv[]) { @@ -316,6 +326,8 @@ int main(int argc,const char *argv[]) {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; + + CacheInitialize(); // Parse the command line and initialize the package library CommandLine CmdL(Args,_config); @@ -389,8 +401,9 @@ int main(int argc,const char *argv[]) // Print any errors or warnings found during parsing if (_error->empty() == false) { + bool Errors = _error->PendingError(); _error->DumpErrors(); - return 100; + return Errors == true?100:0; } return 0; diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc new file mode 100644 index 000000000..f3dd4205a --- /dev/null +++ b/cmdline/apt-get.cc @@ -0,0 +1,764 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: apt-get.cc,v 1.1 1998/10/02 04:39:56 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 <apt-pkg/depcache.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/pkgcachegen.h> +#include <apt-pkg/algorithms.h> + +#include <config.h> + +#include <fstream.h> + /*}}}*/ + +ostream c0out; +ostream c1out; +ostream c2out; +ofstream devnull("/dev/null"); +unsigned int ScreenWidth = 80; + +// ShowList - Show a list /*{{{*/ +// --------------------------------------------------------------------- +/* This prints out a string of space seperated words with a title and + a two space indent line wraped to the current screen width. */ +void ShowList(ostream &out,string Title,string List) +{ + if (List.empty() == true) + return; + + // Acount for the leading space + int ScreenWidth = ::ScreenWidth - 3; + + out << Title << endl; + string::size_type Start = 0; + while (Start < List.size()) + { + string::size_type End; + if (Start + ScreenWidth >= List.size()) + End = List.size(); + else + End = List.rfind(' ',Start+ScreenWidth); + + if (End == string::npos || End < Start) + End = Start + ScreenWidth; + out << " " << string(List,Start,End - Start) << endl; + Start = End + 1; + } +} + /*}}}*/ +// ShowBroken - Debugging aide /*{{{*/ +// --------------------------------------------------------------------- +/* 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,pkgDepCache &Cache) +{ + out << "Sorry, but the following packages are broken - this means they have unmet" << endl; + out << "dependencies:" << endl; + pkgCache::PkgIterator I = Cache.PkgBegin(); + for (;I.end() != true; I++) + { + if (Cache[I].InstBroken() == true) + { + // Print out each package and the failed dependencies + out <<" " << I.Name() << ":"; + int Indent = strlen(I.Name()) + 3; + bool First = true; + for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++) + { + if (Cache.IsImportantDep(D) == false || (Cache[D] & + pkgDepCache::DepInstall) != 0) + continue; + + if (First == false) + for (int J = 0; J != Indent; J++) + out << ' '; + First = false; + + if (D->Type == pkgCache::Dep::Conflicts) + out << " Conflicts:" << D.TargetPkg().Name(); + else + out << " Depends:" << D.TargetPkg().Name(); + + // Show a quick summary of the version requirements + if (D.TargetVer() != 0) + out << " (" << D.CompType() << " " << D.TargetVer() << + ")" << endl; + else + out << endl; + } + } + } +} + /*}}}*/ +// ShowNew - Show packages to newly install /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowNew(ostream &out,pkgDepCache &Dep) +{ + /* Print out a list of packages that are going to be removed extra + to what the user asked */ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + for (;I.end() != true; I++) + if (Dep[I].NewInstall() == true) + List += string(I.Name()) + " "; + ShowList(out,"The following NEW packages will be installed:",List); +} + /*}}}*/ +// ShowDel - Show packages to delete /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowDel(ostream &out,pkgDepCache &Dep) +{ + /* Print out a list of packages that are going to be removed extra + to what the user asked */ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + for (;I.end() != true; I++) + if (Dep[I].Delete() == true) + List += string(I.Name()) + " "; + ShowList(out,"The following packages will be REMOVED:",List); +} + /*}}}*/ +// ShowKept - Show kept packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowKept(ostream &out,pkgDepCache &Dep) +{ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + for (;I.end() != true; I++) + { + // Not interesting + if (Dep[I].Upgrade() == true || Dep[I].Upgradable() == false || + I->CurrentVer == 0 || Dep[I].Delete() == true) + continue; + + List += string(I.Name()) + " "; + } + ShowList(out,"The following packages have been kept back",List); +} + /*}}}*/ +// ShowUpgraded - Show upgraded packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowUpgraded(ostream &out,pkgDepCache &Dep) +{ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + for (;I.end() != true; I++) + { + // Not interesting + if (Dep[I].Upgrade() == false || Dep[I].NewInstall() == true) + continue; + + List += string(I.Name()) + " "; + } + ShowList(out,"The following packages will be upgraded",List); +} + /*}}}*/ +// ShowHold - Show held but changed packages /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void ShowHold(ostream &out,pkgDepCache &Dep) +{ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + for (;I.end() != true; I++) + { + if (Dep[I].InstallVer != (pkgCache::Version *)I.CurrentVer() && + I->SelectedState == pkgCache::State::Hold) + List += string(I.Name()) + " "; + } + + ShowList(out,"The following held packages will be changed:",List); +} + /*}}}*/ +// ShowEssential - Show an essential package warning /*{{{*/ +// --------------------------------------------------------------------- +/* This prints out a warning message that is not to be ignored. It shows + all essential packages and their dependents that are to be removed. + It is insanely risky to remove the dependents of an essential package! */ +void ShowEssential(ostream &out,pkgDepCache &Dep) +{ + pkgCache::PkgIterator I = Dep.PkgBegin(); + string List; + bool *Added = new bool[Dep.HeaderP->PackageCount]; + for (int I = 0; I != Dep.HeaderP->PackageCount; I++) + Added[I] = false; + + for (;I.end() != true; I++) + { + if ((I->Flags & pkgCache::Flag::Essential) != pkgCache::Flag::Essential) + continue; + + // The essential package is being removed + if (Dep[I].Delete() == true) + { + if (Added[I->ID] == false) + { + Added[I->ID] = true; + List += string(I.Name()) + " "; + } + } + + if (I->CurrentVer == 0) + continue; + + // Print out any essential package depenendents that are to be removed + for (pkgDepCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++) + { + pkgCache::PkgIterator P = D.SmartTargetPkg(); + if (Dep[P].Delete() == true) + { + if (Added[P->ID] == true) + continue; + Added[P->ID] = true; + List += string(P.Name()) + " "; + } + } + } + + if (List.empty() == false) + out << "WARNING: The following essential packages will be removed" << endl; + ShowList(out,"This should NOT be done unless you know exactly what you are doing!",List); + + delete [] Added; +} + /*}}}*/ +// Stats - Show some statistics /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void Stats(ostream &out,pkgDepCache &Dep) +{ + unsigned long Upgrade = 0; + unsigned long Install = 0; + for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++) + { + if (Dep[I].NewInstall() == true) + Install++; + else + if (Dep[I].Upgrade() == true) + Upgrade++; + } + + out << Upgrade << " packages upgraded, " << + Install << " newly installed, " << + Dep.DelCount() << " to remove and " << + Dep.KeepCount() << " not upgraded." << endl; + + if (Dep.BadCount() != 0) + out << Dep.BadCount() << " packages not fully installed or removed." << endl; +} + /*}}}*/ + +// class CacheFile - Cover class for some dependency cache functions /*{{{*/ +// --------------------------------------------------------------------- +/* */ +class CacheFile +{ + public: + + FileFd *File; + MMap *Map; + pkgDepCache *Cache; + + inline operator pkgDepCache &() {return *Cache;}; + inline pkgDepCache *operator ->() {return Cache;}; + inline pkgDepCache &operator *() {return *Cache;}; + + bool Open(); + CacheFile() : File(0), Map(0), Cache(0) {}; + ~CacheFile() + { + delete Cache; + delete Map; + delete File; + } +}; + /*}}}*/ +// CacheFile::Open - Open the cache file /*{{{*/ +// --------------------------------------------------------------------- +/* This routine generates the caches and then opens the dependency cache + and verifies that the system is OK. */ +bool CacheFile::Open() +{ + // Create a progress class + OpTextProgress Progress(*_config); + + // Read the source list + pkgSourceList List; + if (List.ReadMainList() == false) + return _error->Error("The list of sources could not be read."); + + // Build all of the caches + pkgMakeStatusCache(List,Progress); + if (_error->PendingError() == true) + return _error->Error("The package lists or status file could not be parsed or opened."); + + Progress.Done(); + + // Open the cache file + File = new FileFd(_config->FindDir("Dir::Cache::pkgcache"),FileFd::ReadOnly); + if (_error->PendingError() == true) + return false; + + Map = new MMap(*File,MMap::Public | MMap::ReadOnly); + if (_error->PendingError() == true) + return false; + + Cache = new pkgDepCache(*Map,Progress); + if (_error->PendingError() == true) + return false; + + Progress.Done(); + + // Check that the system is OK + if (Cache->DelCount() != 0 || Cache->InstCount() != 0) + return _error->Error("Internal Error, non-zero counts"); + + // Apply corrections for half-installed packages + if (pkgApplyStatus(*Cache) == false) + return false; + + // Nothing is broken + if (Cache->BrokenCount() == 0) + return true; + + // Attempt to fix broken things + if (_config->FindB("APT::Get::Fix-Broken",false) == true) + { + c1out << "Correcting dependencies..." << flush; + if (pkgFixBroken(*Cache) == false || Cache->BrokenCount() != 0) + { + c1out << " failed." << endl; + ShowBroken(c1out,*this); + + return _error->Error("Unable to correct dependencies"); + } + + c1out << " Done" << endl; + } + else + { + c1out << "You might want to run `apt-get -f install' to correct these." << endl; + ShowBroken(c1out,*this); + + return _error->Error("Unmet dependencies. Try using -f."); + } + + return true; +} + /*}}}*/ + +// InstallPackages - Actually download and install the packages /*{{{*/ +// --------------------------------------------------------------------- +/* This displays the informative messages describing what is going to + happen and then calls the download routines */ +bool InstallPackages(pkgDepCache &Cache,bool ShwKept) +{ + ShowDel(c1out,Cache); + ShowNew(c1out,Cache); + if (ShwKept == true) + ShowKept(c1out,Cache); + ShowHold(c1out,Cache); + if (_config->FindB("APT::Get::Show-Upgraded",false) == true) + ShowUpgraded(c1out,Cache); + ShowEssential(c1out,Cache); + Stats(c1out,Cache); + + // Sanity check + if (Cache.BrokenCount() != 0) + { + ShowBroken(c1out,Cache); + return _error->Error("Internal Error, InstallPackages was called with broken packages!"); + } + + if (Cache.DelCount() == 0 && Cache.InstCount() == 0 && + Cache.BadCount() == 0) + return true; + + return true; +} + /*}}}*/ + +// DoUpdate - Update the package lists /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool DoUpdate(CommandLine &CmdL) +{ +} + /*}}}*/ +// DoUpgrade - Upgrade all packages /*{{{*/ +// --------------------------------------------------------------------- +/* Upgrade all packages without installing new packages or erasing old + packages */ +bool DoUpgrade(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.Open() == false) + return false; + + // Do the upgrade + pkgProblemResolver Resolve(Cache); + if (pkgAllUpgrade(Cache) == false) + { + ShowBroken(c1out,Cache); + return _error->Error("Internal Error, AllUpgrade broke stuff"); + } + + return InstallPackages(Cache,true); +} + /*}}}*/ +// DoInstall - Install packages from the command line /*{{{*/ +// --------------------------------------------------------------------- +/* Install named packages */ +bool DoInstall(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.Open() == false) + return false; + + int ExpectedInst = 0; + pkgProblemResolver Fix(Cache); + + for (const char **I = CmdL.FileList + 1; *I != 0; I++) + { + // Duplicate the string + unsigned int Length = strlen(*I); + char S[300]; + if (Length >= sizeof(S)) + continue; + strcpy(S,*I); + + // See if we are removing the package + bool Remove = false; + if (S[Length - 1] == '-') + { + Remove = true; + S[--Length] = 0; + } + + // Locate the package + pkgCache::PkgIterator Pkg = Cache->FindPkg(S); + if (Pkg.end() == true) + return _error->Error("Couldn't find package %s",S); + + // Check if there is something new to install + pkgDepCache::StateCache &State = (*Cache)[Pkg]; + if (State.CandidateVer == 0) + return _error->Error("Package %s has no installation candidate",S); + + Fix.Protect(Pkg); + if (Remove == true) + { + Cache->MarkDelete(Pkg); + 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) + Cache->MarkInstall(Pkg,true); + } + + // Call the scored problem resolver + if (Fix.Resolve(true) == false) + _error->Discard(); + + // Now we check the state of the packages, + if (Cache->BrokenCount() != 0) + { + ShowBroken(c1out,Cache); + return _error->Error("Sorry, broken packages"); + } + + /* Print out a list of packages that are going to be installed extra + to what the user asked */ + if (Cache->InstCount() != ExpectedInst) + { + string List; + pkgCache::PkgIterator I = Cache->PkgBegin(); + for (;I.end() != true; I++) + { + if ((*Cache)[I].Install() == false) + continue; + + const char **J; + for (J = CmdL.FileList + 1; *J != 0; J++) + if (strcmp(*J,I.Name()) == 0) + break; + + if (*J == 0) + List += string(I.Name()) + " "; + } + + ShowList(c1out,"The following extra packages will be installed:",List); + } + + return InstallPackages(Cache,false); +} + /*}}}*/ +// DoDistUpgrade - Automatic smart upgrader /*{{{*/ +// --------------------------------------------------------------------- +/* Intelligent upgrader that will install and remove packages at will */ +bool DoDistUpgrade(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.Open() == false) + return false; + + c0out << "Calculating Upgrade... " << flush; + if (pkgDistUpgrade(*Cache) == false) + { + c0out << "Failed" << endl; + ShowBroken(c1out,Cache); + return false; + } + + c0out << "Done" << endl; + + return InstallPackages(Cache,true); +} + /*}}}*/ +// DoDSelectUpgrade - Do an upgrade by following dselects selections /*{{{*/ +// --------------------------------------------------------------------- +/* Follows dselect's selections */ +bool DoDSelectUpgrade(CommandLine &CmdL) +{ + CacheFile Cache; + if (Cache.Open() == false) + return false; + + // Install everything with the install flag set + pkgCache::PkgIterator I = Cache->PkgBegin(); + for (;I.end() != true; I++) + { + /* Install the package only if it is a new install, the autoupgrader + will deal with the rest */ + if (I->SelectedState == pkgCache::State::Install) + Cache->MarkInstall(I,false); + } + + /* Now install their deps too, if we do this above then order of + the status file is significant for | groups */ + for (I = Cache->PkgBegin();I.end() != true; I++) + { + /* Install the package only if it is a new install, the autoupgrader + will deal with the rest */ + if (I->SelectedState == pkgCache::State::Install) + Cache->MarkInstall(I); + } + + // Apply erasures now, they override everything else. + for (I = Cache->PkgBegin();I.end() != true; I++) + { + // Remove packages + if (I->SelectedState == pkgCache::State::DeInstall || + I->SelectedState == pkgCache::State::Purge) + Cache->MarkDelete(I); + } + + /* Use updates smart upgrade to do the rest, it will automatically + ignore held items */ + if (pkgAllUpgrade(Cache) == false) + { + ShowBroken(c1out,Cache); + return _error->Error("Internal Error, AllUpgrade broke stuff"); + } + + return InstallPackages(Cache,false); +} + /*}}}*/ +// DoClean - Remove download archives /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool DoClean(CommandLine &CmdL) +{ + return true; +} + /*}}}*/ +// DoCheck - Perform the check operation /*{{{*/ +// --------------------------------------------------------------------- +/* Opening automatically checks the system, this command is mostly used + for debugging */ +bool DoCheck(CommandLine &CmdL) +{ + CacheFile Cache; + Cache.Open(); + + return true; +} + /*}}}*/ + +// ShowHelp - Show a help screen /*{{{*/ +// --------------------------------------------------------------------- +/* */ +int ShowHelp() +{ + cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE << + " compiled on " << __DATE__ << " " << __TIME__ << endl; + + cout << "Usage: apt-get [options] command" << endl; + cout << " apt-get [options] install pkg1 [pkg2 ...]" << endl; + cout << endl; + cout << "apt-get is a simple command line interface for downloading and" << endl; + cout << "installing packages. The most frequently used commands are update" << endl; + cout << "and install." << endl; + cout << endl; + cout << "Commands:" << endl; + cout << " update - Retrieve new lists of packages" << endl; + cout << " upgrade - Perform an upgrade" << endl; + cout << " install - Install new packages (pkg is libc6 not libc6.deb)" << endl; + cout << " dist-upgrade - Distribution upgrade, see apt-get(8)" << endl; + cout << " dselect-upgrade - Follow dselect selections" << endl; + cout << " clean - Erase downloaded archive files" << endl; + cout << " check - Verify that there are no broken dependencies" << endl; + cout << endl; + cout << "Options:" << endl; + cout << " -h This help text." << endl; + cout << " -q Loggable output - no progress indicator" << endl; + cout << " -qq No output except for errors" << endl; + cout << " -d Download only - do NOT install or unpack archives" << endl; + cout << " -s No-act. Perform ordering simulation" << endl; + cout << " -y Assume Yes to all queries and do not prompt" << endl; + cout << " -f Attempt to continue if the integrity check fails" << endl; + cout << " -m Attempt to continue if archives are unlocatable" << endl; + cout << " -u Show a list of upgraded packages as well" << endl; + cout << " -c=? Read this configuration file" << endl; + cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl; + cout << "See the apt-get(8), sources.list(8) and apt.conf(8) manual" << endl; + cout << "pages for more information." << endl; + return 100; +} + /*}}}*/ +// GetInitialize - Initialize things for apt-get /*{{{*/ +// --------------------------------------------------------------------- +/* */ +void GetInitialize() +{ + _config->Set("quiet",0); + _config->Set("help",false); + _config->Set("APT::Get::Download-Only",false); + _config->Set("APT::Get::Simulate",false); + _config->Set("APT::Get::Assume-Yes",false); + _config->Set("APT::Get::Fix-Broken",false); +} + /*}}}*/ + +int main(int argc,const char *argv[]) +{ + CommandLine::Args Args[] = { + {'h',"help","help",0}, + {'q',"quiet","quiet",CommandLine::IntLevel}, + {'q',"silent","quiet",CommandLine::IntLevel}, + {'d',"download-only","APT::Get::Download-Only",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}, + {'m',"ignore-missing","APT::Get::Fix-Broken",0}, + {'c',"config-file",0,CommandLine::ConfigFile}, + {'o',"option",0,CommandLine::ArbItem}, + {0,0,0,0}}; + + // Parse the command line and initialize the package library + CommandLine CmdL(Args,_config); + if (pkgInitialize(*_config) == false || + CmdL.Parse(argc,argv) == false) + { + _error->DumpErrors(); + return 100; + } + + // See if the help should be shown + if (_config->FindB("help") == true || + CmdL.FileSize() == 0) + return ShowHelp(); + + // Setup the output streams + c0out.rdbuf(cout.rdbuf()); + c1out.rdbuf(cout.rdbuf()); + c2out.rdbuf(cout.rdbuf()); + if (_config->FindI("quiet",0) > 0) + c0out.rdbuf(devnull.rdbuf()); + if (_config->FindI("quiet",0) > 1) + c1out.rdbuf(devnull.rdbuf()); + + // Match the operation + struct + { + const char *Match; + bool (*Handler)(CommandLine &); + } Map[] = {{"update",&DoUpdate}, + {"upgrade",&DoUpgrade}, + {"install",&DoInstall}, + {"dist-upgrade",&DoDistUpgrade}, + {"dselect-upgrade",&DoDSelectUpgrade}, + {"clean",&DoClean}, + {"check",&DoCheck}, + {0,0}}; + int I; + for (I = 0; Map[I].Match != 0; I++) + { + if (strcmp(CmdL.FileList[0],Map[I].Match) == 0) + { + Map[I].Handler(CmdL); + break; + } + } + + // No matching name + if (Map[I].Match == 0) + _error->Error("Invalid operation %s", CmdL.FileList[0]); + + // Print any errors or warnings found during parsing + if (_error->empty() == false) + { + bool Errors = _error->PendingError(); + _error->DumpErrors(); + if (Errors == true) + cout << "Returning 100." << endl; + return Errors == true?100:0; + } + + return 0; +} diff --git a/cmdline/makefile b/cmdline/makefile index bbe1f5e46..65139c032 100644 --- a/cmdline/makefile +++ b/cmdline/makefile @@ -12,7 +12,7 @@ SOURCE = apt-cache.cc include $(PROGRAM_H) # The apt-config program -PROGRAM=apt-config +PROGRAM=apt-get SLIBS = -lapt-pkg -SOURCE = apt-config.cc +SOURCE = apt-get.cc include $(PROGRAM_H) diff --git a/doc/examples/apt.conf b/doc/examples/apt.conf new file mode 100644 index 000000000..0a6477c6e --- /dev/null +++ b/doc/examples/apt.conf @@ -0,0 +1,47 @@ +// $Id: apt.conf,v 1.1 1998/10/02 04:39:59 jgg Exp $ +/* This file is an index of all APT configuration directives. It should + NOT actually be used as a real config file, though it is a completely + valid file. +*/ + +APT { + Architecture "i386"; + + Get { + Download-Only "false"; + Simulate "false"; + Assume-Yes "false"; + Fix-Broken "false"; + Show-Upgraded "false"; + }; +}; + +Dir +{ + State "/var/state/apt/" + { + lists "lists/"; + xstatus "xstatus"; + userstatus "status.user"; + status "/var/lib/dpkg/status"; + }; + + Cache "/var/cache/apt/" { + archives "archives/"; + srcpkgcache "srcpkgcache.bin"; + pkgcache "pkgcache.bin"; + }; + + Etc "/etc/apt/" { + sourcelist "sources.list"; + main "apt.conf"; + }; +}; + +DSelect { + +} + +Debug { + pkgProblemResolver "true"; +} diff --git a/doc/examples/sources.list b/doc/examples/sources.list new file mode 100644 index 000000000..0fcc006d4 --- /dev/null +++ b/doc/examples/sources.list @@ -0,0 +1,4 @@ +# See sources.list(5) for more information +# Remember that you can only use http, ftp or file URIs +deb http://ftp1.us.debian.org/debian unstable main contrib non-free +deb http://non-us.debian.org/debian-non-US unstable non-US diff --git a/doc/files.sgml b/doc/files.sgml index d9fa9da1b..2d4b1eac0 100644 --- a/doc/files.sgml +++ b/doc/files.sgml @@ -4,7 +4,7 @@ <title>APT Files</title> <author>Jason Gunthorpe <email>jgg@debian.org</email></author> -<version>$Id: files.sgml,v 1.2 1998/07/12 02:11:09 jgg Exp $</version> +<version>$Id: files.sgml,v 1.3 1998/10/02 04:39:57 jgg Exp $</version> <abstract> This document describes the complete implementation and format of the @@ -161,16 +161,6 @@ URIs in the source list support a large number of access schemes. file:/var/debian </example> -<tag>mirror<item> - The mirror scheme is special in that it does not specify the location of a - debian archive but specifies the location of a list of mirrors to use - to access the archive. Some technique will be used to determine the - best choice for a mirror. The mirror file is specified in the Mirror File - section. If/when URIs take off they should obsolete this field. - <example> - mirror:http://www.debian.org/archivemirrors - </example> - <tag>smb<item> A possible future expansion may be to have direct support for smb (Samba servers). @@ -203,10 +193,9 @@ The other alternative that was considered was to use a deep directory structure but this poses two problems, it makes it very difficult to prune directories back when sources are no longer used and complicates the handling of the partial directory. This gives a very simple way to deal with all -of the situations that can arise. The equals sign was choosen on the -suggestion of Manoj because it is very infrequently used in filenames. -Also note that the same rules described in the <em>Archive Directory</> -section regarding the partial sub dir apply here as well. +of the situations that can arise. Also note that the same rules described in +the <em>Archive Directory</> section regarding the partial sub dir apply +here as well. </sect1> </sect> @@ -216,8 +205,8 @@ section regarding the partial sub dir apply here as well. <sect>Extra Status File (xstatus) <p> -The extra status file serves the same purpose as the normal dpkg status file -(/var/lib/dpkg/status) except that it stores information unique to diety. +The extra status file serves the same purpose as the normal dpkg status file +(/var/lib/dpkg/status) except that it stores information unique to apt. This includes the autoflag, target distribution and version and any other uniqe features that come up over time. It duplicates nothing from the normal dpkg status file. Please see other APT documentation for a discussion @@ -280,92 +269,8 @@ name + version match.. <sect> The Methods Directory (/usr/lib/apt/methods) <p> -Like dselect, APT will support plugable acquisition methods to complement -its internaly supported methods. The files in -this directory are execultables named after the URI type. APT will -sort the required URIs and spawn these programs giving a full sorted, quoted -list of URIs. - -<p> -The interface is simple, the program will be given a list -of URIs on the command line. The URIs will be a pairs of strings, the first -being the actual URI and the second being the filename to write the data to. -The current directory will be set properly by APT and it is -expected the method will put files relative to the current directory. -The output of these programs is strictly speficied. The programs must accept -nothing from stdin (stdin will be an invalid fd) and they must output -status information to stdout according to the format below. -Stderr will be redirected to the logging facility. - -<p> -Each line sent to stdout must be a line that has a single letter and a -space. Strings after the first letter do not need quoting, they are taken -as is till the end of the line. The tag letters, listed in expected order, -is as follows: - -<taglist> - -<tag>F - Change URI<item> -This specifies a change in URI. All information after this will be applied -to the new URI. When the URI is changed it is assumed that the old URI has -completed unless an error is set. The format is <var>F URI</> - -<tag>S - Object Size<item> -This specifies the expected size of the object. APT will use this to -compute percent done figures. If it is not sent then a kilobyte meter -will be used instead of a percent display. The foramat is <var>S INTEGER</> - -<tag>E - Error Information<item> -Exactly one line of error information can be set for each URI. The -information will be summarized for the user. If an E tag is send before -any F tags then the error is assumed to be a fatal method error and all URI -fetches for that method are aborted with that error string. The format -is <var>E String</> - -<tag>I - Informative progress information<item> -The I tag allows the method to specify the status of the connection. -Typically the GUI will show the last recieved I line. The format is -<var>I String</> As a general rule an I tag should be ommitted before a -lengthy operation only. Things that always take a short period are not -suited for I tags. I tags should change wnenever the methods state changes. -Some standard forms, in order of occurance, are <var>Connecting to SITE</>, -<var>Connecting to SITE (1.1.1.1)</>, <var>Waiting for file</>, -<var>Authenticating</>, <var>Downloading</>, <var>Resuming (size)</>, -<var>Computing MD5</> <var>I</> lines should never print out information that -APT is already aware of, such as file names. - -<tag>R - Set final path<item> -The R tag allows the method to tell APT that the file is present in the -local file system. APT might copy it into a the download directory. The format -is <var>R String</> - -<tag>M - MD5Sum of the file<item> -The method is expected to compute the md5 hash on the fly as the download -progresses. The final md5 of the file is to be output when the file is -completed. If the md5 is not output it will not be checked! Some methods -such as the file method will not check md5's because they are most -commonly used on mirrors or local CD-ROM's, a paranoid option may be -provided in future to force checking. The format is <var>M MD5-String</> - -<tag>L - Log output<item> -This tag indicates a string that should be dumped to some log file. The -string is for debugging and is not ment to be seen by the user. The format -is <var>L String</> Log things should only be used in a completed method -if they have special relavence to what is happening. -</taglist> - -<p> -APT monitors the progress of the transfer by watching the file size. This -means the method must not create any temp files and must use a fairly small -buffer. The method is also responsible for If-Modified-Since (IMS) queries -for the object. It should check ../outputname to get the time stamp but not -size. The size may be different because the file was uncompressed after -it was transfed. A method must <em>never</> change the file in .., it may -only change the output file in the current directory. - -<p> -The APT 'http' program is the reference implementation of this specification, -it implements all of the features a method is expected to do. +The Methods directory is more fully described in the APT Methods interface +document. </sect> <!-- }}} --> <!-- The Mirror List {{{ --> @@ -374,17 +279,58 @@ it implements all of the features a method is expected to do. <p> The mirror list is stored on the primary debian web server (www.debian.org) -and contains a machine readable list of all known debian mirrors. The mirror -URI type will cause this list to be downloaded and considered. It has the -same form as the source list. When the source list specifies mirror -as the target the mirror list is scanned to find the nescessary parts for -the requested distributions and components. This means the user could -have a line like: +and contains a machine readable list of all known debian mirrors. It's +format and style mirror the Package file. + +<taglist> +<tag>Site<item> +This is the proper host name of the site. It should not be a host within +debian.org and generally cnames should be advoided here. + +<tag>Aliases<item> +These list any commonly used aliases for the site. This field is used to make +sure that a site is not added twice. + +<tag>Type<item> +This field can either be <em>Push-Primary</> or <em>leaf</>. +<em>Push-Primary</> are authorized top level mirrors of the archive, all +other mirrors are leaf. + +<tag>Archive-[access]<item> +The Archive field gives the path(s) to the debian archive. [access] +specifies the access method and may be one of ftp, http, rsync, nfs, or +smb. For many of the types it is possible to prefix the path with :### +indicating that an alternate port should be used. Generaly paths +start with a / and end with a /, rsync is an exception in that the +first directory component is not a path but a label. + +<tag>WWW-[access]<item> +The WWW field gives the path(s) to the debian web site. -<var>deb mirror:http://www.debian.org/mirrorlist stable main non-us</var> +<tag>CDImage-[access]<item> +The WWW field gives the path(s) to the debian CD-ROM images -which would likely cause APT to choose two separate sites to download from, -one for main and another for non-us. +<tag>Incoming-[access]<item> +The Incoming field gives the path(s) to a mirror of the debian incoming +directory. + +<tag>nonUS-[access]<item> +The nonUS field gives the path(s) to a mirror of the non-US distribution. + +<tag>Maintainer<item> +This is the email address of the maintainer of the mirror. + +<tag>Location<item> +Location gives the general geographical region the mirror is in. + +<tag>Sponsor<item> +The Sponsor field indicates who owns the mirror and a URL to a web page +describing the organization. + +<tag>Comment<item> +General free-form text. + +</taglist> <p> Some form of network measurement will have to be used to gauge performance |