From b9884e7b4f775a74fc121ee112d5696640573665 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 30 Jan 2026 19:49:06 +0100 Subject: [PATCH 1/3] kmod: Don't insist on kernel images being suffixed with - Since we don't require the version to be in the kernel image filename anymore, let's not insist on the - anymore. --- mkosi/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 7ba9cacb18..69cb17e9a9 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -1395,7 +1395,11 @@ def fixup_vmlinuz_location(context: Context) -> None: # Some architectures ship an uncompressed vmlinux (ppc64el, riscv64) for type in ("vmlinuz", "vmlinux"): - for d in context.root.glob(f"boot/{type}-*"): + todo = [*context.root.glob(f"boot/{type}-*")] + if (p := context.root / "boot" / type).exists(): + todo += [p] + + for d in todo: if d.is_symlink(): continue From dce8b65dfd0c7f90226c9261d1bca64d04c813e6 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 4 Feb 2026 11:27:13 +0100 Subject: [PATCH 2/3] run: Always bind-mount non-canonical directories in / In weird CI setups or such, there might be stuff in non-canonical directories in /. This stuff only has a minimal chance to affect the image build accidentally, so let's mount them in by default in case the image build actually does need to look up stuff in these directories. --- mkosi/run.py | 61 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/mkosi/run.py b/mkosi/run.py index 786b0ad10e..311a624707 100644 --- a/mkosi/run.py +++ b/mkosi/run.py @@ -652,24 +652,51 @@ def sandbox_cmd( elif p.is_dir(): cmdline += ["--ro-bind", p, Path("/") / p.relative_to(tools)] + # Always bind mount in everything that isn't a well-known directory. We assume that not mounting + # these in has a higher chance of causing issues than mounting these in. + for p in Path("/").iterdir(): + if p not in ( + Path("/bin"), + Path("/boot"), + Path("/dev"), + Path("/etc"), + Path("/home"), + Path("/lib"), + Path("/lib32"), + Path("/lib64"), + Path("/nix"), + Path("/opt"), + Path("/proc"), + Path("/root"), + Path("/run"), + Path("/sbin"), + Path("/srv"), + Path("/sys"), + Path("/tmp"), + Path("/usr"), + Path("/var"), + ): + if p.is_symlink(): + cmdline += ["--symlink", p.readlink(), p] + else: + cmdline += ["--bind", p, p] + if relaxed: - for p in Path("/").iterdir(): - if p not in ( - Path("/proc"), - Path("/usr"), - Path("/opt"), - Path("/nix"), - Path("/bin"), - Path("/sbin"), - Path("/lib"), - Path("/lib32"), - Path("/lib64"), - Path("/etc"), - ): - if p.is_symlink(): - cmdline += ["--symlink", p.readlink(), p] - else: - cmdline += ["--bind", p, p] + for p in ( + Path("/boot"), + Path("/dev"), + Path("/home"), + Path("/root"), + Path("/run"), + Path("/srv"), + Path("/sys"), + Path("/tmp"), + Path("/var"), + ): + if p.is_symlink(): + cmdline += ["--symlink", p.readlink(), p] + elif p.exists(): + cmdline += ["--bind", p, p] cmdline += ["--ro-bind", tools / "etc", "/etc"] From 6744421f9ab2e49c58e96df76fb5860ffe63202b Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 4 Feb 2026 11:30:55 +0100 Subject: [PATCH 3/3] Add BuildStream support The GnomeOS folks are looking into mkosi to build their images instead of BuildStream. While BuildStream will still take care of providing the rootfs tree, mkosi would take over the responsibility of packaging that directory tree into a disk image. Let's add support for BuildStream to mkosi to make this possible. Unlike the other supported distributions, BuildStream is not intended to be consumed by installing individual packages. Instead, BuildStream elements should be exposed which provide the full rootfs that should go into the image. That's why we limit the number of packages that can be specified to a single one, which should always provide all contents that should go into the image. --- mkosi/distribution/__init__.py | 1 + mkosi/distribution/buildstream.py | 61 ++++++++++++++++ mkosi/installer/bst.py | 73 +++++++++++++++++++ mkosi/resources/man/mkosi.1.md | 7 +- .../mkosi.conf.d/buildstream.conf | 9 +++ .../mkosi-initrd/mkosi.conf.d/stub.conf | 1 + .../mkosi-tools/mkosi.conf.d/buildstream.conf | 9 +++ 7 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 mkosi/distribution/buildstream.py create mode 100644 mkosi/installer/bst.py create mode 100644 mkosi/resources/mkosi-initrd/mkosi.conf.d/buildstream.conf create mode 100644 mkosi/resources/mkosi-tools/mkosi.conf.d/buildstream.conf diff --git a/mkosi/distribution/__init__.py b/mkosi/distribution/__init__.py index 5d42b8f5b3..ac7cc3862c 100644 --- a/mkosi/distribution/__init__.py +++ b/mkosi/distribution/__init__.py @@ -42,6 +42,7 @@ class Distribution(StrEnum): rocky = enum.auto() alma = enum.auto() azure = enum.auto() + buildstream = enum.auto() custom = enum.auto() def is_centos_variant(self) -> bool: diff --git a/mkosi/distribution/buildstream.py b/mkosi/distribution/buildstream.py new file mode 100644 index 0000000000..6e02cc800a --- /dev/null +++ b/mkosi/distribution/buildstream.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from mkosi.config import Config +from mkosi.context import Context + +from mkosi.log import die +from mkosi.config import Architecture +from mkosi.installer.bst import BST +from mkosi.distribution import ( + Distribution, + DistributionInstaller, + PackageType, +) + +class Installer(DistributionInstaller, distribution=Distribution.buildstream): + @classmethod + def pretty_name(cls) -> str: + return "BuildStream" + + @classmethod + def filesystem(cls) -> str: + return "btrfs" + + @classmethod + def package_type(cls) -> PackageType: + return PackageType.none + + @classmethod + def default_release(cls) -> str: + return "snapshot" + + @classmethod + def package_manager(cls, config: "Config") -> type[BST]: + return BST + + @classmethod + def setup(cls, context: Context) -> None: + pass + + @classmethod + def install(cls, context: Context) -> None: + pass + + @classmethod + def architecture(cls, arch: Architecture) -> str: + a = { + Architecture.x86_64: "x86_64", + }.get(arch) # fmt: skip + + if not a: + die(f"Architecture {a} is not supported by {cls.pretty_name()}") + + return a + + @classmethod + def latest_snapshot(cls, config: Config) -> str: + die(f"Latest snapshot not supported by {cls.pretty_name()}") + + @classmethod + def is_kernel_package(cls, package: str) -> bool: + return False diff --git a/mkosi/installer/bst.py b/mkosi/installer/bst.py new file mode 100644 index 0000000000..8c7317dc3c --- /dev/null +++ b/mkosi/installer/bst.py @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +from collections.abc import Sequence +from pathlib import Path + +from mkosi.config import Config +from mkosi.context import Context +from mkosi.installer import PackageManager +from mkosi.run import run +from mkosi.log import die + + +class BST(PackageManager): + @classmethod + def executable(cls, config: Config) -> str: + return "bst" + + @classmethod + def subdir(cls, config: Config) -> Path: + return Path("bst") + + @classmethod + def architecture(cls, context: Context) -> str: + return context.config.distribution.installer.architecture(context.config.architecture) + + @classmethod + def setup(cls, context: Context) -> None: + if len(context.config.packages) > 1: + die("Only a single element can be specified in Packages= when using bst") + + @classmethod + def install( + cls, + context: Context, + packages: Sequence[str], + *, + apivfs: bool = True, + allow_downgrade: bool = False, + ) -> None: + options = [ + "--same-dir", + *context.rootoptions(), + # bst might need to lookup files/paths across the user's home directory so make sure it is + # available. + "--bind", Path.home(), Path.home(), + "--setenv", "HOME", Path.home(), + ] + + # We don't really want to run bst as (fake) root but it uses bubblewrap which stubbornly refuses to + # run when invoked unprivileged but with capabilities. We get around this by running as fake root but + # still setting $HOME to the user's home to reuse the buildstream cache directory. + run( + ["bst", "build", *packages], + sandbox=cls.sandbox(context, apivfs=apivfs, options=options), + env=cls.finalize_environment(context), + ) + run( + ["bst", "artifact", "checkout", "--force", "--directory=/buildroot", *packages], + sandbox=cls.sandbox(context, apivfs=apivfs, options=options), + env=cls.finalize_environment(context), + ) + + @classmethod + def remove(cls, context: Context, packages: Sequence[str]) -> None: + die("Removing packages is not supported for bst") + + @classmethod + def sync(cls, context: Context, force: bool) -> None: + pass + + @classmethod + def createrepo(cls, context: Context) -> None: + die("Creating package repositories is not supported for bst") diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index 99f683b211..4fd6759087 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -488,9 +488,9 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : The distribution to install in the image. Takes one of the following arguments: `fedora`, `debian`, `kali`, `ubuntu`, `arch`, `opensuse`, `mageia`, `centos`, `rhel`, `rhel-ubi`, `openmandriva`, `rocky`, `alma`, - `azure` or `custom`. If not specified, defaults to the distribution of - the host or `custom` if the distribution of the host is not a supported - distribution. + `azure`, `buildstream` or `custom`. If not specified, defaults to the + distribution of the host or `custom` if the distribution of the host is + not a supported distribution. `Release=`, `--release=`, `-r` : The release of the distribution to install in the image. The precise @@ -536,6 +536,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, | `mageia` | https://www.mageia.org | | | `openmandriva` | http://mirrors.openmandriva.org | | | `azure` | https://packages.microsoft.com/ | | + | `buildstream` | | | `Snapshot=` : Download packages from the given snapshot instead of downloading the latest diff --git a/mkosi/resources/mkosi-initrd/mkosi.conf.d/buildstream.conf b/mkosi/resources/mkosi-initrd/mkosi.conf.d/buildstream.conf new file mode 100644 index 0000000000..1e76355e02 --- /dev/null +++ b/mkosi/resources/mkosi-initrd/mkosi.conf.d/buildstream.conf @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Match] +Distribution=buildstream + +[Content] +# BuildStream is a generic distribution so we don't know which package to install, hence override to the +# empty list. +Packages= diff --git a/mkosi/resources/mkosi-initrd/mkosi.conf.d/stub.conf b/mkosi/resources/mkosi-initrd/mkosi.conf.d/stub.conf index 42b6b04781..21dce3ccf0 100644 --- a/mkosi/resources/mkosi-initrd/mkosi.conf.d/stub.conf +++ b/mkosi/resources/mkosi-initrd/mkosi.conf.d/stub.conf @@ -3,6 +3,7 @@ [Match] Format=uki Distribution=!arch +Distribution=!buildstream [Content] Packages=systemd-boot diff --git a/mkosi/resources/mkosi-tools/mkosi.conf.d/buildstream.conf b/mkosi/resources/mkosi-tools/mkosi.conf.d/buildstream.conf new file mode 100644 index 0000000000..1e76355e02 --- /dev/null +++ b/mkosi/resources/mkosi-tools/mkosi.conf.d/buildstream.conf @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[Match] +Distribution=buildstream + +[Content] +# BuildStream is a generic distribution so we don't know which package to install, hence override to the +# empty list. +Packages=