X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/f0863b2140790b894049d4b3a96f5e021909946e..5aaad5d620b6f255b4ef08a3e9a66d2c61ac3750:/cmdline/apt-get.cc?ds=sidebyside diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index a41c50b0a..64882e3e8 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: apt-get.cc,v 1.118 2002/04/02 07:16:24 jgg Exp $ +// $Id: apt-get.cc,v 1.156 2004/08/28 01:05:16 mdz Exp $ /* ###################################################################### apt-get - Cover for dpkg @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,9 @@ #include "acqprogress.h" +#include #include +#include #include #include #include @@ -65,7 +68,7 @@ ostream c0out(0); ostream c1out(0); ostream c2out(0); ofstream devnull("/dev/null"); -unsigned int ScreenWidth = 80; +unsigned int ScreenWidth = 80 - 1; /* - 1 for the cursor */ // class CacheFile - Cover class for some dependency cache functions /*{{{*/ // --------------------------------------------------------------------- @@ -80,6 +83,13 @@ class CacheFile : public pkgCacheFile void Sort(); bool CheckDeps(bool AllowBroken = false); + bool BuildCaches(bool WithLock = true) + { + OpTextProgress Prog(*_config); + if (pkgCacheFile::BuildCaches(Prog,WithLock) == false) + return false; + return true; + } bool Open(bool WithLock = true) { OpTextProgress Prog(*_config); @@ -103,28 +113,39 @@ class CacheFile : public pkgCacheFile // YnPrompt - Yes No Prompt. /*{{{*/ // --------------------------------------------------------------------- /* Returns true on a Yes.*/ -bool YnPrompt() +bool YnPrompt(bool Default=true) { - // This needs to be a capital - const char *Yes = _("Y"); - if (_config->FindB("APT::Get::Assume-Yes",false) == true) { - c1out << Yes << endl; + c1out << _("Y") << endl; return true; } - - char C = 0; - char Jnk = 0; - if (read(STDIN_FILENO,&C,1) != 1) + + char response[1024] = ""; + cin.getline(response, sizeof(response)); + + if (!cin) return false; - while (C != '\n' && Jnk != '\n') - if (read(STDIN_FILENO,&Jnk,1) != 1) - return false; + + if (strlen(response) == 0) + return Default; + + regex_t Pattern; + int Res; + + Res = regcomp(&Pattern, nl_langinfo(YESEXPR), + REG_EXTENDED|REG_ICASE|REG_NOSUB); + + if (Res != 0) { + char Error[300]; + regerror(Res,&Pattern,Error,sizeof(Error)); + return _error->Error(_("Regex compilation error - %s"),Error); + } - if (!(toupper(C) == *Yes || C == '\n' || C == '\r')) - return false; - return true; + Res = regexec(&Pattern, response, 0, NULL, 0); + if (Res == 0) + return true; + return false; } /*}}}*/ // AnalPrompt - Annoying Yes No Prompt. /*{{{*/ @@ -143,29 +164,59 @@ bool AnalPrompt(const char *Text) // --------------------------------------------------------------------- /* This prints out a string of space separated words with a title and a two space indent line wraped to the current screen width. */ -bool ShowList(ostream &out,string Title,string List) +bool ShowList(ostream &out,string Title,string List,string VersionsList) { if (List.empty() == true) return true; + // trim trailing space + int NonSpace = List.find_last_not_of(' '); + if (NonSpace != -1) + { + List = List.erase(NonSpace + 1); + if (List.empty() == true) + return true; + } // Acount for the leading space int ScreenWidth = ::ScreenWidth - 3; out << Title << endl; string::size_type Start = 0; + string::size_type VersionsStart = 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; + if(_config->FindB("APT::Get::Show-Versions",false) == true && + VersionsList.size() > 0) { + string::size_type End; + string::size_type VersionsEnd; + + End = List.find(' ',Start); + VersionsEnd = VersionsList.find('\n', VersionsStart); + + out << " " << string(List,Start,End - Start) << " (" << + string(VersionsList,VersionsStart,VersionsEnd - VersionsStart) << + ")" << endl; + + if (End == string::npos || End < Start) + End = Start + ScreenWidth; + + Start = End + 1; + VersionsStart = VersionsEnd + 1; + } else { + 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; + } } + return false; } /*}}}*/ @@ -176,14 +227,14 @@ bool ShowList(ostream &out,string Title,string List) description. The output looks like: - Sorry, but the following packages have unmet dependencies: + The following packages have unmet dependencies: exim: Depends: libc6 (>= 2.1.94) but 2.1.3-10 is to be installed Depends: libldap2 (>= 2.0.2-2) but it is not going to be installed Depends: libsasl7 but it is not going to be installed */ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) { - out << _("Sorry, but the following packages have unmet dependencies:") << endl; + out << _("The following packages have unmet dependencies:") << endl; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -221,7 +272,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) // Compute a single dependency element (glob or) pkgCache::DepIterator Start; pkgCache::DepIterator End; - D.GlobOr(Start,End); + D.GlobOr(Start,End); // advances D if (Cache->IsImportantDep(End) == false) continue; @@ -308,17 +359,20 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) /* */ void ShowNew(ostream &out,CacheFile &Cache) { - /* Print out a list of packages that are going to be removed extra + /* Print out a list of packages that are going to be installed extra to what the user asked */ string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); - if (Cache[I].NewInstall() == true) - List += string(I.Name()) + " "; + if (Cache[I].NewInstall() == true) { + List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CandVersion) + "\n"; + } } - ShowList(out,_("The following NEW packages will be installed:"),List); + ShowList(out,_("The following NEW packages will be installed:"),List,VersionsList); } /*}}}*/ // ShowDel - Show packages to delete /*{{{*/ @@ -329,6 +383,7 @@ void ShowDel(ostream &out,CacheFile &Cache) /* Print out a list of packages that are going to be removed extra to what the user asked */ string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -338,10 +393,12 @@ void ShowDel(ostream &out,CacheFile &Cache) List += string(I.Name()) + "* "; else List += string(I.Name()) + " "; + + VersionsList += string(Cache[I].CandVersion)+ "\n"; } } - ShowList(out,_("The following packages will be REMOVED:"),List); + ShowList(out,_("The following packages will be REMOVED:"),List,VersionsList); } /*}}}*/ // ShowKept - Show kept packages /*{{{*/ @@ -350,6 +407,7 @@ void ShowDel(ostream &out,CacheFile &Cache) void ShowKept(ostream &out,CacheFile &Cache) { string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -360,8 +418,9 @@ void ShowKept(ostream &out,CacheFile &Cache) continue; List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - ShowList(out,_("The following packages have been kept back"),List); + ShowList(out,_("The following packages have been kept back:"),List,VersionsList); } /*}}}*/ // ShowUpgraded - Show upgraded packages /*{{{*/ @@ -370,6 +429,7 @@ void ShowKept(ostream &out,CacheFile &Cache) void ShowUpgraded(ostream &out,CacheFile &Cache) { string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -379,8 +439,9 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) continue; List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - ShowList(out,_("The following packages will be upgraded"),List); + ShowList(out,_("The following packages will be upgraded:"),List,VersionsList); } /*}}}*/ // ShowDowngraded - Show downgraded packages /*{{{*/ @@ -389,6 +450,7 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) bool ShowDowngraded(ostream &out,CacheFile &Cache) { string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -398,8 +460,9 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) continue; List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - return ShowList(out,_("The following packages will be DOWNGRADED"),List); + return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList); } /*}}}*/ // ShowHold - Show held but changed packages /*{{{*/ @@ -408,15 +471,18 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) bool ShowHold(ostream &out,CacheFile &Cache) { string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() && - I->SelectedState == pkgCache::State::Hold) - List += string(I.Name()) + " "; + I->SelectedState == pkgCache::State::Hold) { + List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; + } } - return ShowList(out,_("The following held packages will be changed:"),List); + return ShowList(out,_("The following held packages will be changed:"),List,VersionsList); } /*}}}*/ // ShowEssential - Show an essential package warning /*{{{*/ @@ -427,6 +493,7 @@ bool ShowHold(ostream &out,CacheFile &Cache) bool ShowEssential(ostream &out,CacheFile &Cache) { string List; + string VersionsList; bool *Added = new bool[Cache->Head().PackageCount]; for (unsigned int I = 0; I != Cache->Head().PackageCount; I++) Added[I] = false; @@ -445,6 +512,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) { Added[I->ID] = true; List += string(I.Name()) + " "; + //VersionsList += string(Cache[I].CurVersion) + "\n"; ??? } } @@ -469,14 +537,16 @@ bool ShowEssential(ostream &out,CacheFile &Cache) char S[300]; snprintf(S,sizeof(S),_("%s (due to %s) "),P.Name(),I.Name()); List += S; + //VersionsList += "\n"; ??? } } } delete [] Added; - return ShowList(out,_("WARNING: The following essential packages will be removed\n" - "This should NOT be done unless you know exactly what you are doing!"),List); + return ShowList(out,_("WARNING: The following essential packages will be removed.\n" + "This should NOT be done unless you know exactly what you are doing!"),List,VersionsList); } + /*}}}*/ // Stats - Show some statistics /*{{{*/ // --------------------------------------------------------------------- @@ -504,7 +574,7 @@ void Stats(ostream &out,pkgDepCache &Dep) ReInstall++; } - ioprintf(out,_("%lu packages upgraded, %lu newly installed, "), + ioprintf(out,_("%lu upgraded, %lu newly installed, "), Upgrade,Install); if (ReInstall != 0) @@ -516,7 +586,7 @@ void Stats(ostream &out,pkgDepCache &Dep) Dep.DelCount(),Dep.KeepCount()); if (Dep.BadCount() != 0) - ioprintf(out,_("%lu packages not fully installed or removed.\n"), + ioprintf(out,_("%lu not fully installed or removed.\n"), Dep.BadCount()); } /*}}}*/ @@ -563,7 +633,7 @@ bool CacheFile::CheckDeps(bool AllowBroken) // Check that the system is OK if (DCache->DelCount() != 0 || DCache->InstCount() != 0) - return _error->Error("Internal Error, non-zero counts"); + return _error->Error("Internal error, non-zero counts"); // Apply corrections for half-installed packages if (pkgApplyStatus(*DCache) == false) @@ -599,6 +669,49 @@ bool CacheFile::CheckDeps(bool AllowBroken) return true; } + +static bool CheckAuth(pkgAcquire& Fetcher) +{ + string UntrustedList; + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd(); ++I) + { + if (!(*I)->IsTrusted()) + { + UntrustedList += string((*I)->ShortDesc()) + " "; + } + } + + if (UntrustedList == "") + { + return true; + } + + ShowList(c2out,_("WARNING: The following packages cannot be authenticated!"),UntrustedList,""); + + if (_config->FindB("APT::Get::AllowUnauthenticated",false) == true) + { + c2out << _("Authentication warning overridden.\n"); + return true; + } + + if (_config->FindI("quiet",0) < 2 + && _config->FindB("APT::Get::Assume-Yes",false) == false) + { + c2out << _("Install these packages without verification [y/N]? ") << flush; + if (!YnPrompt(false)) + return _error->Error(_("Some packages could not be authenticated")); + + return true; + } + else if (_config->FindB("APT::Get::Force-Yes",false) == true) + { + return true; + } + + return _error->Error(_("There are problems and -y was used without --force-yes")); +} + + /*}}}*/ // InstallPackages - Actually download and install the packages /*{{{*/ @@ -606,7 +719,7 @@ bool CacheFile::CheckDeps(bool AllowBroken) /* This displays the informative messages describing what is going to happen and then calls the download routines */ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, - bool Saftey = true) + bool Safety = true) { if (_config->FindB("APT::Get::Purge",false) == true) { @@ -627,18 +740,19 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (ShwKept == true) ShowKept(c1out,Cache); Fail |= !ShowHold(c1out,Cache); - if (_config->FindB("APT::Get::Show-Upgraded",false) == true) + if (_config->FindB("APT::Get::Show-Upgraded",true) == true) ShowUpgraded(c1out,Cache); Fail |= !ShowDowngraded(c1out,Cache); - Essential = !ShowEssential(c1out,Cache); + if (_config->FindB("APT::Get::Download-Only",false) == false) + Essential = !ShowEssential(c1out,Cache); Fail |= Essential; Stats(c1out,Cache); - + // Sanity check if (Cache->BrokenCount() != 0) { ShowBroken(c1out,Cache,false); - return _error->Error("Internal Error, InstallPackages was called with broken packages!"); + return _error->Error(_("Internal error, InstallPackages was called with broken packages!")); } if (Cache->DelCount() == 0 && Cache->InstCount() == 0 && @@ -647,17 +761,18 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, // No remove flag if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false) - return _error->Error(_("Packages need to be removed but Remove is disabled.")); + return _error->Error(_("Packages need to be removed but remove is disabled.")); // Run the simulator .. if (_config->FindB("APT::Get::Simulate") == true) { pkgSimulate PM(Cache); - pkgPackageManager::OrderResult Res = PM.DoInstall(); + int status_fd = _config->FindI("APT::Status-Fd",-1); + pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd); if (Res == pkgPackageManager::Failed) return false; if (Res != pkgPackageManager::Completed) - return _error->Error("Internal Error, Ordering didn't finish"); + return _error->Error(_("Internal error, Ordering didn't finish")); return true; } @@ -698,23 +813,23 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (DebBytes != Cache->DebSize()) { c0out << DebBytes << ',' << Cache->DebSize() << endl; - c0out << "How odd.. The sizes didn't match, email apt@packages.debian.org" << endl; + c0out << _("How odd.. The sizes didn't match, email apt@packages.debian.org") << endl; } // Number of bytes if (DebBytes != FetchBytes) - ioprintf(c1out,_("Need to get %sB/%sB of archives. "), + ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); else - ioprintf(c1out,_("Need to get %sB of archives. "), + ioprintf(c1out,_("Need to get %sB of archives.\n"), SizeToStr(DebBytes).c_str()); // Size delta if (Cache->UsrSize() >= 0) - ioprintf(c1out,_("After unpacking %sB will be used.\n"), + ioprintf(c1out,_("After unpacking %sB of additional disk space will be used.\n"), SizeToStr(Cache->UsrSize()).c_str()); else - ioprintf(c1out,_("After unpacking %sB will be freed.\n"), + ioprintf(c1out,_("After unpacking %sB disk space will be freed.\n"), SizeToStr(-1*Cache->UsrSize()).c_str()); if (_error->PendingError() == true) @@ -728,10 +843,10 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, struct statvfs Buf; string OutputDir = _config->FindDir("Dir::Cache::Archives"); if (statvfs(OutputDir.c_str(),&Buf) != 0) - return _error->Errno("statvfs","Couldn't determine free space in %s", + return _error->Errno("statvfs",_("Couldn't determine free space in %s"), OutputDir.c_str()); if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - return _error->Error(_("Sorry, you don't have enough free space in %s to hold all the .debs."), + return _error->Error(_("You don't have enough free space in %s."), OutputDir.c_str()); } @@ -743,14 +858,14 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, return _error->Error(_("There are problems and -y was used without --force-yes")); } - if (Essential == true && Saftey == true) + if (Essential == true && Safety == true) { if (_config->FindB("APT::Get::Trivial-Only",false) == true) return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); const char *Prompt = _("Yes, do as I say!"); ioprintf(c2out, - _("You are about to do something potentially harmful\n" + _("You are about to do something potentially harmful.\n" "To continue type in the phrase '%s'\n" " ?] "),Prompt); c2out << flush; @@ -771,7 +886,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool 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; + c2out << _("Do you want to continue [Y/n]? ") << flush; if (YnPrompt() == false) { @@ -792,6 +907,9 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, return true; } + if (!CheckAuth(Fetcher)) + return false; + /* Unlock the dpkg lock if we are not going to be doing an install after. */ if (_config->FindB("APT::Get::Download-Only",false) == true) @@ -875,11 +993,12 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (Failed == true && PM->FixMissing() == false) { cerr << _("Unable to correct missing packages.") << endl; - return _error->Error(_("Aborting Install.")); + return _error->Error(_("Aborting install.")); } _system->UnLock(); - pkgPackageManager::OrderResult Res = PM->DoInstall(); + int status_fd = _config->FindI("APT::Status-Fd",-1); + pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd); if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; if (Res == pkgPackageManager::Completed) @@ -927,10 +1046,15 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, pkgDepCache::StateCache &State = Cache[Pkg]; if (Remove == true && Pkg->CurrentVer == 0) { + Fix.Clear(Pkg); + Fix.Protect(Pkg); + Fix.Remove(Pkg); + /* We want to continue searching for regex hits, so we return false here otherwise this is not really an error. */ if (AllowFail == false) - return false; + return false; + ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.Name()); return true; } @@ -964,12 +1088,12 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, else { ioprintf(c1out, - _("Package %s has no available version, but exists in the database.\n" - "This typically means that the package was mentioned in a dependency and\n" - "never uploaded, has been obsoleted or is not available with the contents\n" - "of sources.list\n"),Pkg.Name()); + _("Package %s is not available, but is referred to by another package.\n" + "This may mean that the package is missing, has been obsoleted, or\n" + "is only available from another source\n"),Pkg.Name()); string List; + string VersionsList; SPtrArray Seen = new bool[Cache.Head().PackageCount]; memset(Seen,0,Cache.Head().PackageCount*sizeof(*Seen)); pkgCache::DepIterator Dep = Pkg.RevDependsList(); @@ -981,8 +1105,9 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, continue; Seen[Dep.ParentPkg()->ID] = true; List += string(Dep.ParentPkg().Name()) + " "; + //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ??? } - ShowList(c1out,_("However the following packages replace it:"),List); + ShowList(c1out,_("However the following packages replace it:"),List,VersionsList); } _error->Error(_("Package %s has no installation candidate"),Pkg.Name()); @@ -1005,7 +1130,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, if (_config->FindB("APT::Get::ReInstall",false) == true) { if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) - ioprintf(c1out,_("Sorry, re-installation of %s is not possible, it cannot be downloaded.\n"), + ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), Pkg.Name()); else Cache.SetReInstall(Pkg,true); @@ -1013,7 +1138,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, else { if (AllowFail == true) - ioprintf(c1out,_("Sorry, %s is already the newest version.\n"), + ioprintf(c1out,_("%s is already the newest version.\n"), Pkg.Name()); } } @@ -1032,7 +1157,8 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, const char *VerTag,bool IsRel) { - pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release:pkgVersionMatch::Version)); + pkgVersionMatch Match(VerTag,(IsRel == true?pkgVersionMatch::Release : + pkgVersionMatch::Version)); pkgCache::VerIterator Ver = Match.Find(Pkg); @@ -1066,24 +1192,54 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, string VerTag; string TmpSrc = Name; string::size_type Slash = TmpSrc.rfind('='); + + // honor default release + string DefRel = _config->Find("APT::Default-Release"); + pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc); + if (Slash != string::npos) { VerTag = string(TmpSrc.begin() + Slash + 1,TmpSrc.end()); TmpSrc = string(TmpSrc.begin(),TmpSrc.begin() + Slash); + } + else if(!Pkg.end() && DefRel.empty() == false) + { + // we have a default release, try to locate the pkg. we do it like + // this because GetCandidateVer() will not "downgrade", that means + // "apt-get source -t stable apt" won't work on a unstable system + for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; + Ver++) + { + for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; + VF++) + { + /* If this is the status file, and the current version is not the + version in the status file (ie it is not installed, or somesuch) + then it is not a candidate for installation, ever. This weeds + out bogus entries that may be due to config-file states, or + other. */ + if ((VF.File()->Flags & pkgCache::Flag::NotSource) == + pkgCache::Flag::NotSource && Pkg.CurrentVer() != Ver) + continue; + + //std::cout << VF.File().Archive() << std::endl; + if(VF.File().Archive() && (VF.File().Archive() == DefRel)) + { + VerTag = Ver.VerStr(); + break; + } + } + } } - + /* Lookup the version of the package we would install if we were to install a version and determine the source package name, then look - in the archive for a source package of the same name. In theory - we could stash the version string as well and match that too but - today there aren't multi source versions in the archive. */ - if (_config->FindB("APT::Get::Only-Source") == false && - VerTag.empty() == true) + in the archive for a source package of the same name. */ + if (_config->FindB("APT::Get::Only-Source") == false) { - pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc); if (Pkg.end() == false) { - pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg); + pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg); if (Ver.end() == false) { pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList()); @@ -1141,10 +1297,7 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, } } - if (Last == 0) - return 0; - - if (Last->Jump(Offset) == false) + if (Last == 0 || Last->Jump(Offset) == false) return 0; return Last; @@ -1177,19 +1330,25 @@ bool DoUpdate(CommandLine &CmdL) AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); pkgAcquire Fetcher(&Stat); - // Populate it with the source selection - if (List.GetIndexes(&Fetcher) == false) - return false; // Just print out the uris an exit if the --print-uris flag was used if (_config->FindB("APT::Get::Print-URIs") == true) { + // Populate it with the source selection and get all Indexes + // (GetAll=true) + if (List.GetIndexes(&Fetcher,true) == false) + return false; + pkgAcquire::UriIterator I = Fetcher.UriBegin(); for (; I != Fetcher.UriEnd(); I++) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl; return true; } + + // Populate it with the source selection + if (List.GetIndexes(&Fetcher) == false) + return false; // Run it if (Fetcher.Run() == pkgAcquire::Failed) @@ -1209,7 +1368,7 @@ bool DoUpdate(CommandLine &CmdL) } // Clean out any old list files - if (_config->FindB("APT::Get::List-Cleanup",true) == true) + if (!Failed && _config->FindB("APT::Get::List-Cleanup",true) == true) { if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false || Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false) @@ -1218,7 +1377,7 @@ bool DoUpdate(CommandLine &CmdL) // Prepare the cache. CacheFile Cache; - if (Cache.Open() == false) + if (Cache.BuildCaches() == false) return false; if (Failed == true) @@ -1241,7 +1400,7 @@ bool DoUpgrade(CommandLine &CmdL) if (pkgAllUpgrade(Cache) == false) { ShowBroken(c1out,Cache,false); - return _error->Error(_("Internal Error, AllUpgrade broke stuff")); + return _error->Error(_("Internal error, AllUpgrade broke stuff")); } return InstallPackages(Cache,true); @@ -1286,14 +1445,14 @@ bool DoInstall(CommandLine &CmdL) while (Cache->FindPkg(S).end() == true) { // Handle an optional end tag indicating what to do - if (S[Length - 1] == '-') + if (Length >= 1 && S[Length - 1] == '-') { Remove = true; S[--Length] = 0; continue; } - if (S[Length - 1] == '+') + if (Length >= 1 && S[Length - 1] == '+') { Remove = false; S[--Length] = 0; @@ -1327,7 +1486,8 @@ bool DoInstall(CommandLine &CmdL) // Check if the name is a regex const char *I; for (I = S; *I != 0; I++) - if (*I == '.' || *I == '?' || *I == '*' || *I == '|') + if (*I == '?' || *I == '*' || *I == '|' || + *I == '[' || *I == '^' || *I == '$') break; if (*I == 0) return _error->Error(_("Couldn't find package %s"),S); @@ -1341,7 +1501,7 @@ bool DoInstall(CommandLine &CmdL) if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE | REG_NOSUB)) != 0) { - char Error[300]; + char Error[300]; regerror(Res,&Pattern,Error,sizeof(Error)); return _error->Error(_("Regex compilation error - %s"),Error); } @@ -1353,6 +1513,9 @@ bool DoInstall(CommandLine &CmdL) if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0) continue; + ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"), + Pkg.Name(),S); + if (VerTag != 0) if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) return false; @@ -1411,7 +1574,7 @@ bool DoInstall(CommandLine &CmdL) c1out << _("The following information may help to resolve the situation:") << endl; c1out << endl; ShowBroken(c1out,Cache,false); - return _error->Error(_("Sorry, broken packages")); + return _error->Error(_("Broken packages")); } /* Print out a list of packages that are going to be installed extra @@ -1419,6 +1582,7 @@ bool DoInstall(CommandLine &CmdL) if (Cache->InstCount() != ExpectedInst) { string List; + string VersionsList; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { pkgCache::PkgIterator I(Cache,Cache.List[J]); @@ -1430,17 +1594,110 @@ bool DoInstall(CommandLine &CmdL) if (strcmp(*J,I.Name()) == 0) break; - if (*J == 0) + if (*J == 0) { List += string(I.Name()) + " "; + VersionsList += string(Cache[I].CandVersion) + "\n"; + } } - ShowList(c1out,_("The following extra packages will be installed:"),List); + ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); + } + + /* Print out a list of suggested and recommended packages */ + { + string SuggestsList, RecommendsList, List; + string SuggestsVersions, RecommendsVersions; + for (unsigned J = 0; J < Cache->Head().PackageCount; J++) + { + pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); + + /* Just look at the ones we want to install */ + if ((*Cache)[Pkg].Install() == false) + continue; + + // get the recommends/suggests for the candidate ver + pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); + for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; ) + { + pkgCache::DepIterator Start; + pkgCache::DepIterator End; + D.GlobOr(Start,End); // advances D + + // FIXME: we really should display a or-group as a or-group to the user + // the problem is that ShowList is incapable of doing this + string RecommendsOrList,RecommendsOrVersions; + string SuggestsOrList,SuggestsOrVersions; + bool foundInstalledInOrGroup = false; + for(;;) + { + /* Skip if package is installed already, or is about to be */ + string target = string(Start.TargetPkg().Name()) + " "; + + if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install + || Cache[Start.TargetPkg()].Install()) + { + foundInstalledInOrGroup=true; + break; + } + + /* Skip if we already saw it */ + if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1) + { + foundInstalledInOrGroup=true; + break; + } + + // this is a dep on a virtual pkg, check if any package that provides it + // should be installed + if(Start.TargetPkg().ProvidesList() != 0) + { + pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); + for (; I.end() == false; I++) + { + pkgCache::PkgIterator Pkg = I.OwnerPkg(); + if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && + Pkg.CurrentVer() != 0) + foundInstalledInOrGroup=true; + } + } + + if (Start->Type == pkgCache::Dep::Suggests) + { + SuggestsOrList += target; + SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + } + + if (Start->Type == pkgCache::Dep::Recommends) + { + RecommendsOrList += target; + RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + } + + if (Start >= End) + break; + Start++; + } + + if(foundInstalledInOrGroup == false) + { + RecommendsList += RecommendsOrList; + RecommendsVersions += RecommendsOrVersions; + SuggestsList += SuggestsOrList; + SuggestsVersions += SuggestsOrVersions; + } + + } + } + + ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions); + ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions); + } // See if we need to prompt if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0) return InstallPackages(Cache,false,false); - + return InstallPackages(Cache,false); } /*}}}*/ @@ -1453,7 +1710,7 @@ bool DoDistUpgrade(CommandLine &CmdL) if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; - c0out << _("Calculating Upgrade... ") << flush; + c0out << _("Calculating upgrade... ") << flush; if (pkgDistUpgrade(*Cache) == false) { c0out << _("Failed") << endl; @@ -1526,7 +1783,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) if (Fix.Resolve() == false) { ShowBroken(c1out,Cache,false); - return _error->Error("Internal Error, problem resolver broke stuff"); + return _error->Error(_("Internal error, problem resolver broke stuff")); } } @@ -1534,7 +1791,7 @@ bool DoDSelectUpgrade(CommandLine &CmdL) if (pkgAllUpgrade(Cache) == false) { ShowBroken(c1out,Cache,false); - return _error->Error("Internal Error, problem resolver broke stuff"); + return _error->Error(_("Internal error, problem resolver broke stuff")); } return InstallPackages(Cache,false); @@ -1653,6 +1910,9 @@ bool DoSource(CommandLine &CmdL) DscFile *Dsc = new DscFile[CmdL.FileSize()]; + // insert all downloaded uris into this set to avoid downloading them + // twice + set queued; // Load the requestd sources into the fetcher unsigned J = 0; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) @@ -1689,7 +1949,28 @@ bool DoSource(CommandLine &CmdL) if (_config->FindB("APT::Get::Tar-Only",false) == true && I->Type != "tar") continue; - + + // don't download the same uri twice (should this be moved to + // the fetcher interface itself?) + if(queued.find(Last->Index().ArchiveURI(I->Path)) != queued.end()) + continue; + queued.insert(Last->Index().ArchiveURI(I->Path)); + + // check if we have a file with that md5 sum already localy + if(!I->MD5Hash.empty() && FileExists(flNotDir(I->Path))) + { + FileFd Fd(flNotDir(I->Path), FileFd::ReadOnly); + MD5Summation sum; + sum.AddFD(Fd.Fd(), Fd.Size()); + Fd.Close(); + if((string)sum.Result() == I->MD5Hash) + { + ioprintf(c1out,_("Skipping already downloaded file '%s'\n"), + flNotDir(I->Path).c_str()); + continue; + } + } + new pkgAcqFile(&Fetcher,Last->Index().ArchiveURI(I->Path), I->MD5Hash,I->Size, Last->Index().SourceInfo(*Last,*I),Src); @@ -1705,10 +1986,10 @@ bool DoSource(CommandLine &CmdL) struct statvfs Buf; string OutputDir = "."; if (statvfs(OutputDir.c_str(),&Buf) != 0) - return _error->Errno("statvfs","Couldn't determine free space in %s", + return _error->Errno("statvfs",_("Couldn't determine free space in %s"), OutputDir.c_str()); if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) - return _error->Error(_("Sorry, you don't have enough free space in %s"), + return _error->Error(_("You don't have enough free space in %s"), OutputDir.c_str()); // Number of bytes @@ -1722,7 +2003,7 @@ bool DoSource(CommandLine &CmdL) if (_config->FindB("APT::Get::Simulate",false) == true) { for (unsigned I = 0; I != J; I++) - ioprintf(cout,_("Fetch Source %s\n"),Dsc[I].Package.c_str()); + ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str()); return true; } @@ -1794,6 +2075,7 @@ bool DoSource(CommandLine &CmdL) if (system(S) != 0) { fprintf(stderr,_("Unpack command '%s' failed.\n"),S); + fprintf(stderr,_("Check if the 'dpkg-dev' package is installed.\n")); _exit(1); } } @@ -1888,7 +2170,7 @@ bool DoBuildDep(CommandLine &CmdL) rec.Package = Opts->Value; rec.Type = pkgSrcRecords::Parser::BuildDependIndep; rec.Op = 0; - BuildDeps.insert(BuildDeps.begin(), rec); + BuildDeps.push_back(rec); } if (BuildDeps.size() == 0) @@ -1901,34 +2183,67 @@ bool DoBuildDep(CommandLine &CmdL) unsigned int ExpectedInst = 0; vector ::iterator D; pkgProblemResolver Fix(Cache); + bool skipAlternatives = false; // skip remaining alternatives in an or group for (D = BuildDeps.begin(); D != BuildDeps.end(); D++) { - pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); - if (Pkg.end() == true) - { - /* for a build-conflict; ignore unknown packages */ - if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || - (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep) - continue; + bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or); - return _error->Error(_("%s dependency on %s cannot be satisfied because the package %s cannot be found"), - Last->BuildDepType((*D).Type),Src.c_str(),(*D).Package.c_str()); + if (skipAlternatives == true) + { + if (!hasAlternatives) + skipAlternatives = false; // end of or group + continue; } - pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); - - if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || + + if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep) - { - /* - * conflict; need to remove if we have an installed version - * that satisfies the version criterial - */ - if (IV.end() == false && - Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) - TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst); - } - else - { + { + pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); + // Build-conflicts on unknown packages are silently ignored + if (Pkg.end() == true) + continue; + + pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); + + /* + * Remove if we have an installed version that satisfies the + * version criteria + */ + if (IV.end() == false && + Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + TryToInstall(Pkg,Cache,Fix,true,false,ExpectedInst); + } + else // BuildDep || BuildDepIndep + { + pkgCache::PkgIterator Pkg = Cache->FindPkg((*D).Package); + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << "Looking for " << (*D).Package << "...\n"; + + if (Pkg.end() == true) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " (not found)" << (*D).Package << endl; + + if (hasAlternatives) + continue; + + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because the package %s cannot be found"), + Last->BuildDepType((*D).Type),Src.c_str(), + (*D).Package.c_str()); + } + + /* + * if there are alternatives, we've already picked one, so skip + * the rest + * + * TODO: this means that if there's a build-dep on A|B and B is + * installed, we'll still try to install A; more importantly, + * if A is currently broken, we cannot go back and try B. To fix + * this would require we do a Resolve cycle for each package we + * add to the install list. Ugh + */ + /* * If this is a virtual package, we need to check the list of * packages that provide it and see if any of those are @@ -1936,24 +2251,99 @@ bool DoBuildDep(CommandLine &CmdL) */ pkgCache::PrvIterator Prv = Pkg.ProvidesList(); for (; Prv.end() != true; Prv++) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Checking provider " << Prv.OwnerPkg().Name() << endl; + if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) break; - - if (Prv.end() == true) - { - /* - * depends; need to install or upgrade if we don't have the - * package installed or if the version does not satisfy the - * build dep. This is complicated by the fact that if we - * depend on a version lower than what we already have - * installed it is not clear what should be done; in practice - * this case should be rare though and right now nothing - * is done about it :-( - */ - if (IV.end() == true || - Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false) - TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst); - } + } + + // Get installed version and version we are going to install + pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); + + if ((*D).Version[0] != '\0') { + // Versioned dependency + + pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); + + for (; CV.end() != true; CV++) + { + if (Cache->VS().CheckDep(CV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + break; + } + if (CV.end() == true) + if (hasAlternatives) + { + continue; + } + else + { + return _error->Error(_("%s dependency for %s cannot be satisfied " + "because no available versions of package %s " + "can satisfy version requirements"), + Last->BuildDepType((*D).Type),Src.c_str(), + (*D).Package.c_str()); + } + } + else + { + // Only consider virtual packages if there is no versioned dependency + if (Prv.end() == false) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Is provided by installed package " << Prv.OwnerPkg().Name() << endl; + skipAlternatives = hasAlternatives; + continue; + } + } + + if (IV.end() == false) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Is installed\n"; + + if (Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == true) + { + skipAlternatives = hasAlternatives; + continue; + } + + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " ...but the installed version doesn't meet the version requirement\n"; + + if (((*D).Op & pkgCache::Dep::LessEq) == pkgCache::Dep::LessEq) + { + return _error->Error(_("Failed to satisfy %s dependency for %s: Installed package %s is too new"), + Last->BuildDepType((*D).Type), + Src.c_str(), + Pkg.Name()); + } + } + + + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Trying to install " << (*D).Package << endl; + + if (TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst) == true) + { + // We successfully installed something; skip remaining alternatives + skipAlternatives = hasAlternatives; + continue; + } + else if (hasAlternatives) + { + if (_config->FindB("Debug::BuildDeps",false) == true) + cout << " Unsatisfiable, trying alternatives\n"; + continue; + } + else + { + return _error->Error(_("Failed to satisfy %s dependency for %s: %s"), + Last->BuildDepType((*D).Type), + Src.c_str(), + (*D).Package.c_str()); + } } } @@ -1963,8 +2353,7 @@ bool DoBuildDep(CommandLine &CmdL) // Now we check the state of the packages, if (Cache->BrokenCount() != 0) - return _error->Error(_("Some broken packages were found while trying to process build-dependencies.\n" - "You might want to run `apt-get -f install' to correct these.")); + return _error->Error(_("Build-dependencies for %s could not be satisfied."),*I); } if (InstallPackages(Cache, false, true) == false) @@ -2000,7 +2389,7 @@ bool ShowHelp(CommandLine &CmdL) if (_config->FindB("version") == true) { - cout << _("Supported Modules:") << endl; + cout << _("Supported modules:") << endl; for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++) { @@ -2073,8 +2462,9 @@ bool ShowHelp(CommandLine &CmdL) " -m Attempt to continue if archives are unlocatable\n" " -u Show a list of upgraded packages as well\n" " -b Build the source package after fetching it\n" + " -V Show verbose version numbers\n" " -c=? Read this configuration file\n" - " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n" + " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n" "See the apt-get(8), sources.list(5) and apt.conf(5) manual\n" "pages for more information and options.\n" " This APT has Super Cow Powers.\n"); @@ -2093,7 +2483,7 @@ void GetInitialize() _config->Set("APT::Get::Assume-Yes",false); _config->Set("APT::Get::Fix-Broken",false); _config->Set("APT::Get::Force-Yes",false); - _config->Set("APT::Get::APT::Get::No-List-Cleanup",true); + _config->Set("APT::Get::List-Cleanup",true); } /*}}}*/ // SigWinch - Window size change signal handler /*{{{*/ @@ -2116,6 +2506,7 @@ int main(int argc,const char *argv[]) CommandLine::Args Args[] = { {'h',"help","help",0}, {'v',"version","version",0}, + {'V',"verbose-versions","APT::Get::Show-Versions",0}, {'q',"quiet","quiet",CommandLine::IntLevel}, {'q',"silent","quiet",CommandLine::IntLevel}, {'d',"download-only","APT::Get::Download-Only",0}, @@ -2148,6 +2539,7 @@ int main(int argc,const char *argv[]) {0,"remove","APT::Get::Remove",0}, {0,"only-source","APT::Get::Only-Source",0}, {0,"arch-only","APT::Get::Arch-Only",0}, + {0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; @@ -2193,7 +2585,7 @@ int main(int argc,const char *argv[]) } // Deal with stdout not being a tty - if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1) + if (!isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1) _config->Set("quiet","1"); // Setup the output streams