X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/51c4e07f4cba0615ff269b5a8d04dfd3d1313b00..92296fe4b0862a04ea3d965b4cd2d4a420e3be9f:/apt-private/private-install.cc diff --git a/apt-private/private-install.cc b/apt-private/private-install.cc index d2b4bed51..aa28780da 100644 --- a/apt-private/private-install.cc +++ b/apt-private/private-install.cc @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -42,37 +42,123 @@ /*}}}*/ class pkgSourceList; +bool CheckNothingBroken(CacheFile &Cache) /*{{{*/ +{ + // Now we check the state of the packages, + if (Cache->BrokenCount() == 0) + return true; + + 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.") << std::endl; + /* + if (Packages == 1) + { + c1out << std::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.") << std::endl; + } + */ + + c1out << _("The following information may help to resolve the situation:") << std::endl; + c1out << std::endl; + ShowBroken(c1out,Cache,false); + if (_error->PendingError() == true) + return false; + else + return _error->Error(_("Broken packages")); +} + /*}}}*/ // 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, bool Safety) +static void RemoveDownloadNeedingItemsFromFetcher(pkgAcquire &Fetcher, bool &Transient) { - if (_config->FindB("APT::Get::Purge",false) == true) + for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();) { - pkgCache::PkgIterator I = Cache->PkgBegin(); - for (; I.end() == false; ++I) + if ((*I)->Local == true) { - if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete) - Cache->MarkDelete(I,true); + ++I; + continue; } + + // Close the item and check if it was found in cache + (*I)->Finished(); + if ((*I)->Complete == false) + Transient = true; + + // Clear it out of the fetch list + delete *I; + I = Fetcher.ItemsBegin(); } - - bool Fail = false; - bool Essential = false; - +} +bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) +{ + if (_config->FindB("APT::Get::Purge", false) == true) + for (pkgCache::PkgIterator I = Cache->PkgBegin(); I.end() == false; ++I) + if (Cache[I].Delete() == true && Cache[I].Purge() == false) + Cache->MarkDelete(I,true); + + // Create the download object + aptAcquireWithTextStatus Fetcher; + if (_config->FindB("APT::Get::Print-URIs", false) == true) + { + // force a hashsum for compatibility reasons + _config->CndSet("Acquire::ForceHash", "md5sum"); + } + else if (_config->FindB("APT::Get::Simulate") == true) + ; + else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false) + return false; + + // Read the source list + if (Cache.BuildSourceList() == false) + return false; + pkgSourceList * const List = Cache.GetSourceList(); + + // Create the text record parser + pkgRecords Recs(Cache); + if (_error->PendingError() == true) + return false; + + // Create the package manager and prepare to download + std::unique_ptr PM(_system->CreatePM(Cache)); + if (PM->GetArchives(&Fetcher,List,&Recs) == false || + _error->PendingError() == true) + return false; + + if (_config->FindB("APT::Get::Fix-Missing",false) == true && + _config->FindB("APT::Get::Download",true) == false) + { + bool Missing = false; + RemoveDownloadNeedingItemsFromFetcher(Fetcher, Missing); + if (Missing) + PM->FixMissing(); + Fetcher.Shutdown(); + if (PM->GetArchives(&Fetcher,List,&Recs) == false || + _error->PendingError() == true) + return false; + } + // Show all the various warning indicators ShowDel(c1out,Cache); ShowNew(c1out,Cache); if (ShwKept == true) ShowKept(c1out,Cache); - Fail |= !ShowHold(c1out,Cache); + bool const Hold = !ShowHold(c1out,Cache); if (_config->FindB("APT::Get::Show-Upgraded",true) == true) ShowUpgraded(c1out,Cache); - Fail |= !ShowDowngraded(c1out,Cache); + bool const Downgrade = !ShowDowngraded(c1out,Cache); + + bool Essential = false; if (_config->FindB("APT::Get::Download-Only",false) == false) Essential = !ShowEssential(c1out,Cache); - Fail |= Essential; + Stats(c1out,Cache); // Sanity check @@ -89,7 +175,26 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) // 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.")); - + + // Fail safe check + bool const Fail = (Essential || Downgrade || Hold); + if (_config->FindI("quiet",0) >= 2 || + _config->FindB("APT::Get::Assume-Yes",false) == true) + { + if (_config->FindB("APT::Get::Force-Yes",false) == true) { + _error->Warning(_("--force-yes is deprecated, use one of the options starting with --allow instead.")); + } + + if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) { + if (Essential == true && _config->FindB("APT::Get::allow-remove-essential", false) == false) + return _error->Error(_("Essential packages were removed and -y was used without --allow-remove-essential.")); + if (Downgrade == true && _config->FindB("APT::Get::allow-downgrades", false) == false) + return _error->Error(_("Packages were downgraded and -y was used without --allow-downgrades.")); + if (Hold == true && _config->FindB("APT::Get::allow-change-held-packages", false) == false) + return _error->Error(_("Held packages were changed and -y was used without --allow-change-held-packages.")); + } + } + // Run the simulator .. if (_config->FindB("APT::Get::Simulate") == true) { @@ -105,38 +210,11 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) return _error->Error(_("Internal error, Ordering didn't finish")); return true; } - - // Create the text record parser - pkgRecords Recs(Cache); - if (_error->PendingError() == true) - return false; - - // Create the download object - AcqTextStatus Stat(std::cout, ScreenWidth,_config->FindI("quiet",0)); - pkgAcquire Fetcher(&Stat); - if (_config->FindB("APT::Get::Print-URIs", false) == true) - { - // force a hashsum for compatibility reasons - _config->CndSet("Acquire::ForceHash", "md5sum"); - } - else if (Fetcher.GetLock(_config->FindDir("Dir::Cache::Archives")) == false) - return false; - - // Read the source list - if (Cache.BuildSourceList() == false) - return false; - pkgSourceList *List = Cache.GetSourceList(); - - // Create the package manager and prepare to download - std::unique_ptr PM(_system->CreatePM(Cache)); - if (PM->GetArchives(&Fetcher,List,&Recs) == false || - _error->PendingError() == true) - return false; // Display statistics - unsigned long long FetchBytes = Fetcher.FetchNeeded(); - unsigned long long FetchPBytes = Fetcher.PartialPresent(); - unsigned long long DebBytes = Fetcher.TotalNeeded(); + auto const FetchBytes = Fetcher.FetchNeeded(); + auto const FetchPBytes = Fetcher.PartialPresent(); + auto const DebBytes = Fetcher.TotalNeeded(); if (DebBytes != Cache->DebSize()) { c0out << DebBytes << ',' << Cache->DebSize() << std::endl; @@ -167,21 +245,23 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"), SizeToStr(-1*Cache->UsrSize()).c_str()); - if (_error->PendingError() == true) + if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false) return false; - if (CheckFreeSpaceBeforeDownload(_config->FindDir("Dir::Cache::Archives"), (FetchBytes - FetchPBytes)) == false) + if (_error->PendingError() == true) return false; - // Fail safe check - if (_config->FindI("quiet",0) >= 2 || - _config->FindB("APT::Get::Assume-Yes",false) == true) + // Just print out the uris an exit if the --print-uris flag was used + if (_config->FindB("APT::Get::Print-URIs") == true) { - if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) - return _error->Error(_("There are problems and -y was used without --force-yes")); - } + pkgAcquire::UriIterator I = Fetcher.UriBegin(); + for (; I != Fetcher.UriEnd(); ++I) + std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << + std::to_string(I->Owner->FileSize) << ' ' << I->Owner->HashSum() << std::endl; + return true; + } - if (Essential == true && Safety == true) + if (Essential == true && Safety == true && _config->FindB("APT::Get::allow-remove-essential", false) == false) { if (_config->FindB("APT::Get::Trivial-Only",false) == true) return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); @@ -189,46 +269,35 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) // TRANSLATOR: This string needs to be typed by the user as a confirmation, so be // careful with hard to type or special characters (like non-breaking spaces) const char *Prompt = _("Yes, do as I say!"); - ioprintf(c2out, + std::string question; + strprintf(question, _("You are about to do something potentially harmful.\n" "To continue type in the phrase '%s'\n" " ?] "),Prompt); - c2out << std::flush; - if (AnalPrompt(Prompt) == false) + if (AnalPrompt(question, Prompt) == false) { c2out << _("Abort.") << std::endl; exit(1); - } + } } else - { + { // Prompt to continue if (Ask == true || Fail == true) - { + { if (_config->FindB("APT::Get::Trivial-Only",false) == true) return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); - + if (_config->FindI("quiet",0) < 2 && _config->FindB("APT::Get::Assume-Yes",false) == false) { - c2out << _("Do you want to continue?") << std::flush; - if (YnPrompt() == false) + if (YnPrompt(_("Do you want to continue?")) == false) { c2out << _("Abort.") << std::endl; exit(1); - } - } - } - } - - // Just print out the uris an exit if the --print-uris flag was used - if (_config->FindB("APT::Get::Print-URIs") == true) - { - pkgAcquire::UriIterator I = Fetcher.UriBegin(); - for (; I != Fetcher.UriEnd(); ++I) - std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << - I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; - return true; + } + } + } } if (!CheckAuth(Fetcher, true)) @@ -238,46 +307,15 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) after. */ if (_config->FindB("APT::Get::Download-Only",false) == true) _system->UnLock(); - + // Run it + bool Failed = false; while (1) { bool Transient = false; - if (_config->FindB("APT::Get::Download",true) == false) - { - for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();) - { - if ((*I)->Local == true) - { - ++I; - continue; - } - - // Close the item and check if it was found in cache - (*I)->Finished(); - if ((*I)->Complete == false) - Transient = true; - - // Clear it out of the fetch list - delete *I; - I = Fetcher.ItemsBegin(); - } - } - - bool Failed = false; if (AcquireRun(Fetcher, 0, &Failed, &Transient) == false) return false; - /* If we are in no download mode and missing files and there were - 'failures' then the user must specify -m. Furthermore, there - is no such thing as a transient error in no-download mode! */ - if (Transient == true && - _config->FindB("APT::Get::Download",true) == false) - { - Transient = false; - Failed = true; - } - if (_config->FindB("APT::Get::Download-Only",false) == true) { if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) @@ -285,15 +323,13 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) c1out << _("Download complete and in download only mode") << std::endl; return true; } - + if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) - { return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?")); - } - + if (Transient == true && Failed == true) return _error->Error(_("--fix-missing and media swapping is not currently supported")); - + // Try to deal with missing package files if (Failed == true && PM->FixMissing() == false) { @@ -301,23 +337,26 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) return _error->Error(_("Aborting install.")); } + auto const progress = APT::Progress::PackageManagerProgressFactory(); _system->UnLock(); - - APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); - pkgPackageManager::OrderResult Res = PM->DoInstall(progress); + pkgPackageManager::OrderResult const Res = PM->DoInstall(progress); delete progress; if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; if (Res == pkgPackageManager::Completed) break; - + + _system->Lock(); + // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); if (PM->GetArchives(&Fetcher,List,&Recs) == false) return false; - - _system->Lock(); + + Failed = false; + if (_config->FindB("APT::Get::Download",true) == false) + RemoveDownloadNeedingItemsFromFetcher(Fetcher, Failed); } std::set const disappearedPkgs = PM->GetDisappearedPackages(); @@ -333,13 +372,25 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl; } + // cleanup downloaded debs + if (_config->FindB("APT::Keep-Downloaded-Packages", true) == false) + { + std::string const archivedir = _config->FindDir("Dir::Cache::archives"); + for (auto I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); ++I) + { + if (flNotFile((*I)->DestFile) != archivedir || (*I)->Local) + continue; + RemoveFile("Keep-Downloaded-Packages=false", (*I)->DestFile); + } + } + return true; } /*}}}*/ // DoAutomaticRemove - Remove all automatic unused packages /*{{{*/ // --------------------------------------------------------------------- /* Remove unused automatic packages */ -static bool DoAutomaticRemove(CacheFile &Cache) +bool DoAutomaticRemove(CacheFile &Cache) { bool Debug = _config->FindI("Debug::pkgAutoRemove",false); bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); @@ -387,8 +438,7 @@ static bool DoAutomaticRemove(CacheFile &Cache) // install it in the first place, so nuke it instead of show it if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0) { - if (Pkg.CandVersion() != 0) - tooMuch.insert(Pkg); + tooMuch.insert(Pkg); Cache->MarkDelete(Pkg, false, 0, false); } // only show stuff in the list that is not yet marked for removal @@ -425,7 +475,7 @@ static bool DoAutomaticRemove(CacheFile &Cache) if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false)) continue; if (Debug == true) - std::clog << "Save " << Pkg << " as another installed garbage package depends on it" << std::endl; + std::clog << "Save " << APT::PrettyPkg(Cache, Pkg) << " as another installed garbage package depends on it" << std::endl; Cache->MarkInstall(Pkg, false, 0, false); if (hideAutoRemove == false) ++autoRemoveCount; @@ -470,7 +520,16 @@ static bool DoAutomaticRemove(CacheFile &Cache) else ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n", "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount); - c1out << P_("Use 'apt-get autoremove' to remove it.", "Use 'apt-get autoremove' to remove them.", autoRemoveCount) << std::endl; + std::string autocmd = "apt autoremove"; + if (getenv("SUDO_USER") != nullptr) + { + auto const envsudocmd = getenv("SUDO_COMMAND"); + auto const envshell = getenv("SHELL"); + if (envsudocmd == nullptr || envshell == nullptr || strcmp(envsudocmd, envshell) != 0) + autocmd = "sudo " + autocmd; + } + ioprintf(c1out, P_("Use '%s' to remove it.", "Use '%s' to remove them.", autoRemoveCount), autocmd.c_str()); + c1out << std::endl; } return true; } @@ -480,11 +539,16 @@ static const unsigned short MOD_REMOVE = 1; static const unsigned short MOD_INSTALL = 2; bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, int UpgradeMode) +{ + std::vector VolatileCmdL; + return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, UpgradeMode); +} +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, int UpgradeMode) { std::map verset; - return DoCacheManipulationFromCommandLine(CmdL, Cache, verset, UpgradeMode); + return DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, UpgradeMode); } -bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, +bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, std::vector &VolatileCmdL, CacheFile &Cache, std::map &verset, int UpgradeMode) { // Enter the special broken fixing mode if the user specified arguments @@ -504,7 +568,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, _config->Set("APT::Get::Purge", true); fallback = MOD_REMOVE; } - else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) + else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0 || + strcasecmp(CmdL.FileList[0], "auto-remove") == 0) { _config->Set("APT::Get::AutomaticRemove", "true"); fallback = MOD_REMOVE; @@ -519,6 +584,20 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, verset = APT::VersionSet::GroupedFromCommandLine(Cache, CmdL.FileList + 1, mods, fallback, helper); + for (auto const &I: VolatileCmdL) + { + pkgCache::PkgIterator const P = Cache->FindPkg(I); + if (P.end()) + continue; + + // Set any version providing the .deb as the candidate. + for (auto Prv = P.ProvidesList(); Prv.end() == false; Prv++) + Cache.GetDepCache()->SetCandidateVersion(Prv.OwnerVer()); + + // via cacheset to have our usual virtual handling + APT::VersionContainerInterface::FromPackage(&(verset[MOD_INSTALL]), Cache, P, APT::CacheSetHelper::CANDIDATE, helper); + } + if (_error->PendingError() == true) { helper.showVirtualPackageErrors(Cache); @@ -544,13 +623,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) { - for (unsigned short i = 0; order[i] != 0; ++i) - { - if (order[i] != MOD_INSTALL) - continue; - InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); - InstallAction.doAutoInstall(); - } + InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); + InstallAction.doAutoInstall(); } if (_error->PendingError() == true) @@ -584,33 +658,8 @@ bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, return false; } - // 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.") << std::endl; - /* - if (Packages == 1) - { - c1out << std::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.") << std::endl; - } - */ - - c1out << _("The following information may help to resolve the situation:") << std::endl; - c1out << std::endl; - ShowBroken(c1out,Cache,false); - if (_error->PendingError() == true) - return false; - else - return _error->Error(_("Broken packages")); - } + if (CheckNothingBroken(Cache) == false) + return false; } if (!DoAutomaticRemove(Cache)) return false; @@ -634,7 +683,7 @@ struct PkgIsExtraInstalled { pkgCacheFile * const Cache; APT::VersionSet const * const verset; PkgIsExtraInstalled(pkgCacheFile * const Cache, APT::VersionSet const * const Container) : Cache(Cache), verset(Container) {} - bool operator() (pkgCache::PkgIterator const Pkg) + bool operator() (pkgCache::PkgIterator const &Pkg) { if ((*Cache)[Pkg].Install() == false) return false; @@ -645,28 +694,23 @@ struct PkgIsExtraInstalled { bool DoInstall(CommandLine &CmdL) { CacheFile Cache; - // first check for local pkgs and add them to the cache - for (const char **I = CmdL.FileList; *I != 0; I++) - { - if(FileExists(*I) && flExtension(*I) == "deb") - Cache.GetSourceList()->AddVolatileFile(new debDebPkgFileIndex(*I)); - } + std::vector VolatileCmdL; + Cache.GetSourceList()->AddVolatileFiles(CmdL, &VolatileCmdL); // then open the cache if (Cache.OpenForInstall() == false || Cache.CheckDeps(CmdL.FileSize() != 1) == false) return false; - - std::map verset; - if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset, 0)) + std::map verset; + if(!DoCacheManipulationFromCommandLine(CmdL, VolatileCmdL, Cache, verset, 0)) return false; /* Print out a list of packages that are going to be installed extra to what the user asked */ SortedPackageUniverse Universe(Cache); if (Cache->InstCount() != verset[MOD_INSTALL].size()) - ShowList(c1out, _("The following extra packages will be installed:"), Universe, + ShowList(c1out, _("The following additional packages will be installed:"), Universe, PkgIsExtraInstalled(&Cache, &verset[MOD_INSTALL]), &PrettyFullName, CandidateVersion(&Cache)); @@ -772,7 +816,17 @@ bool DoInstall(CommandLine &CmdL) // TryToInstall - Mark a package for installation /*{{{*/ void TryToInstall::operator() (pkgCache::VerIterator const &Ver) { + if (unlikely(Ver.end())) + { + _error->Fatal("The given version to TryToInstall is invalid!"); + return; + } pkgCache::PkgIterator Pkg = Ver.ParentPkg(); + if (unlikely(Pkg.end())) + { + _error->Fatal("The given version to TryToInstall has an invalid parent package!"); + return; + } Cache->GetDepCache()->SetCandidateVersion(Ver); pkgDepCache::StateCache &State = (*Cache)[Pkg]; @@ -800,8 +854,9 @@ void TryToInstall::operator() (pkgCache::VerIterator const &Ver) { else Cache->GetDepCache()->SetReInstall(Pkg, true); } else - ioprintf(c1out,_("%s is already the newest version.\n"), - Pkg.FullName(true).c_str()); + // TRANSLATORS: First string is package name, second is version + ioprintf(c1out,_("%s is already the newest version (%s).\n"), + Pkg.FullName(true).c_str(), Pkg.CurrentVer().VerStr()); } // Install it with autoinstalling enabled (if we not respect the minial