Translate

Archives

GRUB2 Poor Design Decisions

The more I use GRUB2 the more I have come to realize that some of the design decisions relating to GRUB2 must have been made by the same committee that designed the camel and the dodo.

In GRUB Legacy, you simply edited /boot/grub/menu.lst to customize GRUB. Not so in GRUB2! Obviously somebody had way too much time on their hands and decided that a simple method which had stood the test of time – direct editing of the GRUB configuration file – should be replaced with some far more complex for no good or discernible reason. Thus GRUB2 places its configuration files in three separate locations:

  • /etc/default/grub This configuration file contains the GRUB2 menu settings that are read by the /etc/grub.d/ GRUB scripts and written to /boot/grub/grub.cfg. It is intended to be the main customization file for GRUB2 for most people, similar to /boot/grub/menu.lst in GRUB Legacy.
  • /etc/grub.d/ This new directory contains GRUB2 scripts. These scripts are building blocks from which the grub.cfg file is built. When the update-grub is invoked, the scripts are read in a certain sequence and /boot/grub/grub.cfg is created.
  • /boot/grub/grub.cfg This is the file that replaces GRUB Legacy’s /boot/grub/menu.lst.

The documented method in GRUB2 to change a boot option or add another menu item is to edit the /etc/default/grub configuration file, run the update-grub command which uses the scripts in /etc/grub.d/ to create a new /boot/grub/grub.cfg file. A whole cadre of developers has sprung up to develop GUI editors for GRUB2 configuration. Numerous technical articles has been written on GRUB2 but users seem to be more confused than ever on how to configure GRUB2. My recommendation is to simply directly edit /boot/grub.cfg and abandon all the other files and tools which, in the end, simply write a new /boot/grub/grub.cfg.

Turning to the /boot/grub directory. In GRUB Legacy this directory contained only a small number of files. Not so with GRUB2. This directory now contains numerous files. If you use grub-install it copies all sort files to /boot/grub. For example here is a list of the files that were installed in this directory when I built GRUB2 v1.98 and used grub-install to install it:

acpi.mod                     gcry_rijndael.mod   part_msdos.mod
affs.mod                     gcry_rmd160.mod     part_sun.mod
afs_be.mod                   gcry_seed.mod       parttool.lst
afs.mod                      gcry_serpent.mod    parttool.mod
aout.mod                     gcry_sha1.mod       password.mod
ata.mod                      gcry_sha256.mod     password_pbkdf2.mod
ata_pthru.mod                gcry_sha512.mod     pbkdf2.mod
at_keyboard.mod              gcry_tiger.mod      pci.mod
befs_be.mod                  gcry_twofish.mod    play.mod
befs.mod                     gcry_whirlpool.mod  png.mod
biosdisk.mod                 gettext.mod         probe.mod
bitmap.mod                   gfxmenu.mod         pxeboot.img
bitmap_scale.mod             gfxterm.mod         pxecmd.mod
blocklist.mod                gptsync.mod         pxe.mod
boot.img                     grubenv             raid5rec.mod
boot.mod                     gzio.mod            raid6rec.mod
bsd.mod                      halt.mod            raid.mod
bufio.mod                    handler.lst         read.mod
cat.mod                      handler.mod         reboot.mod
cdboot.img                   hashsum.mod         reiserfs.mod
chain.mod                    hdparm.mod          relocator.mod
charset.mod                  hello.mod           scsi.mod
cmp.mod                      help.mod            search_fs_file.mod
command.lst                  hexdump.mod         search_fs_uuid.mod
configfile.mod               hfs.mod             search_label.mod
core.img                     hfsplus.mod         search.mod
cpio.mod                     iso9660.mod         serial.mod
cpuid.mod                    jfs.mod             setjmp.mod
crc.mod                      jpeg.mod            setpci.mod
crypto.lst                   kernel.img          sfs.mod
crypto.mod                   keystatus.mod       sh.mod
datehook.mod                 linux16.mod         sleep.mod
date.mod                     linux.mod           tar.mod
datetime.mod                 lnxboot.img         terminal.lst
device.map                   loadenv.mod         terminal.mod
diskboot.img                 locale              terminfo.mod
dm_nv.mod                    loopback.mod        test.mod
drivemap.mod                 lsmmap.mod          tga.mod
echo.mod                     ls.mod              trig.mod
efiemu32.o                   lspci.mod           true.mod
efiemu64.o                   lvm.mod             udf.mod
efiemu.mod                   mdraid.mod          ufs1.mod
elf.mod                      memdisk.mod         ufs2.mod
example_functional_test.mod  memrw.mod           uhci.mod
ext2.mod                     minicmd.mod         usb_keyboard.mod
extcmd.mod                   minix.mod           usb.mod
fat.mod                      mmap.mod            usbms.mod
font.mod                     moddep.lst          usbtest.mod
fshelp.mod                   msdospart.mod       vbeinfo.mod
fs.lst                       multiboot2.mod      vbe.mod
functional_test.mod          multiboot.mod       vbetest.mod
gcry_arcfour.mod             normal.mod          vga.mod
gcry_blowfish.mod            ntfscomp.mod        vga_text.mod
gcry_camellia.mod            ntfs.mod            video_fb.mod
gcry_cast5.mod               ohci.mod            video.lst
gcry_crc.mod                 part_acorn.mod      video.mod
gcry_des.mod                 part_amiga.mod      videotest.mod
gcry_md4.mod                 part_apple.mod      xfs.mod
gcry_md5.mod                 part_gpt.mod        xnu.mod
gcry_rfc2268.mod             partmap.lst         xnu_uuid.mod


I am on an Intel X64 platform. Why are modules for handling Amiga (part_amiga.mod) or Apple (part_apple.mod) partitions installed on my system? Why do I need the demonstration module hello.mod? I am never going to use them. The installation script grub-install needs to have some intelligence added to it so that modules which are incompatible with your platform are not installed. In addition, it would be nice if the modules could be placed in a subdirectory of /boot/grub in order to reduce the number of files in /boot/grub. The GRUB2 variable prefix allow you to place a prefix in front of the grub subdirectory but does not allow you to place the modules in another directory or a subdirectory.

The build system is needlessly complicated. If I want to create a new command, say colortest, I can place a single file colortest.c in the ../common source subdirectory (which contains to source code for most commands, one per source file) , but then I have to add the following lines to ../conf/common.mk:


# For colortest.mod.
pkglib_MODULES += colortest.mod
colortest_mod_SOURCES = commands/colortest.c

clean-module-colortest.mod.1:
        rm -f colortest.mod mod-colortest.o mod-colortest.c pre-colortest.o colortest_mod-commands_colortest.o und-colortest.lst

CLEAN_MODULE_TARGETS += clean-module-colortest.mod.1

clean-module-colortest.mod-symbol.1:
        rm -f def-colortest.lst

CLEAN_MODULE_TARGETS += clean-module-colortest.mod-symbol.1
DEFSYMFILES += def-colortest.lst
mostlyclean-module-colortest.mod.1:
        rm -f colortest_mod-commands_colortest.d

MOSTLYCLEAN_MODULE_TARGETS += mostlyclean-module-colortest.mod.1
UNDSYMFILES += und-colortest.lst

ifneq ($(TARGET_APPLE_CC),1)
colortest.mod: pre-colortest.o mod-colortest.o $(TARGET_OBJ2ELF)
        -rm -f $@
        $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ pre-colortest.o mod-colortest.o
        if test ! -z "$(TARGET_OBJ2ELF)"; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi
        $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@
else
colortest.mod: pre-colortest.o mod-colortest.o $(TARGET_OBJ2ELF)
        -rm -f $@
        -rm -f $@.bin
        $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin pre-colortest.o mod-colortest.o
        $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@
        -rm -f $@.bin
endif

pre-colortest.o: $(colortest_mod_DEPENDENCIES) colortest_mod-commands_colortest.o
        -rm -f $@
        $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ colortest_mod-commands_colortest.o

mod-colortest.o: mod-colortest.c
        $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -c -o $@ $<

mod-colortest.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
        sh $(srcdir)/genmodsrc.sh 'colortest' $< > $@ || (rm -f $@; exit 1)

ifneq ($(TARGET_APPLE_CC),1)
def-colortest.lst: pre-colortest.o
        $(NM) -g --defined-only -P -p $< | sed 's/^\([^ ]*\).*/\1 colortest/' > $@
else
def-colortest.lst: pre-colortest.o
        $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]'  | sed 's/^\([^ ]*\).*/\1 colortest/' > $@
endif

und-colortest.lst: pre-colortest.o
        echo 'colortest' > $@
        $(NM) -u -P -p $< | cut -f1 -d' ' >> $@

colortest_mod-commands_colortest.o: commands/colortest.c $(commands/colortest.c_DEPENDENCIES)
        $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -MD -c -o $@ $<
-include colortest_mod-commands_colortest.d

clean-module-colortest_mod-commands_colortest-extra.1:
        rm -f cmd-colortest_mod-commands_colortest.lst fs-colortest_mod-commands_colortest.lst partmap-colortest_mod-commands_colortest.lst handler-colortest_mod-commands_colortest.lst parttool-colortest_mod-commands_colortest.lst video-colortest_mod-commands_colortest.lst terminal-colortest_mod-commands_colortest.lst
CLEAN_MODULE_TARGETS += clean-module-colortest_mod-commands_colortest-extra.1

COMMANDFILES += cmd-colortest_mod-commands_colortest.lst
FSFILES += fs-colortest_mod-commands_colortest.lst
PARTTOOLFILES += parttool-colortest_mod-commands_colortest.lst
PARTMAPFILES += partmap-colortest_mod-commands_colortest.lst
HANDLERFILES += handler-colortest_mod-commands_colortest.lst
TERMINALFILES += terminal-colortest_mod-commands_colortest.lst
VIDEOFILES += video-colortest_mod-commands_colortest.lst

cmd-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) gencmdlist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/gencmdlist.sh colortest > $@ || (rm -f $@; exit 1)

fs-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genfslist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genfslist.sh colortest > $@ || (rm -f $@; exit 1)

parttool-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genparttoollist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genparttoollist.sh colortest > $@ || (rm -f $@; exit 1)

partmap-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genpartmaplist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genpartmaplist.sh colortest > $@ || (rm -f $@; exit 1)
handler-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genhandlerlist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genhandlerlist.sh colortest > $@ || (rm -f $@; exit 1)

terminal-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genterminallist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genterminallist.sh colortest > $@ || (rm -f $@; exit 1)

video-colortest_mod-commands_colortest.lst: commands/colortest.c $(commands/colortest.c_DEPENDENCIES) genvideolist.sh
        set -e;           $(TARGET_CC) -Icommands -I$(srcdir)/commands $(TARGET_CPPFLAGS)  $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $<         | sh $(srcdir)/genvideolist.sh colortest > $@ || (rm -f $@; exit 1)

colortest_mod_CFLAGS = $(COMMON_CFLAGS)
colortest_mod_LDFLAGS = $(COMMON_LDFLAGS)


Most of the above is cookie cutter build code. I simply took the relevant lines for another module and changed the module name to colortest. It should be possible to eliminate most of the above with a more intelligent build environment. In some build environments I have encountered over the years it can be as simple as adding the name of the module to a list of modules which are to be built. Why complicate things when there are well proven simple ways to achieve the same end?

The introduction of support for graphic screens in GRUB2 has introduced subtle problems with color support. Colors work as expected if you use the following configuration:

root=(hd0,1)

timeout=10
default=0

if loadfont /grub/font/unicode.pf2
then
   set gfxmode="1024x768x32"
   set gfxpayload=keep
   insmod gfxterm
   insmod vbe
   terminal_output gfxterm
   terminal gfxterm
   insmod tga
   use_bg=true
   background_image /grub/image/f13rockets.tga
fi

set color_normal=yellow/black
set color_highlight=blue/yellow
set menu_color_normal=yellow/black
set menu_color_highlight=white/light-gray

menuentry "Fedora 13" {
   linux /vmlinuz-2.6.33.5-124.fc13.x86_64 ro root=/dev/mapper/vg_ultra-lv_root rd_LVM_LV=vg_ultra/lv_root rd_LVM_LV=vg_ultra/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYTABLE=us rhgb quiet
   initrd /initramfs-2.6.33.5-124.fc13.x86_64.img
}


but revert to using gray/black in command mode when you move the set color_normal and set color_highlight lines to before the graphics card setting, i.e:

root=(hd0,1)

timeout=10
default=0

set color_normal=yellow/black
set color_highlight=blue/yellow

if loadfont /grub/font/unicode.pf2
then
   set gfxmode="1024x768x32"
   set gfxpayload=keep
   insmod gfxterm
   insmod vbe
   terminal_output gfxterm
   terminal gfxterm
   insmod tga
   use_bg=true
   background_image /grub/image/f13rockets.tga
fi

set menu_color_normal=yellow/black
set menu_color_highlight=white/light-gray

menuentry "Fedora 13" {
   linux /vmlinuz-2.6.33.5-124.fc13.x86_64 ro root=/dev/mapper/vg_ultra-lv_root rd_LVM_LV=vg_ultra/lv_root rd_LVM_LV=vg_ultra/lv_swap rd_NO_LUKS rd_NO_MD rd_NO_DM LANG=en_US.UTF-8 SYSFONT=latarcyrheb-sun16 KEYTABLE=us rhgb quiet
   initrd /initramfs-2.6.33.5-124.fc13.x86_64.img
}


It took me a while to understand what was going on when I first encountered this issue. The default color in command mode was gray/black even though the set command showed that the color settings were correct.

Finally, for no good reason the development sources have a dependency on Ruby. See autogen.sh, genmk.rb, configure.ac and configure. Why? Probably because the original version of GRUB2 was written by a Japanese programmer. Requiring Ruby for GRUB2 development is a needless complication of a relatively simple process. Any dependency on Ruby should be removed.

Contrary to what you may be thinking, I actually like GRUB2. It is a huge improvement over GRUB Legacy. All my GNU/Linux systems now use it and I am an active developer of GRUB2 modules. I just think that the main developers of GRUB2 have managed to seriously complicate a relatively simple piece of software from a user’s perspective. However from a developer’s perspective, except for certain functionality such as EFI support, the source code is well structured and partitioned and there is good built-in support for extensions.
 

1 comment to GRUB2 Poor Design Decisions

  • Couldn’t agree more with you comments regarding hide/unhide.
    My solution was to toggle the bits in the MBR
    myself and not try to deal with what appears
    to me as something straight out of Micro$oft.
    I wonder if this is a symptom of the
    commercialization of Ubuntu?
    Very poor programming decision.
    e.