-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
installkernel.ebuild: install grub-mkconfig hook for ukis
TODO: multi-profile UKI support Also need a fix for the secureboot/shim situation in the chainloader command. Co-authored-by: Peter Levine <plevine457@gmail.com> See-also: gentoo/gentoo#39113 Signed-off-by: Nowa Ammerlaan <nowa@gentoo.org>
- Loading branch information
1 parent
f60ca6b
commit 7e71056
Showing
2 changed files
with
234 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
#! /bin/sh | ||
set -e | ||
|
||
# grub-mkconfig helper script, installed by sys-kernel/installkernel[grub,uki] | ||
# | ||
# Copyright 2025 Gentoo Authors | ||
# Distributed under the terms of the GNU General Public License v3+ | ||
# | ||
# Bug: https://bugs.gentoo.org/942201 | ||
|
||
prefix="/usr" | ||
exec_prefix="/usr" | ||
datarootdir="/usr/share" | ||
|
||
. "$pkgdatadir/grub-mkconfig_lib" | ||
|
||
export TEXTDOMAIN=grub | ||
export TEXTDOMAINDIR="${datarootdir}/locale" | ||
|
||
# loop-AES arranges things so that /dev/loop/X can be our root device, but | ||
# the initrds that Linux uses don't like that. | ||
case ${GRUB_DEVICE} in | ||
/dev/loop/*|/dev/loop[0-9]) | ||
GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"` | ||
;; | ||
esac | ||
|
||
: ${GRUB_CMDLINE_LINUX_RECOVERY:=single} | ||
|
||
# Default to disabling partition uuid support to maintian compatibility with | ||
# older kernels. | ||
: ${GRUB_DISABLE_LINUX_PARTUUID=true} | ||
|
||
# btrfs may reside on multiple devices. We cannot pass them as value of root= parameter | ||
# and mounting btrfs requires user space scanning, so force UUID in this case. | ||
if ( [ "x${GRUB_DEVICE_UUID}" = "x" ] && [ "x${GRUB_DEVICE_PARTUUID}" = "x" ] ) \ | ||
|| ( [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ | ||
&& [ "x${GRUB_DISABLE_LINUX_PARTUUID}" = "xtrue" ] ) \ | ||
|| ( ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \ | ||
&& ! test -e "/dev/disk/by-partuuid/${GRUB_DEVICE_PARTUUID}" ) \ | ||
|| ( test -e "${GRUB_DEVICE}" && uses_abstraction "${GRUB_DEVICE}" lvm ); then | ||
LINUX_ROOT_DEVICE=${GRUB_DEVICE} | ||
elif [ "x${GRUB_DEVICE_UUID}" = "x" ] \ | ||
|| [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ]; then | ||
LINUX_ROOT_DEVICE=PARTUUID=${GRUB_DEVICE_PARTUUID} | ||
else | ||
LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID} | ||
fi | ||
|
||
case x"$GRUB_FS" in | ||
xbtrfs) | ||
rootsubvol="`make_system_path_relative_to_its_root /`" | ||
rootsubvol="${rootsubvol#/}" | ||
if [ "x${rootsubvol}" != x ]; then | ||
GRUB_CMDLINE_LINUX="rootflags=subvol=${rootsubvol} ${GRUB_CMDLINE_LINUX}" | ||
fi;; | ||
xzfs) | ||
rpool=`${grub_probe} --device ${GRUB_DEVICE} --target=fs_label 2>/dev/null || true` | ||
bootfs="`make_system_path_relative_to_its_root / | sed -e "s,@$,,"`" | ||
LINUX_ROOT_DEVICE="ZFS=${rpool}${bootfs%/}" | ||
;; | ||
esac | ||
|
||
title_correction_code= | ||
|
||
linux_entry () | ||
{ | ||
os="$1" | ||
version="$2" | ||
type="$3" | ||
args="$4" | ||
|
||
class="--class ${os} --class gnu-linux --class gnu --class os" | ||
|
||
if [ -z "$boot_device_id" ]; then | ||
boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" | ||
fi | ||
if [ x$type != xsimple ] ; then | ||
case $type in | ||
recovery) | ||
title="$(gettext_printf "%s, with UKI %s (recovery mode)" "${os}" "${version}")" ;; | ||
*) | ||
title="$(gettext_printf "%s, with UKI %s" "${os}" "${version}")" ;; | ||
esac | ||
if [ x"$title" = x"$GRUB_ACTUAL_DEFAULT" ] || [ x"Previous Linux versions>$title" = x"$GRUB_ACTUAL_DEFAULT" ]; then | ||
replacement_title="$(echo "Advanced options for ${os}" | sed 's,>,>>,g')>$(echo "$title" | sed 's,>,>>,g')" | ||
quoted="$(echo "$GRUB_ACTUAL_DEFAULT" | grub_quote)" | ||
title_correction_code="${title_correction_code}if [ \"x\$default\" = '$quoted' ]; then default='$(echo "$replacement_title" | grub_quote)'; fi;" | ||
grub_warn "$(gettext_printf "Please don't use old title \`%s' for GRUB_DEFAULT, use \`%s' (for versions before 2.00) or \`%s' (for 2.00 or later)" "$GRUB_ACTUAL_DEFAULT" "$replacement_title" "gnulinux-advanced-$boot_device_id>gnulinux-$version-$type-$boot_device_id")" | ||
fi | ||
echo "menuentry '$(echo "$title" | grub_quote)' ${class} \$menuentry_id_option 'gnulinux-$version-$type-$boot_device_id' {" | sed "s/^/$submenu_indentation/" | ||
else | ||
echo "menuentry '$(echo "$os" | grub_quote)' ${class} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/" | ||
fi | ||
if [ x$type != xrecovery ] ; then | ||
save_default_entry | grub_add_tab | ||
fi | ||
|
||
# Use ELILO's generic "efifb" when it's known to be available. | ||
# FIXME: We need an interface to select vesafb in case efifb can't be used. | ||
if [ "x$GRUB_GFXPAYLOAD_LINUX" = x ]; then | ||
echo " load_video" | sed "s/^/$submenu_indentation/" | ||
if grep -qx "CONFIG_FB_EFI=y" "${config}" 2> /dev/null \ | ||
&& grep -qx "CONFIG_VT_HW_CONSOLE_BINDING=y" "${config}" 2> /dev/null; then | ||
echo ' if [ "x$grub_platform" = xefi ]; then' | sed "s/^/$submenu_indentation/" | ||
echo " set gfxpayload=keep" | sed "s/^/$submenu_indentation/" | ||
echo ' fi' | sed "s/^/$submenu_indentation/" | ||
fi | ||
else | ||
if [ "x$GRUB_GFXPAYLOAD_LINUX" != xtext ]; then | ||
echo " load_video" | sed "s/^/$submenu_indentation/" | ||
fi | ||
echo " set gfxpayload=$GRUB_GFXPAYLOAD_LINUX" | sed "s/^/$submenu_indentation/" | ||
fi | ||
|
||
echo " insmod chain" | sed "s/^/$submenu_indentation/" | ||
|
||
if [ x$dirname = x/ ]; then | ||
if [ -z "${prepare_root_cache}" ]; then | ||
prepare_root_cache="$(prepare_grub_to_access_device ${esp} | grub_add_tab)" | ||
fi | ||
printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/" | ||
else | ||
if [ -z "${prepare_boot_cache}" ]; then | ||
prepare_boot_cache="$(prepare_grub_to_access_device ${esp} | grub_add_tab)" | ||
fi | ||
printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/" | ||
fi | ||
message="$(gettext_printf "Loading UKI %s ..." ${version})" | ||
sed "s/^/$submenu_indentation/" << EOF | ||
echo '$(echo "$message" | grub_quote)' | ||
chainloader ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} | ||
EOF | ||
sed "s/^/$submenu_indentation/" << EOF | ||
} | ||
EOF | ||
} | ||
|
||
machine=`uname -m` | ||
globs="$GRUB_UKI_GLOBS" | ||
[ -z "$globs" ] && globs="/boot/EFI/Linux/*.efi /boot/EFI/EFI/Linux/*.efi /boot/efi/EFI/Linux/*.efi /efi/EFI/Linux/*.efi" | ||
|
||
list= | ||
for i in ${globs} ; do | ||
if grub_file_is_not_garbage "$i" ; then list="$list $i" ; fi | ||
done | ||
|
||
prepare_boot_cache= | ||
prepare_root_cache= | ||
boot_device_id= | ||
title_correction_code= | ||
|
||
# Extra indentation to add to menu entries in a submenu. We're not in a submenu | ||
# yet, so it's empty. In a submenu it will be equal to '\t' (one tab). | ||
submenu_indentation="" | ||
|
||
# Perform a reverse version sort on the entire list. | ||
# Temporarily replace the '.old' suffix by ' 1' and append ' 2' for all | ||
# other files to order the '.old' files after their non-old counterpart | ||
# in reverse-sorted order. | ||
|
||
entry_id_list= | ||
for uki in ${list}; do | ||
entry_id_list="$entry_id_list $(basename -s .efi ${uki%%-*})" | ||
done | ||
|
||
unique_entry_ids=$(echo $entry_id_list | tr ' ' '\n' | sort -u) | ||
|
||
reverse_sorted_list=$(echo $list | tr ' ' '\n' | sed -e 's/\.old$/ 1/; / 1$/! s/$/ 2/' | version_sort -r | sed -e 's/ 1$/.old/; s/ 2$//') | ||
|
||
for entry_id in ${unique_entry_ids}; do | ||
if [ "x$GRUB_TOP_LEVEL" != x ]; then | ||
reverse_sorted_list=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_list}) | ||
fi | ||
|
||
is_top_level=true | ||
for linux in ${reverse_sorted_list}; do | ||
base=$(basename -s .efi ${linux}) | ||
if [ "x${base#${entry_id}}" = "x${base}" ]; then | ||
# UKI does not start with our entry ID | ||
continue | ||
fi | ||
gettext_printf "Found unified kernel image: %s\n" "$linux" >&2 | ||
basename=`basename $linux` | ||
dirname=`dirname $linux` | ||
rel_dirname=`make_system_path_relative_to_its_root $dirname` | ||
esp=`df -P $linux | tail -1 | cut -d' ' -f 1` | ||
version=`echo $basename | sed -e "s,^[^0-9]*-,,g"` | ||
alt_version=`echo $version | sed -e "s,\.old$,,g"` | ||
linux_root_device_thisversion="${LINUX_ROOT_DEVICE}" | ||
|
||
# The GRUB_DISABLE_SUBMENU option used to be different than others since it was | ||
# mentioned in the documentation that has to be set to 'y' instead of 'true' to | ||
# enable it. This caused a lot of confusion to users that set the option to 'y', | ||
# 'yes' or 'true'. This was fixed but all of these values must be supported now. | ||
if [ "x${GRUB_DISABLE_SUBMENU}" = xyes ] || [ "x${GRUB_DISABLE_SUBMENU}" = xy ]; then | ||
GRUB_DISABLE_SUBMENU="true" | ||
fi | ||
|
||
if [ "x$is_top_level" = xtrue ] && [ "x${GRUB_DISABLE_SUBMENU}" != xtrue ]; then | ||
linux_entry "${entry_id}" "${version}" simple \ | ||
"${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" | ||
|
||
submenu_indentation="$grub_tab" | ||
|
||
if [ -z "$boot_device_id" ]; then | ||
boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")" | ||
fi | ||
# TRANSLATORS: %s is replaced with an entry ID | ||
echo "submenu '$(gettext_printf "Advanced options for %s" "${entry_id}" | grub_quote)' \$menuentry_id_option 'gnulinux-advanced-$boot_device_id' {" | ||
is_top_level=false | ||
fi | ||
|
||
linux_entry "${entry_id}" "${version}" advanced \ | ||
"${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" | ||
if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then | ||
linux_entry "${entry_id}" "${version}" recovery \ | ||
"${GRUB_CMDLINE_LINUX_RECOVERY} ${GRUB_CMDLINE_LINUX}" | ||
fi | ||
done | ||
|
||
# If at least one kernel was found, then we need to | ||
# add a closing '}' for the submenu command. | ||
if [ x"$is_top_level" != xtrue ]; then | ||
echo '}' | ||
fi | ||
|
||
echo "$title_correction_code" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters