27 #include <unordered_map>
28 #include <sys/utsname.h>
32 #undef ZYPP_BASE_LOGGER_LOGGROUP
33 #define ZYPP_BASE_LOGGER_LOGGROUP "PurgeKernels"
56 using GroupMap = std::unordered_map<std::string, GroupInfo>;
61 struct utsname unameData;
62 if ( uname( &unameData) == 0 ) {
67 setUnameR( std::string( unameData.release ) );
74 MIL <<
"Failed to detect running kernel: " << errno << std::endl;
82 MIL <<
"Set uname " << uname << std::endl;
99 MIL <<
"Parsed info from uname: " << std::endl;
107 void fillKeepList(
const GroupMap &installedKernels, std::set<sat::Solvable> &keepList , std::set<sat::Solvable> &removeList )
const;
134 if ( !pool.resolver().resolvePool() ) {
135 MIL <<
"Pool failed to resolve, not doing anything" << std::endl;
139 MIL <<
"Request to remove package: " << pi << std::endl;
142 const str::regex validRemovals(
"(kernel-syms(-.*)?|kgraft-patch(-.*)?|kernel-livepatch(-.*)?|.*-kmp(-.*)?)");
145 MIL <<
"Package " << pi <<
" is locked by the user, not removing." << std::endl;
150 std::set<sat::Solvable> currentSetOfRemovals;
151 for (
const PoolItem & p : pool.byStatus( toBeUninstalledFilter ) ) {
152 currentSetOfRemovals.insert( p.satSolvable() );
157 if ( !pool.resolver().resolvePool() ) {
158 MIL <<
"Failed to resolve pool, skipping " << pi << std::endl;
159 pool.resolver().problems();
165 std::set<sat::Solvable> removedInThisRun;
166 removedInThisRun.insert( slv );
168 for (
const PoolItem & p : pool.byStatus( toBeUninstalledFilter ) ) {
171 if ( p.status().isByUser()
172 || (currentSetOfRemovals.find( p.satSolvable() ) != currentSetOfRemovals.end())
177 removedInThisRun.insert( p.satSolvable() );
179 MIL <<
"Package " << p <<
" was marked by the solver for removal." << std::endl;
182 if ( removeList.find( p.satSolvable() ) != removeList.end() )
185 if ( keepList.find( p.satSolvable() ) != keepList.end() ) {
186 MIL <<
"Package " << p <<
" is in keep spec, skipping" << pi << std::endl;
193 MIL <<
"Package " << p <<
" should not be removed, skipping " << pi << std::endl;
199 MIL <<
"Successfully marked package: " << pi <<
" for removal."<<std::endl;
202 MIL <<
"Trying to remove debuginfo for: " << pi <<
"."<<std::endl;
205 if ( solvable.arch() == Arch_noarch ||
209 for (
const char * suffix : {
"-debugsource",
"-debuginfo" } ) {
218 if ( debugPackage.arch() != solvable.arch() )
221 MIL <<
"Found debug package for " << solvable <<
" : " << debugPackage << std::endl;
227 MIL <<
"Finished removing debuginfo for: " << pi <<
"."<<std::endl;
243 std::string versionStr = b.
asString();
245 if ( buildCntRegex.
matches( versionStr.data(), matches ) ) {
246 if ( matches.
size() >= 2 ) {
247 versionStr.replace( matches.
begin(0), (matches.
end(0) - matches.
begin(0))+1, matches[1] );
248 return a ==
Edition(versionStr);
262 const unsigned tokenGrp = 1;
263 const unsigned modifierGrp = 2;
266 MIL <<
"Parsing keep spec: " << _keepSpec << std::endl;
268 std::vector<std::string> words;
270 if ( words.empty() ) {
271 WAR <<
"Invalid keep spec: " << _keepSpec <<
" using default latest,running." << std::endl;
275 _keepRunning =
false;
276 _keepLatestOffsets.clear();
277 _keepOldestOffsets.clear();
279 for (
const std::string &word : words ) {
280 if ( word ==
"running" ) {
285 _keepSpecificEditions.insert(
Edition(word) );
289 auto addKeepOff = [](
const auto &off,
auto &set,
const auto &constraint ){
290 const off_t num = off.empty() ? 0 : str::strtonum<off_t>( off );
291 if ( !constraint(num) )
return false;
292 set.insert(
static_cast<size_t>(std::abs(num)) );
296 if ( what[tokenGrp] ==
"oldest" ) {
297 addKeepOff( what[modifierGrp], _keepOldestOffsets, [ &word ]( off_t num ) {
299 WAR <<
"Ignoring invalid modifier in keep spec: " << word <<
", oldest supports only positive modifiers." << std::endl;
305 addKeepOff( what[modifierGrp], _keepLatestOffsets, [ &word ]( off_t num ) {
307 WAR <<
"Ignoring invalid modifier in keep spec: " << word <<
", latest supports only negative modifiers." << std::endl;
329 const auto markAsKeep = [ &keepList, &removeList ](
sat::Solvable pck ) {
330 MIL <<
"Marking package " << pck <<
" as to keep." << std::endl;
331 keepList.insert( pck ) ;
332 removeList.erase( pck );
335 const auto versionPredicate = [](
const auto &edition ){
336 return [ &edition ](
const auto &elem ) {
337 return versionMatch( edition, elem.first );
341 for (
const auto &groupInfo : installedKernels ) {
343 MIL <<
"Starting with group " << groupInfo.first << std::endl;
345 for (
const auto &archMap : groupInfo.second.archToEdMap ) {
347 MIL <<
"Starting with arch " << archMap.first << std::endl;
350 size_t currROff = archMap.second.size() - 1;
356 && ( ( archMap.first == _kernelArch && groupInfo.second.groupFlavour == _runningKernelFlavour )
359 MIL <<
"Matching packages against running kernel "<< _runningKernelEdition <<
"-" << _runningKernelFlavour <<
"-" <<_kernelArch << std::endl;
361 auto it = std::find_if( map.begin(), map.end(), versionPredicate( _runningKernelEdition ) );
362 if ( it == map.end() ) {
366 MIL <<
"Running kernel "<< _runningKernelEdition <<
"-" << _runningKernelFlavour <<
"-" <<_kernelArch <<
" not installed."<<std::endl;
367 MIL <<
"NOT removing any packages for flavor "<<_runningKernelFlavour<<
"-"<<_kernelArch<<
" ."<<std::endl;
369 for (
const auto &kernelMap : map ) {
378 MIL <<
"Found possible running candidate edition: " << it->first << std::endl;
380 for ( nit++ ; nit != map.end() && versionMatch( _runningKernelEdition, nit->first ) ; nit++ ) {
381 MIL <<
"Found possible more recent running candidate edition: " << nit->first << std::endl;
387 if ( it != map.end() ) {
394 for (
const auto &kernelMap : map ) {
396 if ( _keepOldestOffsets.find( currOff ) != _keepOldestOffsets.end() || _keepLatestOffsets.find( currROff ) != _keepLatestOffsets.end() ) {
397 std::for_each( kernelMap.second.begin(), kernelMap.second.end(), markAsKeep );
405 std::for_each( kernelMap.second.begin(), kernelMap.second.end(), [ & ](
sat::Solvable solv ){
406 for ( Capability prov : solv.provides() ) {
407 if ( prov.detail().name() == solv.name() && _keepSpecificEditions.count( prov.detail().ed() ) ) {
418 : _pimpl( new
Impl() )
425 MIL << std::endl <<
"--------------------- Starting to mark obsolete kernels ---------------------"<<std::endl;
428 WAR <<
"Keep spec is empty, removing nothing." << std::endl;
435 WAR <<
"Unable to detect running kernel, but keeping the running kernel was requested. Not removing any packages." << std::endl;
440 pool.resolver().setForceResolve(
true );
445 const str::regex kernelFlavourRegex(
"^kernel-(.*)$");
453 std::set<sat::Solvable> packagesToRemove;
455 const auto addPackageToMap = [&installedKrnlPackages, &packagesToRemove] (
const GroupInfo::GroupType type,
const std::string &ident,
const std::string &flavour,
const sat::Solvable &installedKrnlPck ) {
457 if ( !installedKrnlPackages.count( ident ) )
458 installedKrnlPackages.insert( std::make_pair( ident,
GroupInfo(type, flavour) ) );
460 auto &groupInfo = installedKrnlPackages[ ident ];
461 if ( groupInfo.groupType != type || groupInfo.groupFlavour != flavour ) {
462 ERR <<
"Got inconsistent type and flavour for ident this is a BUG: " << ident << std::endl
463 <<
"Original Flavour-Type: "<<groupInfo.groupFlavour<<
"-"<<groupInfo.groupType << std::endl
464 <<
"Competing Flavour-Type: "<< flavour <<
"-" << type << std::endl;
467 const auto currArch = installedKrnlPck.arch();
468 if ( !groupInfo.archToEdMap.count( currArch ) )
471 auto &editionToSolvableMap = groupInfo.archToEdMap[ currArch ];
477 auto currCount = INT_MAX;
479 for (
Capability prov : installedKrnlPck.provides() ) {
480 if ( prov.detail().name() == installedKrnlPck.name() ) {
482 edToUse = installedKrnlPck.edition();
483 const auto &relStr = edToUse.
release();
484 currCount = std::count( relStr.begin(), relStr.end(),
'.');
486 const auto &pckEd = prov.detail().ed();
487 const auto &relStr = pckEd.release();
488 if (
const auto pntCnt = std::count( relStr.begin(), relStr.end(),
'.'); pntCnt < currCount ) {
496 if ( !editionToSolvableMap.count( edToUse ) )
497 editionToSolvableMap.insert( std::make_pair( edToUse,
SolvableList{} ) );
499 editionToSolvableMap[edToUse].push_back( installedKrnlPck );
502 packagesToRemove.insert( installedKrnlPck );
506 std::set<sat::Solvable> packagesToKeep;
515 MIL <<
"Searching for obsolete multiversion kernel packages." << std::endl;
519 MIL <<
"Found installed multiversion kernel package " << installedKrnlPck << std::endl;
521 if ( installedKrnlPck.provides().matches(
Capability(
"kernel-uname-r")) ) {
522 MIL <<
"Identified as a kernel package " << std::endl;
527 if ( what[1].empty() ) {
528 WAR <<
"Could not detect flavour for: " << installedKrnlPck <<
" ...skipping" << std::endl;
532 std::string flavour = what[1];
535 const auto dash = flavour.find_first_of(
'-');
536 if ( dash != std::string::npos ) {
537 flavour = flavour.substr( 0, dash );
546 const str::regex explicitelyHandled(
"kernel-syms(-.*)?|kernel(-.*)?-devel");
548 MIL <<
"Not a kernel package, inspecting more closely " << std::endl;
551 if ( installedKrnlPck.arch() == Arch_noarch ) {
553 MIL <<
"Handling package explicitely due to architecture (noarch)."<< std::endl;
565 if ( match.size() > 1 && match[1].size() )
566 flav = match[1].substr(1);
568 else if ( match.size() > 2 && match[2].size() )
569 flav = match[2].substr(1);
570 else if ( installedKrnlPck.name() ==
"kernel-syms" )
573 MIL <<
"Handling package explicitely due to name match."<< std::endl;
576 MIL <<
"Package not explicitely handled" << std::endl;
582 MIL <<
"Grouped packages: " << std::endl;
583 std::for_each( installedKrnlPackages.begin(), installedKrnlPackages.end(),[](
const auto &ident ){
584 MIL <<
"\tGroup ident: "<<ident.first<<std::endl;
585 MIL <<
"\t Group type: "<<ident.second.groupType<<std::endl;
586 MIL <<
"\t Group flav: "<<ident.second.groupFlavour<<std::endl;
587 std::for_each( ident.second.archToEdMap.begin(), ident.second.archToEdMap.end(), []( const auto &arch) {
588 MIL <<
"\t\tArch: "<<arch.first<<std::endl;
589 std::for_each( arch.second.begin(), arch.second.end(), []( const auto &edition) {
590 MIL <<
"\t\t\tEdition: "<<edition.first<<std::endl;
591 std::for_each( edition.second.begin(), edition.second.end(), []( const auto &packageId) {
592 MIL <<
"\t\t\t\t "<<sat::Solvable(packageId)<<std::endl;
598 _pimpl->fillKeepList( installedKrnlPackages, packagesToKeep, packagesToRemove );
601 _pimpl->removePackageAndCheck( slv, packagesToKeep, packagesToRemove );