diff --git a/Containerfile b/Containerfile index 6069e31..3b0722c 100644 --- a/Containerfile +++ b/Containerfile @@ -4,11 +4,11 @@ COPY ./packages /packages FROM cgr.dev/chainguard/wolfi-base AS builder -RUN --mount=type=bind,from=ctx,source=/packages,target=/repo \ - apk add --allow-untrusted \ - -X /repo \ - -X https://packages.wolfi.dev/os \ - -U --initdb -p /mnt \ +RUN --mount=type=bind,from=ctx,source=/packages,target=/repo < -Date: Wed, 20 Aug 2025 17:09:23 +0100 -Subject: [PATCH] feat: support systemd-boot via config and build flag - ---- - Cargo.toml | 13 +++++++- - src/bootupd.rs | 62 +++++++++++++++++++++++++++++++++++---- - src/cli/bootupd.rs | 21 +++++++++++-- - src/efi.rs | 20 +++++++++++-- - src/main.rs | 2 ++ - src/systemdbootconfigs.rs | 42 ++++++++++++++++++++++++++ - 6 files changed, 149 insertions(+), 11 deletions(-) - create mode 100644 src/systemdbootconfigs.rs - -diff --git a/Cargo.toml b/Cargo.toml -index c3208f8..02b53c2 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -15,6 +15,10 @@ include = ["src", "LICENSE", "Makefile", "systemd"] - platforms = ["*-unknown-linux-gnu"] - tier = "2" - -+[features] -+default = [] -+systemd-boot = [] -+ - [[bin]] - name = "bootupd" - path = "src/main.rs" -@@ -27,7 +31,14 @@ bootc-internal-utils = "0.0.0" - cap-std-ext = "4.0.6" - camino = "1.1.11" - chrono = { version = "0.4.41", features = ["serde"] } --clap = { version = "4.5", default-features = false, features = ["cargo", "derive", "std", "help", "usage", "suggestions"] } -+clap = { version = "4.5", default-features = false, features = [ -+ "cargo", -+ "derive", -+ "std", -+ "help", -+ "usage", -+ "suggestions", -+] } - env_logger = "0.11" - fail = { version = "0.5", features = ["failpoints"] } - fn-error-context = "0.2.1" -diff --git a/src/bootupd.rs b/src/bootupd.rs -index 131548b..9ac7167 100644 ---- a/src/bootupd.rs -+++ b/src/bootupd.rs -@@ -25,6 +25,14 @@ use std::fs::{self, File}; - use std::io::{BufRead, BufReader, BufWriter, Write}; - use std::path::{Path, PathBuf}; - -+#[derive(Debug, Clone, Copy, PartialEq, Eq)] -+// TODO: Implement dynamic bootloader detection -+pub(crate) enum Bootloader { -+ _Auto, -+ Grub, -+ SystemdBoot, -+} -+ - pub(crate) enum ConfigMode { - None, - Static, -@@ -46,9 +54,10 @@ pub(crate) fn install( - dest_root: &str, - device: Option<&str>, - configs: ConfigMode, -- update_firmware: bool, -+ mut update_firmware: bool, - target_components: Option<&[String]>, - auto_components: bool, -+ bootloader: Bootloader, - ) -> Result<()> { - // TODO: Change this to an Option<&str>; though this probably balloons into having - // DeviceComponent and FileBasedComponent -@@ -93,15 +102,34 @@ pub(crate) fn install( - continue; - } - -+ // skip for BIOS if systemd-boot -+ if component.name() == "BIOS" && bootloader == Bootloader::SystemdBoot { -+ println!( -+ "Skip installing component {} for systemd-boot", -+ component.name() -+ ); -+ continue; -+ } -+ -+ if bootloader == Bootloader::SystemdBoot { -+ log::warn!( -+ "Disabling firmware updates for component {}", -+ component.name() -+ ); -+ update_firmware = false; -+ } - let meta = component - .install(&source_root, dest_root, device, update_firmware) - .with_context(|| format!("installing component {}", component.name()))?; - log::info!("Installed {} {}", component.name(), meta.meta.version); - state.installed.insert(component.name().into(), meta); -- // Yes this is a hack...the Component thing just turns out to be too generic. -- if let Some(vendor) = component.get_efi_vendor(&source_root)? { -- assert!(installed_efi_vendor.is_none()); -- installed_efi_vendor = Some(vendor); -+ -+ if bootloader != Bootloader::SystemdBoot { -+ // Yes this is a hack...the Component thing just turns out to be too generic. -+ if let Some(vendor) = component.get_efi_vendor(&source_root)? { -+ assert!(installed_efi_vendor.is_none()); -+ installed_efi_vendor = Some(vendor); -+ } - } - } - let sysroot = &openat::Dir::open(dest_root)?; -@@ -116,10 +144,32 @@ pub(crate) fn install( - target_arch = "powerpc64", - target_arch = "riscv64" - ))] -+ log::warn!("Configuring grub2 with uuid {uuid}"); - crate::grubconfigs::install(sysroot, installed_efi_vendor.as_deref(), uuid)?; - // On other architectures, assume that there's nothing to do. - } -- None => {} -+ None => { -+ log::info!("Skipping static config generation"); -+ } -+ } -+ -+ // Configure systemd-boot -+ // #[cfg(feature = "systemd-boot")] -+ if bootloader == Bootloader::SystemdBoot { -+ let efi = crate::efi::Efi::default(); -+ log::info!("Installing systemd-boot"); -+ // Use dest_root/boot as the root for ESP detection, matching conventions elsewhere -+ let boot_root = Path::new(dest_root).join("boot"); -+ let esp_device = crate::blockdev::get_esp_partition(device)? -+ .ok_or_else(|| anyhow!("No ESP device found"))?; -+ let mnt = efi.ensure_mounted_esp(&boot_root, Path::new(&esp_device))?; -+ let esp_dir = openat::Dir::open(&mnt).context("Opening mounted ESP directory")?; -+ crate::systemdbootconfigs::install(&esp_dir)?; -+ } else { -+ anyhow::bail!( -+ "Failed to find mounted ESP for systemd-boot installation in {:?}.", -+ Path::new(dest_root).join("boot") -+ ); - } - - // Unmount the ESP, etc. -diff --git a/src/cli/bootupd.rs b/src/cli/bootupd.rs -index 4a6b8cf..fe21ba4 100644 ---- a/src/cli/bootupd.rs -+++ b/src/cli/bootupd.rs -@@ -1,4 +1,4 @@ --use crate::bootupd::{self, ConfigMode}; -+use crate::bootupd::{self, Bootloader, ConfigMode}; - use anyhow::{Context, Result}; - use clap::Parser; - use log::LevelFilter; -@@ -73,6 +73,12 @@ pub struct InstallOpts { - /// then only enable installation to the ESP. - #[clap(long)] - auto: bool, -+ -+ /// The bootloader to configure -+ /// -+ /// Defaults to Grub -+ #[clap(long, default_value = "grub")] -+ bootloader: String, - } - - #[derive(Debug, Parser)] -@@ -103,13 +109,23 @@ impl DCommand { - - /// Runner for `install` verb. - pub(crate) fn run_install(opts: InstallOpts) -> Result<()> { -- let configmode = if opts.write_uuid { -+ let bootloader = match opts.bootloader.as_str() { -+ "grub" => Bootloader::Grub, -+ "systemd-boot" => Bootloader::SystemdBoot, -+ _ => anyhow::bail!("Unknown bootloader: {}", opts.bootloader), -+ }; -+ -+ // If systemd-boot, always use ConfigMode::None -+ let configmode = if let Bootloader::SystemdBoot = bootloader { -+ ConfigMode::None -+ } else if opts.write_uuid { - ConfigMode::WithUUID - } else if opts.with_static_configs { - ConfigMode::Static - } else { - ConfigMode::None - }; -+ - bootupd::install( - &opts.src_root, - &opts.dest_root, -@@ -118,6 +134,7 @@ impl DCommand { - opts.update_firmware, - opts.components.as_deref(), - opts.auto, -+ bootloader, - ) - .context("boot data installation failed")?; - Ok(()) -diff --git a/src/efi.rs b/src/efi.rs -index 61de605..41352c5 100644 ---- a/src/efi.rs -+++ b/src/efi.rs -@@ -273,6 +273,7 @@ impl Component for Efi { - .context("Failed to backup GRUB config")?; - } - -+ log::warn!("Replacing grub.cfg in /boot/efi/EFI/{vendor} with static grub.cfg"); - grubconfigs::install(&sysroot, Some(&vendor), true)?; - // Synchronize the filesystem containing /boot/efi/EFI/{vendor} to disk. - fsfreeze_thaw_cycle(efidir.open_file(".")?)?; -@@ -343,8 +344,23 @@ impl Component for Efi { - device: &str, - update_firmware: bool, - ) -> Result { -- let Some(meta) = get_component_update(src_root, self)? else { -- anyhow::bail!("No update metadata for component {} found", self.name()); -+ let meta = match get_component_update(src_root, self)? { -+ Some(meta) => meta, -+ None => { -+ log::debug!( -+ "No update metadata for component {} found, continuing (systemd-boot case)", -+ self.name() -+ ); -+ // You may want to return a default InstalledContent or handle this case differently. -+ return Ok(InstalledContent { -+ meta: ContentMetadata { -+ timestamp: chrono::Utc::now(), -+ version: "systemd-boot".to_string(), -+ }, -+ filetree: None, -+ adopted_from: None, -+ }); -+ } - }; - log::debug!("Found metadata {}", meta.version); - let srcdir_name = component_updatedirname(self); -diff --git a/src/main.rs b/src/main.rs -index 5554366..c769a9e 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -46,6 +46,8 @@ mod model_legacy; - mod ostreeutil; - mod packagesystem; - mod sha512string; -+#[cfg(feature = "systemd-boot")] -+mod systemdbootconfigs; - mod util; - - use clap::crate_name; -diff --git a/src/systemdbootconfigs.rs b/src/systemdbootconfigs.rs -new file mode 100644 -index 0000000..a0bb7e8 ---- /dev/null -+++ b/src/systemdbootconfigs.rs -@@ -0,0 +1,42 @@ -+use std::path::Path; -+ -+use anyhow::{Context, Result}; -+use fn_error_context::context; -+ -+/// Install files required for systemd-boot -+#[context("Installing systemd-boot")] -+pub(crate) fn install(esp_path: &openat::Dir) -> Result<()> { -+ let esp_path = esp_path.recover_path().context("ESP path is not valid")?; -+ let status = std::process::Command::new("bootctl") -+ .args([ -+ "install", -+ "--esp-path", -+ esp_path.to_str().context("ESP path is not valid UTF-8")?, -+ ]) -+ .status() -+ .context("Failed to execute bootctl")?; -+ -+ if !status.success() { -+ anyhow::bail!( -+ "bootctl install failed with status code {}", -+ status.code().unwrap_or(-1) -+ ); -+ } -+ -+ // If loader.conf is present in the bootupd configuration, replace the original config with it -+ let src_loader_conf = "/usr/lib/bootupd/systemd-boot/loader.conf"; -+ let dst_loader_conf = Path::new(&esp_path).join("loader/loader.conf"); -+ if Path::new(src_loader_conf).exists() { -+ std::fs::copy(src_loader_conf, &dst_loader_conf) -+ .context("Failed to copy loader.conf to ESP")?; -+ log::info!( -+ "Copied {} to {}", -+ src_loader_conf, -+ dst_loader_conf.display() -+ ); -+ } else { -+ log::warn!("{} does not exist, skipping copy", src_loader_conf); -+ } -+ -+ Ok(()) -+} --- -2.50.1 diff --git a/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch b/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch deleted file mode 100644 index 385fbab..0000000 --- a/manifests/bootupd/0002-chore-move-logic-into-efi.rs.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 51e021993581d52a4ecdd5f531ec497d18da4058 Mon Sep 17 00:00:00 2001 -From: Robert Sturla -Date: Fri, 22 Aug 2025 10:09:04 +0100 -Subject: [PATCH 2/2] chore: move logic into efi.rs - ---- - Cargo.toml | 2 +- - src/bios.rs | 1 + - src/bootupd.rs | 21 +-------- - src/component.rs | 1 + - src/efi.rs | 111 +++++++++++++++++++++++++++-------------------- - 5 files changed, 68 insertions(+), 68 deletions(-) - -diff --git a/Cargo.toml b/Cargo.toml -index 02b53c2..6e1b162 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -16,7 +16,7 @@ platforms = ["*-unknown-linux-gnu"] - tier = "2" - - [features] --default = [] -+default = ["systemd-boot"] - systemd-boot = [] - - [[bin]] -diff --git a/src/bios.rs b/src/bios.rs -index 4b34c20..e84537d 100644 ---- a/src/bios.rs -+++ b/src/bios.rs -@@ -112,6 +112,7 @@ impl Component for Bios { - dest_root: &str, - device: &str, - _update_firmware: bool, -+ _bootloader: crate::bootupd::Bootloader, - ) -> Result { - let Some(meta) = get_component_update(src_root, self)? else { - anyhow::bail!("No update metadata for component {} found", self.name()); -diff --git a/src/bootupd.rs b/src/bootupd.rs -index 9ac7167..703edfd 100644 ---- a/src/bootupd.rs -+++ b/src/bootupd.rs -@@ -119,7 +119,7 @@ pub(crate) fn install( - update_firmware = false; - } - let meta = component -- .install(&source_root, dest_root, device, update_firmware) -+ .install(&source_root, dest_root, device, update_firmware, bootloader) - .with_context(|| format!("installing component {}", component.name()))?; - log::info!("Installed {} {}", component.name(), meta.meta.version); - state.installed.insert(component.name().into(), meta); -@@ -153,24 +153,7 @@ pub(crate) fn install( - } - } - -- // Configure systemd-boot -- // #[cfg(feature = "systemd-boot")] -- if bootloader == Bootloader::SystemdBoot { -- let efi = crate::efi::Efi::default(); -- log::info!("Installing systemd-boot"); -- // Use dest_root/boot as the root for ESP detection, matching conventions elsewhere -- let boot_root = Path::new(dest_root).join("boot"); -- let esp_device = crate::blockdev::get_esp_partition(device)? -- .ok_or_else(|| anyhow!("No ESP device found"))?; -- let mnt = efi.ensure_mounted_esp(&boot_root, Path::new(&esp_device))?; -- let esp_dir = openat::Dir::open(&mnt).context("Opening mounted ESP directory")?; -- crate::systemdbootconfigs::install(&esp_dir)?; -- } else { -- anyhow::bail!( -- "Failed to find mounted ESP for systemd-boot installation in {:?}.", -- Path::new(dest_root).join("boot") -- ); -- } -+ // Systemd-boot installation is now handled by the EFI component's install method. - - // Unmount the ESP, etc. - drop(target_components); -diff --git a/src/component.rs b/src/component.rs -index 5ca32df..37b38c6 100644 ---- a/src/component.rs -+++ b/src/component.rs -@@ -55,6 +55,7 @@ pub(crate) trait Component { - dest_root: &str, - device: &str, - update_firmware: bool, -+ bootloader: crate::bootupd::Bootloader, - ) -> Result; - - /// Implementation of `bootupd generate-update-metadata` for a given component. -diff --git a/src/efi.rs b/src/efi.rs -index 41352c5..f59f8fe 100644 ---- a/src/efi.rs -+++ b/src/efi.rs -@@ -343,66 +343,81 @@ impl Component for Efi { - dest_root: &str, - device: &str, - update_firmware: bool, -+ bootloader: crate::bootupd::Bootloader, - ) -> Result { -- let meta = match get_component_update(src_root, self)? { -- Some(meta) => meta, -- None => { -- log::debug!( -- "No update metadata for component {} found, continuing (systemd-boot case)", -- self.name() -- ); -- // You may want to return a default InstalledContent or handle this case differently. -- return Ok(InstalledContent { -+ let esp_path = self.get_mounted_esp(Path::new(dest_root))?.or_else(|| { -+ if device.is_empty() { -+ None -+ } else { -+ let esp_device = blockdev::get_esp_partition(device).ok().flatten()?; -+ self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device)) -+ .ok() -+ } -+ }); -+ -+ match bootloader { -+ crate::bootupd::Bootloader::SystemdBoot => { -+ log::info!("Installing systemd-boot via bootctl"); -+ let esp_dir = openat::Dir::open(esp_path.as_ref().ok_or_else(|| { -+ anyhow::anyhow!("No ESP mount found for systemd-boot install") -+ })?) -+ .context("Opening mounted ESP directory for systemd-boot")?; -+ crate::systemdbootconfigs::install(&esp_dir)?; -+ Ok(InstalledContent { - meta: ContentMetadata { - timestamp: chrono::Utc::now(), - version: "systemd-boot".to_string(), - }, - filetree: None, - adopted_from: None, -- }); -+ }) - } -- }; -- log::debug!("Found metadata {}", meta.version); -- let srcdir_name = component_updatedirname(self); -- let ft = crate::filetree::FileTree::new_from_dir(&src_root.sub_dir(&srcdir_name)?)?; -+ crate::bootupd::Bootloader::Grub | crate::bootupd::Bootloader::_Auto => { -+ let meta = match get_component_update(src_root, self)? { -+ Some(meta) => meta, -+ None => { -+ log::debug!( -+ "No update metadata for component {} found, continuing (GRUB case)", -+ self.name() -+ ); -+ return Ok(InstalledContent { -+ meta: ContentMetadata { -+ timestamp: chrono::Utc::now(), -+ version: "grub".to_string(), -+ }, -+ filetree: None, -+ adopted_from: None, -+ }); -+ } -+ }; -+ log::debug!("Found metadata {}", meta.version); -+ let srcdir_name = component_updatedirname(self); -+ let ft = crate::filetree::FileTree::new_from_dir(&src_root.sub_dir(&srcdir_name)?)?; - -- // Let's attempt to use an already mounted ESP at the target -- // dest_root if one is already mounted there in a known ESP location. -- let destpath = if let Some(destdir) = self.get_mounted_esp(Path::new(dest_root))? { -- destdir -- } else { -- // Using `blockdev` to find the partition instead of partlabel because -- // we know the target install toplevel device already. -- if device.is_empty() { -- anyhow::bail!("Device value not provided"); -- } -- let esp_device = blockdev::get_esp_partition(device)? -- .ok_or_else(|| anyhow::anyhow!("Failed to find ESP device"))?; -- self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device))? -- }; -+ let destpath = esp_path -+ .ok_or_else(|| anyhow::anyhow!("No ESP mount found for GRUB install"))?; -+ let destd = &openat::Dir::open(&destpath) -+ .with_context(|| format!("opening dest dir {}", destpath.display()))?; -+ validate_esp_fstype(destd)?; - -- let destd = &openat::Dir::open(&destpath) -- .with_context(|| format!("opening dest dir {}", destpath.display()))?; -- validate_esp_fstype(destd)?; -- -- // TODO - add some sort of API that allows directly setting the working -- // directory to a file descriptor. -- std::process::Command::new("cp") -- .args(["-rp", "--reflink=auto"]) -- .arg(&srcdir_name) -- .arg(destpath) -- .current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd())) -- .run()?; -- if update_firmware { -- if let Some(vendordir) = self.get_efi_vendor(&src_root)? { -- self.update_firmware(device, destd, &vendordir)? -+ std::process::Command::new("cp") -+ .args(["-rp", "--reflink=auto"]) -+ .arg(&srcdir_name) -+ .arg(&destpath) -+ .current_dir(format!("/proc/self/fd/{}", src_root.as_raw_fd())) -+ .run()?; -+ if update_firmware { -+ if let Some(vendordir) = self.get_efi_vendor(&src_root)? { -+ self.update_firmware(device, destd, &vendordir)? -+ } -+ } -+ Ok(InstalledContent { -+ meta, -+ filetree: Some(ft), -+ adopted_from: None, -+ }) - } - } -- Ok(InstalledContent { -- meta, -- filetree: Some(ft), -- adopted_from: None, -- }) - } - - fn run_update( --- -2.50.1 diff --git a/manifests/bootupd/systemd-boot.patch b/manifests/bootupd/systemd-boot.patch new file mode 100644 index 0000000..c5463f6 --- /dev/null +++ b/manifests/bootupd/systemd-boot.patch @@ -0,0 +1,426 @@ +From b63c79c6fef604884323dd8580a3499649daf00d Mon Sep 17 00:00:00 2001 +From: Robert Sturla +Date: Fri, 29 Aug 2025 22:52:00 +0100 +Subject: [PATCH] [PATCH] feat: add systemd-boot support + +Signed-off-by: Robert Sturla +Signed-off-by: RJ Sampson +--- + Cargo.toml | 19 ++++++--- + README.md | 7 +++- + build.rs | 9 ++++ + src/bios.rs | 1 + + src/bootupd.rs | 87 ++++++++++++++++++++++++++++++++++++--- + src/component.rs | 1 + + src/efi.rs | 45 +++++++++++++++----- + src/main.rs | 3 ++ + src/systemdbootconfigs.rs | 61 +++++++++++++++++++++++++++ + 9 files changed, 210 insertions(+), 23 deletions(-) + create mode 100644 build.rs + create mode 100644 src/systemdbootconfigs.rs + +diff --git a/Cargo.toml b/Cargo.toml +index 4d6fce7..29fb775 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -7,6 +7,7 @@ authors = ["Colin Walters "] + edition = "2021" + rust-version = "1.84.1" + homepage = "https://github.com/coreos/bootupd" ++build = "build.rs" + + include = ["src", "LICENSE", "Makefile", "systemd"] + +@@ -15,6 +16,11 @@ include = ["src", "LICENSE", "Makefile", "systemd"] + platforms = ["*-unknown-linux-gnu"] + tier = "2" + ++[features] ++default = [] ++rpm = ["rpm-rs"] ++systemd-boot = [] ++ + [[bin]] + name = "bootupd" + path = "src/main.rs" +@@ -27,7 +33,14 @@ bootc-internal-utils = "0.0.0" + cap-std-ext = "4.0.6" + camino = "1.2.0" + chrono = { version = "0.4.42", features = ["serde"] } +-clap = { version = "4.5", default-features = false, features = ["cargo", "derive", "std", "help", "usage", "suggestions"] } ++clap = { version = "4.5", default-features = false, features = [ ++ "cargo", ++ "derive", ++ "std", ++ "help", ++ "usage", ++ "suggestions", ++] } + env_logger = "0.11" + fail = { version = "0.5", features = ["failpoints"] } + fn-error-context = "0.2.1" +@@ -63,7 +76,3 @@ pre-release-commit-message = "cargo: bootupd release {{version}}" + sign-commit = true + sign-tag = true + tag-message = "bootupd {{version}}" +- +-[features] +-default = [] +-rpm = ["rpm-rs"] +diff --git a/README.md b/README.md +index 917fc66..29411a3 100644 +--- a/README.md ++++ b/README.md +@@ -34,6 +34,10 @@ that's for tools like `grubby` and `ostree`. + bootupd supports updating GRUB and shim for UEFI firmware on x86_64, aarch64, + and riscv64, and GRUB for BIOS firmware on x86_64 and ppc64le. + ++bootupd only supports installing the systemd-boot shim currently, though may be ++updated to also handle updates in future. systemd-boot support just proxies ++to the relevant `bootctl` commands. ++ + The project is used in Bootable Containers and ostree/rpm-ostree based systems: + - [`bootc install`](https://github.com/containers/bootc/#using-bootc-install) + - [Fedora CoreOS](https://docs.fedoraproject.org/en-US/fedora-coreos/bootloader-updates/) +@@ -78,7 +82,7 @@ care of GRUB and shim. See discussion in [this issue](https://github.com/coreos + ### systemd bootctl + + [systemd bootctl](https://man7.org/linux/man-pages/man1/bootctl.1.html) can update itself; +-this project would probably just proxy that if we detect systemd-boot is in use. ++this project just proxies that if we detect systemd-boot is present. + + ## Other goals + +@@ -151,4 +155,3 @@ bootupd now uses `systemd-run` instead to guarantee the following: + - If we want a non-CLI API (whether that's DBus or Cap'n Proto or varlink or + something else), we will create an independent daemon with a stable API for + this specific need. +- +diff --git a/build.rs b/build.rs +new file mode 100644 +index 0000000..e598d38 +--- /dev/null ++++ b/build.rs +@@ -0,0 +1,9 @@ ++fn main() { ++ if std::env::var("CARGO_FEATURE_SYSTEMD_BOOT").is_ok() { ++ if let Ok(arch) = std::env::var("CARGO_CFG_TARGET_ARCH") { ++ if arch.starts_with("riscv") { ++ panic!("The systemd-boot feature is not supported on RISC-V."); ++ } ++ } ++ } ++} +diff --git a/src/bios.rs b/src/bios.rs +index b4eaca5..66e2f6f 100644 +--- a/src/bios.rs ++++ b/src/bios.rs +@@ -112,6 +112,7 @@ impl Component for Bios { + dest_root: &str, + device: &str, + _update_firmware: bool, ++ _bootloader: &crate::bootupd::Bootloader, + ) -> Result { + let src_dir = openat::Dir::open(src_root) + .with_context(|| format!("opening source directory {src_root}"))?; +diff --git a/src/bootupd.rs b/src/bootupd.rs +index 4dc10c3..2b2d147 100644 +--- a/src/bootupd.rs ++++ b/src/bootupd.rs +@@ -25,6 +25,13 @@ use std::fs::{self, File}; + use std::io::{BufRead, BufReader, BufWriter, Write}; + use std::path::{Path, PathBuf}; + ++#[derive(Debug, Clone, Copy, PartialEq, Eq)] ++pub(crate) enum Bootloader { ++ Grub2, ++ #[cfg(feature = "systemd-boot")] ++ SystemdBoot, ++} ++ + pub(crate) enum ConfigMode { + None, + Static, +@@ -81,6 +88,8 @@ pub(crate) fn install( + anyhow::bail!("No components specified"); + } + ++ let bootloader = select_bootloader(&source_root_dir); ++ + let mut state = SavedState::default(); + let mut installed_efi_vendor = None; + for &component in target_components.iter() { +@@ -93,20 +102,51 @@ pub(crate) fn install( + continue; + } + ++ #[cfg(feature = "systemd-boot")] ++ if bootloader == Bootloader::SystemdBoot && component.name() == "BIOS" { ++ log::warn!("Skip installing BIOS component when using systemd-boot"); ++ continue; ++ } ++ ++ let update_firmware = match bootloader { ++ Bootloader::Grub2 => update_firmware, ++ #[cfg(feature = "systemd-boot")] ++ Bootloader::SystemdBoot => false, ++ }; ++ + let meta = component +- .install(&source_root, dest_root, device, update_firmware) ++ .install( ++ &source_root, ++ dest_root, ++ device, ++ update_firmware, ++ &bootloader, ++ ) + .with_context(|| format!("installing component {}", component.name()))?; + log::info!("Installed {} {}", component.name(), meta.meta.version); + state.installed.insert(component.name().into(), meta); +- // Yes this is a hack...the Component thing just turns out to be too generic. +- if let Some(vendor) = component.get_efi_vendor(&Path::new(source_root))? { +- assert!(installed_efi_vendor.is_none()); +- installed_efi_vendor = Some(vendor); ++ ++ match bootloader { ++ Bootloader::Grub2 => { ++ // Yes this is a hack...the Component thing just turns out to be too generic. ++ if let Some(vendor) = component.get_efi_vendor(&Path::new(source_root))? { ++ assert!(installed_efi_vendor.is_none()); ++ installed_efi_vendor = Some(vendor); ++ } ++ } ++ #[cfg(feature = "systemd-boot")] ++ _ => {} + } + } + let sysroot = &openat::Dir::open(dest_root)?; + +- match configs.enabled_with_uuid() { ++ // If systemd-boot is enabled, do not run grubconfigs::install ++ let configs_with_uuid = match bootloader { ++ Bootloader::Grub2 => configs.enabled_with_uuid(), ++ #[cfg(feature = "systemd-boot")] ++ _ => None, ++ }; ++ match configs_with_uuid { + Some(uuid) => { + let meta = get_static_config_meta()?; + state.static_configs = Some(meta); +@@ -716,6 +756,41 @@ fn strip_grub_config_file( + Ok(()) + } + ++/// Determine whether the necessary bootloader files are present for GRUB. ++fn has_grub(source_root_dir: &openat::Dir) -> bool { ++ source_root_dir.open_file("usr/sbin/grub2-install").is_ok() ++} ++ ++/// Determine whether the necessary bootloader files are present for systemd-boot. ++#[cfg(feature = "systemd-boot")] ++fn has_systemd_boot(source_root_dir: &openat::Dir) -> bool { ++ source_root_dir.open_file(efi::SYSTEMD_BOOT_EFI).is_ok() ++} ++ ++/// Select the bootloader based on available binaries and feature flags. ++fn select_bootloader(source_root_dir: &openat::Dir) -> Bootloader { ++ #[cfg(not(feature = "systemd-boot"))] ++ { ++ if has_grub(source_root_dir) { ++ Bootloader::Grub2 ++ } else { ++ log::warn!("No bootloader binaries found, defaulting to Grub2"); ++ Bootloader::Grub2 ++ } ++ } ++ #[cfg(feature = "systemd-boot")] ++ { ++ if has_grub(source_root_dir) { ++ Bootloader::Grub2 ++ } else if has_systemd_boot(source_root_dir) { ++ Bootloader::SystemdBoot ++ } else { ++ log::warn!("No bootloader binaries found, defaulting to Grub2"); ++ Bootloader::Grub2 ++ } ++ } ++} ++ + #[cfg(test)] + mod tests { + use super::*; +diff --git a/src/component.rs b/src/component.rs +index 8c3ec3c..e3b752d 100644 +--- a/src/component.rs ++++ b/src/component.rs +@@ -55,6 +55,7 @@ pub(crate) trait Component { + dest_root: &str, + device: &str, + update_firmware: bool, ++ bootloader: &crate::bootupd::Bootloader, + ) -> Result; + + /// Implementation of `bootupd generate-update-metadata` for a given component. +diff --git a/src/efi.rs b/src/efi.rs +index 25d6ccd..c96cedb 100644 +--- a/src/efi.rs ++++ b/src/efi.rs +@@ -22,7 +22,7 @@ use rustix::{fd::AsFd, fd::BorrowedFd, fs::StatVfsMountFlags}; + use walkdir::WalkDir; + use widestring::U16CString; + +-use crate::bootupd::RootContext; ++use crate::bootupd::{Bootloader, RootContext}; + use crate::freezethaw::fsfreeze_thaw_cycle; + use crate::model::*; + use crate::ostreeutil; +@@ -53,6 +53,10 @@ const EFIVARFS: &str = "/sys/firmware/efi/efivars"; + /// Systemd boot loader info EFI variable names + const LOADER_INFO_VAR_STR: &str = "LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"; + const STUB_INFO_VAR_STR: &str = "StubInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f"; ++#[cfg(all(feature = "systemd-boot", target_arch = "aarch64"))] ++pub(crate) const SYSTEMD_BOOT_EFI: &str = "usr/lib/systemd/boot/efi/systemd-bootaarch64.efi"; ++#[cfg(all(feature = "systemd-boot", target_arch = "x86_64"))] ++pub(crate) const SYSTEMD_BOOT_EFI: &str = "usr/lib/systemd/boot/efi/systemd-bootx64.efi"; + + /// Return `true` if the system is booted via EFI + pub(crate) fn is_efi_booted() -> Result { +@@ -368,16 +372,8 @@ impl Component for Efi { + dest_root: &str, + device: &str, + update_firmware: bool, ++ bootloader: &Bootloader, + ) -> Result { +- let src_dir = openat::Dir::open(src_root) +- .with_context(|| format!("opening source directory {src_root}"))?; +- let Some(meta) = get_component_update(&src_dir, self)? else { +- anyhow::bail!("No update metadata for component {} found", self.name()); +- }; +- log::debug!("Found metadata {}", meta.version); +- let srcdir_name = component_updatedirname(self); +- let ft = crate::filetree::FileTree::new_from_dir(&src_dir.sub_dir(&srcdir_name)?)?; +- + // Let's attempt to use an already mounted ESP at the target + // dest_root if one is already mounted there in a known ESP location. + let destpath = if let Some(destdir) = self.get_mounted_esp(Path::new(dest_root))? { +@@ -393,6 +389,35 @@ impl Component for Efi { + self.mount_esp_device(Path::new(dest_root), Path::new(&esp_device))? + }; + ++ let src_dir = openat::Dir::open(src_root) ++ .with_context(|| format!("opening source directory {src_root}"))?; ++ ++ match bootloader { ++ #[cfg(feature = "systemd-boot")] ++ Bootloader::SystemdBoot => { ++ log::info!("Installing systemd-boot via bootctl"); ++ let esp_dir = openat::Dir::open(&destpath)?; ++ crate::systemdbootconfigs::install(&src_dir, &esp_dir)?; ++ return Ok(InstalledContent { ++ meta: ContentMetadata { ++ timestamp: Utc::now(), ++ version: "systemd-boot".to_string(), ++ versions: None, ++ }, ++ filetree: None, ++ adopted_from: None, ++ }); ++ } ++ _ => {} ++ } ++ ++ let Some(meta) = get_component_update(&src_dir, self)? else { ++ anyhow::bail!("No update metadata for component {} found", self.name()); ++ }; ++ log::debug!("Found metadata {}", meta.version); ++ let srcdir_name = component_updatedirname(self); ++ let ft = crate::filetree::FileTree::new_from_dir(&src_dir.sub_dir(&srcdir_name)?)?; ++ + let destd = &openat::Dir::open(&destpath) + .with_context(|| format!("opening dest dir {}", destpath.display()))?; + validate_esp_fstype(destd)?; +diff --git a/src/main.rs b/src/main.rs +index 5554366..53daad2 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -48,6 +48,9 @@ mod packagesystem; + mod sha512string; + mod util; + ++#[cfg(feature = "systemd-boot")] ++mod systemdbootconfigs; ++ + use clap::crate_name; + + /// Binary entrypoint, for both daemon and client logic. +diff --git a/src/systemdbootconfigs.rs b/src/systemdbootconfigs.rs +new file mode 100644 +index 0000000..9fe063d +--- /dev/null ++++ b/src/systemdbootconfigs.rs +@@ -0,0 +1,61 @@ ++use std::path::Path; ++ ++use anyhow::{Context, Result}; ++use fn_error_context::context; ++ ++const CONFIG_DIR: &str = "usr/lib/bootupd/systemd-boot"; ++ ++/// Install files required for systemd-boot ++/// This mostly proxies the bootctl install command ++#[context("Installing systemd-boot")] ++pub(crate) fn install(src_root: &openat::Dir, esp_path: &openat::Dir) -> Result<()> { ++ let esp_path_buf = esp_path.recover_path().context("ESP path is not valid")?; ++ let esp_path_str = esp_path_buf ++ .to_str() ++ .context("ESP path is not valid UTF-8")?; ++ let status = std::process::Command::new("bootctl") ++ .args(["install", "--esp-path", esp_path_str]) ++ .status() ++ .context("Failed to execute bootctl")?; ++ ++ if !status.success() { ++ anyhow::bail!( ++ "bootctl install failed with status code {}", ++ status.code().unwrap_or(-1) ++ ); ++ } ++ ++ // If loader.conf is present in the bootupd configuration, replace the original config with it ++ let configdir_path = Path::new(CONFIG_DIR); ++ if let Err(e) = try_copy_loader_conf(src_root, configdir_path, esp_path_str) { ++ log::debug!("Optional loader.conf copy skipped: {}", e); ++ } ++ ++ Ok(()) ++} ++ ++/// Try to copy loader.conf from configdir to ESP, returns error if not present or copy fails ++fn try_copy_loader_conf( ++ src_root: &openat::Dir, ++ configdir_path: &Path, ++ esp_path_str: &str, ++) -> Result<()> { ++ let configdir = src_root ++ .sub_dir(configdir_path) ++ .context(format!("Config directory '{}' not found", CONFIG_DIR))?; ++ let dst_loader_conf = Path::new(esp_path_str).join("loader/loader.conf"); ++ match configdir.open_file("loader.conf") { ++ Ok(mut src_file) => { ++ let mut dst_file = std::fs::File::create(&dst_loader_conf) ++ .context("Failed to create loader.conf in ESP")?; ++ std::io::copy(&mut src_file, &mut dst_file) ++ .context("Failed to copy loader.conf to ESP")?; ++ log::info!("loader.conf copied to {}", dst_loader_conf.display()); ++ Ok(()) ++ } ++ Err(e) => { ++ log::debug!("loader.conf not found in configdir, skipping: {}", e); ++ Err(anyhow::anyhow!(e)) ++ } ++ } ++} +-- +2.51.0 + diff --git a/manifests/composefs-rs.yaml b/manifests/composefs-rs.yaml index f031053..7ebd2b1 100644 --- a/manifests/composefs-rs.yaml +++ b/manifests/composefs-rs.yaml @@ -1,6 +1,6 @@ package: name: composefs-rs - version: 0_git20250721 + version: 0_git20251018 epoch: 0 description: Boot and upgrade via container images copyright: @@ -16,7 +16,7 @@ pipeline: with: repository: https://github.com/containers/composefs-rs.git branch: main - expected-commit: 50991e3b00babaa867c594a6f0fb193b0684537e + expected-commit: f3cdb75924597ce9ffa1cc48d6e4e011e02f333d - uses: cargo/build with: diff --git a/manifests/kernel-initramfs.yaml b/manifests/kernel-initramfs.yaml index 0dc06e5..b488cd3 100644 --- a/manifests/kernel-initramfs.yaml +++ b/manifests/kernel-initramfs.yaml @@ -2,8 +2,8 @@ package: name: kernel-initramfs - version: 6.15.6 - epoch: 1 + version: 6.17.3 + epoch: 0 description: The Linux kernel initramfs copyright: - license: GPL-2.0 diff --git a/manifests/kernel-uki.yaml b/manifests/kernel-uki.yaml index 793dc06..b819064 100644 --- a/manifests/kernel-uki.yaml +++ b/manifests/kernel-uki.yaml @@ -2,8 +2,8 @@ package: name: kernel-uki - version: 6.15.6 - epoch: 1 + version: 6.17.3 + epoch: 0 description: Unified Kernel Image (UKI) for the Linux kernel target-architecture: - x86_64 @@ -23,9 +23,8 @@ environment: - kernel - kernel-modules - kernel-initramfs + - systemd - systemd-ukify - - systemd-uki-tools - - systemd-measure - python3 - dracut - kmod diff --git a/manifests/kernel.yaml b/manifests/kernel.yaml index 4748856..5b05b78 100644 --- a/manifests/kernel.yaml +++ b/manifests/kernel.yaml @@ -2,8 +2,8 @@ package: name: kernel - version: 6.15.6 - epoch: 2 + version: 6.17.3 + epoch: 0 description: The Linux kernel copyright: - license: GPL-2.0 @@ -40,7 +40,7 @@ pipeline: with: repository: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git tag: v${{package.version}} - expected-commit: 1562d948232546cfad45a1beddc70fe0c7b34950 + expected-commit: f4b756a52c29ce3909c06bba248acf31d1276597 - runs: mv config-${{build.arch}}* .config diff --git a/manifests/ostree.yaml b/manifests/ostree.yaml index 885e3b3..1202e7a 100644 --- a/manifests/ostree.yaml +++ b/manifests/ostree.yaml @@ -1,6 +1,6 @@ package: name: ostree - version: "2025.4" + version: "2025.6" epoch: 0 description: "Operating system and container binary deployment and upgrades" copyright: @@ -28,7 +28,7 @@ pipeline: with: repository: https://github.com/ostreedev/ostree.git tag: v${{package.version}} - expected-commit: 1a9350c94395cf743fc43e715931998fd67c520b + expected-commit: 82185d9aaf0a79b100378f13a54c3d5d3763a971 - runs: env NOCONFIGURE=1 ./autogen.sh diff --git a/manifests/py3-pefile.yaml b/manifests/py3-pefile.yaml deleted file mode 100644 index 8457394..0000000 --- a/manifests/py3-pefile.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/chainguard-dev/melange/refs/heads/main/pkg/config/schema.json - -package: - name: py3-pefile - version: "2024.8.26" - epoch: 0 - description: Python module to read and work with PE (Portable Executable) files - copyright: - - license: MIT - dependencies: - provider-priority: 0 - -environment: - contents: - packages: - - build-base - - busybox - - py3-supported-flit-core - - py3-supported-pip - - py3-supported-python - - py3-supported-setuptools - - py3-supported-wheel - -vars: - pypi-package: pefile - -data: - - name: py-versions - items: - 3.10: "310" - 3.11: "311" - 3.12: "312" - 3.13: "313" - -pipeline: - - uses: fetch - with: - uri: https://files.pythonhosted.org/packages/source/p/pefile/pefile-${{package.version}}.tar.gz - expected-sha512: 62781f2ab84040a13304ce550dd1e943991df152c5f2951281906e837b1659694051a074ff49cd08d5d508e9b70009b56418a4237511c4464c4eba9bda4bccf7 - -subpackages: - - range: py-versions - name: py${{range.key}}-${{vars.pypi-package}} - description: ${{vars.pypi-package}} installed for python${{range.key}} - dependencies: - runtime: - - py${{range.key}}-future - provides: - - py3-${{vars.pypi-package}} - provider-priority: ${{range.value}} - pipeline: - - uses: py/pip-build-install - with: - python: python${{range.key}} - - runs: | - docdir="/usr/share/doc/${{package.name}}" - mkdir -p "$docdir" - cp -R docs "$docdir"/ || true - install -m 644 -D LICENSE /usr/share/licenses/${{package.name}}/LICENSE - - uses: strip - test: - pipeline: - - uses: python/import - with: - python: python${{range.key}} - import: ${{vars.pypi-package}} - - - name: py3-supported-${{vars.pypi-package}} - description: meta package providing ${{vars.pypi-package}} for supported python versions. - dependencies: - runtime: - - py3.10-${{vars.pypi-package}} - - py3.11-${{vars.pypi-package}} - - py3.12-${{vars.pypi-package}} - - py3.13-${{vars.pypi-package}} -# update: -# enabled: true -# release-monitor: -# identifier: 5933 # Replace with actual pefile release monitor ID if available diff --git a/manifests/systemd.yaml b/manifests/systemd.yaml deleted file mode 100644 index a94cf17..0000000 --- a/manifests/systemd.yaml +++ /dev/null @@ -1,819 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/chainguard-dev/melange/refs/heads/main/pkg/config/schema.json - -package: - name: systemd - version: "257.8" - epoch: 1 - description: The systemd System and Service Manager - copyright: - - license: LGPL-2.1-or-later AND GPL-2.0-or-later - resources: - cpu: 4 - memory: 12Gi - dependencies: - runtime: - - dbus - - kmod - - merged-lib - - merged-sbin - - merged-usrsbin - - quota-tools - - systemd-boot - - wolfi-baselayout - -vars: - llvm-vers: 19 - -data: - - name: standalone-binaries - items: - "systemd-repart": "systemd-repart.standalone" - "systemd-sysusers": "systemd-sysusers.standalone" - "systemd-tmpfiles": "systemd-tmpfiles.standalone" - - - name: filesystems - items: - "ext4": "ext4" - "xfs": "xfs" - -environment: - contents: - packages: - - acl-dev - - audit-dev - - bpftool - - build-base - - ca-certificates-bundle - - clang-${{vars.llvm-vers}} - - cmake - - coreutils - - cryptsetup-dev - - curl-dev - - dbus-dev - - findutils - - gnutar - - gperf - - iptables-dev - - kmod - - kmod-dev - - libarchive-dev - - libbpf - - libbpf-dev - - libcap-dev - - libgcrypt-dev - - libgpg-error-dev - - libidn2-dev - - libmicrohttpd-dev - - libmount - - libseccomp-dev - - libuuid - - libxslt - - linux-headers - - linux-pam-dev - - llvm-${{vars.llvm-vers}} - - meson - - ninja - - openssf-compiler-options - - pcre2-dev - - posix-libc-utils - - py3-jinja2 - - py3-pyelftools - - py3-pefile - - python3 - - quota-tools - - rsync - - tpm2-tss - - util-linux-dev - - valgrind-dev - - xz-dev - -pipeline: - - uses: git-checkout - with: - repository: https://github.com/systemd/systemd - tag: v${{package.version}} - expected-commit: 5e38d199a623563698ab4a69acbbe3afa9135198 - - - uses: meson/configure - with: - opts: | - -Dmode=release \ - -Dvmspawn=enabled \ - -Dinstall-tests=true \ - -Dstandalone-binaries=true \ - -Dsplit-bin=false \ - -Ddefault-dnssec=no \ - -Dukify=enabled \ - -Defi=true - - - uses: meson/compile - - - uses: meson/install - - - runs: | - # We've never used init we don't intend to - rm ${{targets.destdir}}/usr/lib/systemd/system/rc-local.service - -subpackages: - - name: "systemd-test" - description: "Installable systemd-tests" - dependencies: - runtime: - - merged-sbin - - systemd - - systemd-container - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/tests ${{targets.subpkgdir}}/usr/lib/systemd - cd ${{targets.destdir}} - - find . -name '*test*' -print \ - | tar --xattrs '--xattrs-include=*' -pcz '--files-from=-' -f - \ - | tar --xattrs '--xattrs-include=*' -xzf - -C /home/build/melange-out/systemd-test - - find . -name '*test*' -exec rm -f '{}' \; - - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - test: - environment: - contents: - packages: - - bash - - coreutils - - findutils - - python3 - - tzdata - - busybox - - tpm2-tss - - libidn2 # There's a lot of dlopen tests - - libbpf - - libzstd1 - - libarchive - - kmod-libs - pipeline: - - runs: | - mkdir -p /var/tmp/ - # Skipping tests: - # test-execute - won't work in qemu until we have caps, bwrap and docker already skip this - # test-namespace - won't work in qemu until we have caps, bwrap and docker already skip this - # test-bpf-foreign-programs - won't work in qemu, bwrap and docker already skip this - # test-sd-device - but got the following error: No such device - # test-path-util - failed at src/test/test-path-util.c:385, function test_find_executable_full(). Aborting. - # test-label - Error occurred while opening directory =>: Read-only file system - # test-dns-domain - Assertion 'r >= expected' failed at src/test/test-dns-domain.c:782, function test_dns_name_apply_idna_one(). Aborting. - # test-compress-benchmark - failed at src/test/test-compress-benchmark.c:105, function test_compress_decompress(). Aborting. - # test-capability - but got error: Protocol error - # test-bcd - >= 0' failed at src/boot/test-bcd.c:19, function load_bcd(). - # test-tpm2 - none setup in the test env. - # test-fd-util - Failed to fork off '(caf-noproc)': Operation not permitted - # test-fstab-generator - lots of set -x seems to fail messing with mounts? - # 2025/03/28 11:52:30 INFO Assertion 'mkdtemp_malloc("/tmp/test-rm-rf.XXXXXXX", &d) >= 0' failed at src/test/test-rm-rf.c:19, function test_rm_rf_chmod_inner(). Aborting. - # 2025/03/28 11:52:30 INFO (setresuid) terminated by signal ABRT. - # 2025/03/28 11:52:30 INFO Assertion 'r >= 0' failed at src/test/test-rm-rf.c:100, function test_rm_rf_chmod(). Aborting. - /usr/lib/systemd/tests/run-unit-tests.py -u \ - -s test-sd-device \ - -s test-path-util \ - -s test-label \ - -s test-dns-domain \ - -s test-compress-benchmark \ - -s test-capability \ - -s test-bcd \ - -s test-tpm2 \ - -s test-fd-util \ - -s test-fstab-generator.sh \ - -s test-rm-rf \ - -s test-namespace \ - -s test-mount-util \ - -s test-bpf-foreign-programs \ - -s test-execute - - - range: standalone-binaries - name: ${{range.key}}-standalone - description: Standalone version of ${{range.key}} - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin - mv ${{targets.destdir}}/usr/bin/${{range.value}} ${{targets.subpkgdir}}/usr/bin/${{range.key}} - test: - pipeline: - - runs: | - ${{range.key}} --help - ${{range.key}} --version - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: systemd-ukify - description: "Unified Kernel Image (UKI) builder" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin - mv ${{targets.destdir}}/usr/bin/ukify ${{targets.subpkgdir}}/usr/bin/ukify - test: - pipeline: - - runs: | - ukify --help - ukify --version - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - python3 - - py3-pefile - - - name: systemd-uki-tools - description: "Unified Kernel Image (UKI) tools" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/boot/efi - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/linuxx64.efi.stub ${{targets.subpkgdir}}/usr/lib/systemd/boot/efi/linuxx64.efi.stub - - - name: systemd-measure - description: "Pre-calculate and sign expected TPM2 PCR 11 values for booted unified kernel images" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/systemd-measure ${{targets.subpkgdir}}/usr/lib/systemd/systemd-measure - - - name: systemd-shutdown-standalone - description: Standalone version of ${{range.key}} - # Can't test this with --version because the binary checks the pid before anything else - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd - mv ${{targets.destdir}}/usr/lib/systemd/systemd-shutdown.standalone ${{targets.subpkgdir}}/usr/lib/systemd/systemd-shutdown - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-dev" - description: "headers for systemd" - dependencies: - runtime: - - libudev - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - uses: split/dev - test: - pipeline: - - uses: test/pkgconf - - - name: "libudev" - description: "udev library" - dependencies: - provider-priority: 10 - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - mv ${{targets.destdir}}/usr/lib/libudev.so.* ${{targets.subpkgdir}}/usr/lib - test: - pipeline: - - uses: test/tw/ldd-check - - - name: "libsystemd" - description: "systemd library" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - mv ${{targets.destdir}}/usr/lib/libsystemd.so.* ${{targets.subpkgdir}}/usr/lib - test: - pipeline: - - uses: test/tw/ldd-check - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "libsystemd-shared" - description: "systemd library" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib - cp ${{targets.destdir}}/usr/lib/systemd/libsystemd-shared-*.so ${{targets.subpkgdir}}/usr/lib/ - test: - pipeline: - - uses: test/tw/ldd-check - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-boot-installed" - description: "systemd bootloader (installed for EFI)" - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/ - - if: ${{build.arch}} == 'aarch64' - runs: | - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/systemd-bootaa64.efi ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/BOOTAA64.EFI - - if: ${{build.arch}} == 'x86_64' - runs: | - cp ${{targets.destdir}}/usr/lib/systemd/boot/efi/systemd-bootx64.efi ${{targets.subpkgdir}}/boot/efi/EFI/BOOT/BOOTX64.EFI - test: - environment: - contents: - packages: - - file - - grep - pipeline: - - if: ${{build.arch}} == 'aarch64' - runs: | - file /boot/efi/EFI/BOOT/BOOTAA64.EFI | grep "executable for EFI" - - if: ${{build.arch}} == 'x86_64' - runs: | - file /boot/efi/EFI/BOOT/BOOTX64.EFI | grep "executable for EFI" - dependencies: - runtime: - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - - name: "systemd-boot" - description: "systemd bootloader" - dependencies: - runtime: - - libsystemd-shared - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/etc/ - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/kernel/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system-generators/ - mv ${{targets.destdir}}/etc/kernel ${{targets.subpkgdir}}/etc/ - mv ${{targets.destdir}}/usr/bin/kernel-install ${{targets.subpkgdir}}/usr/bin/ - mv ${{targets.destdir}}/usr/bin/bootctl ${{targets.subpkgdir}}/usr/bin/ - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-boot-update.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/kernel ${{targets.subpkgdir}}/usr/lib/ - mv ${{targets.destdir}}/usr/lib/systemd/boot ${{targets.subpkgdir}}/usr/lib/systemd/ - mv ${{targets.destdir}}/usr/lib/systemd/systemd-bless-boot ${{targets.subpkgdir}}/usr/lib/systemd/ - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-bless-boot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system-generators/systemd-bless-boot-generator ${{targets.subpkgdir}}/usr/lib/systemd/system-generators/ - test: - pipeline: - - uses: test/verify-service - - runs: | - bootctl --version - bootctl --help - kernel-install --version - kernel-install --help - - - name: systemd-container - description: "systemd container tools" - dependencies: - runtime: - - gnutar - - merged-lib - - merged-sbin - - merged-usrsbin - - systemd - - wolfi-baselayout - pipeline: - - runs: | - # Move machine, vm/nspawn, import, export and portable components - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}} - - find . -name '*machine*' \ - -not -name 'systemd-machine-id*' \ - -not -name 'sysinit.target.wants' \ - -not -name 'sysinit.target.wants' \ - -not -name 'systemd-pcr*.service' \ - -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*nspawn*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*vmspawn*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*import*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*export*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*portable*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - - # Remove those files from the main package - find . -name '*machine*' -not -name 'systemd-machine-id*' -exec rm -f '{}' \; - - find . -name '*nspawn*' -exec rm -f '{}' \; - find . -name '*vmspawn*' -exec rm -f '{}' \; - find . -name '*import*' -exec rm -f '{}' \; - find . -name '*export*' -exec rm -f '{}' \; - find . -name '*portable*' -exec rm -f '{}' \; - find . -name '*portable*' -type d -exec rmdir '{}' \; - - # Misc utilties - mv usr/lib/systemd/systemd-pull ${{targets.subpkgdir}}/usr/lib/systemd/ - mv usr/bin/systemd-dissect ${{targets.subpkgdir}}/usr/bin/ - test: - environment: - contents: - # without openssl-provider-legacy import errors referencing CRYPTOGRAPHY_OPENSSL_NO_LEGACY - packages: - - curl - - gnutar - pipeline: - - uses: test/verify-service - - runs: | - machinectl --help - machinectl --version - portablectl --version - portablectl --help - systemd-dissect --help - systemd-dissect --version - systemd-nspawn --help - systemd-nspawn --version - systemd-vmspawn --help - systemd-vmspawn --version - /usr/lib/systemd/systemd-export --help - /usr/lib/systemd/systemd-export --version - /usr/lib/systemd/systemd-import --help - /usr/lib/systemd/systemd-import --version - /usr/lib/systemd/systemd-import-fs --help - /usr/lib/systemd/systemd-import-fs --version - /usr/lib/systemd/systemd-importd --help - /usr/lib/systemd/systemd-importd --version - /usr/lib/systemd/systemd-machined --help - /usr/lib/systemd/systemd-machined --version - /usr/lib/systemd/systemd-portabled --help - /usr/lib/systemd/systemd-portabled --version - /usr/lib/systemd/systemd-pull --help - /usr/lib/systemd/systemd-pull --version - - runs: | - # Run a pull command - SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-pull tar https://dl-cdn.alpinelinux.org/alpine/v3.21/releases/x86_64/alpine-minirootfs-3.21.2-x86_64.tar.gz test --verify=checksum --verify=checksum --direct --force - - # ensure it exists - # - # # test if it works - ls -la /var/lib/machines/test - - - name: "udev" - description: "/dev hotplug management daemon" - dependencies: - runtime: - - libsystemd-shared - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}} - find . -name '*udev*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - find . -name '*systemd-hwdb*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - \ - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*udev*' -exec rm -f {} \; - find . -name '*systemd-hwdb*' -exec rm -f {} \; - test: - pipeline: - - uses: test/verify-service - - runs: | - systemd-hwdb --version - systemd-hwdb --help - udevadm --help - udevadm --version - - name: Systemd-hwdb checks - runs: | - systemd-hwdb update -s - - EXPECTED=$(cat < "${{targets.subpkgdir}}/etc/machine-id" - test: - pipeline: - - runs: | - [ -f /usr/bin/init -a -x /usr/bin/init ] - grep "uninitialized" /etc/machine-id - - - name: "systemd-default-network" - description: "Configure network to DHCP on default interfaces" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/20-eth.network ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/21-enp.network ${{targets.subpkgdir}}/etc/systemd/network/ - cp files/22-end.network ${{targets.subpkgdir}}/etc/systemd/network/ - - - name: "systemd-logind-service" - description: "Logind service" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/multi-user.target.wants - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-logind.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system/dbus-org.freedesktop.login1.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mv ${{targets.destdir}}/usr/lib/systemd/system/multi-user.target.wants/systemd-logind.service ${{targets.subpkgdir}}/usr/lib/systemd/system/multi-user.target.wants/ - mv ${{targets.destdir}}/usr/lib/systemd/systemd-logind ${{targets.subpkgdir}}/usr/lib/systemd/ - test: - pipeline: - - uses: test/verify-service - - - name: "systemd-logind-stub" - description: "Fake login service to boot directly into a shell" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - cp ${{targets.destdir}}/usr/lib/systemd/system/serial-getty@.service ${{targets.subpkgdir}}/usr/lib/systemd/system/ - sed -i "s|^ExecStart=.*agetty.*|ExecStart=-/bin/sh -l|" ${{targets.subpkgdir}}/usr/lib/systemd/system/serial-getty@.service - - - name: "systemd-firstboot" - description: "Initialize basic system settings on or before the first boot-up of a system" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - - systemd-homed # systemd-homed-firstboot - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/ - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system/sysinit.target.wants/ - mv ${{targets.destdir}}/usr/bin/systemd-firstboot ${{targets.subpkgdir}}/usr/bin/systemd-firstboot - mv ${{targets.destdir}}/usr/lib/systemd/system/sysinit.target.wants/systemd-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/sysinit.target.wants/systemd-firstboot.service - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/systemd-firstboot.service - mv ${{targets.destdir}}/usr/lib/systemd/system/systemd-homed-firstboot.service ${{targets.subpkgdir}}/usr/lib/systemd/system/systemd-homed-firstboot.service - test: - pipeline: - - uses: test/verify-service - - name: "Check version" - runs: | - systemd-firstboot --version - systemd-firstboot --help - - - range: filesystems - name: systemd-repart-rootfs-${{range.key}} - description: "Config file to auto grow root ${{range.key}} filesystem" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - mkdir -p ${{targets.subpkgdir}}/usr/lib/repart.d/ - cp files/50-root-${{range.key}}.conf ${{targets.subpkgdir}}/usr/lib/repart.d/50-root.conf - - - name: "systemd-homed" - description: "systemd-homed is a system service designed to manage home directories" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}}/etc/systemd - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - find . -name '*home*' -print | tar -pcz --files-from=- -f - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - - find . -name '*home*' -exec rm -f '{}' \; - test: - pipeline: - - uses: test/verify-service - - runs: | - homectl --help - - - name: "systemd-userdb" - description: "dynamic user/group manager" - dependencies: - runtime: - - ${{package.name}} - - merged-lib - - merged-sbin - - merged-usrsbin - - wolfi-baselayout - pipeline: - - runs: | - cd ${{targets.destdir}}/ - mkdir -p ${{targets.subpkgdir}}/etc/systemd - mkdir -p ${{targets.subpkgdir}}/usr/lib/systemd/system - mkdir -p ${{targets.subpkgdir}}/usr/bin/ - find . -name '*userdb*' -print | tar --xattrs --xattrs-include='*' -pcz --files-from=- -f - | tar --xattrs --xattrs-include='*' -xzf - -C ${{targets.subpkgdir}} - find . -name '*userdb*' -exec rm -f '{}' \; - test: - pipeline: - - uses: test/verify-service - - runs: | - userdbctl --help - -update: - enabled: true - github: - identifier: systemd/systemd - strip-prefix: v - -test: - environment: - contents: - packages: - - build-base - - systemd-dev - - libsystemd - pipeline: - - uses: test/verify-service - with: - skip-files: syslog.socket # intentionally shipped without a corresponding service - - name: "Check systemctl version" - runs: | - systemctl --version - busctl --version - busctl --help - coredumpctl --version - coredumpctl --help - hostnamectl --version - hostnamectl --help - journalctl --version - journalctl --help - localectl --version - localectl --help - loginctl --version - loginctl --help - networkctl --version - networkctl --help - oomctl --version - oomctl --help - resolvectl --version - resolvectl --help - run0 --version - run0 --help - systemctl --help - systemd-ac-power --version - systemd-ac-power --help - systemd-analyze --help - systemd-ask-password --version - systemd-ask-password --help - systemd-cat --version - systemd-cat --help - systemd-cgls --version - systemd-cgls --help - systemd-cgtop --version - systemd-cgtop --help - systemd-confext --version - systemd-confext --help - systemd-creds --version - systemd-creds --help - systemd-delta --version - systemd-delta --help - systemd-detect-virt --help - systemd-escape --version - systemd-escape --help - systemd-id128 --version - systemd-id128 --help - systemd-inhibit --version - systemd-inhibit --help - systemd-machine-id-setup --version - systemd-machine-id-setup --help - systemd-mount --version - systemd-mount --help - systemd-notify --version - systemd-notify --help - systemd-path --version - systemd-path --help - systemd-repart --version - systemd-repart --help - systemd-resolve --version - systemd-resolve --help - systemd-run --version - systemd-run --help - systemd-socket-activate --version - systemd-socket-activate --help - systemd-stdio-bridge --version - systemd-stdio-bridge --help - systemd-sysext --version - systemd-sysext --help - systemd-sysusers --version - systemd-sysusers --help - systemd-tmpfiles --version - systemd-tmpfiles --help - systemd-tty-ask-password-agent --version - systemd-tty-ask-password-agent --help - systemd-umount --version - systemd-umount --help - systemd-vpick --version - systemd-vpick --help - timedatectl --version - timedatectl --help - varlinkctl --version - varlinkctl --help - halt --help - init --help - poweroff --help - reboot --help - resolvconf --version - resolvconf --help - runlevel --help - shutdown --help - telinit --help - - name: "Check libsystemd" - runs: | - ldconfig -p | grep libsystemd.so - echo '#include - int main() { sd_bus *bus; return sd_bus_default_system(&bus); }' > test.c - cc test.c -lsystemd -o test_systemd - rm test.c test_systemd - - name: "Verify stanalone binaries removed" - runs: | - STANDALONE_BINARIES=$(find /usr -name '*.standalone' ) - test -z "${STANDALONE_BINARIES}" diff --git a/manifests/systemd/files/20-eth.network b/manifests/systemd/files/20-eth.network deleted file mode 100644 index 5be26f6..0000000 --- a/manifests/systemd/files/20-eth.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=eth* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/21-enp.network b/manifests/systemd/files/21-enp.network deleted file mode 100644 index 1698a51..0000000 --- a/manifests/systemd/files/21-enp.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=enp* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/22-end.network b/manifests/systemd/files/22-end.network deleted file mode 100644 index f2b0378..0000000 --- a/manifests/systemd/files/22-end.network +++ /dev/null @@ -1,4 +0,0 @@ -[Match] -Name=end* -[Network] -DHCP=yes diff --git a/manifests/systemd/files/50-root-ext4.conf b/manifests/systemd/files/50-root-ext4.conf deleted file mode 100644 index a4dd0bc..0000000 --- a/manifests/systemd/files/50-root-ext4.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Partition] -Type=root -Format=ext4 diff --git a/manifests/systemd/files/50-root-xfs.conf b/manifests/systemd/files/50-root-xfs.conf deleted file mode 100644 index 8fe16ee..0000000 --- a/manifests/systemd/files/50-root-xfs.conf +++ /dev/null @@ -1,3 +0,0 @@ -[Partition] -Type=root -Format=xfs