kernel-update: cleanup, make specifying version optional

Signed-off-by: Martin Matous <m@matous.dev>
This commit is contained in:
Martin Matous 2025-03-17 15:08:58 +01:00
parent 584f0f913e
commit f2bc5e846d
Signed by: mmatous
GPG key ID: 8BED4CD352953224
2 changed files with 50 additions and 65 deletions

View file

@ -79,7 +79,11 @@ Status: active use
Dependencies: dracut, Gentoo (not really but eselect, specific names and paths...) Dependencies: dracut, Gentoo (not really but eselect, specific names and paths...)
Usage: `kernel-update.py update <old-version> <new-version>` This will update kernel using `/usr/src/linux/.config` to the latest installed `sys-kernel/gentoo-sources`.
Usage: `kernel-update.py`
Alt.: `kernel-update.py <old-version> <new-version>`
--- ---
@ -152,4 +156,4 @@ Status: one-off
Dependencies: pykeepass Dependencies: pykeepass
Usage: `try-luks-from-kdbx.py /path/to/kdbx /path/to/block-device` Usage: `try-luks-from-kdbx.py /path/to/kdbx /path/to/block-device`

View file

@ -1,14 +1,12 @@
#!/usr/bin/env python #!/usr/bin/env python3
import argparse import argparse
import os import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
from pathlib import Path from pathlib import Path
SRC_DIR = Path('/usr/src') SRC_DIR = Path('/usr/src')
BOOT_DIR = Path('/boot') BOOT_DIR = Path('/boot')
@ -16,56 +14,50 @@ BOOT_DIR = Path('/boot')
def update_config(old_dir: Path, new_dir: Path, make_cmd: list[str]) -> None: def update_config(old_dir: Path, new_dir: Path, make_cmd: list[str]) -> None:
if old_dir == new_dir: if old_dir == new_dir:
return return
old_config = old_dir/'.config' old_config = old_dir / '.config'
new_config = new_dir/'.config' new_config = new_dir / '.config'
while new_config.is_file(): while new_config.is_file():
response = input('New config present. Overwrite? [y/N]').strip().lower() response = input('New config present. Overwrite? [y/N]\n').strip().lower()
if response == 'y': if response == 'y':
break break
elif response == '' or response == 'n': elif response in ('', 'n'):
return return
else: else:
print("unrecognized option {}", response) print('unrecognized option {}', response)
print(f'Copying config from {old_config} to {new_config}') print(f'Copying config from {old_config} to {new_config}')
shutil.copy2(old_config, new_config) shutil.copy2(old_config, new_config)
print(f'Setting symlink to {new_dir}') print(f'Setting symlink to {new_dir}')
subprocess.run(['eselect', 'kernel', 'set', new_dir.name]) (SRC_DIR / 'linux').symlink_to(new_dir, target_is_directory=True)
print('Migrating config options') print('Migrating config options')
migrate = make_cmd + ['-C', new_dir.as_posix(), 'oldconfig'] migrate = [*make_cmd, '--directory', new_dir.as_posix(), 'oldconfig']
subprocess.run(migrate) subprocess.run(migrate, check=True)
menuconfig = make_cmd + ['-C', new_dir.as_posix(), 'menuconfig'] menuconfig = [*make_cmd, '--directory', new_dir.as_posix(), 'menuconfig']
while True: while True:
subprocess.run(menuconfig) subprocess.run(menuconfig, check=True)
response = input('Stop editing? [Y/n]').strip().lower() response = input('Stop editing? [Y/n]').strip().lower()
if response == '' or response == 'y': if response in ('', 'y'):
break break
elif response == 'n': elif response == 'n':
continue continue
else: else:
print("unrecognized option {}", response) print('unrecognized option {}', response)
def compile_kernel(new_dir: Path, make_cmd: list[str]) -> None: def compile_kernel(new_dir: Path, make_cmd: list[str]) -> None:
cc = make_cmd + ['-C', new_dir.as_posix()] cc = [*make_cmd, '--directory', new_dir.as_posix()]
subprocess.run(cc) subprocess.run(cc, check=True)
def install_kernel(kernel_dir: Path, make_cmd: list[str], kver: str) -> None: def install_kernel(kernel_dir: Path, make_cmd: list[str], kver: str) -> None:
install_modules = make_cmd + ['-C', kernel_dir.as_posix(), 'modules_install'] install_modules = [*make_cmd, '--directory', kernel_dir.as_posix(), 'modules_install']
subprocess.run(install_modules) subprocess.run(install_modules, check=True)
kver = kver[6:] # drop "linux-" prefix
kver = kver[6:] # assumes proper dracut config in /etc, incl. signing keys
# assumes proper dracut config in /etc
dracut = ['dracut', f'--kver={kver}', '--force', '--no-machineid'] dracut = ['dracut', f'--kver={kver}', '--force', '--no-machineid']
res = subprocess.run(dracut) res = subprocess.run(dracut, check=True)
print(res) print(res)
return
# todo: sign uki
uki_dir = res.split('')
sign_uki = ['sbctl', 'bundle', '--save', '']
subprocess.run(sign_uki)
def linux_folder(src_dir: Path, version: str) -> Path: def linux_folder(src_dir: Path, version: str) -> Path:
revision = '' revision = ''
@ -73,19 +65,19 @@ def linux_folder(src_dir: Path, version: str) -> Path:
if len(version) > 1: if len(version) > 1:
revision = '-' + version[1] revision = '-' + version[1]
version = version[0] version = version[0]
return (src_dir / (f'linux-{version}-gentoo{revision}')) return src_dir / (f'linux-{version}-gentoo{revision}')
def update_kernel(boot_dir: Path, args: argparse.Namespace) -> None: def update_kernel(args: argparse.Namespace) -> None:
old_dir = linux_folder(SRC_DIR, args.old_version) old_dir = linux_folder(SRC_DIR, args.old_version)
new_dir = linux_folder(SRC_DIR, args.new_version) new_dir = linux_folder(SRC_DIR, args.new_version)
new_version = new_dir.name new_version = new_dir.name
make_cmd = ['make', f'-j{len(os.sched_getaffinity(0))}'] make_cmd = ['make', f'--jobs={len(os.sched_getaffinity(0))}']
# https://docs.kernel.org/kbuild/llvm.html
if args.llvm: if args.llvm:
# https://docs.kernel.org/kbuild/llvm.html
make_cmd.extend(['LLVM=1']) make_cmd.extend(['LLVM=1'])
none_selected = not (args.backup or args.config or args.compile or args.install or args.rollback) none_selected = not any((args.config, args.compile, args.install))
if none_selected: if none_selected:
update_config(old_dir, new_dir, make_cmd) update_config(old_dir, new_dir, make_cmd)
compile_kernel(new_dir, make_cmd) compile_kernel(new_dir, make_cmd)
@ -97,38 +89,27 @@ def update_kernel(boot_dir: Path, args: argparse.Namespace) -> None:
if args.install: if args.install:
install_kernel(new_dir, make_cmd, new_version) install_kernel(new_dir, make_cmd, new_version)
def main() -> None:
parser = argparse.ArgumentParser(description='Convenience for manual kernel updates')
subparsers = parser.add_subparsers()
update = subparsers.add_parser('update', def main() -> None:
usage=f'{sys.argv[0]} update 5.15.12 5.16.3', parser = argparse.ArgumentParser(description='Helper for manual kernel updates', usage=f'{sys.argv[0]}')
) parser.add_argument('--llvm', '-l', action='store_true', help='Use clang/llvm to compile kernel')
update.add_argument( parser.add_argument('--config', '-C', action='store_true', help='Migrate config from old kernel')
'--llvm', '-l', action='store_true', parser.add_argument('--compile', '-c', action='store_true', help='Compile new kernel')
help="Use clang/llvm to compile kernel") parser.add_argument('--install', '-i', action='store_true', help='Install new kernel')
update.add_argument( parser.add_argument('old_version', help='Old kernel version (optional)', nargs='?', default=None)
'--backup', '-b', action='store_true', parser.add_argument('new_version', help='New kernel version (optional)', nargs='?', default=None)
help="Backup old kernel files as .old")
update.add_argument(
'--rollback', '-r', action='store_true',
help='Restore .old kernel files as main boot choice')
update.add_argument(
'--config', '-C', action='store_true',
help='Migrate config from old kernel')
update.add_argument(
'--compile', '-c', action='store_true',
help='Compile new kernel')
update.add_argument(
'--install', '-i', action='store_true',
help='Install new kernel')
update.add_argument('old_version', help='Old kernel version')
update.add_argument('new_version', help='New kernel version')
update.set_defaults(func=update_kernel)
args = parser.parse_args() args = parser.parse_args()
args.func(BOOT_DIR, args) if args.old_version and not args.new_version:
args.new_version = args.old_version
args.old_version = None
if not args.old_version:
args.old_version = (SRC_DIR / 'linux').readlink().name.split('-')[1]
if not args.new_version:
subdirs = Path(SRC_DIR).glob('linux-*-gentoo*') # too broad but good enough, blame fnmatch
args.new_version = sorted(subdir.name for subdir in subdirs if subdir.is_dir())[-1].split('-')[1]
update_kernel(args)
if __name__ == "__main__": if __name__ == '__main__':
main() main()