From: Laurence Kiln <246209442+LaurenceKiln@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:00:55 +0000 (+0200) Subject: Allow KernelModules= globs to also match relative to modules root dir X-Git-Tag: v26~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=189394b8b981d00a610dcaedc4e73642ef45b009;p=thirdparty%2Fmkosi.git Allow KernelModules= globs to also match relative to modules root dir --- diff --git a/mkosi/kmod.py b/mkosi/kmod.py index dd5ae646c..17ba1762c 100644 --- a/mkosi/kmod.py +++ b/mkosi/kmod.py @@ -42,8 +42,10 @@ def globs_match_filename( glob += "*" if ( - # match the full path - (glob.startswith("/") and fnmatch.fnmatch(f"/{name}", glob)) + # Match globs starting with / relative to kernel/ first, since in-tree module are the common case + (glob.startswith("/") and fnmatch.fnmatch(f"/{name}", f"/kernel{glob}")) + # Now match absolute globs relative to lib/modules/KVER/ + or (glob.startswith("/") and fnmatch.fnmatch(f"/{name}", glob)) # match a subset of the path, at path element boundary or ("/" in glob and fnmatch.fnmatch(f"/{name}", f"*/{glob}")) # match the basename @@ -107,9 +109,13 @@ def filter_kernel_modules( globs = [normalize_module_glob(p) for p in include if not p.startswith("re:")] for m in modules: - rel = os.fspath(Path(*m.parts[5:])) + rel = os.fspath(m.relative_to(modulesd)) + # old regexes match relative to modulesd/subdir/ not modulesd/ + legacy_rel = os.fspath(Path(*m.parts[5:])) - if (patterns and regex.search(rel)) or globs_match_module(normalize_module_name(rel), globs): + if (patterns and regex.search(legacy_rel)) or globs_match_module( + normalize_module_name(rel), globs + ): keep.add(rel) if exclude: @@ -119,8 +125,11 @@ def filter_kernel_modules( remove = set() for m in modules: - rel = os.fspath(Path(*m.parts[5:])) - if rel not in keep and regex.search(rel): + rel = os.fspath(m.relative_to(modulesd)) + # old regexes match relative to modulesd/subdir/ not modulesd/ + legacy_rel = os.fspath(Path(*m.parts[5:])) + + if rel not in keep and regex.search(legacy_rel): remove.add(m) modules -= remove @@ -145,6 +154,8 @@ def filter_firmware( if exclude: logging.debug(f"Firmware exclude: {' '.join(exclude)}") + firmwared = Path("usr/lib/firmware") + # globs can be also used to exclude firmware, so we we need to apply them # to the inherited list of firmware files too. globs = [p for p in include if not p.startswith("re:")] @@ -156,14 +167,13 @@ def filter_firmware( regex = re.compile("|".join(patterns)) for f in firmware: - rel = os.fspath(Path(*f.parts[3:])) + rel = os.fspath(f.relative_to(firmwared)) if (patterns and regex.search(rel)) or not globs_match_firmware(rel, globs, match_default=True): remove.add(f) firmware -= remove if include: - firmwared = Path("usr/lib/firmware") with chdir(root): all_firmware = {p for p in firmwared.rglob("*") if p.is_file() or p.is_symlink()} @@ -171,7 +181,7 @@ def filter_firmware( regex = re.compile("|".join(patterns)) for f in all_firmware: - rel = os.fspath(Path(*f.parts[3:])) + rel = os.fspath(f.relative_to(firmwared)) if (patterns and regex.search(rel)) or globs_match_firmware(rel, globs): firmware.add(f) diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index cdcec7fd0..f52c42747 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -1168,15 +1168,29 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, The modules that were last matched by a positive pattern are included in the image, as well as their module and firmware dependencies. - The module paths are taken relative to the `/usr/lib/modules///kernel/` directory, - and the `.ko` suffix and compression suffix are ignored during matching. - The patterns may include just the basename (e.g. `loop`), + The `.ko` suffix and compression suffix are ignored during matching. + + Globs are matched against module paths relative to `/usr/lib/module/`, + e.g. the module at `/usr/lib/module//kernel/foo/bar.ko.xz` + becomes `kernel/foo/bar` for matching purposes. + + Globs beginning with "/" are treated specially. The glob is *first* matched + against a path relative to `/usr/lib/module//kernel`, and only then against + `/usr/lib/module//`. This is a convenience, since usually only the in-tree + modules under `kernel/` are of interest. + + For example, the module at`/usr/lib/module//kernel/foo/bar.ko.xz` + can be matched by either `/foo/bar` or `/kernel/foo/bar`. + + The glob patterns may include just the basename (e.g. `loop`), which must match the basename of the module, the relative path (e.g. `block/loop`), which must match the final components of the module path up to the basename, or an absolute path (e.g. `/drivers/block/loop`), which must match the full path to the module. + When suffixed with `/`, the pattern will match all modules underneath that directory. + The patterns may include shell-style globs (`*`, `?`, `[…-…]`). If the special value `default` is used, the default kernel modules diff --git a/tests/test_kmod.py b/tests/test_kmod.py index c7e127d47..e8f2a5e4b 100644 --- a/tests/test_kmod.py +++ b/tests/test_kmod.py @@ -40,6 +40,15 @@ def test_globs_match_module() -> None: assert not kmod.globs_match_module("drivers/ata/ahci.ko.zst", ["-*"]) assert not kmod.globs_match_module("drivers/ata/ahci.ko.xz", ["-*"]) + # absolute glob behavior unchanged when paths are relative to /lib/module/ + assert kmod.globs_match_module("kernel/drivers/ata/ahci.ko", ["drivers/*"]) + assert kmod.globs_match_module("kernel/drivers/ata/ahci.ko", ["/drivers/*"]) + assert not kmod.globs_match_module("kernel/drivers/ata/ahci.ko.xz", ["/ata/*"]) + + # absolute globs match both relative to kernel/ and module_dir root + assert kmod.globs_match_module("kernel/drivers/ata/ahci.ko.xz", ["/drivers/ata/ahci"]) + assert kmod.globs_match_module("kernel/drivers/ata/ahci.ko.xz", ["/kernel/drivers/ata/ahci"]) + def test_normalize_module_glob() -> None: assert kmod.normalize_module_glob("raid[0-9]") == "raid[0-9]"