templates: Introduce GRUB_TOP_LEVEL_* vars

A user may wish to use an image that is not sorted as the "latest"
version as the top-level entry. For example, in Arch Linux, if a user
has the LTS and regular kernels installed, "/boot/vmlinuz-linux-lts"
gets sorted as the "latest" compared to "/boot/vmlinuz-linux", meaning
the LTS kernel becomes the top-level entry. However, a user may wish to
use the regular kernel as the top-level default with the LTS only
existing as a backup.

This need can be seen in Arch Linux's AUR with two user-submitted
packages[0][1] providing an update hook which patches /etc/grub.d/10_linux
to move the desired kernel to the top-level. This patch serves to solve
this in a more generic way.

Introduce the GRUB_TOP_LEVEL, GRUB_TOP_LEVEL_XEN and GRUB_TOP_LEVEL_OS_PROBER
variables to allow users to specify the top-level entry.

Create grub_move_to_front() as a helper function which moves entries to
the front of a list. This function does the heavy lifting of moving
the menu entry to the front in each script.

In 10_netbsd, since there isn't an explicit list variable, extract the
items that are being iterated through into a list so that we can
optionally apply grub_move_to_front() to the list before the loop.

[0]: https://aur.archlinux.org/packages/grub-linux-default-hook
[1]: https://aur.archlinux.org/packages/grub-linux-rt-default-hook

Signed-off-by: Denton Liu <liu.denton@gmail.com>
Reviewed-by: Oskari Pirhonen <xxc3ncoredxx@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
Denton Liu 2022-10-24 03:46:42 -07:00 committed by Daniel Kiper
parent a85714545f
commit 62037e01b2
9 changed files with 69 additions and 1 deletions

View File

@ -1444,6 +1444,16 @@ for all respectively normal entries.
The values of these options replace the values of @samp{GRUB_CMDLINE_LINUX}
and @samp{GRUB_CMDLINE_LINUX_DEFAULT} for Linux and Xen menu entries.
@item GRUB_TOP_LEVEL
@item GRUB_TOP_LEVEL_XEN
This option should be an absolute path to a kernel image. If provided, the
image specified will be made the top-level entry if it is found in the scan.
@item GRUB_TOP_LEVEL_OS_PROBER
This option should be a line of output from @command{os-prober}. As
@samp{GRUB_TOP_LEVEL}, if provided, the image specified will be made the
top-level entry if it is found in the scan.
@item GRUB_EARLY_INITRD_LINUX_CUSTOM
@itemx GRUB_EARLY_INITRD_LINUX_STOCK
List of space-separated early initrd images to be loaded from @samp{/boot}.

View File

@ -233,6 +233,9 @@ export GRUB_DEFAULT \
GRUB_CMDLINE_NETBSD \
GRUB_CMDLINE_NETBSD_DEFAULT \
GRUB_CMDLINE_GNUMACH \
GRUB_TOP_LEVEL \
GRUB_TOP_LEVEL_XEN \
GRUB_TOP_LEVEL_OS_PROBER \
GRUB_EARLY_INITRD_LINUX_CUSTOM \
GRUB_EARLY_INITRD_LINUX_STOCK \
GRUB_TERMINAL_INPUT \

View File

@ -218,6 +218,32 @@ version_sort ()
esac
}
# Given an item as the first argument and a list as the subsequent arguments,
# returns the list with the first argument moved to the front if it exists in
# the list.
grub_move_to_front ()
{
item="$1"
shift
item_found=false
for i in "$@"; do
if [ "x$i" = "x$item" ]; then
item_found=true
fi
done
if [ "x$item_found" = xtrue ]; then
echo "$item"
fi
for i in "$@"; do
if [ "x$i" = "x$item" ]; then
continue
fi
echo "$i"
done
}
# One layer of quotation is eaten by "" and the second by sed; so this turns
# ' into \'.
grub_quote () {

View File

@ -229,6 +229,10 @@ submenu_indentation=""
reverse_sorted_kernels=$(echo ${kernels} | tr ' ' '\n' | sed -e 's/\.old$/ 1/; / 1$/! s/$/ 2/' | version_sort -r | sed -e 's/ 1$/.old/; s/ 2$//')
if [ "x$GRUB_TOP_LEVEL" != x ]; then
reverse_sorted_kernels=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_kernels})
fi
is_top_level=true
for kernel in ${reverse_sorted_kernels}; do

View File

@ -164,6 +164,10 @@ submenu_indentation=""
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$//')
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 kfreebsd in ${reverse_sorted_list}; do

View File

@ -202,6 +202,10 @@ submenu_indentation=""
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$//')
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
gettext_printf "Found linux image: %s\n" "$linux" >&2

View File

@ -146,8 +146,14 @@ pattern="^ELF[^,]*executable.*statically linked"
# yet, so it's empty. In a submenu it will be equal to '\t' (one tab).
submenu_indentation=""
list="/netbsd $(ls -t /netbsd?* 2>/dev/null)"
if [ "x$GRUB_TOP_LEVEL" != x ]; then
list=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${list})
fi
is_top_level=true
for k in /netbsd $(ls -t /netbsd?* 2>/dev/null) ; do
for k in ${list}; do
if ! grub_file_is_not_garbage "$k" ; then
continue
fi

View File

@ -245,6 +245,13 @@ submenu_indentation=""
reverse_sorted_xen_list=$(echo ${xen_list} | tr ' ' '\n' | sed -e 's/\.old$/ 1/; / 1$/! s/$/ 2/' | version_sort -r | sed -e 's/ 1$/.old/; s/ 2$//')
reverse_sorted_linux_list=$(echo ${linux_list} | tr ' ' '\n' | sed -e 's/\.old$/ 1/; / 1$/! s/$/ 2/' | version_sort -r | sed -e 's/ 1$/.old/; s/ 2$//')
if [ "x$GRUB_TOP_LEVEL_XEN" != x ]; then
reverse_sorted_xen_list=$(grub_move_to_front "$GRUB_TOP_LEVEL_XEN" ${reverse_sorted_xen_list})
fi
if [ "x$GRUB_TOP_LEVEL" != x ]; then
reverse_sorted_linux_list=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_linux_list})
fi
is_top_level=true
for current_xen in ${reverse_sorted_xen_list}; do

View File

@ -113,6 +113,10 @@ EOF
used_osprober_linux_ids=
if [ "x$GRUB_TOP_LEVEL_OS_PROBER" != x ]; then
OSPROBED=$(grub_move_to_front "$GRUB_TOP_LEVEL_OS_PROBER" ${OSPROBED})
fi
for OS in ${OSPROBED} ; do
DEVICE="`echo ${OS} | cut -d ':' -f 1`"
LONGNAME="`echo ${OS} | cut -d ':' -f 2 | tr '^' ' '`"