From 5141602112d25eb01a4c2f27d3df8320c82e7813 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 11:13:15 -0600 Subject: [PATCH 01/13] feat(scripts): add ability to operate automatically on fedora-based systems Fedora-like systems use no kernel or initramfs symlinks in /, and instead use the direct images in /boot. We need to switch modes to allow these to operate automatically on kernel updates. --- data/kernel/zz-kernelstub | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/data/kernel/zz-kernelstub b/data/kernel/zz-kernelstub index f0c6c9f..c278d2a 100755 --- a/data/kernel/zz-kernelstub +++ b/data/kernel/zz-kernelstub @@ -1,8 +1,21 @@ #!/bin/bash -INITRD="/boot/initrd.img-$1" -KERNEL="$2" +# Grab OS information to figure out how to operate +source /etc/os-release + +# Determine how to handle kernel paths: +if [[ "$ID_LIKE" == *"fedora"* ]]; then + echo "Operating in Fedora-mode (initramfs, /boot)" + INITRD="/boot/initramfs-$1.img" + KERNEL="$2" +elif [[ "$ID_LIKE" == *"ubuntu"* ]]; then + echo "Operating in Ubuntu-mode (initrd.img, /symlinks)" + INITRD="/initrd.img" + KERNEL="/vmlinuz" +fi kernelstub \ --verbose \ - --preserve-live-mode + --preserve-live-mode \ + --kernel-path $KERNEL \ + --initrd-path $INITRD From c80e755c77b75afd86349a5bfeb4a6ad498f2ee1 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 11:23:09 -0600 Subject: [PATCH 02/13] docs: update readme --- README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d884499..9d800e6 100644 --- a/README.md +++ b/README.md @@ -31,15 +31,28 @@ dh-python Then use these commands to build the package: ``` -git clone https://github.com/pop-os/kernelstub +git clone https://github.com/isantop/kernelstub cd kernelstub dpkg-buildpackage -b -us -uc sudo dpkg -i ../kernelstub*.deb ``` -For installation on non-debian systems, or if you prefer to use Python + +For installation on RPM-based systems (Fedora, RHEL, etc.), the Python packaging +can automatically build an RPM package for use on your system: +``` +git clone https://github.com/isantop/kernelstub +cd kernelstub +python3 setup.py bdist_rpm +``` +After this, you can install the resulting RPM package directly: +``` +sudo rpm -i dist/kernelstub-*.rpm +``` + +For installation on other systems, or if you prefer to use Python packaging, use: ``` -git clone https://github.com/pop-os/kernelstub +git clone https://github.com/isantop/kernelstub cd kernelstub sudo python3 setup.py install --record=installed_files.txt ``` From 13939237b814145053ddbd43ece0f0c26e1ca404 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 11:46:20 -0600 Subject: [PATCH 03/13] feat(kernel_option): allow use with python-rpm as well --- data/initramfs/zz-kernelstub | 19 ++++++++++++++++--- kernelstub/kernel_option.py | 18 ++++++++++++++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/data/initramfs/zz-kernelstub b/data/initramfs/zz-kernelstub index 62a4c03..3138b27 100755 --- a/data/initramfs/zz-kernelstub +++ b/data/initramfs/zz-kernelstub @@ -1,8 +1,21 @@ #!/bin/bash -KERNEL="/boot/vmlinuz-$1" -INITRD="$2" +# Grab OS information to figure out how to operate +source /etc/os-release + +# Determine how to handle kernel paths: +if [[ "$ID_LIKE" == *"fedora"* ]]; then + echo "Operating in Fedora-mode (initramfs, /boot)" + INITRD="/boot/initramfs-$1.img" + KERNEL="/boot/vmlinuz-$1" +elif [[ "$ID_LIKE" == *"ubuntu"* ]]; then + echo "Operating in Ubuntu-mode (initrd.img, /symlinks)" + INITRD="/initrd.img" + KERNEL="/vmlinuz" +fi kernelstub \ --verbose \ - --preserve-live-mode + --preserve-live-mode \ + --kernel-path $KERNEL \ + --initrd-path $INITRD diff --git a/kernelstub/kernel_option.py b/kernelstub/kernel_option.py index 12edd2a..24ea0c3 100755 --- a/kernelstub/kernel_option.py +++ b/kernelstub/kernel_option.py @@ -1,6 +1,18 @@ #!/usr/bin/python3 -from debian.changelog import Version +try: + from debian.changelog import Version + def vCompare(version1:str, version2:str): + if Version(version1) > Version(version2): + return True + return False + +except ImportError: + from rpm import versionCompare as Version + def vCompare(version1:str, version2:str): + if versionCompare(version1, version2) == 1: + return True + return False import os import os.path @@ -12,6 +24,8 @@ def options(path): key = "kernel" elif name.startswith("initrd.img-"): key = "initrd" + elif name.startswith("initramfs"): + key = "initrd" if key is None: continue @@ -36,7 +50,7 @@ def get_newest_option(opts): continue # If this option is newer, store this option and continue - if latest_version is None or Version(version) > Version(latest_version): + if latest_version is None or vCompare (version, latest_version): latest_version = version latest_option = option From b84543e1bab208a94b80f656bd8f0e42576229fb Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 11:49:29 -0600 Subject: [PATCH 04/13] feat(opsys): add ID_LIKE field from os-release --- kernelstub/opsys.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernelstub/opsys.py b/kernelstub/opsys.py index 09abb87..d793ba9 100644 --- a/kernelstub/opsys.py +++ b/kernelstub/opsys.py @@ -28,6 +28,7 @@ class OS(): name_pretty = "Linux" name = "Linux" + like = ["Linux"] version = "1.0" cmdline = ['quiet', 'splash'] kernel_name = 'vmlinuz' @@ -43,6 +44,7 @@ class OS(): def __init__(self): self.name_pretty = self.get_os_name() self.name = self.clean_names(self.name_pretty) + self.like = self.get_os_like() self.version = self.get_os_version() self.cmdline = self.get_os_cmdline() @@ -116,6 +118,14 @@ def get_os_version(self): if item.startswith('VERSION_ID='): version = item.split('=')[1] return self.strip_quotes(version[:-1]) + + def get_os_like(self): + os_release = self.get_os_release() + for item in os_release: + if item.startswith('ID_LIKE='): + like = item.split('=')[1] + like = self.strip_quotes(like) + return like.split() def strip_quotes(self, value): new_value = value From df1fd86a7bf3c2108a8b6bb3e6dff320fd5fdc5b Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 11:56:19 -0600 Subject: [PATCH 05/13] feat(opsys): add support for OS mode toggle --- kernelstub/opsys.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kernelstub/opsys.py b/kernelstub/opsys.py index d793ba9..bd7107a 100644 --- a/kernelstub/opsys.py +++ b/kernelstub/opsys.py @@ -40,6 +40,7 @@ class OS(): initrd_path = '/initrd.img' old_kernel_path = '/vmlinuz.old' old_initrd_path = '/initrd.img.old' + os_mode = 'debian' def __init__(self): self.name_pretty = self.get_os_name() @@ -47,6 +48,7 @@ def __init__(self): self.like = self.get_os_like() self.version = self.get_os_version() self.cmdline = self.get_os_cmdline() + self.set_os_mode() def clean_names(self, name): # This is a list of characters we can't/don't want to have in technical @@ -134,6 +136,12 @@ def strip_quotes(self, value): if value.endswith('"'): new_value = new_value[:-1] return new_value + + def set_os_mode(self): + if 'debian' in self.like: + self.os_mode = 'debian' + elif 'fedora' in self.like: + self.os_mode = 'fedora' def get_os_release(self): try: From 07c56beae23bf924f6ca2a4cadce4fd314ae7ad8 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 12:22:57 -0600 Subject: [PATCH 06/13] feat: add support for fedora-like kernels --- kernelstub/kernel_option.py | 24 ++++++++++++++++++++++-- kernelstub/opsys.py | 3 ++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/kernelstub/kernel_option.py b/kernelstub/kernel_option.py index 24ea0c3..7c46824 100755 --- a/kernelstub/kernel_option.py +++ b/kernelstub/kernel_option.py @@ -1,5 +1,9 @@ #!/usr/bin/python3 +import logging + +log = logging.getLogger('kernelstub.kernel_option') + try: from debian.changelog import Version def vCompare(version1:str, version2:str): @@ -8,9 +12,9 @@ def vCompare(version1:str, version2:str): return False except ImportError: - from rpm import versionCompare as Version + from rpm import labelCompare def vCompare(version1:str, version2:str): - if versionCompare(version1, version2) == 1: + if labelCompare(version1, version2) == 1: return True return False import os @@ -19,12 +23,16 @@ def vCompare(version1:str, version2:str): def options(path): items={} for name in os.listdir(path): + log.info('Checking item %s', name) key = None if name.startswith("vmlinuz-"): + log.info('Item %s is kernel-image', name) key = "kernel" elif name.startswith("initrd.img-"): + log.info('Item %s is debian-style initrd', name) key = "initrd" elif name.startswith("initramfs"): + log.info('Item %s is fedora-style initrd', name) key = "initrd" if key is None: @@ -32,31 +40,41 @@ def options(path): parts = name.split("-", 1) version = parts[1] + if version.endswith('.img'): + version = version[:-4] + log.info('Item version is %s', version) if not version in items: + log.info('Adding item %s to list', name) items[version] = {} items[version][key] = os.path.join(path, name) + log.info('Found items: %s', items) return items def get_newest_option(opts): + log.info('Getting latest boot item version') latest_version = None latest_option = None for version, option in opts.items(): + log.info('Checking option %s', option) # If option is not complete, skip if 'kernel' not in option or 'initrd' not in option: + log.info('%s does not contain all items, skipping...', version) continue # If this option is newer, store this option and continue if latest_version is None or vCompare (version, latest_version): + log.info('%s is the latest version', version) latest_version = version latest_option = option return latest_option, latest_version def latest_option(path): + log.info('Checking for boot items in %s', path) opts = options(path) latest_option, latest_version = get_newest_option(opts) @@ -66,6 +84,8 @@ def latest_option(path): if len(opts) > 0: previous_option, latest_version = get_newest_option(opts) + log.info('Latest option: %s', latest_option) + log.info('Previous option: %s', previous_option) return latest_option, previous_option if __name__ == "__main__": diff --git a/kernelstub/opsys.py b/kernelstub/opsys.py index bd7107a..ca40676 100644 --- a/kernelstub/opsys.py +++ b/kernelstub/opsys.py @@ -22,7 +22,7 @@ terms. """ -import platform +import logging, platform class OS(): @@ -43,6 +43,7 @@ class OS(): os_mode = 'debian' def __init__(self): + self.log = logging.getLogger('kernelstub.Opsys') self.name_pretty = self.get_os_name() self.name = self.clean_names(self.name_pretty) self.like = self.get_os_like() From 75e4ad4bcc3646b1546b76d66bfa65ce0a1b79dd Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 12:23:13 -0600 Subject: [PATCH 07/13] chore: bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4095250..dac8fad 100755 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ def run(self): run_pyflakes3() setup(name='kernelstub', - version='3.1.4', + version='4.0.0', description='Automatic kernel efistub manager for UEFI', url='https://launchpad.net/kernelstub', author='Ian Santopietro', From 240dd440664e216ea24bfd9ebbafd36523f6886a Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Fri, 4 Aug 2023 12:24:35 -0600 Subject: [PATCH 08/13] fix(kernel_option): change output to debug mode --- kernelstub/kernel_option.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/kernelstub/kernel_option.py b/kernelstub/kernel_option.py index 7c46824..f6dd41f 100755 --- a/kernelstub/kernel_option.py +++ b/kernelstub/kernel_option.py @@ -23,16 +23,16 @@ def vCompare(version1:str, version2:str): def options(path): items={} for name in os.listdir(path): - log.info('Checking item %s', name) + log.debug('Checking item %s', name) key = None if name.startswith("vmlinuz-"): - log.info('Item %s is kernel-image', name) + log.debug('Item %s is kernel-image', name) key = "kernel" elif name.startswith("initrd.img-"): - log.info('Item %s is debian-style initrd', name) + log.debug('Item %s is debian-style initrd', name) key = "initrd" elif name.startswith("initramfs"): - log.info('Item %s is fedora-style initrd', name) + log.debug('Item %s is fedora-style initrd', name) key = "initrd" if key is None: @@ -42,39 +42,39 @@ def options(path): version = parts[1] if version.endswith('.img'): version = version[:-4] - log.info('Item version is %s', version) + log.debug('Item version is %s', version) if not version in items: - log.info('Adding item %s to list', name) + log.debug('Adding item %s to list', name) items[version] = {} items[version][key] = os.path.join(path, name) - log.info('Found items: %s', items) + log.debug('Found items: %s', items) return items def get_newest_option(opts): - log.info('Getting latest boot item version') + log.debug('Getting latest boot item version') latest_version = None latest_option = None for version, option in opts.items(): - log.info('Checking option %s', option) + log.debug('Checking option %s', option) # If option is not complete, skip if 'kernel' not in option or 'initrd' not in option: - log.info('%s does not contain all items, skipping...', version) + log.debug('%s does not contain all items, skipping...', version) continue # If this option is newer, store this option and continue if latest_version is None or vCompare (version, latest_version): - log.info('%s is the latest version', version) + log.debug('%s is the latest version', version) latest_version = version latest_option = option return latest_option, latest_version def latest_option(path): - log.info('Checking for boot items in %s', path) + log.debug('Checking for boot items in %s', path) opts = options(path) latest_option, latest_version = get_newest_option(opts) @@ -84,8 +84,8 @@ def latest_option(path): if len(opts) > 0: previous_option, latest_version = get_newest_option(opts) - log.info('Latest option: %s', latest_option) - log.info('Previous option: %s', previous_option) + log.debug('Latest option: %s', latest_option) + log.debug('Previous option: %s', previous_option) return latest_option, previous_option if __name__ == "__main__": From e779e390be493a78b57cef2e5579e6df6e6363b6 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Wed, 9 Aug 2023 15:36:15 -0600 Subject: [PATCH 09/13] fix(opsys): add fallback in case distro is not derivative and doesn't have ID_LIKE --- kernelstub/opsys.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernelstub/opsys.py b/kernelstub/opsys.py index ca40676..47cb724 100644 --- a/kernelstub/opsys.py +++ b/kernelstub/opsys.py @@ -129,6 +129,13 @@ def get_os_like(self): like = item.split('=')[1] like = self.strip_quotes(like) return like.split() + + # Fallback on ID= if we aren't on a derivative + for item in os_release: + if item.startswith('ID='): + like = item.split('=')[1] + like = self.strip_quotes(like) + return like.split() def strip_quotes(self, value): new_value = value From d3bee5427159ef907e9566bbeaef057a9b59f5a0 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Wed, 9 Aug 2023 15:48:57 -0600 Subject: [PATCH 10/13] fix(scripts): also fallback in update scripts --- data/kernel/zz-kernelstub | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/data/kernel/zz-kernelstub b/data/kernel/zz-kernelstub index c278d2a..01ffc84 100755 --- a/data/kernel/zz-kernelstub +++ b/data/kernel/zz-kernelstub @@ -3,6 +3,11 @@ # Grab OS information to figure out how to operate source /etc/os-release +# If ID_LIKE is empty, use ID instead. Base Distros don't always use ID_LIKE +if [[ "$ID_LIKE" == "" ]]; then + ID_LIKE="$ID" +fi + # Determine how to handle kernel paths: if [[ "$ID_LIKE" == *"fedora"* ]]; then echo "Operating in Fedora-mode (initramfs, /boot)" From b41283539ad4d4cc7dc3c1c3fa4443f3e4c07c89 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Wed, 9 Aug 2023 16:15:35 -0600 Subject: [PATCH 11/13] fix(scripts): change "ubuntu" to "debian Be as generic as possible --- data/kernel/zz-kernelstub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/kernel/zz-kernelstub b/data/kernel/zz-kernelstub index 01ffc84..ae0d478 100755 --- a/data/kernel/zz-kernelstub +++ b/data/kernel/zz-kernelstub @@ -13,8 +13,8 @@ if [[ "$ID_LIKE" == *"fedora"* ]]; then echo "Operating in Fedora-mode (initramfs, /boot)" INITRD="/boot/initramfs-$1.img" KERNEL="$2" -elif [[ "$ID_LIKE" == *"ubuntu"* ]]; then - echo "Operating in Ubuntu-mode (initrd.img, /symlinks)" +elif [[ "$ID_LIKE" == *"debian"* ]]; then + echo "Operating in Debian-mode (initrd.img, /symlinks)" INITRD="/initrd.img" KERNEL="/vmlinuz" fi From 64d3340b3a8fa09efaae681402d5e4282814bb42 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Wed, 9 Aug 2023 16:23:37 -0600 Subject: [PATCH 12/13] fix(scripts): sync initramfs script to kernel script --- data/initramfs/zz-kernelstub | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/data/initramfs/zz-kernelstub b/data/initramfs/zz-kernelstub index 3138b27..ae0d478 100755 --- a/data/initramfs/zz-kernelstub +++ b/data/initramfs/zz-kernelstub @@ -3,13 +3,18 @@ # Grab OS information to figure out how to operate source /etc/os-release +# If ID_LIKE is empty, use ID instead. Base Distros don't always use ID_LIKE +if [[ "$ID_LIKE" == "" ]]; then + ID_LIKE="$ID" +fi + # Determine how to handle kernel paths: if [[ "$ID_LIKE" == *"fedora"* ]]; then echo "Operating in Fedora-mode (initramfs, /boot)" INITRD="/boot/initramfs-$1.img" - KERNEL="/boot/vmlinuz-$1" -elif [[ "$ID_LIKE" == *"ubuntu"* ]]; then - echo "Operating in Ubuntu-mode (initrd.img, /symlinks)" + KERNEL="$2" +elif [[ "$ID_LIKE" == *"debian"* ]]; then + echo "Operating in Debian-mode (initrd.img, /symlinks)" INITRD="/initrd.img" KERNEL="/vmlinuz" fi From 44e30a06bcb5f9d044b55ad074dda96d9e1bd188 Mon Sep 17 00:00:00 2001 From: Ian Santopietro Date: Wed, 9 Aug 2023 17:19:14 -0600 Subject: [PATCH 13/13] chore: update version --- debian/changelog | 6 ++++++ setup.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index b083220..794a401 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +kernelstub (4.0.1) bionic; urgency=medium + + * Add support for Fedora-like kernel setups + + -- Ian Santopietro Wed, 09 Aug 2023 17:18:19 -0600 + kernelstub (3.1.4) bionic; urgency=medium * Do live mode check immediately after parsing config diff --git a/setup.py b/setup.py index dac8fad..de04b40 100755 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ def run(self): run_pyflakes3() setup(name='kernelstub', - version='4.0.0', + version='4.0.1', description='Automatic kernel efistub manager for UEFI', url='https://launchpad.net/kernelstub', author='Ian Santopietro',