]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Allow KernelModules= globs to also match relative to modules root dir
authorLaurence Kiln <246209442+LaurenceKiln@users.noreply.github.com>
Mon, 8 Dec 2025 11:00:55 +0000 (13:00 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 15 Dec 2025 19:16:23 +0000 (20:16 +0100)
mkosi/kmod.py
mkosi/resources/man/mkosi.1.md
tests/test_kmod.py

index dd5ae646cedc123226445f76fa3689be98eb5527..17ba1762ccd661ab05b57ad710caad133471690f 100644 (file)
@@ -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)
 
index cdcec7fd02b44d55306b341fb90e02abc07d6807..f52c427477f4ce6843d515212814b45094dec769 100644 (file)
@@ -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/<kver>/<subdir>/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/<kver>`,
+    e.g. the module at `/usr/lib/module/<kver>/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/<kver>/kernel`, and only then against
+    `/usr/lib/module/<kver>/`. This is a convenience, since usually only the in-tree
+    modules under `kernel/` are of interest.
+
+    For example, the module at`/usr/lib/module/<kver>/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
index c7e127d4702163b4272774fbac7f262d663cdd94..e8f2a5e4b4443f96dadbbe9dccdc67a32cc29814 100644 (file)
@@ -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/<kver>
+    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]"