Skip to content

Commit

Permalink
Merge pull request FrostyX#138 from jturel/check_kernel_version_insta…
Browse files Browse the repository at this point in the history
…lled

Use package manager to determine latest kernel
  • Loading branch information
jturel committed May 8, 2020
2 parents 90dd965 + 9c345ac commit 220fc40
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 16 deletions.
14 changes: 14 additions & 0 deletions tracer/packageManagers/ipackageManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ def provided_by(self, app):
"""Returns name of package which provides given application"""
raise NotImplementedError

def find_package(self, pkg_name, search):
"""Find a package by name and some other input criteria"""
raise NotImplementedError

def compare_packages(self, package1, package2):
"""
Compares two packages by their version information
Returns:
0 if they are equal
1 if package1 > package2
-1 if package2 > package1
"""
raise NotImplementedError

@staticmethod
def _pkg_name_without_version(pkg_name):
try:
Expand Down
83 changes: 77 additions & 6 deletions tracer/packageManagers/rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
from tracer.resources.package import Package
from tracer.resources.collections import PackagesCollection
from tracer.resources.exceptions import LockedDatabase, DatabasePermissions
from tracer.resources.applications import Applications
import sqlite3
import rpm
import os
Expand Down Expand Up @@ -109,18 +108,53 @@ def package_files(self, pkg_name):
# Tracer will not find uninstalled applications
return []

def find_package(self, name, evra):
evra = self._splitEvra(evra)
ts = rpm.TransactionSet()
mi = ts.dbMatch("name", name)

for hdr in mi:
if hdr[rpm.RPMTAG_EPOCH] == evra[0] and hdr[rpm.RPMTAG_VERSION] == evra[1] and hdr[rpm.RPMTAG_RELEASE] == evra[2] and hdr[rpm.RPMTAG_ARCH] == evra[3]:
package = Package(name)
self._load_package_info_from_hdr(package, hdr)

return package

return None

def load_package_info(self, package):
"""From database load informations about given package and set them to it"""
description = None
category = None
if not package:
return None

ts = rpm.TransactionSet()
mi = ts.dbMatch("name", package.name)
package_hdr = next(mi)
package.description = package_hdr[rpm.RPMTAG_SUMMARY].decode()
package.category = package_hdr[rpm.RPMTAG_GROUP].decode()

""" Find the latest one if there are multiple versions"""
latest = None
for hdr in mi:
if latest is None:
latest = hdr
else:
compare = rpm.labelCompare((str(latest[rpm.RPMTAG_EPOCH]), str(latest[rpm.RPMTAG_VERSION]), str(latest[rpm.RPMTAG_RELEASE])),
(str(hdr[rpm.RPMTAG_EPOCH]), str(hdr[rpm.RPMTAG_VERSION]), str(hdr[rpm.RPMTAG_RELEASE])))

if compare == -1:
latest = hdr

if latest is None:
return

self._load_package_info_from_hdr(package, latest)

def compare_packages(self, p1, p2):
"""
labelCompare returns:
0 if the EVR matches
1 if EVR(1) > EVR(2)
-1 if EVR(2) > EVR(1)
"""
return rpm.labelCompare((str(p1.epoch), str(p1.version), str(p1.release)), (str(p2.epoch), str(p2.version), str(p2.release)))

def provided_by(self, app):
"""Returns name of package which provides given application"""
Expand All @@ -137,6 +171,43 @@ def provided_by(self, app):
return package
return None

def _splitEvra(self, evra):
"""
Derived from rpmUtils.miscutils.splitFilename
https://github.com/rpm-software-management/yum/blob/master/rpmUtils/miscutils.py
Given: 9-123a.ia64
Return: (9, 123a, 1, ia64)
"""

archIndex = evra.rfind('.')
arch = evra[archIndex + 1:]

relIndex = evra[:archIndex].rfind('-')
rel = evra[relIndex + 1:archIndex]

verIndex = evra[:relIndex].rfind('-')
ver = evra[verIndex + 1:relIndex]

epochIndex = evra.find(':')
if epochIndex == -1:
epoch = None
else:
epoch = evra[:epochIndex]

return epoch, ver, rel, arch

def _load_package_info_from_hdr(self, package, hdr):
package.description = hdr[rpm.RPMTAG_SUMMARY].decode()
package.category = hdr[rpm.RPMTAG_GROUP].decode()

epoch = hdr[rpm.RPMTAG_EPOCH]
if epoch:
package.epoch = epoch.decode()

package.version = hdr[rpm.RPMTAG_VERSION].decode()
package.release = hdr[rpm.RPMTAG_RELEASE].decode()

def _file_provided_by(self, file):
"""Returns name of package which provides given file"""
ts = rpm.TransactionSet()
Expand Down
14 changes: 14 additions & 0 deletions tracer/resources/PackageManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,17 @@ def load_package_info(self, package):
def provided_by(self, app):
"""Returns name of package which provides given application"""
return self.package_managers[0].provided_by(app)

def find_package(self, pkg_name, search):
"""Find a package by name and some other input criteria"""
return self.package_managers[0].find_package(pkg_name, search)

def compare_packages(self, package1, package2):
"""
Compares two packages by their version information
Returns:
0 if they are equal
1 if package1 > package2
-1 if package2 > package1
"""
return self.package_managers[0].compare_packages(package1, package2)
3 changes: 3 additions & 0 deletions tracer/resources/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class Package:
modified = None #: UNIX timestamp of the modification
description = None
category = None
epoch = None
version = None
release = None

def __init__(self, name, modified=None):
self.name = name
Expand Down
10 changes: 9 additions & 1 deletion tracer/resources/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
from tracer.resources.PackageManager import PackageManager
from tracer.resources.processes import Process


class System(object):

@staticmethod
Expand Down Expand Up @@ -112,6 +111,15 @@ def boot_time():
def python_version():
return "{}.{}.{}".format(version_info.major, version_info.minor, version_info.micro)

@staticmethod
def running_kernel_package():
return System.package_manager().find_package(System.kernel_package_name(), os.uname()[2])

@staticmethod
def kernel_package_name():
""" TODO: infer kernel package from current distribution """
return 'kernel'

@staticmethod
def user():
# getlogin is prefered because it return current username even
Expand Down
22 changes: 13 additions & 9 deletions tracer/resources/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
from __future__ import absolute_import

import os
from pkg_resources import parse_version
from psutil import NoSuchProcess
from tracer.resources.package import Package
from tracer.resources.system import System
from tracer.resources.FilenameCleaner import FilenameCleaner
from tracer.resources.processes import AffectedProcess
Expand Down Expand Up @@ -122,22 +122,26 @@ def trace_affected(self, user=None):
affected[a.name].affected_instances.append(p)
except NoSuchProcess:
pass
if self._has_updated_kernel() and not self._applications.find('kernel').ignore:

if not self._applications.find('kernel').ignore and self._has_updated_kernel():
# Add fake AffectedApplication
affected['kernel'] = AffectedApplication({"name": "kernel", "type": Applications.TYPES["STATIC"],
"helper": _("You will have to reboot your computer")})

return ApplicationsCollection(affected.values())

def _has_updated_kernel(self):
if os.path.isdir('/lib/modules/'):
for k_version in next(os.walk('/lib/modules/'))[1]:
if 'debug' in k_version:
continue
running = System.running_kernel_package()

if running is None:
""" If the running kernel package could not be determined, abort """
return False

kernel_package_name = System.kernel_package_name()
latest = Package(kernel_package_name)
latest.load_info(self._PACKAGE_MANAGER)

if parse_version(os.uname()[2]) < parse_version(k_version):
return True
return False
return self._PACKAGE_MANAGER.compare_packages(running, latest) == -1

def _apply_rules(self, process):
parent = process.parent()
Expand Down

0 comments on commit 220fc40

Please sign in to comment.