Skip to content

Commit

Permalink
Add service to ensure systemd-boot installed
Browse files Browse the repository at this point in the history
On systemd-boot systems, the bootloader is updated with `bootctl update`
on every boot. Unfortunately, it doesn't currently work because
`bootctl` considers systemd-boot to be installed if `/EFI/systemd` is
non-empty in the ESP. The image builder only populates `/EFI/BOOT`, so
systemd-boot is not considered installed.

If `bootctl` does not consider systemd-boot to be installed,
`eos-ensure-sd-boot` will check the `LoaderInfo` EFI variable to see if
the current bootloader is systemd-boot. If so, it populates
`/EFI/systemd` so that the next time `bootctl update` runs, it will
update the bootloader.

https://phabricator.endlessm.com/T34703
  • Loading branch information
dbnicholson committed Apr 12, 2023
1 parent b27e2f3 commit 3469c96
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
dist_systemdunit_DATA = \
eos-config-journal.service \
eos-enable-zram.service \
eos-ensure-sd-boot.service \
eos-firewall-localonly.service \
eos-firstboot.service \
eos-image-boot-dm-setup.service \
Expand Down Expand Up @@ -87,6 +88,7 @@ dist_polkitrules_DATA = \
dist_sbin_SCRIPTS = \
eos-config-journal \
eos-enable-zram \
eos-ensure-sd-boot \
eos-firewall-localonly \
eos-firstboot \
eos-image-boot-dm-setup \
Expand Down
75 changes: 75 additions & 0 deletions eos-ensure-sd-boot
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash

# eos-ensure-sd-boot: Ensure systemd-boot is installed
#
# Copyright © 2023 Endless OS Foundation LLC
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.

# Ensure systemd-boot is considered installed by bootctl (when
# appropriate) so that bootctl update works.

set -e
set -o pipefail

LOADER_INFO_VAR=LoaderInfo-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
LOADER_INFO_PATH="/sys/firmware/efi/efivars/$LOADER_INFO_VAR"

# Read the LoaderInfo EFI variable.
get_loader_info() {
[ -f "$LOADER_INFO_PATH" ] || return 0

# The LoaderInfo variable is a NUL terminated UTF-16 string. The
# first 4 bytes of any EFI variable are attributes.
dd if="$LOADER_INFO_PATH" ibs=1 skip=4 status=none \
| iconv -f UTF16LE | tr -d '\0'
}

# We only use systemd-boot on x86_64. If we add any other architectures
# later, they'll install it correctly out of the box.
arch=$(uname -m)
if [ "$arch" != x86_64 ]; then
exit 0
fi

# If it's already considered installed, there's nothing to do.
if bootctl is-installed --quiet; then
exit 0
fi

# Only make changes when the boot loader is systemd-boot.
echo "Reading $LOADER_INFO_VAR EFI variable"
loader_info=$(get_loader_info)
if ! [[ $loader_info =~ ^systemd-boot ]]; then
echo "Boot loader is not systemd-boot"
exit 0
fi

# Copy the default boot loader to the systemd-boot path. bootctl
# considers systemd-boot installed if EFI/systemd is non-empty.
esp_path=$(bootctl --print-esp-path)
default_efi="$esp_path/EFI/BOOT/BOOTX64.EFI"
systemd_efi_dir="$esp_path/EFI/systemd"
systemd_efi="$systemd_efi_dir/systemd-bootx64.efi"
echo "Copying $default_efi to $systemd_efi"
mkdir -p "$systemd_efi_dir"
cp -a "$default_efi" "$systemd_efi"

# Validate that systemd-boot is now considered installed.
if ! bootctl is-installed --quiet; then
echo "bootctl does not consider systemd-boot installed" >&2
exit 1
fi
24 changes: 24 additions & 0 deletions eos-ensure-sd-boot.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[Unit]
Description=Ensure systemd-boot is installed
DefaultDependencies=no
Conflicts=shutdown.target
Wants=local-fs.target
After=local-fs.target

# Run before systemd-boot-update so that it will apply updates if the
# installation is fixed.
Before=sysinit.target systemd-boot-update.service

# Only run on x86_64 UEFI as that's the only platform where systemd-boot
# is used. Any other platforms added later will install systemd-boot
# correctly out of the box.
ConditionArchitecture=x86-64
ConditionFirmware=uefi

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/sbin/eos-ensure-sd-boot

[Install]
WantedBy=sysinit.target

0 comments on commit 3469c96

Please sign in to comment.