| 1 | // Include Files /*{{{*/ |
| 2 | #include <config.h> |
| 3 | |
| 4 | #include <apt-pkg/aptconfiguration.h> |
| 5 | #include <apt-pkg/error.h> |
| 6 | #include <apt-pkg/cmndline.h> |
| 7 | #include <apt-pkg/init.h> |
| 8 | #include <apt-pkg/depcache.h> |
| 9 | #include <apt-pkg/sourcelist.h> |
| 10 | #include <apt-pkg/algorithms.h> |
| 11 | #include <apt-pkg/acquire-item.h> |
| 12 | #include <apt-pkg/strutl.h> |
| 13 | #include <apt-pkg/fileutl.h> |
| 14 | #include <apt-pkg/clean.h> |
| 15 | #include <apt-pkg/srcrecords.h> |
| 16 | #include <apt-pkg/version.h> |
| 17 | #include <apt-pkg/cachefile.h> |
| 18 | #include <apt-pkg/cacheset.h> |
| 19 | #include <apt-pkg/sptr.h> |
| 20 | #include <apt-pkg/md5.h> |
| 21 | #include <apt-pkg/versionmatch.h> |
| 22 | #include <apt-pkg/progress.h> |
| 23 | #include <apt-pkg/pkgsystem.h> |
| 24 | #include <apt-pkg/pkgrecords.h> |
| 25 | #include <apt-pkg/indexfile.h> |
| 26 | #include <apt-pkg/install-progress.h> |
| 27 | #include <apt-pkg/init.h> |
| 28 | |
| 29 | #include <set> |
| 30 | #include <locale.h> |
| 31 | #include <langinfo.h> |
| 32 | #include <fstream> |
| 33 | #include <termios.h> |
| 34 | #include <sys/ioctl.h> |
| 35 | #include <sys/stat.h> |
| 36 | #include <sys/statfs.h> |
| 37 | #include <sys/statvfs.h> |
| 38 | #include <signal.h> |
| 39 | #include <unistd.h> |
| 40 | #include <stdio.h> |
| 41 | #include <errno.h> |
| 42 | #include <regex.h> |
| 43 | #include <sys/wait.h> |
| 44 | #include <sstream> |
| 45 | |
| 46 | #include "private-install.h" |
| 47 | #include "private-download.h" |
| 48 | #include "private-cachefile.h" |
| 49 | #include "private-output.h" |
| 50 | #include "private-cacheset.h" |
| 51 | #include "acqprogress.h" |
| 52 | |
| 53 | #include <apti18n.h> |
| 54 | /*}}}*/ |
| 55 | |
| 56 | // InstallPackages - Actually download and install the packages /*{{{*/ |
| 57 | // --------------------------------------------------------------------- |
| 58 | /* This displays the informative messages describing what is going to |
| 59 | happen and then calls the download routines */ |
| 60 | bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask, bool Safety) |
| 61 | { |
| 62 | if (_config->FindB("APT::Get::Purge",false) == true) |
| 63 | { |
| 64 | pkgCache::PkgIterator I = Cache->PkgBegin(); |
| 65 | for (; I.end() == false; ++I) |
| 66 | { |
| 67 | if (I.Purge() == false && Cache[I].Mode == pkgDepCache::ModeDelete) |
| 68 | Cache->MarkDelete(I,true); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | bool Fail = false; |
| 73 | bool Essential = false; |
| 74 | |
| 75 | // Show all the various warning indicators |
| 76 | ShowDel(c1out,Cache); |
| 77 | ShowNew(c1out,Cache); |
| 78 | if (ShwKept == true) |
| 79 | ShowKept(c1out,Cache); |
| 80 | Fail |= !ShowHold(c1out,Cache); |
| 81 | if (_config->FindB("APT::Get::Show-Upgraded",true) == true) |
| 82 | ShowUpgraded(c1out,Cache); |
| 83 | Fail |= !ShowDowngraded(c1out,Cache); |
| 84 | if (_config->FindB("APT::Get::Download-Only",false) == false) |
| 85 | Essential = !ShowEssential(c1out,Cache); |
| 86 | Fail |= Essential; |
| 87 | Stats(c1out,Cache); |
| 88 | |
| 89 | // Sanity check |
| 90 | if (Cache->BrokenCount() != 0) |
| 91 | { |
| 92 | ShowBroken(c1out,Cache,false); |
| 93 | return _error->Error(_("Internal error, InstallPackages was called with broken packages!")); |
| 94 | } |
| 95 | |
| 96 | if (Cache->DelCount() == 0 && Cache->InstCount() == 0 && |
| 97 | Cache->BadCount() == 0) |
| 98 | return true; |
| 99 | |
| 100 | // No remove flag |
| 101 | if (Cache->DelCount() != 0 && _config->FindB("APT::Get::Remove",true) == false) |
| 102 | return _error->Error(_("Packages need to be removed but remove is disabled.")); |
| 103 | |
| 104 | // Run the simulator .. |
| 105 | if (_config->FindB("APT::Get::Simulate") == true) |
| 106 | { |
| 107 | pkgSimulate PM(Cache); |
| 108 | |
| 109 | #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) |
| 110 | APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); |
| 111 | pkgPackageManager::OrderResult Res = PM.DoInstall(progress); |
| 112 | delete progress; |
| 113 | #else |
| 114 | int status_fd = _config->FindI("APT::Status-Fd",-1); |
| 115 | pkgPackageManager::OrderResult Res = PM.DoInstall(status_fd); |
| 116 | #endif |
| 117 | |
| 118 | if (Res == pkgPackageManager::Failed) |
| 119 | return false; |
| 120 | if (Res != pkgPackageManager::Completed) |
| 121 | return _error->Error(_("Internal error, Ordering didn't finish")); |
| 122 | return true; |
| 123 | } |
| 124 | |
| 125 | // Create the text record parser |
| 126 | pkgRecords Recs(Cache); |
| 127 | if (_error->PendingError() == true) |
| 128 | return false; |
| 129 | |
| 130 | // Create the download object |
| 131 | pkgAcquire Fetcher; |
| 132 | AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); |
| 133 | if (_config->FindB("APT::Get::Print-URIs", false) == true) |
| 134 | { |
| 135 | // force a hashsum for compatibility reasons |
| 136 | _config->CndSet("Acquire::ForceHash", "md5sum"); |
| 137 | } |
| 138 | else if (Fetcher.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) |
| 139 | return false; |
| 140 | |
| 141 | // Read the source list |
| 142 | if (Cache.BuildSourceList() == false) |
| 143 | return false; |
| 144 | pkgSourceList *List = Cache.GetSourceList(); |
| 145 | |
| 146 | // Create the package manager and prepare to download |
| 147 | SPtr<pkgPackageManager> PM= _system->CreatePM(Cache); |
| 148 | if (PM->GetArchives(&Fetcher,List,&Recs) == false || |
| 149 | _error->PendingError() == true) |
| 150 | return false; |
| 151 | |
| 152 | // Display statistics |
| 153 | unsigned long long FetchBytes = Fetcher.FetchNeeded(); |
| 154 | unsigned long long FetchPBytes = Fetcher.PartialPresent(); |
| 155 | unsigned long long DebBytes = Fetcher.TotalNeeded(); |
| 156 | if (DebBytes != Cache->DebSize()) |
| 157 | { |
| 158 | c0out << DebBytes << ',' << Cache->DebSize() << std::endl; |
| 159 | c0out << _("How odd.. The sizes didn't match, email apt@packages.debian.org") << std::endl; |
| 160 | } |
| 161 | |
| 162 | // Number of bytes |
| 163 | if (DebBytes != FetchBytes) |
| 164 | //TRANSLATOR: The required space between number and unit is already included |
| 165 | // in the replacement strings, so %sB will be correctly translate in e.g. 1,5 MB |
| 166 | ioprintf(c1out,_("Need to get %sB/%sB of archives.\n"), |
| 167 | SizeToStr(FetchBytes).c_str(),SizeToStr(DebBytes).c_str()); |
| 168 | else if (DebBytes != 0) |
| 169 | //TRANSLATOR: The required space between number and unit is already included |
| 170 | // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB |
| 171 | ioprintf(c1out,_("Need to get %sB of archives.\n"), |
| 172 | SizeToStr(DebBytes).c_str()); |
| 173 | |
| 174 | // Size delta |
| 175 | if (Cache->UsrSize() >= 0) |
| 176 | //TRANSLATOR: The required space between number and unit is already included |
| 177 | // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB |
| 178 | ioprintf(c1out,_("After this operation, %sB of additional disk space will be used.\n"), |
| 179 | SizeToStr(Cache->UsrSize()).c_str()); |
| 180 | else |
| 181 | //TRANSLATOR: The required space between number and unit is already included |
| 182 | // in the replacement string, so %sB will be correctly translate in e.g. 1,5 MB |
| 183 | ioprintf(c1out,_("After this operation, %sB disk space will be freed.\n"), |
| 184 | SizeToStr(-1*Cache->UsrSize()).c_str()); |
| 185 | |
| 186 | if (_error->PendingError() == true) |
| 187 | return false; |
| 188 | |
| 189 | /* Check for enough free space, but only if we are actually going to |
| 190 | download */ |
| 191 | if (_config->FindB("APT::Get::Print-URIs") == false && |
| 192 | _config->FindB("APT::Get::Download",true) == true) |
| 193 | { |
| 194 | struct statvfs Buf; |
| 195 | std::string OutputDir = _config->FindDir("Dir::Cache::Archives"); |
| 196 | if (statvfs(OutputDir.c_str(),&Buf) != 0) { |
| 197 | if (errno == EOVERFLOW) |
| 198 | return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), |
| 199 | OutputDir.c_str()); |
| 200 | else |
| 201 | return _error->Errno("statvfs",_("Couldn't determine free space in %s"), |
| 202 | OutputDir.c_str()); |
| 203 | } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) |
| 204 | { |
| 205 | struct statfs Stat; |
| 206 | if (statfs(OutputDir.c_str(),&Stat) != 0 |
| 207 | #if HAVE_STRUCT_STATFS_F_TYPE |
| 208 | || unsigned(Stat.f_type) != RAMFS_MAGIC |
| 209 | #endif |
| 210 | ) |
| 211 | return _error->Error(_("You don't have enough free space in %s."), |
| 212 | OutputDir.c_str()); |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | // Fail safe check |
| 217 | if (_config->FindI("quiet",0) >= 2 || |
| 218 | _config->FindB("APT::Get::Assume-Yes",false) == true) |
| 219 | { |
| 220 | if (Fail == true && _config->FindB("APT::Get::Force-Yes",false) == false) |
| 221 | return _error->Error(_("There are problems and -y was used without --force-yes")); |
| 222 | } |
| 223 | |
| 224 | if (Essential == true && Safety == true) |
| 225 | { |
| 226 | if (_config->FindB("APT::Get::Trivial-Only",false) == true) |
| 227 | return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); |
| 228 | |
| 229 | // TRANSLATOR: This string needs to be typed by the user as a confirmation, so be |
| 230 | // careful with hard to type or special characters (like non-breaking spaces) |
| 231 | const char *Prompt = _("Yes, do as I say!"); |
| 232 | ioprintf(c2out, |
| 233 | _("You are about to do something potentially harmful.\n" |
| 234 | "To continue type in the phrase '%s'\n" |
| 235 | " ?] "),Prompt); |
| 236 | c2out << std::flush; |
| 237 | if (AnalPrompt(Prompt) == false) |
| 238 | { |
| 239 | c2out << _("Abort.") << std::endl; |
| 240 | exit(1); |
| 241 | } |
| 242 | } |
| 243 | else |
| 244 | { |
| 245 | // Prompt to continue |
| 246 | if (Ask == true || Fail == true) |
| 247 | { |
| 248 | if (_config->FindB("APT::Get::Trivial-Only",false) == true) |
| 249 | return _error->Error(_("Trivial Only specified but this is not a trivial operation.")); |
| 250 | |
| 251 | if (_config->FindI("quiet",0) < 2 && |
| 252 | _config->FindB("APT::Get::Assume-Yes",false) == false) |
| 253 | { |
| 254 | c2out << _("Do you want to continue?") << std::flush; |
| 255 | if (YnPrompt() == false) |
| 256 | { |
| 257 | c2out << _("Abort.") << std::endl; |
| 258 | exit(1); |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | |
| 264 | // Just print out the uris an exit if the --print-uris flag was used |
| 265 | if (_config->FindB("APT::Get::Print-URIs") == true) |
| 266 | { |
| 267 | pkgAcquire::UriIterator I = Fetcher.UriBegin(); |
| 268 | for (; I != Fetcher.UriEnd(); ++I) |
| 269 | std::cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << |
| 270 | I->Owner->FileSize << ' ' << I->Owner->HashSum() << std::endl; |
| 271 | return true; |
| 272 | } |
| 273 | |
| 274 | if (!CheckAuth(Fetcher, true)) |
| 275 | return false; |
| 276 | |
| 277 | /* Unlock the dpkg lock if we are not going to be doing an install |
| 278 | after. */ |
| 279 | if (_config->FindB("APT::Get::Download-Only",false) == true) |
| 280 | _system->UnLock(); |
| 281 | |
| 282 | // Run it |
| 283 | while (1) |
| 284 | { |
| 285 | bool Transient = false; |
| 286 | if (_config->FindB("APT::Get::Download",true) == false) |
| 287 | { |
| 288 | for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I < Fetcher.ItemsEnd();) |
| 289 | { |
| 290 | if ((*I)->Local == true) |
| 291 | { |
| 292 | ++I; |
| 293 | continue; |
| 294 | } |
| 295 | |
| 296 | // Close the item and check if it was found in cache |
| 297 | (*I)->Finished(); |
| 298 | if ((*I)->Complete == false) |
| 299 | Transient = true; |
| 300 | |
| 301 | // Clear it out of the fetch list |
| 302 | delete *I; |
| 303 | I = Fetcher.ItemsBegin(); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | bool Failed = false; |
| 308 | if (AcquireRun(Fetcher, 0, &Failed, &Transient) == false) |
| 309 | return false; |
| 310 | |
| 311 | /* If we are in no download mode and missing files and there were |
| 312 | 'failures' then the user must specify -m. Furthermore, there |
| 313 | is no such thing as a transient error in no-download mode! */ |
| 314 | if (Transient == true && |
| 315 | _config->FindB("APT::Get::Download",true) == false) |
| 316 | { |
| 317 | Transient = false; |
| 318 | Failed = true; |
| 319 | } |
| 320 | |
| 321 | if (_config->FindB("APT::Get::Download-Only",false) == true) |
| 322 | { |
| 323 | if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) |
| 324 | return _error->Error(_("Some files failed to download")); |
| 325 | c1out << _("Download complete and in download only mode") << std::endl; |
| 326 | return true; |
| 327 | } |
| 328 | |
| 329 | if (Failed == true && _config->FindB("APT::Get::Fix-Missing",false) == false) |
| 330 | { |
| 331 | return _error->Error(_("Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?")); |
| 332 | } |
| 333 | |
| 334 | if (Transient == true && Failed == true) |
| 335 | return _error->Error(_("--fix-missing and media swapping is not currently supported")); |
| 336 | |
| 337 | // Try to deal with missing package files |
| 338 | if (Failed == true && PM->FixMissing() == false) |
| 339 | { |
| 340 | c2out << _("Unable to correct missing packages.") << std::endl; |
| 341 | return _error->Error(_("Aborting install.")); |
| 342 | } |
| 343 | |
| 344 | _system->UnLock(); |
| 345 | |
| 346 | #if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) |
| 347 | APT::Progress::PackageManager *progress = APT::Progress::PackageManagerProgressFactory(); |
| 348 | pkgPackageManager::OrderResult Res = PM->DoInstall(progress); |
| 349 | delete progress; |
| 350 | #else |
| 351 | int status_fd = _config->FindI("APT::Status-Fd", -1); |
| 352 | pkgPackageManager::OrderResult Res = PM->DoInstall(status_fd); |
| 353 | #endif |
| 354 | |
| 355 | if (Res == pkgPackageManager::Failed || _error->PendingError() == true) |
| 356 | return false; |
| 357 | if (Res == pkgPackageManager::Completed) |
| 358 | break; |
| 359 | |
| 360 | // Reload the fetcher object and loop again for media swapping |
| 361 | Fetcher.Shutdown(); |
| 362 | if (PM->GetArchives(&Fetcher,List,&Recs) == false) |
| 363 | return false; |
| 364 | |
| 365 | _system->Lock(); |
| 366 | } |
| 367 | |
| 368 | std::set<std::string> const disappearedPkgs = PM->GetDisappearedPackages(); |
| 369 | if (disappearedPkgs.empty() == true) |
| 370 | return true; |
| 371 | |
| 372 | std::string disappear; |
| 373 | for (std::set<std::string>::const_iterator d = disappearedPkgs.begin(); |
| 374 | d != disappearedPkgs.end(); ++d) |
| 375 | disappear.append(*d).append(" "); |
| 376 | |
| 377 | ShowList(c1out, P_("The following package disappeared from your system as\n" |
| 378 | "all files have been overwritten by other packages:", |
| 379 | "The following packages disappeared from your system as\n" |
| 380 | "all files have been overwritten by other packages:", disappearedPkgs.size()), disappear, ""); |
| 381 | c0out << _("Note: This is done automatically and on purpose by dpkg.") << std::endl; |
| 382 | |
| 383 | return true; |
| 384 | } |
| 385 | /*}}}*/ |
| 386 | // DoAutomaticRemove - Remove all automatic unused packages /*{{{*/ |
| 387 | // --------------------------------------------------------------------- |
| 388 | /* Remove unused automatic packages */ |
| 389 | bool DoAutomaticRemove(CacheFile &Cache) |
| 390 | { |
| 391 | bool Debug = _config->FindI("Debug::pkgAutoRemove",false); |
| 392 | bool doAutoRemove = _config->FindB("APT::Get::AutomaticRemove", false); |
| 393 | bool hideAutoRemove = _config->FindB("APT::Get::HideAutoRemove"); |
| 394 | |
| 395 | pkgDepCache::ActionGroup group(*Cache); |
| 396 | if(Debug) |
| 397 | std::cout << "DoAutomaticRemove()" << std::endl; |
| 398 | |
| 399 | if (doAutoRemove == true && |
| 400 | _config->FindB("APT::Get::Remove",true) == false) |
| 401 | { |
| 402 | c1out << _("We are not supposed to delete stuff, can't start " |
| 403 | "AutoRemover") << std::endl; |
| 404 | return false; |
| 405 | } |
| 406 | |
| 407 | bool purgePkgs = _config->FindB("APT::Get::Purge", false); |
| 408 | bool smallList = (hideAutoRemove == false && |
| 409 | strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); |
| 410 | |
| 411 | unsigned long autoRemoveCount = 0; |
| 412 | APT::PackageSet tooMuch; |
| 413 | APT::PackageList autoRemoveList; |
| 414 | // look over the cache to see what can be removed |
| 415 | for (unsigned J = 0; J < Cache->Head().PackageCount; ++J) |
| 416 | { |
| 417 | pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); |
| 418 | if (Cache[Pkg].Garbage) |
| 419 | { |
| 420 | if(Pkg.CurrentVer() != 0 || Cache[Pkg].Install()) |
| 421 | if(Debug) |
| 422 | std::cout << "We could delete %s" << Pkg.FullName(true).c_str() << std::endl; |
| 423 | |
| 424 | if (doAutoRemove) |
| 425 | { |
| 426 | if(Pkg.CurrentVer() != 0 && |
| 427 | Pkg->CurrentState != pkgCache::State::ConfigFiles) |
| 428 | Cache->MarkDelete(Pkg, purgePkgs, 0, false); |
| 429 | else |
| 430 | Cache->MarkKeep(Pkg, false, false); |
| 431 | } |
| 432 | else |
| 433 | { |
| 434 | if (hideAutoRemove == false && Cache[Pkg].Delete() == false) |
| 435 | autoRemoveList.insert(Pkg); |
| 436 | // if the package is a new install and already garbage we don't need to |
| 437 | // install it in the first place, so nuke it instead of show it |
| 438 | if (Cache[Pkg].Install() == true && Pkg.CurrentVer() == 0) |
| 439 | { |
| 440 | if (Pkg.CandVersion() != 0) |
| 441 | tooMuch.insert(Pkg); |
| 442 | Cache->MarkDelete(Pkg, false, 0, false); |
| 443 | } |
| 444 | // only show stuff in the list that is not yet marked for removal |
| 445 | else if(hideAutoRemove == false && Cache[Pkg].Delete() == false) |
| 446 | ++autoRemoveCount; |
| 447 | } |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // we could have removed a new dependency of a garbage package, |
| 452 | // so check if a reverse depends is broken and if so install it again. |
| 453 | if (tooMuch.empty() == false && (Cache->BrokenCount() != 0 || Cache->PolicyBrokenCount() != 0)) |
| 454 | { |
| 455 | bool Changed; |
| 456 | do { |
| 457 | Changed = false; |
| 458 | for (APT::PackageSet::const_iterator Pkg = tooMuch.begin(); |
| 459 | Pkg != tooMuch.end(); ++Pkg) |
| 460 | { |
| 461 | APT::PackageSet too; |
| 462 | too.insert(*Pkg); |
| 463 | for (pkgCache::PrvIterator Prv = Cache[Pkg].CandidateVerIter(Cache).ProvidesList(); |
| 464 | Prv.end() == false; ++Prv) |
| 465 | too.insert(Prv.ParentPkg()); |
| 466 | for (APT::PackageSet::const_iterator P = too.begin(); P != too.end(); ++P) |
| 467 | { |
| 468 | for (pkgCache::DepIterator R = P.RevDependsList(); |
| 469 | R.end() == false; ++R) |
| 470 | { |
| 471 | if (R.IsNegative() == true || |
| 472 | Cache->IsImportantDep(R) == false) |
| 473 | continue; |
| 474 | pkgCache::PkgIterator N = R.ParentPkg(); |
| 475 | if (N.end() == true || (N->CurrentVer == 0 && (*Cache)[N].Install() == false)) |
| 476 | continue; |
| 477 | if (Debug == true) |
| 478 | std::clog << "Save " << Pkg << " as another installed garbage package depends on it" << std::endl; |
| 479 | Cache->MarkInstall(Pkg, false, 0, false); |
| 480 | if (hideAutoRemove == false) |
| 481 | ++autoRemoveCount; |
| 482 | tooMuch.erase(Pkg); |
| 483 | Changed = true; |
| 484 | break; |
| 485 | } |
| 486 | if (Changed == true) |
| 487 | break; |
| 488 | } |
| 489 | if (Changed == true) |
| 490 | break; |
| 491 | } |
| 492 | } while (Changed == true); |
| 493 | } |
| 494 | |
| 495 | std::string autoremovelist, autoremoveversions; |
| 496 | if (smallList == false && autoRemoveCount != 0) |
| 497 | { |
| 498 | for (APT::PackageList::const_iterator Pkg = autoRemoveList.begin(); Pkg != autoRemoveList.end(); ++Pkg) |
| 499 | { |
| 500 | if (Cache[Pkg].Garbage == false) |
| 501 | continue; |
| 502 | autoremovelist += Pkg.FullName(true) + " "; |
| 503 | autoremoveversions += std::string(Cache[Pkg].CandVersion) + "\n"; |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | // Now see if we had destroyed anything (if we had done anything) |
| 508 | if (Cache->BrokenCount() != 0) |
| 509 | { |
| 510 | c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n" |
| 511 | "shouldn't happen. Please file a bug report against apt.") << std::endl; |
| 512 | c1out << std::endl; |
| 513 | c1out << _("The following information may help to resolve the situation:") << std::endl; |
| 514 | c1out << std::endl; |
| 515 | ShowBroken(c1out,Cache,false); |
| 516 | |
| 517 | return _error->Error(_("Internal Error, AutoRemover broke stuff")); |
| 518 | } |
| 519 | |
| 520 | // if we don't remove them, we should show them! |
| 521 | if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) |
| 522 | { |
| 523 | if (smallList == false) |
| 524 | ShowList(c1out, P_("The following package was automatically installed and is no longer required:", |
| 525 | "The following packages were automatically installed and are no longer required:", |
| 526 | autoRemoveCount), autoremovelist, autoremoveversions); |
| 527 | else |
| 528 | ioprintf(c1out, P_("%lu package was automatically installed and is no longer required.\n", |
| 529 | "%lu packages were automatically installed and are no longer required.\n", autoRemoveCount), autoRemoveCount); |
| 530 | c1out << P_("Use 'apt-get autoremove' to remove it.", "Use 'apt-get autoremove' to remove them.", autoRemoveCount) << std::endl; |
| 531 | } |
| 532 | return true; |
| 533 | } |
| 534 | /*}}}*/ |
| 535 | // DoCacheManipulationFromCommandLine /*{{{*/ |
| 536 | static const unsigned short MOD_REMOVE = 1; |
| 537 | static const unsigned short MOD_INSTALL = 2; |
| 538 | |
| 539 | bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache) |
| 540 | { |
| 541 | std::map<unsigned short, APT::VersionSet> verset; |
| 542 | return DoCacheManipulationFromCommandLine(CmdL, Cache, verset); |
| 543 | } |
| 544 | bool DoCacheManipulationFromCommandLine(CommandLine &CmdL, CacheFile &Cache, |
| 545 | std::map<unsigned short, APT::VersionSet> &verset) |
| 546 | { |
| 547 | |
| 548 | // Enter the special broken fixing mode if the user specified arguments |
| 549 | bool BrokenFix = false; |
| 550 | if (Cache->BrokenCount() != 0) |
| 551 | BrokenFix = true; |
| 552 | |
| 553 | SPtr<pkgProblemResolver> Fix; |
| 554 | if (_config->FindB("APT::Get::CallResolver", true) == true) |
| 555 | Fix = new pkgProblemResolver(Cache); |
| 556 | |
| 557 | unsigned short fallback = MOD_INSTALL; |
| 558 | if (strcasecmp(CmdL.FileList[0],"remove") == 0) |
| 559 | fallback = MOD_REMOVE; |
| 560 | else if (strcasecmp(CmdL.FileList[0], "purge") == 0) |
| 561 | { |
| 562 | _config->Set("APT::Get::Purge", true); |
| 563 | fallback = MOD_REMOVE; |
| 564 | } |
| 565 | else if (strcasecmp(CmdL.FileList[0], "autoremove") == 0) |
| 566 | { |
| 567 | _config->Set("APT::Get::AutomaticRemove", "true"); |
| 568 | fallback = MOD_REMOVE; |
| 569 | } |
| 570 | |
| 571 | std::list<APT::VersionSet::Modifier> mods; |
| 572 | mods.push_back(APT::VersionSet::Modifier(MOD_INSTALL, "+", |
| 573 | APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::CANDIDATE)); |
| 574 | mods.push_back(APT::VersionSet::Modifier(MOD_REMOVE, "-", |
| 575 | APT::VersionSet::Modifier::POSTFIX, APT::VersionSet::NEWEST)); |
| 576 | CacheSetHelperAPTGet helper(c0out); |
| 577 | verset = APT::VersionSet::GroupedFromCommandLine(Cache, |
| 578 | CmdL.FileList + 1, mods, fallback, helper); |
| 579 | |
| 580 | if (_error->PendingError() == true) |
| 581 | { |
| 582 | helper.showVirtualPackageErrors(Cache); |
| 583 | return false; |
| 584 | } |
| 585 | |
| 586 | |
| 587 | TryToInstall InstallAction(Cache, Fix, BrokenFix); |
| 588 | TryToRemove RemoveAction(Cache, Fix); |
| 589 | |
| 590 | // new scope for the ActionGroup |
| 591 | { |
| 592 | pkgDepCache::ActionGroup group(Cache); |
| 593 | unsigned short const order[] = { MOD_REMOVE, MOD_INSTALL, 0 }; |
| 594 | |
| 595 | for (unsigned short i = 0; order[i] != 0; ++i) |
| 596 | { |
| 597 | if (order[i] == MOD_INSTALL) |
| 598 | InstallAction = std::for_each(verset[MOD_INSTALL].begin(), verset[MOD_INSTALL].end(), InstallAction); |
| 599 | else if (order[i] == MOD_REMOVE) |
| 600 | RemoveAction = std::for_each(verset[MOD_REMOVE].begin(), verset[MOD_REMOVE].end(), RemoveAction); |
| 601 | } |
| 602 | |
| 603 | if (Fix != NULL && _config->FindB("APT::Get::AutoSolving", true) == true) |
| 604 | { |
| 605 | for (unsigned short i = 0; order[i] != 0; ++i) |
| 606 | { |
| 607 | if (order[i] != MOD_INSTALL) |
| 608 | continue; |
| 609 | InstallAction.propergateReleaseCandiateSwitching(helper.selectedByRelease, c0out); |
| 610 | InstallAction.doAutoInstall(); |
| 611 | } |
| 612 | } |
| 613 | |
| 614 | if (_error->PendingError() == true) |
| 615 | { |
| 616 | return false; |
| 617 | } |
| 618 | |
| 619 | /* If we are in the Broken fixing mode we do not attempt to fix the |
| 620 | problems. This is if the user invoked install without -f and gave |
| 621 | packages */ |
| 622 | if (BrokenFix == true && Cache->BrokenCount() != 0) |
| 623 | { |
| 624 | c1out << _("You might want to run 'apt-get -f install' to correct these:") << std::endl; |
| 625 | ShowBroken(c1out,Cache,false); |
| 626 | return _error->Error(_("Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).")); |
| 627 | } |
| 628 | |
| 629 | if (Fix != NULL) |
| 630 | { |
| 631 | // Call the scored problem resolver |
| 632 | Fix->Resolve(true); |
| 633 | } |
| 634 | |
| 635 | // Now we check the state of the packages, |
| 636 | if (Cache->BrokenCount() != 0) |
| 637 | { |
| 638 | c1out << |
| 639 | _("Some packages could not be installed. This may mean that you have\n" |
| 640 | "requested an impossible situation or if you are using the unstable\n" |
| 641 | "distribution that some required packages have not yet been created\n" |
| 642 | "or been moved out of Incoming.") << std::endl; |
| 643 | /* |
| 644 | if (Packages == 1) |
| 645 | { |
| 646 | c1out << std::endl; |
| 647 | c1out << |
| 648 | _("Since you only requested a single operation it is extremely likely that\n" |
| 649 | "the package is simply not installable and a bug report against\n" |
| 650 | "that package should be filed.") << std::endl; |
| 651 | } |
| 652 | */ |
| 653 | |
| 654 | c1out << _("The following information may help to resolve the situation:") << std::endl; |
| 655 | c1out << std::endl; |
| 656 | ShowBroken(c1out,Cache,false); |
| 657 | if (_error->PendingError() == true) |
| 658 | return false; |
| 659 | else |
| 660 | return _error->Error(_("Broken packages")); |
| 661 | } |
| 662 | } |
| 663 | if (!DoAutomaticRemove(Cache)) |
| 664 | return false; |
| 665 | |
| 666 | // if nothing changed in the cache, but only the automark information |
| 667 | // we write the StateFile here, otherwise it will be written in |
| 668 | // cache.commit() |
| 669 | if (InstallAction.AutoMarkChanged > 0 && |
| 670 | Cache->DelCount() == 0 && Cache->InstCount() == 0 && |
| 671 | Cache->BadCount() == 0 && |
| 672 | _config->FindB("APT::Get::Simulate",false) == false) |
| 673 | Cache->writeStateFile(NULL); |
| 674 | |
| 675 | return true; |
| 676 | } |
| 677 | /*}}}*/ |
| 678 | // DoInstall - Install packages from the command line /*{{{*/ |
| 679 | // --------------------------------------------------------------------- |
| 680 | /* Install named packages */ |
| 681 | bool DoInstall(CommandLine &CmdL) |
| 682 | { |
| 683 | CacheFile Cache; |
| 684 | if (Cache.OpenForInstall() == false || |
| 685 | Cache.CheckDeps(CmdL.FileSize() != 1) == false) |
| 686 | return false; |
| 687 | |
| 688 | std::map<unsigned short, APT::VersionSet> verset; |
| 689 | |
| 690 | if(!DoCacheManipulationFromCommandLine(CmdL, Cache, verset)) |
| 691 | return false; |
| 692 | |
| 693 | /* Print out a list of packages that are going to be installed extra |
| 694 | to what the user asked */ |
| 695 | if (Cache->InstCount() != verset[MOD_INSTALL].size()) |
| 696 | { |
| 697 | std::string List; |
| 698 | std::string VersionsList; |
| 699 | for (unsigned J = 0; J < Cache->Head().PackageCount; J++) |
| 700 | { |
| 701 | pkgCache::PkgIterator I(Cache,Cache.List[J]); |
| 702 | if ((*Cache)[I].Install() == false) |
| 703 | continue; |
| 704 | pkgCache::VerIterator Cand = Cache[I].CandidateVerIter(Cache); |
| 705 | |
| 706 | if (verset[MOD_INSTALL].find(Cand) != verset[MOD_INSTALL].end()) |
| 707 | continue; |
| 708 | |
| 709 | List += I.FullName(true) + " "; |
| 710 | VersionsList += std::string(Cache[I].CandVersion) + "\n"; |
| 711 | } |
| 712 | |
| 713 | ShowList(c1out,_("The following extra packages will be installed:"),List,VersionsList); |
| 714 | } |
| 715 | |
| 716 | /* Print out a list of suggested and recommended packages */ |
| 717 | { |
| 718 | std::string SuggestsList, RecommendsList; |
| 719 | std::string SuggestsVersions, RecommendsVersions; |
| 720 | for (unsigned J = 0; J < Cache->Head().PackageCount; J++) |
| 721 | { |
| 722 | pkgCache::PkgIterator Pkg(Cache,Cache.List[J]); |
| 723 | |
| 724 | /* Just look at the ones we want to install */ |
| 725 | if ((*Cache)[Pkg].Install() == false) |
| 726 | continue; |
| 727 | |
| 728 | // get the recommends/suggests for the candidate ver |
| 729 | pkgCache::VerIterator CV = (*Cache)[Pkg].CandidateVerIter(*Cache); |
| 730 | for (pkgCache::DepIterator D = CV.DependsList(); D.end() == false; ) |
| 731 | { |
| 732 | pkgCache::DepIterator Start; |
| 733 | pkgCache::DepIterator End; |
| 734 | D.GlobOr(Start,End); // advances D |
| 735 | |
| 736 | // FIXME: we really should display a or-group as a or-group to the user |
| 737 | // the problem is that ShowList is incapable of doing this |
| 738 | std::string RecommendsOrList,RecommendsOrVersions; |
| 739 | std::string SuggestsOrList,SuggestsOrVersions; |
| 740 | bool foundInstalledInOrGroup = false; |
| 741 | for(;;) |
| 742 | { |
| 743 | /* Skip if package is installed already, or is about to be */ |
| 744 | std::string target = Start.TargetPkg().FullName(true) + " "; |
| 745 | pkgCache::PkgIterator const TarPkg = Start.TargetPkg(); |
| 746 | if (TarPkg->SelectedState == pkgCache::State::Install || |
| 747 | TarPkg->SelectedState == pkgCache::State::Hold || |
| 748 | Cache[Start.TargetPkg()].Install()) |
| 749 | { |
| 750 | foundInstalledInOrGroup=true; |
| 751 | break; |
| 752 | } |
| 753 | |
| 754 | /* Skip if we already saw it */ |
| 755 | if (int(SuggestsList.find(target)) != -1 || int(RecommendsList.find(target)) != -1) |
| 756 | { |
| 757 | foundInstalledInOrGroup=true; |
| 758 | break; |
| 759 | } |
| 760 | |
| 761 | // this is a dep on a virtual pkg, check if any package that provides it |
| 762 | // should be installed |
| 763 | if(Start.TargetPkg().ProvidesList() != 0) |
| 764 | { |
| 765 | pkgCache::PrvIterator I = Start.TargetPkg().ProvidesList(); |
| 766 | for (; I.end() == false; ++I) |
| 767 | { |
| 768 | pkgCache::PkgIterator Pkg = I.OwnerPkg(); |
| 769 | if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer() && |
| 770 | Pkg.CurrentVer() != 0) |
| 771 | foundInstalledInOrGroup=true; |
| 772 | } |
| 773 | } |
| 774 | |
| 775 | if (Start->Type == pkgCache::Dep::Suggests) |
| 776 | { |
| 777 | SuggestsOrList += target; |
| 778 | SuggestsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; |
| 779 | } |
| 780 | |
| 781 | if (Start->Type == pkgCache::Dep::Recommends) |
| 782 | { |
| 783 | RecommendsOrList += target; |
| 784 | RecommendsOrVersions += std::string(Cache[Start.TargetPkg()].CandVersion) + "\n"; |
| 785 | } |
| 786 | |
| 787 | if (Start >= End) |
| 788 | break; |
| 789 | ++Start; |
| 790 | } |
| 791 | |
| 792 | if(foundInstalledInOrGroup == false) |
| 793 | { |
| 794 | RecommendsList += RecommendsOrList; |
| 795 | RecommendsVersions += RecommendsOrVersions; |
| 796 | SuggestsList += SuggestsOrList; |
| 797 | SuggestsVersions += SuggestsOrVersions; |
| 798 | } |
| 799 | |
| 800 | } |
| 801 | } |
| 802 | |
| 803 | ShowList(c1out,_("Suggested packages:"),SuggestsList,SuggestsVersions); |
| 804 | ShowList(c1out,_("Recommended packages:"),RecommendsList,RecommendsVersions); |
| 805 | |
| 806 | } |
| 807 | |
| 808 | // See if we need to prompt |
| 809 | // FIXME: check if really the packages in the set are going to be installed |
| 810 | if (Cache->InstCount() == verset[MOD_INSTALL].size() && Cache->DelCount() == 0) |
| 811 | return InstallPackages(Cache,false,false); |
| 812 | |
| 813 | return InstallPackages(Cache,false); |
| 814 | } |
| 815 | /*}}}*/ |