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.

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.

Tip: If a broken system boots to the grub rescue prompt, ensure the prefix variable is correct and type insmod normal to load the normal module and then type normal to get it to load the full grub2 shell.

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.

TroubleShooting

See here.

Tips:
Type set to see what variables are set.
In particular 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.

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

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

command description
search find (hdx,y) value for a filesystem with specific label, UUID, etc
terminal configure a textmode terminal
gfxterm configure a graphical terminal
recordfail save state for next boot
echo write to terminal
test interprets [ … ] expressions
linux sets up Grub data-structures so that later execution of the “boot" command will boot into a specified Linux kernel.
chainloader load and jump to the MBR of a different disk partition

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!


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



ċ
generic_isoboot.cfg
(6k)
Steve Si,
20 Feb 2017, 04:53
Comments