Skip to content

Instantly share code, notes, and snippets.

@julian-klode
Last active October 13, 2020 14:57
Show Gist options
  • Save julian-klode/17ade48decb70575d78395c35d004cf4 to your computer and use it in GitHub Desktop.
Save julian-klode/17ade48decb70575d78395c35d004cf4 to your computer and use it in GitHub Desktop.
#include <apt-pkg/cachefile.h>
#include <apt-pkg/cachefilter.h>
#include <apt-pkg/debversion.h>
#include <apt-pkg/error.h>
#include <apt-pkg/init.h>
#include <apt-pkg/pkgsystem.h>
#include <apt-pkg/strutl.h>
#include <cstdlib>
#include <iostream>
#include <regex>
#include <set>
#include <string>
#include <vector>
#include <sys/utsname.h>
// TODO: Order by Debian version
std::unique_ptr<APT::CacheFilter::Matcher> GetInstalledKernelVersions(pkgCache *cache, bool ReturnRemove = false)
{
struct Kernel
{
std::string version;
std::string uname;
bool operator<(const Kernel &b) const
{
return version != b.version
? debVS.CmpVersion(version, b.version) < 0
: debVS.CmpVersion(uname, b.uname) < 0;
}
};
static constexpr const char *kernels[] = {
"linux-image-",
"kfreebsd-image-",
"gnumach-image-",
};
std::set<Kernel> res;
struct utsname uts;
std::set<Kernel>::const_iterator current = res.end();
std::set<Kernel>::const_iterator installed = res.end();
std::string InstalledUname = _config->Find("APT::LastInstalledKernel");
if (getenv("SOURCE_DATE_EPOCH") == 0 && uname(&uts) != 0)
abort();
for (pkgCache::PkgIterator Pkg = cache->PkgBegin(); Pkg.end() == false; ++Pkg)
{
if (Pkg->CurrentVer == 0)
continue;
for (auto kernel : kernels)
{
if (not APT::String::Startswith(Pkg.Name(), kernel))
continue;
if (strstr(Pkg.Name(), "-dbg") != nullptr)
continue;
auto version = std::string(Pkg.Name()).substr(strlen(kernel));
if (version.length() < 2)
continue;
if (strchr("0123456789", version[0]) == nullptr)
continue;
auto iter = res.insert({Pkg.CurrentVer().VerStr(), version});
if (version == uts.release)
current = iter.first;
if (version == InstalledUname)
installed = iter.first;
}
}
if (res.size() == 0)
return nullptr;
auto latest = res.rbegin();
auto previous = ++res.rbegin();
std::set<std::string> keep;
if (current != res.end())
keep.insert(current->uname);
if (installed != res.end())
keep.insert(installed->uname);
if (latest != res.rend())
keep.insert(latest->uname);
if (previous != res.rend())
keep.insert(previous->uname);
std::regex special("([\\.\\+])");
std::ostringstream ss;
for (auto &pattern : _config->FindVector("APT::VersionedKernelPackages"))
{
for (auto &kernel : res)
{
if (ReturnRemove ? keep.find(kernel.uname) == keep.end() : keep.find(kernel.uname) != keep.end())
ss << "|^" << pattern << "-" << std::regex_replace(kernel.uname, special, "\\$1") << "$";
}
}
auto re = ss.str().substr(1);
//std::cout << re << "\n";
return std::make_unique<APT::CacheFilter::PackageNameMatchesRegEx>(re);
}
int main(void)
{
if (pkgInitConfig(*_config) == false)
_error->DumpErrors(), exit(1);
if (pkgInitSystem(*_config, _system) == false)
_error->DumpErrors(), exit(1);
pkgCacheFile file;
if (!file.Open(nullptr, false))
_error->DumpErrors(), exit(1);
auto d = file.GetDepCache();
auto f = GetInstalledKernelVersions(file);
for (pkgCache::PkgIterator Pkg = file->PkgBegin(); Pkg.end() == false; ++Pkg)
if ((*f)(Pkg))
std::cout << "KEEP " << Pkg.Name() << "\n";
_error->DumpErrors();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment