summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/algorithms.cc183
-rw-r--r--apt-pkg/algorithms.h14
-rw-r--r--apt-pkg/deb/deblistparser.cc8
-rw-r--r--apt-pkg/depcache.cc56
-rw-r--r--apt-pkg/depcache.h6
5 files changed, 252 insertions, 15 deletions
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc
index cd09a6944..a8e198054 100644
--- a/apt-pkg/algorithms.cc
+++ b/apt-pkg/algorithms.cc
@@ -16,20 +16,32 @@
#include <config.h>
#include <apt-pkg/algorithms.h>
+#include <apt-pkg/cachefilter.h>
#include <apt-pkg/configuration.h>
#include <apt-pkg/depcache.h>
#include <apt-pkg/dpkgpm.h>
#include <apt-pkg/edsp.h>
#include <apt-pkg/error.h>
+#include <apt-pkg/macros.h>
#include <apt-pkg/packagemanager.h>
#include <apt-pkg/pkgcache.h>
+#include <apt-pkg/string_view.h>
+#include <apt-pkg/strutl.h>
+#include <apt-pkg/version.h>
+
#include <apt-pkg/prettyprinters.h>
#include <cstdlib>
#include <iostream>
+#include <map>
+#include <regex>
+#include <set>
+#include <sstream>
#include <string>
#include <utility>
+#include <vector>
#include <string.h>
+#include <sys/utsname.h>
#include <apti18n.h>
/*}}}*/
@@ -1442,3 +1454,174 @@ void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List)
std::sort(List,List+Count,PrioComp(Cache));
}
/*}}}*/
+
+namespace APT
+{
+
+namespace KernelAutoRemoveHelper
+{
+
+// \brief Returns the uname from a kernel package name, or "" for non-kernel packages.
+std::string getUname(std::string const &packageName)
+{
+
+ static const constexpr char *const prefixes[] = {
+ "linux-image-",
+ "kfreebsd-image-",
+ "gnumach-image-",
+ };
+
+ for (auto prefix : prefixes)
+ {
+ if (likely(not APT::String::Startswith(packageName, prefix)))
+ continue;
+ if (unlikely(APT::String::Endswith(packageName, "-dbgsym")))
+ continue;
+ if (unlikely(APT::String::Endswith(packageName, "-dbg")))
+ continue;
+
+ auto aUname = packageName.substr(strlen(prefix));
+
+ // aUname must start with [0-9]+\.
+ if (aUname.length() < 2)
+ continue;
+ if (strchr("0123456789", aUname[0]) == nullptr)
+ continue;
+ auto dot = aUname.find_first_not_of("0123456789");
+ if (dot == aUname.npos || aUname[dot] != '.')
+ continue;
+
+ return aUname;
+ }
+
+ return "";
+}
+std::string GetProtectedKernelsRegex(pkgCache *cache, bool ReturnRemove)
+{
+ if (_config->FindB("APT::Protect-Kernels", true) == false)
+ return "";
+
+ struct CompareKernel
+ {
+ pkgCache *cache;
+ bool operator()(const std::string &a, const std::string &b) const
+ {
+ return cache->VS->CmpVersion(a, b) < 0;
+ }
+ };
+ bool Debug = _config->FindB("Debug::pkgAutoRemove", false);
+ // kernel version -> list of unames
+ std::map<std::string, std::vector<std::string>, CompareKernel> version2unames(CompareKernel{cache});
+ // needs to be initialized to 0s, might not be set up.
+ utsname uts{};
+ std::string bootedVersion;
+ std::string lastInstalledVersion;
+
+ std::string lastInstalledUname = _config->Find("APT::LastInstalledKernel");
+
+ // Get currently booted version, but only when not on reproducible build.
+ if (getenv("SOURCE_DATE_EPOCH") == 0)
+ {
+ if (uname(&uts) != 0)
+ abort();
+ }
+
+ auto VirtualKernelPkg = cache->FindPkg("$kernel", "any");
+ if (VirtualKernelPkg.end())
+ return "";
+
+ for (pkgCache::PrvIterator Prv = VirtualKernelPkg.ProvidesList(); Prv.end() == false; ++Prv)
+ {
+ auto Pkg = Prv.OwnerPkg();
+ if (likely(Pkg->CurrentVer == 0))
+ continue;
+
+ auto pkgUname = APT::KernelAutoRemoveHelper::getUname(Pkg.Name());
+ auto pkgVersion = Pkg.CurrentVer().VerStr();
+
+ if (pkgUname.empty())
+ continue;
+
+ if (Debug)
+ std::clog << "Found kernel " << pkgUname << "(" << pkgVersion << ")" << std::endl;
+
+ version2unames[pkgVersion].push_back(pkgUname);
+
+ if (pkgUname == uts.release)
+ bootedVersion = pkgVersion;
+ if (pkgUname == lastInstalledUname)
+ lastInstalledVersion = pkgVersion;
+ }
+
+ if (version2unames.size() == 0)
+ return "";
+
+ auto latest = version2unames.rbegin();
+ auto previous = latest;
+ ++previous;
+
+ std::set<std::string> keep;
+
+ if (not bootedVersion.empty())
+ {
+ if (Debug || false)
+ std::clog << "Keeping booted kernel " << bootedVersion << std::endl;
+ keep.insert(bootedVersion);
+ }
+ if (not lastInstalledVersion.empty())
+ {
+ if (Debug || false)
+ std::clog << "Keeping installed kernel " << lastInstalledVersion << std::endl;
+ keep.insert(lastInstalledVersion);
+ }
+ if (latest != version2unames.rend())
+ {
+ if (Debug || false)
+ std::clog << "Keeping latest kernel " << latest->first << std::endl;
+ keep.insert(latest->first);
+ }
+ if (keep.size() < 3 && previous != version2unames.rend())
+ {
+ if (Debug)
+ std::clog << "Keeping previous kernel " << previous->first << std::endl;
+ keep.insert(previous->first);
+ }
+
+ std::regex special("([\\.\\+])");
+ std::ostringstream ss;
+ for (auto &pattern : _config->FindVector("APT::VersionedKernelPackages"))
+ {
+ // Legacy compatibility: Always protected the booted uname and last installed uname
+ if (not lastInstalledUname.empty())
+ ss << "|^" << pattern << "-" << std::regex_replace(lastInstalledUname, special, "\\$1") << "$";
+ if (*uts.release)
+ ss << "|^" << pattern << "-" << std::regex_replace(uts.release, special, "\\$1") << "$";
+ for (auto const &kernel : version2unames)
+ {
+ if (ReturnRemove ? keep.find(kernel.first) == keep.end() : keep.find(kernel.first) != keep.end())
+ {
+ for (auto const &uname : kernel.second)
+ ss << "|^" << pattern << "-" << std::regex_replace(uname, special, "\\$1") << "$";
+ }
+ }
+ }
+
+ auto re = ss.str().substr(1);
+ if (Debug)
+ std::clog << "Kernel protection regex: " << re << "\n";
+
+ return re;
+}
+
+std::unique_ptr<APT::CacheFilter::Matcher> GetProtectedKernelsFilter(pkgCache *cache, bool returnRemove)
+{
+ auto regex = GetProtectedKernelsRegex(cache, returnRemove);
+
+ if (regex.empty())
+ return std::make_unique<APT::CacheFilter::FalseMatcher>();
+
+ return std::make_unique<APT::CacheFilter::PackageNameMatchesRegEx>(regex);
+}
+
+} // namespace KernelAutoRemoveHelper
+} // namespace APT
diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h
index fc578a4ca..12a77d4b8 100644
--- a/apt-pkg/algorithms.h
+++ b/apt-pkg/algorithms.h
@@ -29,11 +29,13 @@
#ifndef PKGLIB_ALGORITHMS_H
#define PKGLIB_ALGORITHMS_H
+#include <apt-pkg/cachefilter.h>
#include <apt-pkg/depcache.h>
#include <apt-pkg/packagemanager.h>
#include <apt-pkg/pkgcache.h>
#include <iostream>
+#include <memory>
#include <string>
#include <apt-pkg/macros.h>
@@ -146,5 +148,17 @@ APT_PUBLIC bool pkgFixBroken(pkgDepCache &Cache);
APT_PUBLIC void pkgPrioSortList(pkgCache &Cache,pkgCache::Version **List);
+namespace APT
+{
+namespace KernelAutoRemoveHelper
+{
+// Public for linking to apt-private, but no A{P,B}I guarantee.
+APT_PUBLIC std::unique_ptr<APT::CacheFilter::Matcher> GetProtectedKernelsFilter(pkgCache *cache, bool returnRemove = false);
+std::string GetProtectedKernelsRegex(pkgCache *cache, bool ReturnRemove = false);
+std::string getUname(std::string const &packageName);
+
+} // namespace KernelAutoRemoveHelper
+
+} // namespace APT
#endif
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 240946529..95f6f6fc8 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -11,6 +11,7 @@
// Include Files /*{{{*/
#include <config.h>
+#include <apt-pkg/algorithms.h>
#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefilter.h>
#include <apt-pkg/configuration.h>
@@ -246,7 +247,12 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver)
if (ParseProvides(Ver) == false)
return false;
-
+ if (not APT::KernelAutoRemoveHelper::getUname(Ver.ParentPkg().Name()).empty())
+ {
+ if (not NewProvides(Ver, "$kernel", "any", Ver.VerStr(), pkgCache::Flag::MultiArchImplicit))
+ return false;
+ }
+
return true;
}
/*}}}*/
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index c7ef7a400..f2b3dbcdc 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -9,6 +9,7 @@
// Include Files /*{{{*/
#include <config.h>
+#include <apt-pkg/algorithms.h>
#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/cachefile.h>
#include <apt-pkg/cacheset.h>
@@ -43,6 +44,23 @@
using std::string;
+// helper for kernel autoremoval /*{{{*/
+
+/** \brief Returns \b true for packages matching a regular
+ * expression in APT::NeverAutoRemove.
+ */
+class APT_PUBLIC DefaultRootSetFunc2 : public pkgDepCache::DefaultRootSetFunc
+{
+ std::unique_ptr<APT::CacheFilter::Matcher> Kernels;
+
+ public:
+ DefaultRootSetFunc2(pkgCache *cache) : Kernels(APT::KernelAutoRemoveHelper::GetProtectedKernelsFilter(cache)){};
+ virtual ~DefaultRootSetFunc2(){};
+
+ bool InRootSet(const pkgCache::PkgIterator &pkg) APT_OVERRIDE { return pkg.end() == false && ((*Kernels)(pkg) || DefaultRootSetFunc::InRootSet(pkg)); };
+};
+
+ /*}}}*/
// helper for Install-Recommends-Sections and Never-MarkAuto-Sections /*{{{*/
static bool
ConfigValueInSubTree(const char* SubTree, const char *needle)
@@ -95,10 +113,14 @@ pkgDepCache::ActionGroup::~ActionGroup()
// DepCache::pkgDepCache - Constructors /*{{{*/
// ---------------------------------------------------------------------
/* */
-pkgDepCache::pkgDepCache(pkgCache * const pCache,Policy * const Plcy) :
- group_level(0), Cache(pCache), PkgState(0), DepState(0),
- iUsrSize(0), iDownloadSize(0), iInstCount(0), iDelCount(0), iKeepCount(0),
- iBrokenCount(0), iPolicyBrokenCount(0), iBadCount(0), d(NULL)
+
+struct pkgDepCache::Private
+{
+ std::unique_ptr<InRootSetFunc> inRootSetFunc;
+};
+pkgDepCache::pkgDepCache(pkgCache *const pCache, Policy *const Plcy) : group_level(0), Cache(pCache), PkgState(0), DepState(0),
+ iUsrSize(0), iDownloadSize(0), iInstCount(0), iDelCount(0), iKeepCount(0),
+ iBrokenCount(0), iPolicyBrokenCount(0), iBadCount(0), d(new Private)
{
DebugMarker = _config->FindB("Debug::pkgDepCache::Marker", false);
DebugAutoInstall = _config->FindB("Debug::pkgDepCache::AutoInstall", false);
@@ -116,6 +138,7 @@ pkgDepCache::~pkgDepCache()
delete [] PkgState;
delete [] DepState;
delete delLocalPolicy;
+ delete d;
}
/*}}}*/
bool pkgDepCache::CheckConsistency(char const *const msgtag) /*{{{*/
@@ -2148,14 +2171,21 @@ APT_PURE signed short pkgDepCache::Policy::GetPriority(pkgCache::PkgFileIterator
/*}}}*/
pkgDepCache::InRootSetFunc *pkgDepCache::GetRootSetFunc() /*{{{*/
{
- DefaultRootSetFunc *f = new DefaultRootSetFunc;
- if(f->wasConstructedSuccessfully())
- return f;
- else
- {
+ DefaultRootSetFunc *f = new DefaultRootSetFunc2(&GetCache());
+ if (f->wasConstructedSuccessfully())
+ return f;
+ else
+ {
delete f;
return NULL;
- }
+ }
+}
+
+pkgDepCache::InRootSetFunc *pkgDepCache::GetCachedRootSetFunc()
+{
+ if (d->inRootSetFunc == nullptr)
+ d->inRootSetFunc.reset(GetRootSetFunc());
+ return d->inRootSetFunc.get();
}
/*}}}*/
bool pkgDepCache::MarkFollowsRecommends()
@@ -2369,9 +2399,9 @@ bool pkgDepCache::MarkAndSweep(InRootSetFunc &rootFunc)
}
bool pkgDepCache::MarkAndSweep()
{
- std::unique_ptr<InRootSetFunc> f(GetRootSetFunc());
- if(f.get() != NULL)
- return MarkAndSweep(*f.get());
+ InRootSetFunc *f(GetCachedRootSetFunc());
+ if (f != NULL)
+ return MarkAndSweep(*f);
else
return false;
}
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
index 78f88ba2f..9a6019092 100644
--- a/apt-pkg/depcache.h
+++ b/apt-pkg/depcache.h
@@ -380,6 +380,9 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace
*/
virtual InRootSetFunc *GetRootSetFunc();
+ /** This should return const really - do not delete. */
+ InRootSetFunc *GetCachedRootSetFunc() APT_HIDDEN;
+
/** \return \b true if the garbage collector should follow recommendations.
*/
virtual bool MarkFollowsRecommends();
@@ -516,7 +519,8 @@ class APT_PUBLIC pkgDepCache : protected pkgCache::Namespace
bool const rPurge, unsigned long const Depth, bool const FromUser);
private:
- void * const d;
+ struct Private;
+ Private *const d;
APT_HIDDEN bool MarkInstall_StateChange(PkgIterator const &Pkg, bool AutoInst, bool FromUser);
APT_HIDDEN bool MarkInstall_DiscardInstall(PkgIterator const &Pkg);