137 - grub2 tutorial

Introduction

This tutorial is about the grub2 boot loader - i.e. the grub> prompt that you see when you boot from a device which has grub2 installed.

Do not confuse grub2 (note: it is in lowercase!) the bootloader/boot manager with legacy grub, grub4dos or GRUB or GRUB2 (which are linux scripts which can be configured to make various grub2 menus).

I have not found any decent guide on grub2 (a very incomplete official manual is here), so this is an attempt to help others and serve as a reminder to me (with useful links)!

As this site is mainly interested in USB booting, I will assume you want to boot from a USB drive to a grub2 menu.

Getting started

If you are a Windows user, you can install grub2 to the MBR and following sectors of a USB drive using:

RMPrepUSB - BootLoaders - Install grub2 to MBR

For linux users:

    • Open a terminal and type sudo su

    • Type fdisk -l (and note which device is your USB)

    • Type mkdir /mnt/USB && mount /dev/sdx1 /mnt/USB (replacing x with your actual usb device)

    • Type grub-install --force --removable --boot-directory=/mnt/USB/boot /dev/sdx (replacing x with your actual USB device)

    • See also here.

If you then try to boot from the USB drive (e.g. using RMPrepUSB - F11), it will boot to the grub rescue> prompt because it will not be able to find the /boot/grub/grub.cfg file or any files under /boot/grub.

grub rescue prompt

The grub rescue console supports a limited number of commands (set, unset, insmod, ls).

You can type set to see what grub2 environment variables have been already set.

See 'Booting the computer' for details of the boot process.

grub2 uses environment variables. For instance, the current root is changed just by a set root=xxxxx command (you can also use root=xxxxx).

cmdpath shows what drive or partition grub was loaded from.

prefix is set to where grub expects to find grub.cfg - the configuration file.

grub2 normally continues by loading some 'modules' from the $prefix/<arch>/ directory by default.

A typical Ubuntu OS will have one or more of these module directories:

/boot/grub/i386-pc - for MBR-mode x86 modules

/boot/grub/i386-efi - for 32-bit EFI-mode

/boot/grub/x86_64.efi - for 64-bit EFI-mode

To boot to the grub rescue prompt, rename these three folders so they cannot be found.

Find these directories from a Ubuntu ISO and copy them to your USB drive (note: will be case-sensitive if ext filesystem).

e.g. If you are MBR-booting (e.g. using QEMU) it will only need the /boot/grub/i386-pc module folder.

Now boot to grub2 again. This time you should see a grub> prompt as it boots to the grub command shell (unless a grub.cfg file was present).

This is because it has found and loaded the normal.mod module and probably several other modules so that it can access different file systems.

Type lsmod to see what modules have been loaded.

Boot to the menu from the grub rescue prompt

If a broken system boots to the grub rescue prompt, type set to view the variables

Ensure the prefix variable and root variables are correct.

prefix should point to the folder that contains the grub module folders.

Type ls to see what partitions are visible

and type insmod normal to load the normal module and then type normal to get it to load the full grub2 shell.

This should run grub.cfg which is in the $prefix folder.

A configfile command may then be used to load another .cfg file from a different location.

grub2 console

With the full 'normal' shell, we have many more commands available, because of the modules that have been loaded.

Hit the <TAB> key to see most of the possible commands (but not all!) now available or l<TAB> to see what commands beginning with l are available.

The pager variable controls screen paging. Type set pager=1 and then help to see what page mode does and then unset pager to turn it off.

The debug variable determines the debug level (try set debug=all).

You can use a help command such as help chainloader to get more information about a command (though often it is inaccurate and incomplete!).

You may find some more useful information about grub2 here.

Tip: If the 'clear' command does not work use 'unset debug' first!

grub2 commands

A list of grub2 commands can be found here.

special environment variables are listed here.

TroubleShooting

See here and here.

Tips:

Type set to see what variables are set.

use set xxxx="dddd ddd ddd" if the value contains spaces and use "${xxxx}" when using the variable.

Beware of case-sensitive strings and file names and paths, etc.!

Some commands (e.g. linux) can expand strings with a backslash character in them into two backslashes by the time they are executed, e.g.

set mypath="/fred/doris\ one.iso"

linux /vmlinuz image=${mypath}

(may get translated to /fred/doris\\ one.iso)

If boot issues, check $prefix and $root.

Use ls command to list files

Check for /boot/grub/grub.cfg

Type normal to attempt to start grub and menu system.

Rescue a non-booting system from the grub2 prompt

Modules

Modules can be considered as 'plug-ins'. They add functionality.

A good explanation of modules can be found here.

A list can be found here.

Load a Menu

Typically, grub2 will look for the /boot/grub/grub.cfg file after loading the normal.mod module.

.cfg configuration files use a modified form of linux scripting (which does not seem to be fully documented!).

A Guide to shell script language (very similar to grub2) can be found here and bash script programming here and a syntax guide here.

Note that grub.cfg files often start by loading many modules.

Some modules also add more commands to the environment. For instance, if you load the video gfxterm module, the background_image command is then available.

grub2 menu entries are in the form:

menuentry 'Ubuntu, with Linux 2.6.32-24-generic' --class ubuntu --class gnu-linux --class gnu --class os {

# load ext2 module

insmod ext2

# set the current root to 2nd drive, 6th partition

set root='(hd1,6)'

# search for a volume of this UUID

search --no-floppy --fs-uuid --set 6655ee5e-45d1-4d1c-9a7d-10f30f16e745

# load the linux kernel and include boot parameters

linux /boot/vmlinuz-2.6.32-24-generic root=UUID=6655ee5e-45d1-4d1c-9a7d-10f30f16e745 ro quiet splash

# load the ramdisk image

initrd /boot/initrd.img-2.6.32-24-generic

}

lines can be commented using #

Note that this menu loads the ext2 module in case the linux boot files are on an ext2 formatted volume

memdisk can be used to map iso file and disk images:

# for ISO

menuentry "DFT ISO image" {

linux16 /memdisk iso

initrd16 /your-image.iso

}

# for floppy

menuentry "DFT floppy image" {

linux16 /memdisk

initrd16 /your-image.img

}

The commands most useful to call from grub.cfg are:

Some commands useful to call from an interactive commandline are:

  • ls, cat, echo, hexdump, parttool, tar, reboot

set menu_num=$1 inside a menuentry will set menu_num to the menu number of that entry.

If the value of a variable contains spaces, you must use 'escaping' using "" or {}, e.g. to write 'abc def' ...

set fred="abc de"

echo ${fred}f

echo "$fred"f

To get a line of input from the user as variable myline (or just use read to pause and get user to press ENTER)

read myline

some other useful commands for menus are:

save_env fred peter - saves the current value of these two variables to the /boot/grub/grubenv special file.

load_env fred doris - loads the stored values of fred and doris from the /boot/grub/grubenv special file.

list_env - lists the variables stored in the /boot/grub/grubenv special file.

set default=2 - sets the default menu item to be highlighted/selected

set timeout=5 - sets 5 second timeout

Some of the other variables used by grub2 are here.

background_image /iso/mywallpaper.jpg - loads a background image, .png and .jpg supported (maybe more if modules are loaded?) - requires the gfxterm module

color_normal=red/blue - command to set foreground/background colours of console text

color_highlight=gray/black - command to set foreground/background colours of menu highlight text (not needed if set menu_color_highlight is used)

set menu_color_highlight=red/blue - variable is used by menu system when it is loaded

set menu_color_normal=gray/black - variable is used by menu system when it is loaded

set gfxmode=1366x768 - set the video mode to 1366 by 768 pixels

configfile /boot/grub/main.cfg - passes control to another config file, don't forget to export any variables if you want them to also be passed on.

set gfxpayload=keep - you may not see anything when linux boots unless this value is correct! try text or auto too. See here.

More complex example grub.cfg is here.

Grub2 Gotchas - see here.

Tip: Checkout the generic_isoboot.cfg file. If you rename this to \boot\grub\grub.cfg and place your ISO files in the \iso folder, it should build an isoboot menu for you!

Example menus

menuentry 'Boot from file /AllMyISOs/antergos-minimal-18.5-x86_64.iso' { set isofile=/AllMyISOs/antergos-minimal-18.5-x86_64.iso search --no-floppy --set=root --file $isofile probe -u $root --set=uuid set img_dev=/dev/disk/by-uuid/$uuid loopback loop $isofile linux (loop)/arch/boot/vmlinuz img_dev=$img_dev img_loop=$isofile initrd (loop)/arch/boot/archiso.img }

menuentry "Antergos installer ISO from a file" { set isofile=antergos-18.2-x86_64.iso # name of the ISO file search --set --file $isofile # get $root of the $isofile partition probe -l $root --set=volumelabel # get $volumelabel of the $root set img_dev=/dev/disk/by-label/$volumelabel loopback loop $isofile linux (loop)/arch/boot/vmlinuz img_dev=$img_dev img_loop=$isofile initrd (loop)/arch/boot/archiso.img }

menuentry "Windows 10" { savedefault set file=/EFI/Microsoft/Boot/bootmgfw.efi insmod fat search --set --file $file chainloader $file }

Scripting

Loosely follows bash shell

Useful functions and notes regular expressions

function pathname { regexp -s 2:"$2" '^(\(.*\))?(/.*)$' "$1"; } # /_ISO/ubuntu 64.iso

function devname { regexp -s "$2" '^(\(.*\)).*$' "$1"; } # (hd0,msdos2)

function pathonly { regexp -s 2:"$2" '^(\(.*\))?(.*/)*' "$1"; } # /_ISO/

function getext { regexp -s 3:"$2" '^(.*/)*(.*)\.(.*)$' "$1"; } # iso

function getfname { regexp -s 2:"$2" '(.*)/+(.*)' "$1"; } # ubuntu 64.iso

function gethdnum { regexp -s 2:"$2" '^(.*)hd(.*),' "$1"; } # 0

function getdev { regexp -s 2:"$2" '^(.*)\((.*),' "$1"; } # hd0

usage where $file = (hd0,msdos1)/_ISO/DIR/some file name with spaces.iso

# set isopath to the fullpath without device name

pathname "$file" isopath # make sure double-quotes around $file - this sets the isopath variable to /_ISO/DIR/some file name with spaces.iso

2: = get second match value, 3: = 3rd matched value

^ = start at beginning

$ = up to end of line

If looking for ( or ) then must precede with \

(\(.*\))? = look for ( then anything then ) ? is zero or more of preceding match which is enclosed in ( )

(/.*)$ = look for / followed by any chars up to end of line

(.+/)* = look for 1 or more chars up to / any number of times

(*+)\. = look for 0 or more chars followed by .

(.+)$ = look for all chars till end of line

e.g. regexp -s 2:"$2" '^(.*)\((.*),'

^ = start at beginning of line, look for any number of chars (.*), look for open parenthesis (, look for any number chars (.*), look for comma , - return 2nd match in parentheses as $2.

testing regexp from the grub2 command line

unset fred ; regexp -s 2:"fred" 'test regexp here' "$file" ; echo $fred

# if filename does not contain ubuntu then abort

if ! regexp '(.*)[uU][bB][uU][nN][tT][uU]' "$myfname" ; then continue ; fi


Password protection

If you set a superuser password then you can password protect the whole menu or individual menu entries.

If a supervisor user is set, then only the supervisor (after login) can use the 'e' and 'c' keys in the menu to edit the menu entries or go to the grub2 console.

It will be assumed that all menu entries require superuser access unless they specify a user group in the menuentry line.

# Protect menu (user must enter correct username and password - long delay if wrong)set superusers="root"password root e2bpassword user1 userpwdexport superusers

--unrestricted can be used in a menuentry or --users=users - see manual.