X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/d59725349555939d39af81cf7746069d6aa3536c..ffee1c2bed4accfe25b2ac9e9f0ab9a0ebae9b5b:/cmdline/apt-get.cc diff --git a/cmdline/apt-get.cc b/cmdline/apt-get.cc index 2ca0855b6..1cffd6730 100644 --- a/cmdline/apt-get.cc +++ b/cmdline/apt-get.cc @@ -40,7 +40,8 @@ #include #include #include - +#include + #include #include @@ -258,8 +259,8 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) } // Print out each package and the failed dependencies - out <<" " << I.Name() << ":"; - unsigned Indent = strlen(I.Name()) + 3; + out << " " << I.FullName(true) << " :"; + unsigned const Indent = I.FullName(true).size() + 3; bool First = true; pkgCache::VerIterator Ver; @@ -312,7 +313,7 @@ void ShowBroken(ostream &out,CacheFile &Cache,bool Now) out << ' ' << End.DepType() << ": "; FirstOr = false; - out << Start.TargetPkg().Name(); + out << Start.TargetPkg().FullName(true); // Show a quick summary of the version requirements if (Start.TargetVer() != 0) @@ -374,7 +375,9 @@ void ShowNew(ostream &out,CacheFile &Cache) { pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].NewInstall() == true) { - List += string(I.Name()) + " "; + if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) + continue; + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CandVersion) + "\n"; } } @@ -396,10 +399,12 @@ void ShowDel(ostream &out,CacheFile &Cache) pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].Delete() == true) { + if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) + continue; if ((Cache[I].iFlags & pkgDepCache::Purge) == pkgDepCache::Purge) - List += string(I.Name()) + "* "; + List += I.FullName(true) + "* "; else - List += string(I.Name()) + " "; + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CandVersion)+ "\n"; } @@ -424,7 +429,7 @@ void ShowKept(ostream &out,CacheFile &Cache) I->CurrentVer == 0 || Cache[I].Delete() == true) continue; - List += string(I.Name()) + " "; + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } ShowList(out,_("The following packages have been kept back:"),List,VersionsList); @@ -444,8 +449,10 @@ void ShowUpgraded(ostream &out,CacheFile &Cache) // Not interesting if (Cache[I].Upgrade() == false || Cache[I].NewInstall() == true) continue; - - List += string(I.Name()) + " "; + if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) + continue; + + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } ShowList(out,_("The following packages will be upgraded:"),List,VersionsList); @@ -465,8 +472,10 @@ bool ShowDowngraded(ostream &out,CacheFile &Cache) // Not interesting if (Cache[I].Downgrade() == false || Cache[I].NewInstall() == true) continue; - - List += string(I.Name()) + " "; + if (Cache[I].CandidateVerIter(Cache).Pseudo() == true) + continue; + + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } return ShowList(out,_("The following packages will be DOWNGRADED:"),List,VersionsList); @@ -484,7 +493,7 @@ bool ShowHold(ostream &out,CacheFile &Cache) pkgCache::PkgIterator I(Cache,Cache.List[J]); if (Cache[I].InstallVer != (pkgCache::Version *)I.CurrentVer() && I->SelectedState == pkgCache::State::Hold) { - List += string(I.Name()) + " "; + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CurVersion) + " => " + Cache[I].CandVersion + "\n"; } } @@ -518,7 +527,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) if (Added[I->ID] == false) { Added[I->ID] = true; - List += string(I.Name()) + " "; + List += I.FullName(true) + " "; //VersionsList += string(Cache[I].CurVersion) + "\n"; ??? } } @@ -542,7 +551,7 @@ bool ShowEssential(ostream &out,CacheFile &Cache) Added[P->ID] = true; char S[300]; - snprintf(S,sizeof(S),_("%s (due to %s) "),P.Name(),I.Name()); + snprintf(S,sizeof(S),_("%s (due to %s) "),P.FullName(true).c_str(),I.FullName(true).c_str()); List += S; //VersionsList += "\n"; ??? } @@ -566,6 +575,9 @@ void Stats(ostream &out,pkgDepCache &Dep) unsigned long ReInstall = 0; for (pkgCache::PkgIterator I = Dep.PkgBegin(); I.end() == false; I++) { + if (pkgCache::VerIterator(Dep, Dep[I].CandidateVer).Pseudo() == true) + continue; + if (Dep[I].NewInstall() == true) Install++; else @@ -681,7 +693,7 @@ bool CacheFile::CheckDeps(bool AllowBroken) } else { - c1out << _("You might want to run `apt-get -f install' to correct these.") << endl; + c1out << _("You might want to run 'apt-get -f install' to correct these.") << endl; ShowBroken(c1out,*this,true); return _error->Error(_("Unmet dependencies. Try using -f.")); @@ -800,20 +812,19 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, pkgRecords Recs(Cache); if (_error->PendingError() == true) return false; - - // Lock the archive directory - FileFd Lock; - if (_config->FindB("Debug::NoLocking",false) == false && - _config->FindB("APT::Get::Print-URIs") == false) - { - Lock.Fd(GetLock(_config->FindDir("Dir::Cache::Archives") + "lock")); - if (_error->PendingError() == true) - return _error->Error(_("Unable to lock the download directory")); - } - + // Create the download object + pkgAcquire Fetcher; AcqTextStatus Stat(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"); + if (Fetcher.Setup(&Stat, "") == false) + return false; + } + else if (Fetcher.Setup(&Stat, _config->FindDir("Dir::Cache::Archives")) == false) + return false; // Read the source list pkgSourceList List; @@ -862,14 +873,21 @@ 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"), - OutputDir.c_str()); - if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) + if (statvfs(OutputDir.c_str(),&Buf) != 0) { + if (errno == EOVERFLOW) + return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), + OutputDir.c_str()); + else + return _error->Errno("statvfs",_("Couldn't determine free space in %s"), + OutputDir.c_str()); + } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) { struct statfs Stat; - if (statfs(OutputDir.c_str(),&Stat) != 0 || - unsigned(Stat.f_type) != RAMFS_MAGIC) + if (statfs(OutputDir.c_str(),&Stat) != 0 +#if HAVE_STRUCT_STATFS_F_TYPE + || unsigned(Stat.f_type) != RAMFS_MAGIC +#endif + ) return _error->Error(_("You don't have enough free space in %s."), OutputDir.c_str()); } @@ -1027,7 +1045,7 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, if (Res == pkgPackageManager::Failed || _error->PendingError() == true) return false; if (Res == pkgPackageManager::Completed) - return true; + break; // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); @@ -1035,7 +1053,24 @@ bool InstallPackages(CacheFile &Cache,bool ShwKept,bool Ask = true, return false; _system->Lock(); - } + } + + std::set const disappearedPkgs = PM->GetDisappearedPackages(); + if (disappearedPkgs.empty() == true) + return true; + + string disappear; + for (std::set::const_iterator d = disappearedPkgs.begin(); + d != disappearedPkgs.end(); ++d) + disappear.append(*d).append(" "); + + ShowList(c1out, P_("The following package disappeared from your system as\n" + "all files have been overwritten by other packages:", + "The following packages disappeared from your system as\n" + "all files have been overwritten by other packages:", disappearedPkgs.size()), disappear, ""); + c0out << _("Note: This is done automatic and on purpose by dpkg.") << std::endl; + + return true; } /*}}}*/ // TryToInstall - Try to install a single package /*{{{*/ @@ -1046,27 +1081,62 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, pkgProblemResolver &Fix,bool Remove,bool BrokenFix, unsigned int &ExpectedInst,bool AllowFail = true) { - /* This is a pure virtual package and there is a single available - provides */ - if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0 && - Pkg.ProvidesList()->NextProvides == 0) + /* This is a pure virtual package and there is a single available + candidate providing it. */ + if (Cache[Pkg].CandidateVer == 0 && Pkg->ProvidesList != 0) { - pkgCache::PkgIterator Tmp = Pkg.ProvidesList().OwnerPkg(); - ioprintf(c1out,_("Note, selecting %s instead of %s\n"), - Tmp.Name(),Pkg.Name()); - Pkg = Tmp; + pkgCache::PkgIterator Prov; + bool found_one = false; + + for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; P++) + { + pkgCache::VerIterator const PVer = P.OwnerVer(); + pkgCache::PkgIterator const PPkg = PVer.ParentPkg(); + + /* Ignore versions that are not a candidate. */ + if (Cache[PPkg].CandidateVer != PVer) + continue; + + if (found_one == false) + { + Prov = PPkg; + found_one = true; + } + else if (PPkg != Prov) + { + found_one = false; // we found at least two + break; + } + } + + if (found_one == true) + { + ioprintf(c1out,_("Note, selecting %s instead of %s\n"), + Prov.FullName(true).c_str(),Pkg.FullName(true).c_str()); + Pkg = Prov; + } } - + // Handle the no-upgrade case if (_config->FindB("APT::Get::upgrade",true) == false && Pkg->CurrentVer != 0) { if (AllowFail == true) ioprintf(c1out,_("Skipping %s, it is already installed and upgrade is not set.\n"), + Pkg.FullName(true).c_str()); + return true; + } + + // Ignore request for install if package would be new + if (_config->FindB("APT::Get::Only-Upgrade", false) == true && + Pkg->CurrentVer == 0) + { + if (AllowFail == true) + ioprintf(c1out,_("Skipping %s, it is not installed and only upgrades are requested.\n"), Pkg.Name()); return true; } - + // Check if there is something at all to install pkgDepCache::StateCache &State = Cache[Pkg]; if (Remove == true && Pkg->CurrentVer == 0) @@ -1080,7 +1150,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, if (AllowFail == false) return false; - ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.Name()); + ioprintf(c1out,_("Package %s is not installed, so not removed\n"),Pkg.FullName(true).c_str()); return true; } @@ -1092,30 +1162,37 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, if (Pkg->ProvidesList != 0) { ioprintf(c1out,_("Package %s is a virtual package provided by:\n"), - Pkg.Name()); + Pkg.FullName(true).c_str()); pkgCache::PrvIterator I = Pkg.ProvidesList(); + unsigned short provider = 0; for (; I.end() == false; I++) { pkgCache::PkgIterator Pkg = I.OwnerPkg(); if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) { + c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr(); if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false) - c1out << " " << Pkg.Name() << " " << I.OwnerVer().VerStr() << - _(" [Installed]") << endl; - else - c1out << " " << Pkg.Name() << " " << I.OwnerVer().VerStr() << endl; - } + c1out << _(" [Installed]"); + c1out << endl; + ++provider; + } } - c1out << _("You should explicitly select one to install.") << endl; + // if we found no candidate which provide this package, show non-candidates + if (provider == 0) + for (I = Pkg.ProvidesList(); I.end() == false; I++) + c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr() + << _(" [Not candidate version]") << endl; + else + c1out << _("You should explicitly select one to install.") << endl; } else { ioprintf(c1out, _("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()); + "is only available from another source\n"),Pkg.FullName(true).c_str()); string List; string VersionsList; @@ -1129,13 +1206,13 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, if (Seen[Dep.ParentPkg()->ID] == true) continue; Seen[Dep.ParentPkg()->ID] = true; - List += string(Dep.ParentPkg().Name()) + " "; + List += Dep.ParentPkg().FullName(true) + " "; //VersionsList += string(Dep.ParentPkg().CurVersion) + "\n"; ??? } ShowList(c1out,_("However the following packages replace it:"),List,VersionsList); } - _error->Error(_("Package %s has no installation candidate"),Pkg.Name()); + _error->Error(_("Package %s has no installation candidate"),Pkg.FullName(true).c_str()); return false; } @@ -1156,7 +1233,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, { if (Pkg->CurrentVer == 0 || Pkg.CurrentVer().Downloadable() == false) ioprintf(c1out,_("Reinstallation of %s is not possible, it cannot be downloaded.\n"), - Pkg.Name()); + Pkg.FullName(true).c_str()); else Cache.SetReInstall(Pkg,true); } @@ -1164,7 +1241,7 @@ bool TryToInstall(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, { if (AllowFail == true) ioprintf(c1out,_("%s is already the newest version.\n"), - Pkg.Name()); + Pkg.FullName(true).c_str()); } } else @@ -1193,18 +1270,23 @@ bool TryToChangeVer(pkgCache::PkgIterator Pkg,pkgDepCache &Cache, { if (IsRel == true) return _error->Error(_("Release '%s' for '%s' was not found"), - VerTag,Pkg.Name()); + VerTag,Pkg.FullName(true).c_str()); return _error->Error(_("Version '%s' for '%s' was not found"), - VerTag,Pkg.Name()); + VerTag,Pkg.FullName(true).c_str()); } if (strcmp(VerTag,Ver.VerStr()) != 0) { ioprintf(c1out,_("Selected version %s (%s) for %s\n"), - Ver.VerStr(),Ver.RelStr().c_str(),Pkg.Name()); + Ver.VerStr(),Ver.RelStr().c_str(),Pkg.FullName(true).c_str()); } Cache.SetCandidateVersion(Ver); + + // Set the all package to the same candidate + if (Ver.Pseudo() == true) + Cache.SetCandidateVersion(Match.Find(Pkg.Group().FindPkg("all"))); + return true; } /*}}}*/ @@ -1215,125 +1297,168 @@ pkgSrcRecords::Parser *FindSrc(const char *Name,pkgRecords &Recs, pkgSrcRecords &SrcRecs,string &Src, pkgDepCache &Cache) { - // We want to pull the version off the package specification.. string VerTag; + string DefRel = _config->Find("APT::Default-Release"); 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); + // extract the version/release from the pkgname + const size_t found = TmpSrc.find_last_of("/="); + if (found != string::npos) { + if (TmpSrc[found] == '/') + DefRel = TmpSrc.substr(found+1); + else + VerTag = TmpSrc.substr(found+1); + TmpSrc = TmpSrc.substr(0,found); + } - 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) + /* 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. */ + bool MatchSrcOnly = _config->FindB("APT::Get::Only-Source"); + const pkgCache::PkgIterator Pkg = Cache.FindPkg(TmpSrc); + if (MatchSrcOnly == false && Pkg.end() == 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++) + if(VerTag.empty() == false || DefRel.empty() == false) { - for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; - VF++) + bool fuzzy = 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++) { - /* 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)) + // try first only exact matches, later fuzzy matches + if (Ver.end() == true) + { + if (fuzzy == true) + break; + fuzzy = true; + Ver = Pkg.VersionList(); + // exit right away from the Pkg.VersionList() loop if we + // don't have any versions + if (Ver.end() == true) + break; + } + // We match against a concrete version (or a part of this version) + if (VerTag.empty() == false && + (fuzzy == true || Cache.VS().CmpVersion(VerTag, Ver.VerStr()) != 0) && // exact match + (fuzzy == false || strncmp(VerTag.c_str(), Ver.VerStr(), VerTag.size()) != 0)) // fuzzy match + continue; + + for (pkgCache::VerFileIterator VF = Ver.FileList(); + VF.end() == false; VF++) { - VerTag = Ver.VerStr(); + /* 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; + + // or we match against a release + if(VerTag.empty() == false || + (VF.File().Archive() != 0 && VF.File().Archive() == DefRel) || + (VF.File().Codename() != 0 && VF.File().Codename() == DefRel)) + { + pkgRecords::Parser &Parse = Recs.Lookup(VF); + Src = Parse.SourcePkg(); + // no SourcePkg name, so it is the "binary" name + if (Src.empty() == true) + Src = TmpSrc; + // the Version we have is possibly fuzzy or includes binUploads, + // so we use the Version of the SourcePkg (empty if same as package) + VerTag = Parse.SourceVer(); + if (VerTag.empty() == true) + VerTag = Ver.VerStr(); + break; + } + } + if (Src.empty() == false) break; + } + if (Src.empty() == true) + { + // Sources files have no codename information + if (VerTag.empty() == true && DefRel.empty() == false) + { + _error->Error(_("Ignore unavailable target release '%s' of package '%s'"), DefRel.c_str(), TmpSrc.c_str()); + return 0; } } } - } - - /* 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. */ - if (_config->FindB("APT::Get::Only-Source") == false) - { - if (Pkg.end() == false) + if (Src.empty() == true) { + // if we don't have found a fitting package yet so we will + // choose a good candidate and proceed with that. + // Maybe we will find a source later on with the right VerTag pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg); - if (Ver.end() == false) + if (Ver.end() == false) { pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList()); Src = Parse.SourcePkg(); + if (VerTag.empty() == true) + VerTag = Parse.SourceVer(); } - } + } + } + + 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 (Src != TmpSrc) + { + ioprintf(c1out, _("Picking '%s' as source package instead of '%s'\n"), Src.c_str(), TmpSrc.c_str()); + } } // The best hit pkgSrcRecords::Parser *Last = 0; unsigned long Offset = 0; string Version; - bool IsMatch = false; - bool MatchSrcOnly = 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) - IsMatch = true; - /* Iterate over all of the hits, which includes the resulting binary packages in the search */ pkgSrcRecords::Parser *Parse; - SrcRecs.Restart(); - while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0) + while (true) { - string Ver = Parse->Version(); - - // 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) + SrcRecs.Restart(); + while ((Parse = SrcRecs.Find(Src.c_str(), MatchSrcOnly)) != 0) { - /* Don't want to fall through because we are doing exact version - matching. */ - if (Cache.VS().CmpVersion(VerTag,Ver) != 0) + const string Ver = Parse->Version(); + + // Ignore all versions which doesn't fit + if (VerTag.empty() == false && + Cache.VS().CmpVersion(VerTag, Ver) != 0) // exact match continue; - - Last = Parse; - Offset = Parse->Offset(); - break; + + // Newer version or an exact match? Save the hit + if (Last == 0 || Cache.VS().CmpVersion(Version,Ver) < 0) { + Last = Parse; + Offset = Parse->Offset(); + Version = Ver; + } + + // was the version check above an exact match? If so, we don't need to look further + if (VerTag.empty() == false && VerTag.size() == Ver.size()) + break; } - - // Newer version or an exact match - if (Last == 0 || Cache.VS().CmpVersion(Version,Ver) < 0 || - (Parse->Package() == Src && IsMatch == false)) - { - IsMatch = Parse->Package() == Src; - Last = Parse; - Offset = Parse->Offset(); - Version = Ver; - } + if (Last != 0 || VerTag.empty() == true) + break; + //if (VerTag.empty() == false && Last == 0) + _error->Error(_("Ignore unavailable version '%s' of package '%s'"), VerTag.c_str(), TmpSrc.c_str()); + return 0; } - + if (Last == 0 || Last->Jump(Offset) == false) return 0; - + return Last; } /*}}}*/ @@ -1350,23 +1475,19 @@ bool DoUpdate(CommandLine &CmdL) if (List.ReadMainList() == false) return false; - // Lock the list directory - FileFd Lock; - if (_config->FindB("Debug::NoLocking",false) == false) - { - Lock.Fd(GetLock(_config->FindDir("Dir::State::Lists") + "lock")); - if (_error->PendingError() == true) - return _error->Error(_("Unable to lock the list directory")); - } - // Create the progress AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); // Just print out the uris an exit if the --print-uris flag was used if (_config->FindB("APT::Get::Print-URIs") == true) { + // force a hashsum for compatibility reasons + _config->CndSet("Acquire::ForceHash", "md5sum"); + // get a fetcher - pkgAcquire Fetcher(&Stat); + pkgAcquire Fetcher; + if (Fetcher.Setup(&Stat) == false) + return false; // Populate it with the source selection and get all Indexes // (GetAll=true) @@ -1400,20 +1521,29 @@ 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); + pkgDepCache::ActionGroup group(*Cache); if(Debug) std::cout << "DoAutomaticRemove()" << std::endl; - if (_config->FindB("APT::Get::Remove",true) == false && - doAutoRemove == true) + // we don't want to autoremove and we don't want to see it, so why calculating? + if (doAutoRemove == false && hideAutoRemove == true) + return true; + + if (doAutoRemove == true && + _config->FindB("APT::Get::Remove",true) == false) { c1out << _("We are not supposed to delete stuff, can't start " "AutoRemover") << std::endl; - doAutoRemove = false; + return false; } + bool purgePkgs = _config->FindB("APT::Get::Purge", false); + bool smallList = (hideAutoRemove == false && + strcasecmp(_config->Find("APT::Get::HideAutoRemove","").c_str(),"small") == 0); + string autoremovelist, autoremoveversions; + unsigned long autoRemoveCount = 0; // look over the cache to see what can be removed for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); ! Pkg.end(); ++Pkg) { @@ -1421,31 +1551,46 @@ bool DoAutomaticRemove(CacheFile &Cache) { 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"; - } + std::cout << "We could delete %s" << Pkg.FullName(true).c_str() << std::endl; + if (doAutoRemove) { if(Pkg.CurrentVer() != 0 && Pkg->CurrentState != pkgCache::State::ConfigFiles) - Cache->MarkDelete(Pkg, _config->FindB("APT::Get::Purge", false)); + Cache->MarkDelete(Pkg, purgePkgs); else Cache->MarkKeep(Pkg, false, false); } + else + { + // only show stuff in the list that is not yet marked for removal + if(Cache[Pkg].Delete() == false) + { + ++autoRemoveCount; + // we don't need to fill the strings if we don't need them + if (smallList == false) + { + autoremovelist += Pkg.FullName(true) + " "; + autoremoveversions += string(Cache[Pkg].CandVersion) + "\n"; + } + } + } } } - if (!hideAutoRemove) - ShowList(c1out, _("The following packages were automatically installed and are no longer required:"), autoremovelist, autoremoveversions); - if (!doAutoRemove && !hideAutoRemove && autoremovelist.size() > 0) + // if we don't remove them, we should show them! + if (doAutoRemove == false && (autoremovelist.empty() == false || autoRemoveCount != 0)) + { + if (smallList == false) + ShowList(c1out, P_("The following package is automatically installed and is no longer required:", + "The following packages were automatically installed and are no longer required:", + autoRemoveCount), autoremovelist, autoremoveversions); + 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 << _("Use 'apt-get autoremove' to remove them.") << std::endl; - - // Now see if we destroyed anything - if (Cache->BrokenCount() != 0) + } + // Now see if we had destroyed anything (if we had done anything) + else if (Cache->BrokenCount() != 0) { c1out << _("Hmm, seems like the AutoRemover destroyed something which really\n" "shouldn't happen. Please file a bug report against apt.") << endl; @@ -1636,48 +1781,24 @@ bool DoInstall(CommandLine &CmdL) 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) + APT::PackageSet pkgset = APT::PackageSet::FromRegEx(Cache, S, c1out); + if (pkgset.empty() == true) 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++) + for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) { - if (regexec(&Pattern,Pkg.Name(),0,0,0) != 0) - continue; - - ioprintf(c1out,_("Note, selecting %s for regex '%s'\n"), - Pkg.Name(),S); - if (VerTag != 0) if (TryToChangeVer(Pkg,Cache,VerTag,VerIsRel) == false) return false; - + Hit |= TryToInstall(Pkg,Cache,Fix,Remove,BrokenFix, ExpectedInst,false); } - regfree(&Pattern); - + if (Hit == false) return _error->Error(_("Couldn't find package %s"),S); } @@ -1695,10 +1816,12 @@ bool DoInstall(CommandLine &CmdL) if(!Remove && Cache[Pkg].Install() == false && (Cache[Pkg].Flags & pkgCache::Flag::Auto) && - _config->FindB("APT::Get::ReInstall",false) == false) + _config->FindB("APT::Get::ReInstall",false) == false && + _config->FindB("APT::Get::Only-Upgrade",false) == false && + _config->FindB("APT::Get::Download-Only",false) == false) { ioprintf(c1out,_("%s set to manually installed.\n"), - Pkg.Name()); + Pkg.FullName(true).c_str()); Cache->MarkAuto(Pkg,false); AutoMarkChanged++; } @@ -1710,7 +1833,7 @@ bool DoInstall(CommandLine &CmdL) packages */ if (BrokenFix == true && Cache->BrokenCount() != 0) { - c1out << _("You might want to run `apt-get -f install' to correct these:") << endl; + 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).")); @@ -1767,7 +1890,7 @@ bool DoInstall(CommandLine &CmdL) break; if (*J == 0) { - List += string(I.Name()) + " "; + List += I.FullName(true) + " "; VersionsList += string(Cache[I].CandVersion) + "\n"; } } @@ -1803,10 +1926,11 @@ bool DoInstall(CommandLine &CmdL) 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()) + string target = Start.TargetPkg().FullName(true) + " "; + pkgCache::PkgIterator const TarPkg = Start.TargetPkg(); + if (TarPkg->SelectedState == pkgCache::State::Install || + TarPkg->SelectedState == pkgCache::State::Hold || + Cache[Start.TargetPkg()].Install()) { foundInstalledInOrGroup=true; break; @@ -1881,6 +2005,46 @@ bool DoInstall(CommandLine &CmdL) return InstallPackages(Cache,false); } + +/* mark packages as automatically/manually installed. */ +bool DoMarkAuto(CommandLine &CmdL) +{ + bool Action = true; + int AutoMarkChanged = 0; + OpTextProgress progress; + CacheFile Cache; + if (Cache.Open() == false) + return false; + + if (strcasecmp(CmdL.FileList[0],"markauto") == 0) + Action = true; + else if (strcasecmp(CmdL.FileList[0],"unmarkauto") == 0) + Action = false; + + for (const char **I = CmdL.FileList + 1; *I != 0; I++) + { + const char *S = *I; + // Locate the package + pkgCache::PkgIterator Pkg = Cache->FindPkg(S); + if (Pkg.end() == true) { + return _error->Error(_("Couldn't find package %s"),S); + } + else + { + if (!Action) + ioprintf(c1out,_("%s set to manually installed.\n"), Pkg.Name()); + else + ioprintf(c1out,_("%s set to automatically installed.\n"), + Pkg.Name()); + + Cache->MarkAuto(Pkg,Action); + AutoMarkChanged++; + } + } + if (AutoMarkChanged && ! _config->FindB("APT::Get::Simulate",false)) + return Cache->writeStateFile(NULL); + return false; +} /*}}}*/ // DoDistUpgrade - Automatic smart upgrader /*{{{*/ // --------------------------------------------------------------------- @@ -2089,13 +2253,23 @@ bool DoSource(CommandLine &CmdL) // Create the download object AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); - pkgAcquire Fetcher(&Stat); + pkgAcquire Fetcher; + if (Fetcher.Setup(&Stat) == false) + return false; DscFile *Dsc = new DscFile[CmdL.FileSize()]; // insert all downloaded uris into this set to avoid downloading them // twice set queued; + + // Diff only mode only fetches .diff files + bool const diffOnly = _config->FindB("APT::Get::Diff-Only", false); + // Tar only mode only fetches .tar files + bool const tarOnly = _config->FindB("APT::Get::Tar-Only", false); + // Dsc only mode only fetches .dsc files + bool const dscOnly = _config->FindB("APT::Get::Dsc-Only", false); + // Load the requestd sources into the fetcher unsigned J = 0; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) @@ -2122,21 +2296,17 @@ bool DoSource(CommandLine &CmdL) Dsc[J].Version = Last->Version(); Dsc[J].Dsc = flNotDir(I->Path); } - - // Diff only mode only fetches .diff files - if (_config->FindB("APT::Get::Diff-Only",false) == true && - I->Type != "diff") - continue; - - // Tar only mode only fetches .tar files - 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; + // Handle the only options so that multiple can be used at once + if (diffOnly == true || tarOnly == true || dscOnly == true) + { + if ((diffOnly == true && I->Type == "diff") || + (tarOnly == true && I->Type == "tar") || + (dscOnly == true && I->Type == "dsc")) + ; // Fine, we want this file downloaded + else + continue; + } // don't download the same uri twice (should this be moved to // the fetcher interface itself?) @@ -2173,14 +2343,21 @@ bool DoSource(CommandLine &CmdL) // Check for enough free space struct statvfs Buf; string OutputDir = "."; - if (statvfs(OutputDir.c_str(),&Buf) != 0) - return _error->Errno("statvfs",_("Couldn't determine free space in %s"), - OutputDir.c_str()); - if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) + if (statvfs(OutputDir.c_str(),&Buf) != 0) { + if (errno == EOVERFLOW) + return _error->WarningE("statvfs",_("Couldn't determine free space in %s"), + OutputDir.c_str()); + else + return _error->Errno("statvfs",_("Couldn't determine free space in %s"), + OutputDir.c_str()); + } else if (unsigned(Buf.f_bfree) < (FetchBytes - FetchPBytes)/Buf.f_bsize) { struct statfs Stat; - if (statfs(OutputDir.c_str(),&Stat) != 0 || - unsigned(Stat.f_type) != RAMFS_MAGIC) + if (statfs(OutputDir.c_str(),&Stat) != 0 +#if HAVE_STRUCT_STATFS_F_TYPE + || unsigned(Stat.f_type) != RAMFS_MAGIC +#endif + ) return _error->Error(_("You don't have enough free space in %s"), OutputDir.c_str()); } @@ -2197,6 +2374,7 @@ bool DoSource(CommandLine &CmdL) { for (unsigned I = 0; I != J; I++) ioprintf(cout,_("Fetch source %s\n"),Dsc[I].Package.c_str()); + delete[] Dsc; return true; } @@ -2207,6 +2385,7 @@ bool DoSource(CommandLine &CmdL) for (; I != Fetcher.UriEnd(); I++) cout << '\'' << I->URI << "' " << flNotDir(I->Owner->DestFile) << ' ' << I->Owner->FileSize << ' ' << I->Owner->HashSum() << endl; + delete[] Dsc; return true; } @@ -2232,6 +2411,7 @@ bool DoSource(CommandLine &CmdL) if (_config->FindB("APT::Get::Download-only",false) == true) { c1out << _("Download complete and in download only mode") << endl; + delete[] Dsc; return true; } @@ -2240,6 +2420,7 @@ bool DoSource(CommandLine &CmdL) if (Process == 0) { + bool const fixBroken = _config->FindB("APT::Get::Fix-Broken", false); for (unsigned I = 0; I != J; I++) { string Dir = Dsc[I].Package + '-' + Cache->VS().UpstreamVersion(Dsc[I].Version.c_str()); @@ -2252,7 +2433,7 @@ bool DoSource(CommandLine &CmdL) // See if the package is already unpacked struct stat Stat; - if (stat(Dir.c_str(),&Stat) == 0 && + if (fixBroken == false && stat(Dir.c_str(),&Stat) == 0 && S_ISDIR(Stat.st_mode) != 0) { ioprintf(c0out ,_("Skipping unpack of already unpacked source in %s\n"), @@ -2293,7 +2474,8 @@ bool DoSource(CommandLine &CmdL) _exit(0); } - + delete[] Dsc; + // Wait for the subprocess int Status = 0; while (waitpid(Process,&Status,0) != Process) @@ -2335,7 +2517,9 @@ bool DoBuildDep(CommandLine &CmdL) // Create the download object AcqTextStatus Stat(ScreenWidth,_config->FindI("quiet",0)); - pkgAcquire Fetcher(&Stat); + pkgAcquire Fetcher; + if (Fetcher.Setup(&Stat) == false) + return false; unsigned J = 0; for (const char **I = CmdL.FileList + 1; *I != 0; I++, J++) @@ -2347,7 +2531,7 @@ bool DoBuildDep(CommandLine &CmdL) // Process the build-dependencies vector BuildDeps; - if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",false)) == false) + if (Last->BuildDepends(BuildDeps, _config->FindB("APT::Get::Arch-Only",true)) == false) return _error->Error(_("Unable to get build-dependency information for %s"),Src.c_str()); // Also ensure that build-essential packages are present @@ -2446,7 +2630,7 @@ bool DoBuildDep(CommandLine &CmdL) for (; Prv.end() != true; Prv++) { if (_config->FindB("Debug::BuildDeps",false) == true) - cout << " Checking provider " << Prv.OwnerPkg().Name() << endl; + cout << " Checking provider " << Prv.OwnerPkg().FullName() << endl; if ((*Cache)[Prv.OwnerPkg()].InstVerIter(*Cache).end() == false) break; @@ -2487,7 +2671,7 @@ bool DoBuildDep(CommandLine &CmdL) if (Prv.end() == false) { if (_config->FindB("Debug::BuildDeps",false) == true) - cout << " Is provided by installed package " << Prv.OwnerPkg().Name() << endl; + cout << " Is provided by installed package " << Prv.OwnerPkg().FullName() << endl; skipAlternatives = hasAlternatives; continue; } @@ -2512,7 +2696,7 @@ bool DoBuildDep(CommandLine &CmdL) 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()); + Pkg.FullName(true).c_str()); } } @@ -2550,7 +2734,10 @@ bool DoBuildDep(CommandLine &CmdL) // Now we check the state of the packages, if (Cache->BrokenCount() != 0) - return _error->Error(_("Build-dependencies for %s could not be satisfied."),*I); + { + ShowBroken(cout, Cache, false); + return _error->Error(_("Build-dependencies for %s could not be satisfied."),*I); + } } if (InstallPackages(Cache, false, true) == false) @@ -2558,7 +2745,6 @@ bool DoBuildDep(CommandLine &CmdL) return true; } /*}}}*/ - // DoMoo - Never Ask, Never Tell /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -2649,6 +2835,8 @@ bool ShowHelp(CommandLine &CmdL) " clean - Erase downloaded archive files\n" " autoclean - Erase old downloaded archive files\n" " check - Verify that there are no broken dependencies\n" + " markauto - Mark the given packages as automatically installed\n" + " unmarkauto - Mark the given packages as manually installed\n" "\n" "Options:\n" " -h This help text.\n" @@ -2727,9 +2915,11 @@ int main(int argc,const char *argv[]) /*{{{*/ {0,"fix-missing","APT::Get::Fix-Missing",0}, {0,"ignore-hold","APT::Ignore-Hold",0}, {0,"upgrade","APT::Get::upgrade",0}, + {0,"only-upgrade","APT::Get::Only-Upgrade",0}, {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,"debian-only","APT::Get::Diff-Only",0}, {0,"tar-only","APT::Get::Tar-Only",0}, {0,"dsc-only","APT::Get::Dsc-Only",0}, {0,"purge","APT::Get::Purge",0}, @@ -2753,6 +2943,8 @@ int main(int argc,const char *argv[]) /*{{{*/ {"purge",&DoInstall}, {"autoremove",&DoInstall}, {"purge",&DoInstall}, + {"markauto",&DoMarkAuto}, + {"unmarkauto",&DoMarkAuto}, {"dist-upgrade",&DoDistUpgrade}, {"dselect-upgrade",&DoDSelectUpgrade}, {"build-dep",&DoBuildDep},