]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Add back --bootable option
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 17 Apr 2023 20:14:43 +0000 (22:14 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 18 Apr 2023 11:50:45 +0000 (13:50 +0200)
There are valid scenarios where one might want to install a kernel
without wanting a bootable image, so let's add back the --bootable=
option as a feature option. It defaults to "auto" which is the current
behavior, but can also be explicitly enabled or disabled. If enabled,
we'll fail if we can't produce a bootable image. If disabled, we won't
generate a bootable image even if all the necessary components are
available.

NEWS.md
mkosi.md
mkosi/__init__.py
mkosi/backend.py
mkosi/config.py

diff --git a/NEWS.md b/NEWS.md
index bd0e4b689f224695aa160c34ea52f1ac57aabee9..a48d49de524187ce5bd197d11cecd20e93bb99d1 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
@@ -68,9 +68,9 @@
 - Removed `--qcow2` option in favor of supporting only raw disk images as the disk image output format.
 - Removed `--bmap` option as it can be trivially added manually by utilizing a finalize script.
 - The `never` value for `--with-network` was spun of into its own custom option `--cache-only`.
-- Removed `--bootable` in favor of automatically generating a bootable image if all the necessary packages
-  are installed. Documentation was added in docs/bootable.ld on how a bootable image can be generated on
-  mainstream distros.
+- `--bootable` now defaults to `auto`. When set to `auto`, mkosi will generate a bootable image only if all
+  the necessary packages are installed. Documentation was added in docs/bootable.md on how a bootable image
+  can be generated on mainstream distros.
 - The RPM db is no longer rebuilt in bdb format on CentOS Stream 8. To be able to install packages on a
   CentOS Stream 8 image with a RPM db in sqlite format, rewrite the db in bdb format using
   `rpm --rebuilddb --define _db_backend bdb`.
index bc26f197b80ec3e0c1cdbce5aa1712df93f992a5..739177b3690ea1ec547609ab50d0d44bce6777a7 100644 (file)
--- a/mkosi.md
+++ b/mkosi.md
@@ -369,6 +369,19 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0",
 
   <!--  FIXME: allow `Force=<n>` -->
 
+`Bootable=`, `--bootable=`
+
+: Takes a boolean or `auto`. Enables or disable generating of a bootable
+  image. If enabled, mkosi will install systemd-boot, run kernel-install,
+  generate unified kernel images for installed kernels and add an ESP
+  partition when the disk image output is used. If systemd-boot is not
+  installed or no kernel images can be found, the build will fail. `auto`
+  behaves as if the option was enabled, but the build won't fail if either
+  no kernel images or systemd-boot can't be found. If disabled, systemd-boot
+  won't be installed even if found inside the image, kernel-install won't be
+  executed, no unified kernel images will be generated and no ESP partition
+  will be added to the image if the disk output format is used.
+
 `KernelCommandLine=`, `--kernel-command-line=`
 
 : Use the specified kernel command line when building images. By default
index f144ca6542efd1ea53ed628c53fd184eb74387aa..0541fe45cf163c540b0a0df88a1c5f6793b1d754 100644 (file)
@@ -463,11 +463,17 @@ def run_finalize_script(state: MkosiState) -> None:
 
 
 def install_boot_loader(state: MkosiState) -> None:
-    if state.for_cache:
+    if state.for_cache or state.config.bootable is False:
+        return
+
+    if state.config.output_format == OutputFormat.cpio and state.config.bootable is None:
         return
 
     directory = state.root / "usr/lib/systemd/boot/efi"
-    if not directory.exists():
+    if not directory.exists() or not any(directory.iterdir()):
+        if state.config.bootable is True:
+            die("A bootable image was requested but systemd-boot was not found at "
+                f"{directory.relative_to(state.root)}")
         return
 
     if state.config.secure_boot:
@@ -712,12 +718,14 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None:
     # benefit that they can be signed like normal EFI binaries, and can encode everything necessary to boot a
     # specific root device, including the root hash.
 
-    # The roothash is specific to the final image so we cannot cache this step.
-    if state.for_cache:
+    if state.for_cache or state.config.bootable is False:
         return
 
-    with complete_step("Generating combined kernel + initrd boot file…"):
-        for kver, kimg in gen_kernel_images(state):
+    if state.config.output_format == OutputFormat.cpio and state.config.bootable is None:
+        return
+
+    for kver, kimg in gen_kernel_images(state):
+        with complete_step(f"Generating unified kernel image for {kimg}"):
             image_id = state.config.image_id or f"mkosi-{state.config.distribution}"
 
             # See https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/#boot-counting
@@ -791,9 +799,12 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None:
 
             run(cmd)
 
-            if not state.staging.joinpath(state.staging / state.config.output_split_kernel.name).exists():
+            if not state.staging.joinpath(state.config.output_split_kernel.name).exists():
                 copy_path(boot_binary, state.staging / state.config.output_split_kernel.name)
 
+    if state.config.bootable is True and not state.staging.joinpath(state.config.output_split_kernel.name).exists():
+        die("A bootable image was requested but no kernel was found")
+
 
 def compress_output(config: MkosiConfig, src: Path, uid: int, gid: int) -> None:
     compress = should_compress_output(config)
@@ -1600,6 +1611,9 @@ def run_kernel_install(state: MkosiState, cached: bool) -> None:
     if state.config.initrds:
         return
 
+    if state.config.bootable is False:
+        return
+
     # CentOS Stream 8 has an old version of kernel-install that unconditionally writes initrds to
     # /boot/<machine-id>/<kver>, so let's detect that and move them to the correct location.
 
@@ -1720,8 +1734,14 @@ def invoke_repart(state: MkosiState, skip: Sequence[str] = [], split: bool = Fal
             definitions.mkdir()
             bootdir = state.root.joinpath("boot/EFI/BOOT")
 
-            if bootdir.exists() and any(bootdir.iterdir()) and any(gen_kernel_images(state)):
-                # If we have at least one kernel images and a bootloader, let's generate an ESP partition.
+            # If Bootable=auto and we have at least one UKI and a bootloader, let's generate an ESP partition.
+            add = (state.config.bootable is True or
+                  (state.config.bootable is None and
+                   bootdir.exists() and
+                   any(bootdir.iterdir()) and
+                   any(gen_kernel_images(state))))
+
+            if add:
                 definitions.joinpath("00-esp.conf").write_text(
                     dedent(
                         """\
index 24cc4910c2d1449edad3b465a9bd6a1e84576176..8f5c1adb4ce0f960d1fb5355a48bc265f21bf32a 100644 (file)
@@ -269,6 +269,7 @@ class MkosiConfig:
     kernel_command_line_extra: list[str]
     acl: bool
     pager: bool
+    bootable: Optional[bool]
 
     # QEMU-specific options
     qemu_gui: bool
index 4233d1c06c2995cd73f1ad567b83f4a1317a755c..68761d78448d647e6c9cc6770b4d8d7632fa7be1 100644 (file)
@@ -498,6 +498,11 @@ class MkosiConfigParser:
             parse=config_parse_boolean,
             default=True,
         ),
+        MkosiConfigSetting(
+            dest="bootable",
+            section="Content",
+            parse=config_parse_feature,
+        ),
         MkosiConfigSetting(
             dest="password",
             section="Content",
@@ -1066,7 +1071,12 @@ class MkosiConfigParser:
             dest="with_tests",
             action=action,
         )
-
+        group.add_argument(
+            "--bootable",
+            metavar="FEATURE",
+            help="Generate ESP partition with systemd-boot and UKIs for installed kernels",
+            action=action,
+        )
         group.add_argument("--password", help="Set the root password", action=action)
         group.add_argument(
             "--password-is-hashed",