2.2 Der Bootloader GRUB 2
Mit GRUB 2 wurde GRUB von Grund auf neu entwickelt. Die Entwickler haben sich sehr viel Zeit gelassen und sich in kleinen Sprüngen der Version 2 genähert. GRUB2 ist bei openSUSE und Ubuntu in Version 2.02, in Debian in Version 2.02-beta3 und in CentOS in Version 2.02-beta2 enthalten. Da die Macher des Bootloaders einen sehr konservativen Ansatz bei der Versionierung verfolgen, darf man sich von »beta« nicht schrecken lassen. Die erste Version des Bootloaders hat beispielsweise nie die Version 1 erreicht; die höchste Versionsnummer war 0.97.
2.2.1 Funktionsweise
Der große Unterschied von GRUB 2 im Vergleich zu GRUB ist, dass die ehemaligen Stages 1.5 und 2, vom Laden der Dateisystemtreiber bis zum Anzeigen des Bootmenüs, zu einem einzigen Stage 2 zusammengelegt wurden. Dabei nutzt GRUB 2 einen minimalistischen und sehr kleinen Kern und viele Module, die je nach Bedarf nachgeladen werden können, um auf die Konfigurationsdatei zugreifen zu können. Auf diese Weise unterstützt GRUB 2 auch das Starten von LVM oder Software-RAIDs mit md.
2.2.2 Installation
GRUB 2 wird genauso wie GRUB mit grub-install (bei CentOS und openSUSE mit grub2-install) installiert, allerdings müssen Sie bei GRUB 2 angeben, wo der Bootloader installiert werden soll. Dabei zeigt GRUB 2 deutlich weniger Ausgaben bei der Installation (siehe Listing 2.1):
# Debian und Ubuntu
grub-install /dev/sda
Installing for i386-pc platform.
Installation finished. No error reported.
# CentOS und openSUSE
Installing for i386-pc platform.
Installation finished. No error reported.
Listing 2.1 Installation von »GRUB 2«
2.2.3 Konfiguration
Die Konfigurationsdatei von GRUB 2 liegt in /boot/grub/grub.cfg bzw. /boot/grub2/grub.cfg. Bitte ändern Sie diese nicht von Hand, sie wird von den Skripten unter /etc/grub.d erstellt. In diesem Verzeichnis wird den Skripten eine Nummer vorangestellt, um die Reihenfolge festzulegen. Das Verfahren, die Konfiguration aus einzelnen Bausteinen (Skripten) zusammenstellen zu lassen, macht GRUB 2 deutlich flexibler und besser automatisierbar als seinem Vorgänger: So werden installierte Kernel automatisch erkannt und in das Bootmenü aufgenommen.
Die hohe Flexibilität wird allerdings durch eine komplexere Konfiguration erkauft. Ohne gutes Shell-Scripting-Know-how kommt man da nicht viel weiter. Einfachere Konfigurationen wie das Bootmenü sind relativ leicht machbar. Einstellungen, die das komplette Bootverhalten beeinflussen, wie beispielsweise Timeouts oder der Kernel, der standardmäßig gestartet werden sollte, werden in der Datei /etc/default/grub vorgenommen.
In der von uns beschriebenen Ubuntu-Version 18.04 sind die folgenden Dateien im Verzeichnis /etc/grub.d zu finden:
-
00_header
Mit diesem Skript werden die Standardeinstellungen aus der Datei /etc/default/grub gesetzt.
-
05_debian_theme
Diese Datei sorgt für das Aussehen des Bootmenüs: Hier werden Farben und Hintergrundbild definiert. -
10_linux
Dieses Skript nimmt alle installierten Kernel in das Bootmenü auf. -
20_linux_xen
Hier werden besondere Einstellungen vorgenommen und spezielle Kernel für die Xen-Virtualisierung gesetzt. -
30_os-prober
Dieses Skript sucht nach installierten (anderen) Betriebssystemen und nimmt sie in das Bootmenü auf. -
30_uefi-firmware
Besondere Einstellungen für UEFI-Systeme werden mit diesem Skript getroffen. -
40_custom
Diese Datei ist für eigene Booteinträge vorhanden. -
41_custom
Hiermit wird die /boot/grub/custom.cfg eingebunden, sofern sie existiert. -
README
Diese Datei enthält Hintergrundinformationen für die Skripte in diesem Verzeichnis.
Die Skriptnummern, die mit 00, 10 oder 20 beginnen, sind reserviert. Alle Nummern dazwischen können Sie für eigene Skripte verwenden. Je nachdem, welche Nummer Sie Ihrem Skript geben, wird es früher oder später im Prozess ausgeführt. Apropos »ausgeführt«: Die Skripte unterhalb von /etc/grub.d müssen alle ausführbar sein.
Wir legen jetzt einen neuen Eintrag im Bootmenü an. Dazu werden am Ende der Datei 40_custom die Zeilen aus Listing 2.2 neu eingefügt:
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry "Ubuntu 18.04.1 LTS, kernel 4.15.0-34-Adminbuch" {
set root='(hd0,1)'
linux /vmlinuz-4.15.0-34-generic \
root=/dev/mapper/ubuntu--vg-root ro console=hvc0
initrd /initrd.img-4.15.0-34-generic
}
Listing 2.2 Eigener Eintrag in der Datei »40_custom«
Das Skript sorgt nur dafür, dass die Zeilen ab der dritten Zeile ausgegeben werden. Die eigentliche Konfiguration findet sich in der geschweiften Klammer nach dem menuentry, der den Text des Eintrags im Bootmenü enthält.
Wie gewohnt kennzeichnet set root die Partition, in der sich das Verzeichnis /boot befindet. Natürlich bietet GRUB 2 eine Besonderheit: Die Festplattennummerierung beginnt bei 0, und die Nummerierung der Partition beginnt bei 1. So wird aus der Partition /dev/sdb3 unter GRUB hd1,2 und unter GRUB 2 hd1,3.
Nach linux (früher kernel) folgt der zu startende Betriebssystemkern. Und initrd ist so, wie bereits beschrieben, die Initial Ramdisk. Mithilfe von update-grub wird ein neuer Bootloader geschrieben, und beim nächsten Start finden wir unseren neuen Eintrag im Bootmenü.
[+] Wie bereits beschrieben, ist GRUB 2 modular aufgebaut und bringt keine Treiber mit, daher muss man eventuell noch Module mit dem Kommando insmod hinzuladen, um aus einem einfachen Menüeintrag ein startfähiges System zu machen.
Beispiele dafür sind LVM, besondere Dateisysteme oder auch RAID. Alle verfügbaren Module Ihrer GRUB-2-Installation finden sich im Verzeichnis /boot/grub/i386-pc oder /boot/grub2/i386-pc und enden auf .mod. In Listing 2.3 finden Sie die Module eines Debian-Stretch-Systems:
root@debian:~# ls /boot/grub/i386-pc
915resolution.mod gcry_whirlpool.mod password_pbkdf2.mod
acpi.mod gdb.mod pata.mod
adler32.mod geli.mod pbkdf2.mod
affs.mod gettext.mod pbkdf2_test.mod
afs.mod gfxmenu.mod pci.mod
ahci.mod gfxterm.mod pcidump.mod
all_video.mod gfxterm_background.mod plan9.mod
aout.mod gfxterm_menu.mod play.mod
archelp.mod gptsync.mod png.mod
at_keyboard.mod gzio.mod priority_queue.mod
ata.mod halt.mod probe.mod
backtrace.mod hashsum.mod procfs.mod
bfs.mod hdparm.mod progress.mod
biosdisk.mod hello.mod pxe.mod
bitmap.mod help.mod pxechain.mod
bitmap_scale.mod hexdump.mod raid5rec.mod
blocklist.mod hfs.mod raid6rec.mod
boot.img hfsplus.mod read.mod
boot.mod hfspluscomp.mod reboot.mod
bsd.mod http.mod regexp.mod
btrfs.mod hwmatch.mod reiserfs.mod
bufio.mod iorw.mod relocator.mod
cat.mod iso9660.mod romfs.mod
cbfs.mod jfs.mod scsi.mod
cbls.mod jpeg.mod search.mod
cbmemc.mod keylayouts.mod search_fs_file.mod
cbtable.mod keystatus.mod search_fs_uuid.mod
cbtime.mod ldm.mod search_label.mod
chain.mod legacy_password_test.mod sendkey.mod
cmdline_cat_test.mod legacycfg.mod serial.mod
cmosdump.mod linux.mod setjmp.mod
cmostest.mod linux16.mod setjmp_test.mod
cmp.mod loadenv.mod setpci.mod
command.lst loopback.mod sfs.mod
configfile.mod ls.mod signature_test.mod
core.img lsacpi.mod sleep.mod
cpio.mod lsapm.mod sleep_test.mod
cpio_be.mod lsmmap.mod spkmodem.mod
cpuid.mod lspci.mod squash4.mod
crc64.mod luks.mod syslinuxcfg.mod
crypto.lst lvm.mod tar.mod
crypto.mod lzopio.mod terminal.lst
cryptodisk.mod macbless.mod terminal.mod
cs5536.mod macho.mod terminfo.mod
date.mod mda_text.mod test.mod
datehook.mod mdraid09.mod test_blockarg.mod
datetime.mod mdraid09_be.mod testload.mod
disk.mod mdraid1x.mod testspeed.mod
diskfilter.mod memdisk.mod tftp.mod
div_test.mod memrw.mod tga.mod
dm_nv.mod minicmd.mod time.mod
drivemap.mod minix.mod tr.mod
echo.mod minix2.mod trig.mod
efiemu.mod minix2_be.mod true.mod
efiemu32.o minix3.mod truecrypt.mod
efiemu64.o minix3_be.mod udf.mod
ehci.mod minix_be.mod ufs1.mod
elf.mod mmap.mod ufs1_be.mod
eval.mod moddep.lst ufs2.mod
exfat.mod modinfo.sh uhci.mod
exfctest.mod morse.mod usb.mod
ext2.mod mpi.mod usb_keyboard.mod
extcmd.mod msdospart.mod usbms.mod
fat.mod multiboot.mod usbserial_common.mod
file.mod multiboot2.mod usbserial_ftdi.mod
font.mod nativedisk.mod usbserial_pl2303.mod
freedos.mod net.mod usbserial_usbdebug.mod
fs.lst newc.mod usbtest.mod
fshelp.mod nilfs2.mod vbe.mod
functional_test.mod normal.mod verify.mod
gcry_arcfour.mod ntfs.mod vga.mod
gcry_blowfish.mod ntfscomp.mod vga_text.mod
gcry_camellia.mod ntldr.mod video.lst
gcry_cast5.mod odc.mod video.mod
gcry_crc.mod offsetio.mod video_bochs.mod
gcry_des.mod ohci.mod video_cirrus.mod
gcry_dsa.mod part_acorn.mod video_colors.mod
gcry_idea.mod part_amiga.mod video_fb.mod
gcry_md4.mod part_apple.mod videoinfo.mod
gcry_md5.mod part_bsd.mod videotest.mod
gcry_rfc2268.mod part_dfly.mod videotest_checksum.mod
gcry_rijndael.mod part_dvh.mod xfs.mod
gcry_rmd160.mod part_gpt.mod xnu.mod
gcry_rsa.mod part_msdos.mod xnu_uuid.mod
gcry_seed.mod part_plan.mod xnu_uuid_test.mod
gcry_serpent.mod part_sun.mod xzio.mod
gcry_sha1.mod part_sunpc.mod zfs.mod
gcry_sha256.mod partmap.lst zfscrypt.mod
gcry_sha512.mod parttool.lst zfsinfo.mod
gcry_tiger.mod parttool.mod
gcry_twofish.mod password.mod
Listing 2.3 GRUB-2-Module eines Debian-Stretch-Systems
Auf dem gleichen System findet sich in der /boot/grub/grub.cfg ein Beispiel dafür, wie ein Teil dieser Module eingesetzt wird (siehe Listing 2.4):
[…]
menuentry 'Debian GNU/Linux, with Linux 3.16.0-4-amd64' --class debian \
--class gnu-linux --class gnu --class os $menuentry_id_option \
'gnulinux-3.16.0-4-amd64-advanced-eac6da17-314e-43c0-956f-379457a505fa' {
load_video
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 \
--hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 \
eac6da17-314e-43c0-956f-379457a505fa
else
search --no-floppy --fs-uuid --set=root eac6da17-314e-43c0-956f-379457a505fa
fi
echo 'Loading Linux 3.16.0-4-amd64 ...'
linux /boot/vmlinuz-3.16.0-4-amd64 root=UUID=eac6da17-314e-43c0-956f-\
379457a505fa ro quiet
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img-3.16.0-4-amd64
}
[…]
Listing 2.4 Die Optionen des Standardkernels aus der »/boot/grub/grub.cfg«
[ ! ] Änderungen in der Datei /boot/grub/grub.cfg werden nicht automatisch übernommen. Mit dem Kommando update-grub wird GRUB 2 aktualisiert, wie in Listing 2.5 zu sehen ist:
root@debian:~# update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.16.0-4-amd64
Found initrd image: /boot/initrd.img-3.16.0-4-amd64
done
Listing 2.5 »update-grub«
Interessant ist, dass die Konfigurationsdatei /etc/default/grub ein Shell-Skript ist. Allerdings werden dort nur Variablen gesetzt, die nach dem Aufruf von update-grub durch /etc/grub.d/00_header ausgewertet werden. In der folgenden Auflistung finden Sie die wichtigsten Variablen:
-
GRUB_DEFAULT=0
Hiermit wird der Standardeintrag gesetzt. -
GRUB_TIMEOUT=5
Nach Ablauf der durch TIMEOUT gesetzten Zeit wird der Standardeintrag gestartet. -
GRUB_HIDDEN_TIMEOUT=0
Wenn nur ein Betriebssystem existiert, wird dieser Wert als Wartezeit benutzt. Sobald ein weiterer Eintrag hinzukommt, ist der Wert bedeutungslos. -
GRUB_HIDDEN_TIMEOUT_QUIET=true
Mit true wird kein Countdown angezeigt, bei false wird er entsprechend angezeigt. -
GRUB_CMDLINE_LINUX=
Hiermit werden Standardoptionen für jede linux-Zeile gesetzt.
Die Variablen werden erst nach einem erneuten Aufruf von update-grub gültig.