User:Goverp/ReusableGRUBMenu
This article contains a manual grub configuration file for an unthemed grub menu, suitable for simple Gentoo (and similar) linux installations. Once installed, it's no longer necessary to run grub-mkconfig after installing a new kernel. The menu code is a lot simpler than that generated by grub-mkconfig. It should work with both BIOS and GPT partition setups. It probably only works for x86/IA64 architectures
The article assumes familiarity with GRUB and Gentoo Linux Kernel configuration.
It may be worthwhile to use "grub-mkconfig" on your system first, and compare the resulting configuration with the one here, especially for machines with different operating systems installed, or configured to use advanced features such as root file systems on RAID arrays or encrypted file systems.
See some #Example menus below.
The configuration must be customized to identify your root device! It needs customization of the lines selecting a background image and colour scheme and the kernel command line parameters and recovery option to pass to the select kernel. If you don't use the names /boot/vmlinuz[...] and optionally /boot/initramfs[...] the script building the menus must be customized.
- Remember that a broken grub.cfg means you may have to use the GRUB command line to boot your system.
- Always run before installing a manually-edited grub configuration.
user $
grub-syntax-check
- Install or reinstall sys-boot/grub including the "emu" platform to provide a grub test environment:
GRUB_PLATFORMS="efi-64 emu"
- Create your new grub configuration in a test directory, say /boot/test/grub.cfg and then run to test it. Use grub's "e" key to edit (or in reality see) the resulting menu entries. (Terminate the emulator by entering command mode and typing "exit".) Only move the configuration into /boot/grub when you are completely happy it's correct.
user $
grub-emu -d /boot/test
- If all else fails, it should be possible to enter the grub command line, and enter something like
set root=/dev/sda1
linux /boot/vmlinuz
initrd /boot/initramfs.img
boot
The configuration provides:
- entries to boot kernels identified by links such as vmlinuz, vmlinuz.old and for consistency, vmlinuz.new;
- a submenu of all vmlinux-v.r.m-xxxx entries so you can boot a chosen kernel by version/release/modification level; and
- a submenu of kernels booted with a recovery option.
#
# Manual grub configuration file for an unthemed grub menu.
# Once installed, you should not need to run grub-mkconfig
# each time you install a new kernel.
#
# You MUST CUSTOMIZE this file before use.
# Keep a copy of your previous menu to hand.
# See https://wiki.gentoo.org/User:Goverp/ReusableGRUBMenu
#
# Paul Gover, September 2020.
# The code immediately below is copied from that produced by grub-mkconfig
# It appears to do something with persisting the chosen boot entry.
### BEGIN /etc/grub.d/00_header ###
if [ -s $prefix/grubenv ]
then load_env
fi
if [ "${next_entry}" ]
then
set default="${next_entry}"
set next_entry=
save_env next_entry
set boot_once=true
else
set default="0"
fi
if [ "${prev_saved_entry}" ]
then
set saved_entry="${prev_saved_entry}"
save_env saved_entry
set prev_saved_entry=
save_env prev_saved_entry
set boot_once=true
fi
function savedefault {
if [ -z "${boot_once}" ]
then
saved_entry="${chosen}"
save_env saved_entry
fi
}
function load_video {
if [ "$feature_all_video_module" = "y" ]
then insmod all_video
else
insmod efi_gop
insmod efi_uga
insmod ieee1275_fb
insmod vbe
insmod vga
insmod video_bochs
insmod video_cirrus
fi
}
if [ "$feature_default_font_path" = "y" ]
then font=unicode
else
insmod part_gpt
insmod f2fs
search --no-floppy --fs-uuid --set=root 558709cf-d87b-4627-8b0b-9fa21f48e5e7
font="/usr/share/grub/unicode.pf2"
fi
if loadfont $font
then
set gfxmode=auto
load_video
insmod gfxterm
set locale_dir=$prefix/locale
set lang=en_GB
insmod gettext
fi
terminal_output gfxterm
if [ "$feature_timeout_style" = "y" ]
then
set timeout_style=menu
set timeout=15
else set timeout=15
fi
### END old /etc/grub.d/00_header as updated by me ###
### Insert grub modules for GPT partition tables, filtering, ext/2/3/4, f2fs and regex
# You can add other grub modules for mdadm, btrfs etc. if needed
# or remove f2fs.
insmod part_gpt
insmod part_msdos
insmod diskfilter
insmod ext2
insmod f2fs
insmod regexp # Enables filename globbing in for loops
### Function to find the newest file version with filename $1-*
# Result will be in $latest
# Not used in the code below, but it's there if you need it.
# Parameter 1 is the path and prefix to kernels, such as /boot/vmlinuz
function findlatest {
latest=
for file in $1-*
do
if [ "$latest" == "" -o $file -nt $latest ]
then latest=$file
fi
done
}
### CUSTOMIZE the following for your choice of background.
insmod jpeg
background_image /boot/grub/DarkestHour.jpg
set color_normal=white/black
set gfxpayload=text
# CUSTOMIZE the line below to find your root device.
# See "info grub" for more information on the alternatives.
# You could use --fs-label or a simple device address
# but uuid is probably more reliable and secure.
search --no-floppy --fs-uuid --set=root 558709cf-d87b-4627-8b0b-9fa21f48e5e7
# CUSTOMIZE your kernel command line parameters.
KernelOptions="rootfstype=f2fs root=LABEL=gentoo fsck.f2fs=-a settimeout mdadm net.ifnames=0 acpi_enforce_resources=lax"
RecoveryOption="softlevel=S"
### Create a menuentry to boot a kernel, optionally with an initramfs
# Parameters:
# 1: the entry title
# 2: the kernel name suffix, either a hyphen followed by a version number, or one of ".old", ".new" or "" (current)
# 3: the command line parameters to pass to the kernel
# If no kernel with the given suffix exists, then skip the menu entry.
#
# Note that both menuentry and submenu run as subprocesses with a new environment
# This apparently means that BootDir and similar need to be passed as parameters in the menu command
function kernelentry {
if [ -f /boot/vmlinuz$2 ]
then
menuentry --id="vmlinuz$2" "$1" "/boot/vmlinuz$2" "/boot/initramfs$2.img" "$3" {
echo "Loading Linux $2 ..."
linux $2 $4
if [ -f $3 ]
then
echo "Loading initramfs $3 ..."
initrd $3
fi
}
fi
}
### Create a title or blank line in the grub menu
function spacer {
menuentry "$1" {
# grub-script-check demands some content in this empty separator
return
}
}
### Compare version numbers; returns true if $1 precedes $2
function precedes {
# regex calls prefix strings with X to avoid leading hyphens being interpreted as options
# Note, if grub script supported printf, it would be much faster to create a canonical version from the VMR-rc fields
# (e.g. 5.9.2-rc3 -> 005090203)
# Parse out V.R.M from the parameters
regexp --set=1:a --set=2:arc "([0-9.]+)(.*\$)" "X$1"
regexp --set=1:b --set=2:brc "([0-9.]+)(.*\$)" "X$2"
while true
do
a1=""
b1=""
# Parse out the next numeric field in the V.R.M
regexp --set=1:a1 --set=2:a "([0-9]+)(.*\$)" "X$a"
regexp --set=1:b1 --set=2:b "([0-9]+)(.*\$)" "X$b"
# In the following comparisons, append 0s to prevent invalid null string comparisons
if [ "${a1}0" -lt "${b1}0" ]
then return 0
elif [ "${a1}0" -gt "${b1}0" ]
then return 1
elif [ "$a1$b1" = "" ]
then break
fi
done
# V.R.M equal, assume the rest contain release candidate (rc) numbers
regexp --set=a1 "([0-9]+)" "X$arc"
regexp --set=b1 "([0-9]+)" "X$brc"
# Note that e.g. 5.4.6-rc1 PRECEDES 5.4.6, since the latter is a real release, not a candidate
if [ -z "$a1" ]
then return 1
elif [ -z "$b1" ]
then return 0
fi
# We have 2 release candidate numbers; compare them
test "${a1}0" -lt "${b1}0"
}
### Finally, build the grub menu
# First, up to three generic kernel entries, depending which symlinks exist
kernelentry "Linux testing kernel" ".new" "$KernelOptions"
kernelentry "Linux kernel" "" "$KernelOptions"
kernelentry "Linux previous kernel" ".old" "$KernelOptions"
spacer
# A couple of useful entries that don't boot linux
menuentry " * Reboot" {
reboot
}
menuentry " * Halt" {
halt
}
spacer
# A submenu for each versioned kernel name in /boot
# Submenus don't seem to inherit script variables, so we must pass them as parameters
submenu --id="kernel_list.new" "Kernels by version --->" "$KernelOptions" {
spacer "Kernels by version"
spacer
# Generate the list of kernels sorted by decending order of version number
# This is a very inefficient algorithm, but noone else is using the cpu...
last="-99999999"
max="-00000000"
while true
do
next="$max"
for kernel in /boot/vmlinuz-*
do
regexp --set=suffix "^/boot/vmlinuz(.*)" "$kernel"
if precedes "$next" "$suffix"
then if precedes "$suffix" "$last"
then next="$suffix"
fi
fi
done
if [ "$next" = "$max" ]
then break
fi
kernelentry "Gentoo GNU/Linux vmlinuz$next" "$next" "$2"
last="$next"
done
}
spacer
# A submenu for each kernel name in /boot, passing the recovery option
submenu --id="recovery" " * Recovery options --->" "$KernelOptions $RecoveryOption" {
spacer "Recovery options"
spacer
# Note the slightly different list to include the symlinks as well as the versioned kernels
for kernel in /boot/vmlinuz*
do
regexp --set=suffix "^/boot/vmlinuz(.*)" "$kernel"
kernelentry "Gentoo GNU/Linux vmlinuz$suffix - Recovery mode" "$suffix" "$2"
done
}
The following menu and submenu are screen images captured from "grub-emu" in a terminal window, and do not show the graphics background.
The main menu:
The Kernels by version submenu: