// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
-// $Id: apt-get.cc,v 1.3 1998/10/19 23:45:36 jgg Exp $
+// $Id: apt-get.cc,v 1.19 1998/11/24 02:35:32 jgg Exp $
/* ######################################################################
apt-get - Cover for dpkg
#include <apt-pkg/sourcelist.h>
#include <apt-pkg/pkgcachegen.h>
#include <apt-pkg/algorithms.h>
+#include <apt-pkg/acquire-item.h>
+#include <apt-pkg/dpkgpm.h>
+#include <apt-pkg/dpkginit.h>
+#include <strutl.h>
#include <config.h>
+#include "acqprogress.h"
+
#include <fstream.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <stdio.h>
/*}}}*/
ostream c0out;
ofstream devnull("/dev/null");
unsigned int ScreenWidth = 80;
+// YnPrompt - Yes No Prompt. /*{{{*/
+// ---------------------------------------------------------------------
+/* Returns true on a Yes.*/
+bool YnPrompt()
+{
+ if (_config->FindB("APT::Get::Assume-Yes",false) == true)
+ {
+ c2out << 'Y' << endl;
+ return true;
+ }
+
+ char C = 0;
+ char Jnk = 0;
+ read(STDIN_FILENO,&C,1);
+ while (C != '\n' && Jnk != '\n') read(STDIN_FILENO,&Jnk,1);
+
+ if (!(C == 'Y' || C == 'y' || C == '\n' || C == '\r'))
+ return false;
+ return true;
+}
+ /*}}}*/
// ShowList - Show a list /*{{{*/
// ---------------------------------------------------------------------
/* This prints out a string of space seperated words with a title and
description. */
void ShowBroken(ostream &out,pkgDepCache &Cache)
{
- out << "Sorry, but the following packages are broken - this means they have unmet" << endl;
- out << "dependencies:" << endl;
+ out << "Sorry, but the following packages have unmet dependencies:" << endl;
pkgCache::PkgIterator I = Cache.PkgBegin();
for (;I.end() != true; I++)
{
continue;
}
- for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; D++)
+ for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false;)
{
- if (Cache.IsImportantDep(D) == false || (Cache[D] &
- pkgDepCache::DepInstall) != 0)
+ // Compute a single dependency element (glob or)
+ pkgCache::DepIterator Start;
+ pkgCache::DepIterator End;
+ D.GlobOr(Start,End);
+
+ if (Cache.IsImportantDep(End) == false ||
+ (Cache[End] & pkgDepCache::DepGInstall) == pkgDepCache::DepGInstall)
continue;
if (First == false)
for (int J = 0; J != Indent; J++)
out << ' ';
First = false;
-
- if (D->Type == pkgCache::Dep::Conflicts)
- out << " Conflicts:" << D.TargetPkg().Name();
- else
- out << " Depends:" << D.TargetPkg().Name();
+
+ cout << ' ' << End.DepType() << ": " << End.TargetPkg().Name();
// Show a quick summary of the version requirements
- if (D.TargetVer() != 0)
- out << " (" << D.CompType() << " " << D.TargetVer() <<
+ if (End.TargetVer() != 0)
+ out << " (" << End.CompType() << " " << End.TargetVer() <<
")";
/* Show a summary of the target package if possible. In the case
of virtual packages we show nothing */
- pkgCache::PkgIterator Targ = D.TargetPkg();
+ pkgCache::PkgIterator Targ = End.TargetPkg();
if (Targ->ProvidesList == 0)
{
out << " but ";
pkgCache::PkgIterator I = Dep.PkgBegin();
string List;
bool *Added = new bool[Dep.HeaderP->PackageCount];
- for (int I = 0; I != Dep.HeaderP->PackageCount; I++)
+ for (unsigned int I = 0; I != Dep.HeaderP->PackageCount; I++)
Added[I] = false;
for (;I.end() != true; I++)
// Print out any essential package depenendents that are to be removed
for (pkgDepCache::DepIterator D = I.CurrentVer().DependsList(); D.end() == false; D++)
{
+ // Skip everything but depends
+ if (D->Type != pkgCache::Dep::PreDepends &&
+ D->Type != pkgCache::Dep::Depends)
+ continue;
+
pkgCache::PkgIterator P = D.SmartTargetPkg();
if (Dep[P].Delete() == true)
{
if (Added[P->ID] == true)
continue;
Added[P->ID] = true;
- List += string(P.Name()) + " ";
+
+ char S[300];
+ sprintf(S,"%s (due to %s) ",P.Name(),I.Name());
+ List += S;
}
}
}
FileFd *File;
MMap *Map;
pkgDepCache *Cache;
+ pkgDpkgLock Lock;
inline operator pkgDepCache &() {return *Cache;};
inline pkgDepCache *operator ->() {return Cache;};
and verifies that the system is OK. */
bool CacheFile::Open()
{
+ if (_error->PendingError() == true)
+ return false;
+
// Create a progress class
OpTextProgress Progress(*_config);
// ---------------------------------------------------------------------
/* This displays the informative messages describing what is going to
happen and then calls the download routines */
-bool InstallPackages(pkgDepCache &Cache,bool ShwKept)
+bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true)
{
+ // Show all the various warning indicators
ShowDel(c1out,Cache);
ShowNew(c1out,Cache);
if (ShwKept == true)
Stats(c1out,Cache);
// Sanity check
- if (Cache.BrokenCount() != 0)
+ 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)
+ if (Cache->DelCount() == 0 && Cache->InstCount() == 0 &&
+ Cache->BadCount() == 0)
return true;
+
+ // Run the simulator ..
+ if (_config->FindB("APT::Get::Simulate") == true)
+ {
+ pkgSimulate PM(Cache);
+ return PM.DoInstall();
+ }
+
+ // Create the text record parser
+ pkgRecords Recs(Cache);
+
+ // Lock the archive directory
+ if (_config->FindB("Debug::NoLocking",false) == false)
+ {
+ FileFd Lock(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock"));
+ if (_error->PendingError() == true)
+ return _error->Error("Unable to lock the download directory");
+ }
+
+ // Create the download object
+ AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
+ pkgAcquire Fetcher(&Stat);
+
+ // Read the source list
+ pkgSourceList List;
+ if (List.ReadMainList() == false)
+ return _error->Error("The list of sources could not be read.");
+
+ // Create the package manager and prepare to download
+ pkgDPkgPM PM(Cache);
+ if (PM.GetArchives(&Fetcher,&List,&Recs) == false)
+ return false;
+
+ // Display statistics
+ unsigned long FetchBytes = Fetcher.FetchNeeded();
+ unsigned long DebBytes = Fetcher.TotalNeeded();
+ if (DebBytes != Cache->DebSize())
+ {
+ c0out << DebBytes << ',' << Cache->DebSize() << endl;
+ c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl;
+ }
- return true;
+ // Number of bytes
+ c1out << "Need to get ";
+ if (DebBytes != FetchBytes)
+ c1out << SizeToStr(FetchBytes) << '/' << SizeToStr(DebBytes);
+ else
+ c1out << SizeToStr(DebBytes);
+
+ c1out << " of archives. After unpacking ";
+
+ // Size delta
+ if (Cache->UsrSize() >= 0)
+ c1out << SizeToStr(Cache->UsrSize()) << " will be used." << endl;
+ else
+ c1out << SizeToStr(-1*Cache->UsrSize()) << " will be freed." << endl;
+
+ if (_error->PendingError() == true)
+ return false;
+
+ // Prompt to continue
+ if (Ask == true)
+ {
+ if (_config->FindI("quiet",0) < 2 ||
+ _config->FindB("APT::Get::Assume-Yes",false) == false)
+ c2out << "Do you want to continue? [Y/n] " << flush;
+ if (YnPrompt() == false)
+ exit(1);
+ }
+
+ // Run it
+ if (Fetcher.Run() == false)
+ return false;
+
+ // Print out errors
+ bool Failed = false;
+ for (pkgAcquire::Item **I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++)
+ {
+ if ((*I)->Status == pkgAcquire::Item::StatDone &&
+ (*I)->Complete == true)
+ continue;
+
+ cerr << "Failed to fetch " << (*I)->Describe() << endl;
+ cerr << " " << (*I)->ErrorText << endl;
+ Failed = true;
+ }
+
+ if (Failed == true && _config->FindB("APT::Fix-Missing",false) == false)
+ return _error->Error("Unable to fetch some archives, maybe try with --fix-missing?");
+
+ // Try to deal with missing package files
+ if (PM.FixMissing() == false)
+ {
+ cerr << "Unable to correct missing packages." << endl;
+ return _error->Error("Aborting Install.");
+ }
+
+ Cache.Lock.Close();
+ return PM.DoInstall();
}
/*}}}*/
// DoUpdate - Update the package lists /*{{{*/
// ---------------------------------------------------------------------
/* */
-bool DoUpdate(CommandLine &CmdL)
+bool DoUpdate(CommandLine &)
{
+ // Get the source list
+ pkgSourceList List;
+ if (List.ReadMainList() == false)
+ return false;
+
+ // Lock the list directory
+ if (_config->FindB("Debug::NoLocking",false) == false)
+ {
+ FileFd Lock(GetLock(_config->FindDir("Dir::State::Lists") + "lock"));
+ if (_error->PendingError() == true)
+ return _error->Error("Unable to lock the list directory");
+ }
+
+ // Create the download object
+ AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0));
+ pkgAcquire Fetcher(&Stat);
+
+ // Populate it with the source selection
+ pkgSourceList::const_iterator I;
+ for (I = List.begin(); I != List.end(); I++)
+ {
+ new pkgAcqIndex(&Fetcher,I);
+ if (_error->PendingError() == true)
+ return false;
+ }
+
+ // Run it
+ if (Fetcher.Run() == false)
+ return false;
+
+ // Clean out any old list files
+ if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false ||
+ Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false)
+ return false;
+
+ // Prepare the cache.
+ CacheFile Cache;
+ if (Cache.Open() == false)
+ return false;
+
+ return true;
}
/*}}}*/
// DoUpgrade - Upgrade all packages /*{{{*/
return false;
// Do the upgrade
- pkgProblemResolver Resolve(Cache);
if (pkgAllUpgrade(Cache) == false)
{
ShowBroken(c1out,Cache);
if (Cache.Open() == false)
return false;
- int ExpectedInst = 0;
- int Packages = 0;
+ unsigned int ExpectedInst = 0;
+ unsigned int Packages = 0;
pkgProblemResolver Fix(Cache);
bool DefRemove = false;
// See if we are removing the package
bool Remove = DefRemove;
- if (S[Length - 1] == '-')
+ if (Cache->FindPkg(S).end() == true)
{
- Remove = true;
- S[--Length] = 0;
- }
- if (S[Length - 1] == '+')
- {
- Remove = false;
- S[--Length] = 0;
+ // Handle an optional end tag indicating what to do
+ if (S[Length - 1] == '-')
+ {
+ Remove = true;
+ S[--Length] = 0;
+ }
+ if (S[Length - 1] == '+')
+ {
+ Remove = false;
+ S[--Length] = 0;
+ }
}
// Locate the package
if (Pkg.end() == true)
return _error->Error("Couldn't find package %s",S);
+ // Handle the no-upgrade case
+ if (_config->FindB("APT::Get::no-upgrade",false) == true &&
+ Pkg->CurrentVer != 0)
+ {
+ c1out << "Skipping " << Pkg.Name() << ", it is already installed and no-upgrade is set." << endl;
+ continue;
+ }
+
// Check if there is something new to install
pkgDepCache::StateCache &State = (*Cache)[Pkg];
if (State.CandidateVer == 0)
c1out << "Package " << S << " has no available version, but exists in the database." << endl;
c1out << "This typically means that the package was mentioned in a dependency and " << endl;
c1out << "never uploaded, or that it is an obsolete package." << endl;
+
+ string List;
+ pkgCache::DepIterator Dep = Pkg.RevDependsList();
+ for (; Dep.end() == false; Dep++)
+ {
+ if (Dep->Type != pkgCache::Dep::Replaces)
+ continue;
+ List += string(Dep.ParentPkg().Name()) + " ";
+ }
+ ShowList(c1out,"However the following packages replace it:",List);
}
return _error->Error("Package %s has no installation candidate",S);
ShowList(c1out,"The following extra packages will be installed:",List);
}
- return InstallPackages(Cache,false);
+ // See if we need to prompt
+ if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0)
+ return InstallPackages(Cache,false,false);
+
+ return InstallPackages(Cache,false);
}
/*}}}*/
// DoDistUpgrade - Automatic smart upgrader /*{{{*/
/* */
bool DoClean(CommandLine &CmdL)
{
+ pkgAcquire Fetcher;
+ Fetcher.Clean(_config->FindDir("Dir::Cache::archives"));
+ Fetcher.Clean(_config->FindDir("Dir::Cache::archives") + "partial/");
return true;
}
/*}}}*/
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 << " -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;
_config->Set("APT::Get::Fix-Broken",false);
}
/*}}}*/
+// SigWinch - Window size change signal handler /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void SigWinch(int)
+{
+ // Riped from GNU ls
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+
+ if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col >= 5)
+ ScreenWidth = ws.ws_col - 1;
+#endif
+}
+ /*}}}*/
int main(int argc,const char *argv[])
{
{'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},
+ {'m',"ignore-missing","APT::Get::Fix-Missing",0},
+ {0,"fix-missing","APT::Get::Fix-Missing",0},
+ {0,"ignore-hold","APT::Ingore-Hold",0},
+ {0,"no-upgrade","APT::Get::no-upgrade",0},
{'c',"config-file",0,CommandLine::ConfigFile},
{'o',"option",0,CommandLine::ArbItem},
{0,0,0,0}};
c0out.rdbuf(devnull.rdbuf());
if (_config->FindI("quiet",0) > 1)
c1out.rdbuf(devnull.rdbuf());
+
+ // Setup the signals
+ signal(SIGPIPE,SIG_IGN);
+ signal(SIGWINCH,SigWinch);
+ SigWinch(0);
// Match the operation
struct
{
if (strcmp(CmdL.FileList[0],Map[I].Match) == 0)
{
- Map[I].Handler(CmdL);
+ if (Map[I].Handler(CmdL) == false && _error->PendingError() == false)
+ _error->Error("Handler silently failed");
break;
}
}