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:
/etc/portage/make.conf
Example GRUB platform variableGRUB_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.
/boot/grub/grub.cfg
GRUB configuration# # 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: