X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/2adb5fda8c34d1eea3e94fe6d1d6c378144ccfad..29d0b55e368aa2ae26ad61f7ecd60b723a3a4e05:/cmdline/apt-get.cc?ds=sidebyside diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 3c03e0fa3..ab6dca388 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.139 2003/08/22 01:51:01 mdz 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,11 +46,14 @@ #include "acqprogress.h" +#include #include +#include #include #include #include #include +#include #include #include #include @@ -57,15 +61,18 @@ #include #include #include +#include /*}}}*/ +#define RAMFS_MAGIC 0x858458f6 + using namespace std; 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 /*{{{*/ // --------------------------------------------------------------------- @@ -104,13 +111,16 @@ class CacheFile : public pkgCacheFile return Open(true); } CacheFile() : List(0) {}; + ~CacheFile() { + delete[] List; + } }; /*}}}*/ // YnPrompt - Yes No Prompt. /*{{{*/ // --------------------------------------------------------------------- /* Returns true on a Yes.*/ -bool YnPrompt() +bool YnPrompt(bool Default=true) { if (_config->FindB("APT::Get::Assume-Yes",false) == true) { @@ -125,7 +135,7 @@ bool YnPrompt() return false; if (strlen(response) == 0) - return true; + return Default; regex_t Pattern; int Res; @@ -269,7 +279,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; @@ -356,7 +366,7 @@ 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; @@ -417,7 +427,7 @@ void ShowKept(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - ShowList(out,_("The following packages have been kept back"),List,VersionsList); + ShowList(out,_("The following packages have been kept back:"),List,VersionsList); } /*}}}*/ // ShowUpgraded - Show upgraded packages /*{{{*/ @@ -438,7 +448,7 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - ShowList(out,_("The following packages will be upgraded"),List,VersionsList); + ShowList(out,_("The following packages will be upgraded:"),List,VersionsList); } /*}}}*/ // ShowDowngraded - Show downgraded packages /*{{{*/ @@ -459,7 +469,7 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) List += string(I.Name()) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } - return ShowList(out,_("The following packages will be DOWNGRADED"),List,VersionsList); + return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList); } /*}}}*/ // ShowHold - Show held but changed packages /*{{{*/ @@ -540,9 +550,10 @@ bool ShowEssential(ostream &out,CacheFile &Cache) } delete [] Added; - return ShowList(out,_("WARNING: The following essential packages will be removed\n" + 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 /*{{{*/ // --------------------------------------------------------------------- @@ -586,7 +597,6 @@ void Stats(ostream &out,pkgDepCache &Dep) Dep.BadCount()); } /*}}}*/ - // CacheFile::NameComp - QSort compare by name /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -624,23 +634,37 @@ void CacheFile::Sort() and verifies that the system is OK. */ bool CacheFile::CheckDeps(bool AllowBroken) { + bool FixBroken = _config->FindB("APT::Get::Fix-Broken",false); + if (_error->PendingError() == true) return false; // 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) return false; + if (_config->FindB("APT::Get::Fix-Policy-Broken",false) == true) + { + FixBroken = true; + if ((DCache->PolicyBrokenCount() > 0)) + { + // upgrade all policy-broken packages with ForceImportantDeps=True + for (pkgCache::PkgIterator I = Cache->PkgBegin(); !I.end(); I++) + if ((*DCache)[I].NowPolicyBroken() == true) + DCache->MarkInstall(I,true,0, false, true); + } + } + // Nothing is broken if (DCache->BrokenCount() == 0 || AllowBroken == true) return true; // Attempt to fix broken things - if (_config->FindB("APT::Get::Fix-Broken",false) == true) + if (FixBroken == true) { c1out << _("Correcting dependencies...") << flush; if (pkgFixBroken(*DCache) == false || DCache->BrokenCount() != 0) @@ -666,13 +690,56 @@ bool CacheFile::CheckDeps(bool AllowBroken) return true; } /*}}}*/ +// CheckAuth - check if each download comes form a trusted source /*{{{*/ +// --------------------------------------------------------------------- +/* */ +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 /*{{{*/ // --------------------------------------------------------------------- /* 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) { @@ -693,19 +760,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); 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 && @@ -714,17 +781,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; } @@ -765,23 +833,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.\n"), SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); - else + else if (DebBytes != 0) ioprintf(c1out,_("Need to get %sB of archives.\n"), SizeToStr(DebBytes).c_str()); // Size delta if (Cache->UsrSize() >= 0) - ioprintf(c1out,_("After unpacking %sB of additional disk space will be used.\n"), + ioprintf(c1out,_("After this operation, %sB of additional disk space will be used.\n"), SizeToStr(Cache->UsrSize()).c_str()); else - ioprintf(c1out,_("After unpacking %sB disk space will be freed.\n"), + ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"), SizeToStr(-1*Cache->UsrSize()).c_str()); if (_error->PendingError() == true) @@ -795,11 +863,16 @@ 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(_("You don't have enough free space in %s."), - OutputDir.c_str()); + { + struct statfs Stat; + if (statfs(OutputDir.c_str(),&Stat) != 0 || + unsigned(Stat.f_type) != RAMFS_MAGIC) + return _error->Error(_("You don't have enough free space in %s."), + OutputDir.c_str()); + } } // Fail safe check @@ -810,14 +883,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; @@ -838,7 +911,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) { @@ -855,10 +928,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, pkgAcquire::UriIterator I = Fetcher.UriBegin(); for (; I != Fetcher.UriEnd(); I++) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << - I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl; + I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; 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) @@ -942,11 +1018,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) @@ -1036,10 +1113,9 @@ 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; @@ -1094,9 +1170,11 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, else ExpectedInst++; - // Install it with autoinstalling enabled. - if (State.InstBroken() == true && BrokenFix == false) + // Install it with autoinstalling enabled (if we not respect the minial + // required deps or the policy) + if ((State.InstBroken() == true || State.InstPolicyBroken() == true) && BrokenFix == false) Cache.MarkInstall(Pkg,true); + return true; } /*}}}*/ @@ -1141,24 +1219,55 @@ 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. */ + bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source"); + if (MatchSrcOnly == 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()); @@ -1166,16 +1275,22 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, } } } - - // No source package name.. - if (Src.empty() == true) - Src = TmpSrc; - + // The best hit pkgSrcRecords::Parser *Last = 0; unsigned long Offset = 0; string Version; bool IsMatch = false; + + // No source package name.. + if (Src.empty() == true) + Src = TmpSrc; + else + // if we have a source pkg name, make sure to only search + // for srcpkg names, otherwise apt gets confused if there + // is a binary package "pkg1" and a source package "pkg1" + // with the same name but that comes from different packages + MatchSrcOnly = true; // If we are matching by version then we need exact matches to be happy if (VerTag.empty() == false) @@ -1185,13 +1300,13 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, binary packages in the search */ pkgSrcRecords::Parser *Parse; SrcRecs.Restart(); - while ((Parse = SrcRecs.Find(Src.c_str(),false)) != 0) + while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0) { string Ver = Parse->Version(); - - // Skip name mismatches - if (IsMatch == true && Parse->Package() != Src) - continue; + + // show name mismatches + if (IsMatch == true && Parse->Package() != Src) + ioprintf(c1out, _("No source package '%s' picking '%s' instead\n"), Parse->Package().c_str(), Src.c_str()); if (VerTag.empty() == false) { @@ -1216,16 +1331,12 @@ 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; } /*}}}*/ - // DoUpdate - Update the package lists /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -1248,57 +1359,103 @@ bool DoUpdate(CommandLine &CmdL) return _error->Error(_("Unable to lock the list directory")); } - // Create the download object + // Create the progress 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) { + // get a fetcher + pkgAcquire Fetcher(&Stat); + + // 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; + I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; } - - // Run it - if (Fetcher.Run() == pkgAcquire::Failed) + + // do the work + CacheFile Cache; + if (_config->FindB("APT::Get::Download",true) == true) + ListUpdate(Stat, List); + + // Rebuild the cache. + if (Cache.BuildCaches() == false) return false; + + return true; +} + /*}}}*/ +// DoAutomaticRemove - Remove all automatic unused packages /*{{{*/ +// --------------------------------------------------------------------- +/* Remove unused automatic packages */ +bool DoAutomaticRemove(CacheFile &Cache) +{ + bool Debug = _config->FindI("Debug::pkgAutoRemove",false); + bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); + bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove"); + pkgDepCache::ActionGroup group(*Cache); - bool Failed = false; - for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) + if(Debug) + std::cout << "DoAutomaticRemove()" << std::endl; + + if (_config->FindB("APT::Get::Remove",true) == false && + doAutoRemove == true) { - if ((*I)->Status == pkgAcquire::Item::StatDone) - continue; + c1out << _("We are not supposed to delete stuff, can't start " + "AutoRemover") << std::endl; + doAutoRemove = false; + } - (*I)->Finished(); - - fprintf(stderr,_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), - (*I)->ErrorText.c_str()); - Failed = true; + string autoremovelist, autoremoveversions; + // look over the cache to see what can be removed + for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg) + { + if (Cache[Pkg].Garbage) + { + if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install()) + if(Debug) + std::cout << "We could delete %s" << Pkg.Name() << std::endl; + + // only show stuff in the list that is not yet marked for removal + if(Cache[Pkg].Delete() == false) + { + autoremovelist += string(Pkg.Name()) + " "; + autoremoveversions += string(Cache[Pkg].CandVersion) + "\n"; + } + if (doAutoRemove) + { + if(Pkg.CurrentVer() != 0 && + Pkg->CurrentState != pkgCache::State::ConfigFiles) + Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false)); + else + Cache->MarkKeep(Pkg, false, false); + } + } } - - // Clean out any old list files - if (_config->FindB("APT::Get::List-Cleanup",true) == true) + if (!hideAutoRemove) + ShowList(c1out, _("The following packages were automatically installed and are no longer required:"), autoremovelist, autoremoveversions); + if (!doAutoRemove && !hideAutoRemove && autoremovelist.size() > 0) + c1out << _("Use 'apt-get autoremove' to remove them.") << std::endl; + + // Now see if we destroyed anything + if (Cache->BrokenCount() != 0) { - if (Fetcher.Clean(_config->FindDir("Dir::State::lists")) == false || - Fetcher.Clean(_config->FindDir("Dir::State::lists") + "partial/") == false) - return false; + c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n" + "shouldn't happen. Please file a bug report against apt.") << endl; + c1out << endl; + c1out << _("The following information may help to resolve the situation:") << endl; + c1out << endl; + ShowBroken(c1out,Cache,false); + + return _error->Error(_("Internal Error, AutoRemover broke stuff")); } - - // Prepare the cache. - CacheFile Cache; - if (Cache.BuildCaches() == false) - return false; - - if (Failed == true) - return _error->Error(_("Some index files failed to download, they have been ignored, or old ones used instead.")); - return true; } /*}}}*/ @@ -1316,12 +1473,67 @@ 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); } /*}}}*/ +// DoInstallTask - Install task from the command line /*{{{*/ +// --------------------------------------------------------------------- +/* Install named task */ +bool TryInstallTask(pkgDepCache &Cache, pkgProblemResolver &Fix, + bool BrokenFix, + unsigned int& ExpectedInst, + const char *taskname, + bool Remove) +{ + const char *start, *end; + pkgCache::PkgIterator Pkg; + char buf[64*1024]; + regex_t Pattern; + + // get the records + pkgRecords Recs(Cache); + + // build regexp for the task + char S[300]; + snprintf(S, sizeof(S), "^Task:.*[, ]%s([, ]|$)", taskname); + if(regcomp(&Pattern,S, REG_EXTENDED | REG_NOSUB | REG_NEWLINE) != 0) + return _error->Error("Failed to compile task regexp"); + + bool found = false; + bool res = true; + + // two runs, first ignore dependencies, second install any missing + for(int IgnoreBroken=1; IgnoreBroken >= 0; IgnoreBroken--) + { + for (Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++) + { + pkgCache::VerIterator ver = Cache[Pkg].CandidateVerIter(Cache); + if(ver.end()) + continue; + pkgRecords::Parser &parser = Recs.Lookup(ver.FileList()); + parser.GetRec(start,end); + strncpy(buf, start, end-start); + buf[end-start] = 0x0; + if (regexec(&Pattern,buf,0,0,0) != 0) + continue; + res &= TryToInstall(Pkg,Cache,Fix,Remove,IgnoreBroken,ExpectedInst); + found = true; + } + } + + // now let the problem resolver deal with any issues + Fix.Resolve(true); + + if(!found) + _error->Error(_("Couldn't find task %s"),taskname); + + regfree(&Pattern); + return res; +} + /*}}}*/ // DoInstall - Install packages from the command line /*{{{*/ // --------------------------------------------------------------------- /* Install named packages */ @@ -1337,6 +1549,7 @@ bool DoInstall(CommandLine &CmdL) if (Cache->BrokenCount() != 0) BrokenFix = true; + unsigned int AutoMarkChanged = 0; unsigned int ExpectedInst = 0; unsigned int Packages = 0; pkgProblemResolver Fix(Cache); @@ -1344,155 +1557,198 @@ bool DoInstall(CommandLine &CmdL) bool DefRemove = false; if (strcasecmp(CmdL.FileList[0],"remove") == 0) DefRemove = true; - - for (const char **I = CmdL.FileList + 1; *I != 0; I++) + else if (strcasecmp(CmdL.FileList[0], "purge") == 0) { - // Duplicate the string - unsigned int Length = strlen(*I); - char S[300]; - if (Length >= sizeof(S)) - continue; - strcpy(S,*I); - - // See if we are removing and special indicators.. - bool Remove = DefRemove; - char *VerTag = 0; - bool VerIsRel = false; - while (Cache->FindPkg(S).end() == true) + _config->Set("APT::Get::Purge", true); + DefRemove = true; + } + else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) + { + _config->Set("APT::Get::AutomaticRemove", "true"); + DefRemove = true; + } + // new scope for the ActionGroup + { + pkgDepCache::ActionGroup group(Cache); + for (const char **I = CmdL.FileList + 1; *I != 0; I++) { - // Handle an optional end tag indicating what to do - if (Length >= 1 && S[Length - 1] == '-') - { - Remove = true; - S[--Length] = 0; + // Duplicate the string + unsigned int Length = strlen(*I); + char S[300]; + if (Length >= sizeof(S)) continue; - } - - if (Length >= 1 && S[Length - 1] == '+') + strcpy(S,*I); + + // See if we are removing and special indicators.. + bool Remove = DefRemove; + char *VerTag = 0; + bool VerIsRel = false; + + // this is a task! + if (Length >= 1 && S[Length - 1] == '^') + { + S[--Length] = 0; + // tasks must always be confirmed + ExpectedInst += 1000; + // see if we can install it + TryInstallTask(Cache, Fix, BrokenFix, ExpectedInst, S, Remove); + continue; + } + + while (Cache->FindPkg(S).end() == true) { - Remove = false; - S[--Length] = 0; - continue; - } + // Handle an optional end tag indicating what to do + if (Length >= 1 && S[Length - 1] == '-') + { + Remove = true; + S[--Length] = 0; + continue; + } - char *Slash = strchr(S,'='); - if (Slash != 0) - { - VerIsRel = false; - *Slash = 0; - VerTag = Slash + 1; - } + if (Length >= 1 && S[Length - 1] == '+') + { + Remove = false; + S[--Length] = 0; + continue; + } - Slash = strchr(S,'/'); - if (Slash != 0) - { - VerIsRel = true; - *Slash = 0; - VerTag = Slash + 1; - } + char *Slash = strchr(S,'='); + if (Slash != 0) + { + VerIsRel = false; + *Slash = 0; + VerTag = Slash + 1; + } - break; - } - - // Locate the package - pkgCache::PkgIterator Pkg = Cache->FindPkg(S); - Packages++; - if (Pkg.end() == true) - { - // Check if the name is a regex - const char *I; - for (I = S; *I != 0; I++) - if (*I == '?' || *I == '*' || *I == '|' || - *I == '[' || *I == '^' || *I == '$') - break; - if (*I == 0) - return _error->Error(_("Couldn't find package %s"),S); - - // Regexs must always be confirmed - ExpectedInst += 1000; + Slash = strchr(S,'/'); + if (Slash != 0) + { + VerIsRel = true; + *Slash = 0; + VerTag = Slash + 1; + } - // Compile the regex pattern - regex_t Pattern; - int Res; - if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE | - REG_NOSUB)) != 0) - { - char Error[300]; - regerror(Res,&Pattern,Error,sizeof(Error)); - return _error->Error(_("Regex compilation error - %s"),Error); + break; } - - // Run over the matches - bool Hit = false; - for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++) + + // Locate the package + pkgCache::PkgIterator Pkg = Cache->FindPkg(S); + Packages++; + if (Pkg.end() == true) { - if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0) - continue; + // Check if the name is a regex + const char *I; + for (I = S; *I != 0; I++) + if (*I == '?' || *I == '*' || *I == '|' || + *I == '[' || *I == '^' || *I == '$') + break; + if (*I == 0) + return _error->Error(_("Couldn't find package %s"),S); + + // Regexs must always be confirmed + ExpectedInst += 1000; + + // Compile the regex pattern + regex_t Pattern; + int Res; + if ((Res = regcomp(&Pattern,S,REG_EXTENDED | REG_ICASE | + REG_NOSUB)) != 0) + { + char Error[300]; + regerror(Res,&Pattern,Error,sizeof(Error)); + return _error->Error(_("Regex compilation error - %s"),Error); + } + + // Run over the matches + bool Hit = false; + for (Pkg = Cache->PkgBegin(); Pkg.end() == false; Pkg++) + { + if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0) + continue; - ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"), - Pkg.Name(),S); + ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"), + Pkg.Name(),S); + if (VerTag != 0) + if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) + return false; + + Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix, + ExpectedInst,false); + } + regfree(&Pattern); + + if (Hit == false) + return _error->Error(_("Couldn't find package %s"),S); + } + else + { if (VerTag != 0) if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) return false; - - Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix, - ExpectedInst,false); - } - regfree(&Pattern); - - if (Hit == false) - return _error->Error(_("Couldn't find package %s"),S); - } - else - { - if (VerTag != 0) - if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) + if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false) return false; - if (TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix,ExpectedInst) == false) - return false; - } - } - /* If we are in the Broken fixing mode we do not attempt to fix the - problems. This is if the user invoked install without -f and gave - packages */ - if (BrokenFix == true && Cache->BrokenCount() != 0) - { - c1out << _("You might want to run `apt-get -f install' to correct these:") << endl; - ShowBroken(c1out,Cache,false); + // see if we need to fix the auto-mark flag + // e.g. apt-get install foo + // where foo is marked automatic + if(!Remove && + Cache[Pkg].Install() == false && + (Cache[Pkg].Flags & pkgCache::Flag::Auto) && + _config->FindB("APT::Get::ReInstall",false) == false) + { + ioprintf(c1out,_("%s set to manually installed.\n"), + Pkg.Name()); + Cache->MarkAuto(Pkg,false); + AutoMarkChanged++; + } + } + } - return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).")); - } + /* If we are in the Broken fixing mode we do not attempt to fix the + problems. This is if the user invoked install without -f and gave + packages */ + if (BrokenFix == true && Cache->BrokenCount() != 0) + { + c1out << _("You might want to run `apt-get -f install' to correct these:") << endl; + ShowBroken(c1out,Cache,false); + + return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).")); + } - // Call the scored problem resolver - Fix.InstallProtect(); - if (Fix.Resolve(true) == false) - _error->Discard(); + // Call the scored problem resolver + Fix.InstallProtect(); + if (Fix.Resolve(true) == false) + _error->Discard(); - // Now we check the state of the packages, - if (Cache->BrokenCount() != 0) - { - c1out << - _("Some packages could not be installed. This may mean that you have\n" - "requested an impossible situation or if you are using the unstable\n" - "distribution that some required packages have not yet been created\n" - "or been moved out of Incoming.") << endl; - if (Packages == 1) + // Now we check the state of the packages, + if (Cache->BrokenCount() != 0) { - c1out << endl; c1out << - _("Since you only requested a single operation it is extremely likely that\n" - "the package is simply not installable and a bug report against\n" - "that package should be filed.") << endl; - } + _("Some packages could not be installed. This may mean that you have\n" + "requested an impossible situation or if you are using the unstable\n" + "distribution that some required packages have not yet been created\n" + "or been moved out of Incoming.") << endl; + /* + if (Packages == 1) + { + c1out << endl; + c1out << + _("Since you only requested a single operation it is extremely likely that\n" + "the package is simply not installable and a bug report against\n" + "that package should be filed.") << endl; + } + */ + + c1out << _("The following information may help to resolve the situation:") << endl; + c1out << endl; + ShowBroken(c1out,Cache,false); + return _error->Error(_("Broken packages")); + } + } + if (!DoAutomaticRemove(Cache)) + return false; - c1out << _("The following information may help to resolve the situation:") << endl; - c1out << endl; - ShowBroken(c1out,Cache,false); - return _error->Error(_("Broken packages")); - } - /* Print out a list of packages that are going to be installed extra to what the user asked */ if (Cache->InstCount() != ExpectedInst) @@ -1512,8 +1768,8 @@ bool DoInstall(CommandLine &CmdL) if (*J == 0) { List += string(I.Name()) + " "; - VersionsList += string(Cache[I].CandVersion) + "\n"; - } + VersionsList += string(Cache[I].CandVersion) + "\n"; + } } ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); @@ -1525,86 +1781,104 @@ bool DoInstall(CommandLine &CmdL) string SuggestsVersions, RecommendsVersions; for (unsigned J = 0; J < Cache->Head().PackageCount; J++) { - pkgCache::PkgIterator I(Cache,Cache.List[J]); + pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); /* Just look at the ones we want to install */ - if ((*Cache)[I].Install() == false) + if ((*Cache)[Pkg].Install() == false) continue; - for (pkgCache::VerIterator V = I.VersionList(); V.end() == false; V++) - { - for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++) + // 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()) { - pkgCache::DepIterator Start; - pkgCache::DepIterator End; - D.GlobOr(Start,End); - - /* - * If this is a virtual package, we need to check the list of - * packages that provide it and see if any of those are - * installed - */ - pkgCache::PrvIterator Prv = Start.TargetPkg().ProvidesList(); - bool providedBySomething = false; - for (; Prv.end() != true; Prv++) - if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) { - providedBySomething = true; - break; - } - - if (providedBySomething) continue; - - do - { - if (Start->Type == pkgCache::Dep::Suggests) { - - /* A suggests relations, let's see if we have it - installed already */ - - string target = string(Start.TargetPkg().Name()) + " "; - if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install || Cache[Start.TargetPkg()].Install()) - break; - /* Does another package suggest it as well? If so, - don't print it twice */ - if (int(SuggestsList.find(target)) > -1) - break; - SuggestsList += target; - SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; - } - - if (Start->Type == pkgCache::Dep::Recommends) { - - /* A recommends relation, let's see if we have it - installed already */ - - string target = string(Start.TargetPkg().Name()) + " "; - if ((*Start.TargetPkg()).SelectedState == pkgCache::State::Install || Cache[Start.TargetPkg()].Install()) - break; - - /* Does another package recommend it as well? If so, - don't print it twice */ - - if (int(RecommendsList.find(target)) > -1) - break; - RecommendsList += target; - SuggestsVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; - } - if (Start == End) - break; - Start++; - } while (1); + foundInstalledInOrGroup=true; + break; + } + + /* Skip if we already saw it */ + if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1) + { + foundInstalledInOrGroup=true; + break; + } + + // this is a dep on a virtual pkg, check if any package that provides it + // should be installed + if(Start.TargetPkg().ProvidesList() != 0) + { + pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); + for (; I.end() == false; I++) + { + pkgCache::PkgIterator Pkg = I.OwnerPkg(); + if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && + Pkg.CurrentVer() != 0) + foundInstalledInOrGroup=true; + } + } + + if (Start->Type == pkgCache::Dep::Suggests) + { + SuggestsOrList += target; + SuggestsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; + } + + if (Start->Type == pkgCache::Dep::Recommends) + { + RecommendsOrList += target; + RecommendsOrVersions += string(Cache[Start.TargetPkg()].CandVersion) + "\n"; } - } + + if (Start >= End) + break; + Start++; + } + + if(foundInstalledInOrGroup == false) + { + RecommendsList += RecommendsOrList; + RecommendsVersions += RecommendsOrVersions; + SuggestsList += SuggestsOrList; + SuggestsVersions += SuggestsOrVersions; + } + + } } + ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions); ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions); } + // if nothing changed in the cache, but only the automark information + // we write the StateFile here, otherwise it will be written in + // cache.commit() + if (AutoMarkChanged > 0 && + Cache->DelCount() == 0 && Cache->InstCount() == 0 && + Cache->BadCount() == 0 && + _config->FindB("APT::Get::Simulate",false) == false) + Cache->writeStateFile(NULL); + // See if we need to prompt if (Cache->InstCount() == ExpectedInst && Cache->DelCount() == 0) return InstallPackages(Cache,false,false); - + return InstallPackages(Cache,false); } /*}}}*/ @@ -1617,7 +1891,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; @@ -1639,6 +1913,8 @@ bool DoDSelectUpgrade(CommandLine &CmdL) if (Cache.OpenForInstall() == false || Cache.CheckDeps() == false) return false; + pkgDepCache::ActionGroup group(Cache); + // Install everything with the install flag set pkgCache::PkgIterator I = Cache->PkgBegin(); for (;I.end() != true; I++) @@ -1690,7 +1966,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")); } } @@ -1698,7 +1974,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); @@ -1817,6 +2093,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++) @@ -1853,7 +2132,33 @@ bool DoSource(CommandLine &CmdL) if (_config->FindB("APT::Get::Tar-Only",false) == true && I->Type != "tar") continue; - + + // Dsc only mode only fetches .dsc files + if (_config->FindB("APT::Get::Dsc-Only",false) == true && + I->Type != "dsc") + 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); @@ -1869,11 +2174,16 @@ 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(_("You don't have enough free space in %s"), - OutputDir.c_str()); + { + struct statfs Stat; + if (statfs(OutputDir.c_str(),&Stat) != 0 || + unsigned(Stat.f_type) != RAMFS_MAGIC) + return _error->Error(_("You don't have enough free space in %s"), + OutputDir.c_str()); + } // Number of bytes if (DebBytes != FetchBytes) @@ -1886,7 +2196,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; } @@ -1896,7 +2206,7 @@ bool DoSource(CommandLine &CmdL) pkgAcquire::UriIterator I = Fetcher.UriBegin(); for (; I != Fetcher.UriEnd(); I++) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << - I->Owner->FileSize << ' ' << I->Owner->MD5Sum() << endl; + I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; return true; } @@ -1958,6 +2268,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); } } @@ -2052,7 +2363,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) @@ -2065,8 +2376,18 @@ 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++) { + bool hasAlternatives = (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or); + + if (skipAlternatives == true) + { + if (!hasAlternatives) + skipAlternatives = false; // end of or group + continue; + } + if ((*D).Type == pkgSrcRecords::Parser::BuildConflict || (*D).Type == pkgSrcRecords::Parser::BuildConflictIndep) { @@ -2088,16 +2409,21 @@ bool DoBuildDep(CommandLine &CmdL) 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) { - // Check if there are any alternatives - if (((*D).Op & pkgCache::Dep::Or) != pkgCache::Dep::Or) - 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()); - // Try the next alternative - continue; + 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()); } /* @@ -2110,9 +2436,6 @@ bool DoBuildDep(CommandLine &CmdL) * this would require we do a Resolve cycle for each package we * add to the install list. Ugh */ - while (D != BuildDeps.end() && - (((*D).Op & pkgCache::Dep::Or) == pkgCache::Dep::Or)) - D++; /* * If this is a virtual package, we need to check the list of @@ -2120,9 +2443,11 @@ bool DoBuildDep(CommandLine &CmdL) * installed */ pkgCache::PrvIterator Prv = Pkg.ProvidesList(); - bool providedBySomething = !Prv.end(); 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; } @@ -2130,9 +2455,8 @@ bool DoBuildDep(CommandLine &CmdL) // Get installed version and version we are going to install pkgCache::VerIterator IV = (*Cache)[Pkg].InstVerIter(*Cache); - if (!providedBySomething || (*D).Version[0] != '\0') { - /* We either have a versioned dependency (so a provides won't do) - or nothing is providing this package */ + if ((*D).Version[0] != '\0') { + // Versioned dependency pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); @@ -2142,25 +2466,81 @@ bool DoBuildDep(CommandLine &CmdL) 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; + } } - /* - * TODO: 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, and right now nothing is - * done about it :-( - */ - if (Prv.end() == true && // Nothing provides it; and - (IV.end() == true || // It is not installed, or - Cache->VS().CheckDep(IV.VerStr(),(*D).Op,(*D).Version.c_str()) == false)) - // the version installed doesn't - // satisfy constraints - TryToInstall(Pkg,Cache,Fix,false,false,ExpectedInst); + 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; + if(_config->FindB("APT::Get::Build-Dep-Automatic", false) == true) + Cache->MarkAuto(Pkg, true); + 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()); + } } } @@ -2170,8 +2550,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) @@ -2202,12 +2581,12 @@ bool DoMoo(CommandLine &CmdL) /* */ bool ShowHelp(CommandLine &CmdL) { - ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION, - COMMON_OS,COMMON_CPU,__DATE__,__TIME__); + ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,VERSION, + COMMON_ARCH,__DATE__,__TIME__); if (_config->FindB("version") == true) { - cout << _("Supported Modules:") << endl; + cout << _("Supported modules:") << endl; for (unsigned I = 0; I != pkgVersioningSystem::GlobalListLen; I++) { @@ -2261,6 +2640,8 @@ bool ShowHelp(CommandLine &CmdL) " upgrade - Perform an upgrade\n" " install - Install new packages (pkg is libc6 not libc6.deb)\n" " remove - Remove packages\n" + " autoremove - Remove automatically all unused packages\n" + " purge - Remove packages and config files\n" " source - Download source archives\n" " build-dep - Configure build-dependencies for source packages\n" " dist-upgrade - Distribution upgrade, see apt-get(8)\n" @@ -2276,13 +2657,13 @@ bool ShowHelp(CommandLine &CmdL) " -d Download only - do NOT install or unpack archives\n" " -s No-act. Perform ordering simulation\n" " -y Assume Yes to all queries and do not prompt\n" - " -f Attempt to continue if the integrity check fails\n" + " -f Attempt to correct a system with broken dependencies in place\n" " -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"); @@ -2301,7 +2682,8 @@ 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); + _config->Set("APT::Get::AutomaticRemove",false); } /*}}}*/ // SigWinch - Window size change signal handler /*{{{*/ @@ -2318,8 +2700,7 @@ void SigWinch(int) #endif } /*}}}*/ - -int main(int argc,const char *argv[]) +int main(int argc,const char *argv[]) /*{{{*/ { CommandLine::Args Args[] = { {'h',"help","help",0}, @@ -2349,7 +2730,8 @@ int main(int argc,const char *argv[]) {0,"force-yes","APT::Get::force-yes",0}, {0,"print-uris","APT::Get::Print-URIs",0}, {0,"diff-only","APT::Get::Diff-Only",0}, - {0,"tar-only","APT::Get::tar-Only",0}, + {0,"tar-only","APT::Get::Tar-Only",0}, + {0,"dsc-only","APT::Get::Dsc-Only",0}, {0,"purge","APT::Get::Purge",0}, {0,"list-cleanup","APT::Get::List-Cleanup",0}, {0,"reinstall","APT::Get::ReInstall",0}, @@ -2357,6 +2739,10 @@ 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,"auto-remove","APT::Get::AutomaticRemove",0}, + {0,"allow-unauthenticated","APT::Get::AllowUnauthenticated",0}, + {0,"install-recommends","APT::Install-Recommends",CommandLine::Boolean}, + {0,"fix-policy","APT::Get::Fix-Policy-Broken",0}, {'c',"config-file",0,CommandLine::ConfigFile}, {'o',"option",0,CommandLine::ArbItem}, {0,0,0,0}}; @@ -2364,6 +2750,9 @@ int main(int argc,const char *argv[]) {"upgrade",&DoUpgrade}, {"install",&DoInstall}, {"remove",&DoInstall}, + {"purge",&DoInstall}, + {"autoremove",&DoInstall}, + {"purge",&DoInstall}, {"dist-upgrade",&DoDistUpgrade}, {"dselect-upgrade",&DoDSelectUpgrade}, {"build-dep",&DoBuildDep}, @@ -2400,9 +2789,21 @@ int main(int argc,const char *argv[]) ShowHelp(CmdL); return 0; } - + + // simulate user-friendly if apt-get has no root privileges + if (getuid() != 0 && _config->FindB("APT::Get::Simulate") == true) + { + if (_config->FindB("APT::Get::Show-User-Simulation-Note",true) == true) + cout << _("NOTE: This is only a simulation!\n" + " apt-get needs root privileges for real execution.\n" + " Keep also in mind that locking is deactivated,\n" + " so don't depend on the relevance to the real current situation!" + ) << std::endl; + _config->Set("Debug::NoLocking",true); + } + // 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 @@ -2432,3 +2833,4 @@ int main(int argc,const char *argv[]) return 0; } + /*}}}*/