Skip to content

composefs: bootc status/upgrade/switch fail with "Type1 boot entries: No such file or directory" on non-EFI systems that use BLS layout #2375

Description

@dustinkirkland

Symptom

On a bootc-composefs system that:

  • Was installed via bootc install to-filesystem (writes a systemd-boot /
    BLS layout to the ESP: /boot/loader/entries/*.conf and
    /boot/EFI/Linux/…)
  • Boots via a non-EFI mechanism at runtime (Raspberry Pi 4/5 direct-kernel
    boot from Pi firmware, U-Boot chained to a bare kernel, coreboot with a
    linux payload, etc.) — i.e. /sys/firmware/efi does not exist

… every bootc verb that touches storage fails at initialization:

$ sudo bootc status
error: Status: Prepending custom prefix to EFI and BLS entries: \
  Getting sorted Type1 boot entries: No such file or directory (os error 2)

$ sudo bootc upgrade --check
error: Initializing storage: Prepending custom prefix to EFI and BLS entries: \
  Getting sorted Type1 boot entries: No such file or directory (os error 2)

$ sudo bootc switch --transport=registry <target>
error: Switching: Initializing storage: … (same)

bootc usr-overlay still works (doesn't go through the same storage-init
path), which is what surfaces this as a partial regression rather than a
full brick.

Root cause

crates/lib/src/bootc_composefs/status.rs::get_bootloader() reads
EFI_LOADER_INFO via read_uefi_var. When there are no EFI vars
(EfiError::SystemNotUEFI or EfiError::MissingVar) it unconditionally
returns Bootloader::Grub.

Bootloader::Grub.kind() returns BootloaderKind::GRUBClassic. In
storage::new (crates/lib/src/store/mod.rs), that drives:

let boot_dir = match get_bootloader()?.kind()? {
    BootloaderKind::GRUBClassic => {
        physical_root.open_dir("boot").context("Opening boot")?
    }
    BootloaderKind::BLSCompatible => {
        esp_mount.fd.try_clone().context("Cloning fd")?
    }
};

On a system where /boot is a separate partition (the ESP mounted at
/boot via systemd.mount-extra=UUID=<ESP>:/boot:auto:ro in the
deployment cmdline — which bootc install to-filesystem itself writes),
/sysroot/boot/ is empty. All subsequent BLS reads via
boot_dir.read_dir("loader/entries") then ENOENT — including the
idempotent prepend_custom_prefix() backwards-compat migration invoked
from storage::new itself.

Environment where this reproduces

  • aarch64 Raspberry Pi 5 with bootc 1.16.7
  • Booted directly from Pi firmware → config.txtkernel_2712.img (no
    U-Boot, no systemd-boot, no GRUB at runtime)
  • Image installed via bootc install to-filesystem — laid down a valid
    BLS layout on the ESP (/boot/loader/entries/bootc_composefs-<sha>-1.conf,
    /boot/EFI/Linux/bootc_composefs-<sha>/{vmlinuz,initrd})
  • /sys/firmware/efi absent

The same code path would fire on any non-EFI ARM board or embedded x86
setup that uses BLS entries for boot metadata but doesn't advertise a
bootloader via EFI variables.

Note on #2356

This bug was likely masked before #2356 (merged 2026-08-04) by an earlier
EBUSY error from the pre-mounted ESP path. With #2356's proper handling
of an already-mounted ESP, execution now reaches prepend_custom_prefix
— which is where the wrong boot_dir gets used. #2356 didn't cause this
bug; it just exposed it.

Proposed fix

get_bootloader() should probe the filesystem for a BLS layout when there
are no EFI vars, before falling back to Grub. PR attached.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions