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`. However, a user may wish to use the regular kernel as the default with the LTS only existing as a backup.
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. Signed-off-by: Denton Liu <liu.den...@gmail.com> --- Notes: The only file that was tested is 10_linux. I do not have access to any of the other images or systems so they remain untested. Changes since v2: * Added more detail to GRUB_TOP_LEVEL docs * Moved GRUB_TOP_LEVEL_OS_PROBER to separate section in docs * Renamed grub_move_entry_to_front() to grub_move_to_front() and added code comment * Give 10_netbsd an intermediate list of images to interact with Interdiff against v2: diff --git a/docs/grub.texi b/docs/grub.texi index 16a445178..db6b20531 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -1446,9 +1446,13 @@ 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 a 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 -If this option is provided, the given image file will be made the top-level -entry if the image file is found in the scan. +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 diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 5be49a07c..f4ae41f86 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -218,23 +218,26 @@ version_sort () esac } -grub_move_entry_to_front () +# 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 () { - entry="$1" + item="$1" shift - entry_found=false + item_found=false for i in "$@"; do - if [ "x$i" = "x$entry" ]; then - entry_found=true + if [ "x$i" = "x$item" ]; then + item_found=true fi done - if [ "x$entry_found" = xtrue ]; then - echo "$entry" + if [ "x$item_found" = xtrue ]; then + echo "$item" fi for i in "$@"; do - if [ "x$i" = "x$entry" ]; then continue; fi + if [ "x$i" = "x$item" ]; then continue; fi echo "$i" done } diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index 0ae5a3927..b7be7041c 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -206,7 +206,7 @@ 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_entry_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_kernels}) + reverse_sorted_kernels=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_kernels}) fi is_top_level=true diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 506b2df66..83e9636e8 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -165,7 +165,7 @@ 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_entry_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_list}) + reverse_sorted_list=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_list}) fi is_top_level=true diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index a479c16af..7263f2983 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -203,7 +203,7 @@ 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_entry_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_list}) + reverse_sorted_list=$(grub_move_to_front "$GRUB_TOP_LEVEL" ${reverse_sorted_list}) fi is_top_level=true diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in index 4eae58e82..3154e9e15 100644 --- a/util/grub.d/10_netbsd.in +++ b/util/grub.d/10_netbsd.in @@ -146,19 +146,17 @@ 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 -grub_top_level_found=false -for k in "$GRUB_TOP_LEVEL" /netbsd $(ls -t /netbsd?* 2>/dev/null) ; do +for k in ${list}; do if ! grub_file_is_not_garbage "$k" ; then continue fi - if [ "x$GRUB_TOP_LEVEL" = "x$k" ] ; then - if [ "x$grub_top_level_found" = xfalse ] ; then - grub_top_level_found=true - else - continue - fi - fi if ! (zcat -f "$k" | file -bL - | grep -q "${pattern}") 2>/dev/null ; then continue fi diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index c32bb979f..386bfb9be 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -246,10 +246,10 @@ reverse_sorted_xen_list=$(echo ${xen_list} | tr ' ' '\n' | sed -e 's/\.old$/ 1/; 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_entry_to_front "$GRUB_TOP_LEVEL_XEN" ${reverse_sorted_xen_list}) + reverse_sorted_xen_list=$(grub_move_to_front "$GRUB_TOP_LEVEL_XEN" ${reverse_sorted_xen_list}) fi -if [ "x$GRUB_TOP_LEVEL_LINUX" != x ]; then - reverse_sorted_linux_list=$(grub_move_entry_to_front "$GRUB_TOP_LEVEL_LINUX" ${reverse_sorted_linux_list}) +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 diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index 9b2a96bd0..656301eaf 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -114,7 +114,7 @@ EOF used_osprober_linux_ids= if [ "x$GRUB_TOP_LEVEL_OS_PROBER" != x ]; then - OSPROBED=$(grub_move_entry_to_front "$GRUB_TOP_LEVEL_OS_PROBER" ${OSPROBED}) + OSPROBED=$(grub_move_to_front "$GRUB_TOP_LEVEL_OS_PROBER" ${OSPROBED}) fi for OS in ${OSPROBED} ; do docs/grub.texi | 10 ++++++++++ util/grub-mkconfig.in | 3 +++ util/grub-mkconfig_lib.in | 24 ++++++++++++++++++++++++ util/grub.d/10_hurd.in | 4 ++++ util/grub.d/10_kfreebsd.in | 4 ++++ util/grub.d/10_linux.in | 4 ++++ util/grub.d/10_netbsd.in | 8 +++++++- util/grub.d/20_linux_xen.in | 7 +++++++ util/grub.d/30_os-prober.in | 4 ++++ 9 files changed, 67 insertions(+), 1 deletion(-) diff --git a/docs/grub.texi b/docs/grub.texi index 107f66ebc..db6b20531 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -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 a 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}. diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in index 62335d027..32c480dae 100644 --- a/util/grub-mkconfig.in +++ b/util/grub-mkconfig.in @@ -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 \ diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 634bc8a50..f4ae41f86 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -218,6 +218,30 @@ 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 () { diff --git a/util/grub.d/10_hurd.in b/util/grub.d/10_hurd.in index 4294bbe4c..b7be7041c 100644 --- a/util/grub.d/10_hurd.in +++ b/util/grub.d/10_hurd.in @@ -205,6 +205,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 diff --git a/util/grub.d/10_kfreebsd.in b/util/grub.d/10_kfreebsd.in index 0a67decaa..83e9636e8 100644 --- a/util/grub.d/10_kfreebsd.in +++ b/util/grub.d/10_kfreebsd.in @@ -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 diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in index c6a1ec935..7263f2983 100644 --- a/util/grub.d/10_linux.in +++ b/util/grub.d/10_linux.in @@ -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 diff --git a/util/grub.d/10_netbsd.in b/util/grub.d/10_netbsd.in index dc0cd1b17..3154e9e15 100644 --- a/util/grub.d/10_netbsd.in +++ b/util/grub.d/10_netbsd.in @@ -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 diff --git a/util/grub.d/20_linux_xen.in b/util/grub.d/20_linux_xen.in index 626aed40c..386bfb9be 100644 --- a/util/grub.d/20_linux_xen.in +++ b/util/grub.d/20_linux_xen.in @@ -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 diff --git a/util/grub.d/30_os-prober.in b/util/grub.d/30_os-prober.in index daa603778..656301eaf 100644 --- a/util/grub.d/30_os-prober.in +++ b/util/grub.d/30_os-prober.in @@ -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 '^' ' '`" -- 2.37.3 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel