When researching my article from last month, An introduction to the Linux boot and startup process, I became interested in learning more about GRUB2. This article provides a quick introduction to configuring GRUB2, which I will mostly refer to as GRUB for simplicity.
GRUB stands for GRand Unified Bootloader. Its function is to take over from BIOS at boot time, load itself, load the Linux kernel into memory, and then turn over execution to the kernel. Once the kernel takes over, GRUB has done its job and it is no longer needed.
GRUB supports multiple Linux kernels and allows the user to select between them at boot time using a menu. I have found this to be a very useful tool because there have been many instances that I have encountered problems with an application or system service that fails with a particular kernel version. Many times, booting to an older kernel can circumvent issues such as these. By default, three kernels are kept–the newest and two previous–when yum or dnf are used to perform upgrades. The number of kernels to be kept before the package manager erases them is configurable in the /etc/dnf/dnf.conf or /etc/yum.conf files. I usually change the installonly_limit value to 9 to retain a total of nine kernels. This has come in handy on a couple occasions when I had to revert to a kernel that was several versions down-level.
The function of the GRUB menu is to allow the user to select one of the installed kernels to boot in the case where the default kernel is not the desired one. Using the up and down arrow keys allows you to select the desired kernel and pressing the Enter key continues the boot process using the selected kernel.
The GRUB menu also provides a timeout so that, if the user does not make any other selection, GRUB will continue to boot with the default kernel without user intervention. Pressing any key on the keyboard except the Enter key terminates the countdown timer which is displayed on the console. Pressing the Enter key immediately continues the boot process with either the default kernel or an optionally selected one.
The GRUB menu also provides a "rescue" kernel, in for use when troubleshooting or when the regular kernels don't complete the boot process for some reason. Unfortunately, this rescue kernel does not boot to rescue mode. More on this later in this article.
The grub.cfg file
The grub.cfg file is the GRUB configuration file. It is generated by the grub2-mkconfig program using a set of primary configuration files and the grub default file as a source for user configuration specifications. The /boot/grub2/grub.cfg file is first generated during Linux installation and regenerated when a new kernel is installed.
The grub.cfg file contains Bash-like code and a list of installed kernels in an array ordered by sequence of installation. For example, if you have four installed kernels, the most recent kernel will be at index 0, the previous kernel will be at index 1, and the oldest kernel will be index 3. If you have access to a grub.cfg file you should look at it to get a feel for what one looks like. The grub.cfg file is just too large to be included in this article.
GRUB configuration files
The main set of configuration files for grub.cfg is located in the /etc/grub.d directory. Each of the files in that directory contains GRUB code that is collected into the final grub.cfg file. The numbering scheme used in the names of these configuration files is designed to provide ordering so that the final grub.cfg file is assembled into the correct sequence. Each of these files has a comment to denote the beginning and end of the section, and those comments are also part of the final grub.cfg file so that it is possible to see from which file each section is generated. The delimiting comments look like this:
### BEGIN /etc/grub.d/10_linux ### ### END /etc/grub.d/10_linux ###
These files should not be modified unless you are a GRUB expert and understand what the changes will do. Even then you should always keep a backup copy of the original, working grub.cfg file. The specific files, 40_custom and 41_custom are intended to be used to generate user modifications to the GRUB configuration. You should still be aware of the consequences of any changes you make to these files and maintain a backup of the original grub.cfg file.
You can also add your own files to the /etc/grub.d directory. One reason for doing that might be to add a menu line for a non-Linux operating system. Just be sure to follow the naming convention to ensure that the additional menu item is added either immediately before or after the 10_linux entry in the configuration file.
GRUB defaults file
Configuration of the original GRUB was fairly simple and straightforward. I would just modify /boot/grub/grub.conf and be good to go. I could still modify GRUB2 by changing /boot/grub2/grub.cfg, but the new version is considerably more complex than the original GRUB. In addition, grub.cfg may be overwritten when a new kernel is installed, so any changes may disappear. However, the GNU.org GRUB Manual does discuss direct creation and modification of /boot/grub2/grub.cfg.
Changing the configuration for GRUB2 is fairly easy once you actually figure out how to do it. I only discovered this while researching GRUB2 for a previous article. The secret formula is in the /etc/default directory, with a file called, naturally enough, grub, which is then used in concert with a simple terminal command. The /etc/default directory contains configuration files for a few programs such as Google Chrome, useradd, and grub.
The /etc/default/grub file is very simple. The grub defaults file has a number of valid key/value pairs listed already. You can simply change the values of existing keys or add other keys that are not already in the file. Listing 1, below, shows an unmodified /etc/default/grub file.
GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="rd.lvm.lv=fedora_fedora25vm/root rd.lvm.lv=fedora_fedora25vm/swap rd.lvm.lv=fedora_fedora25vm/usr rhgb quiet" GRUB_DISABLE_RECOVERY="true"
Listing 1: An original grub default file for Fedora 25.
Section 5.1 of the GRUB Manual contains information about all of the possible keys that can be included in the grub file. I have never had needed to do anything other than modifying the values of some of the keys that are already in the grub default file. Let's look at what each of these keys means as well as some that don't appear in the grub default file.
- GRUB_TIMEOUT The value of this key determines the length of time that the GRUB selection menu is displayed. GRUB offers the capability to keep multiple kernels installed simultaneously and choose between them at boot time using the GRUB menu. The default value for this key is 5 seconds, but I usually change that to 10 seconds to allow more time to view the choices and make a selection.
- GRUB_DISTRIBUTOR This key defines a sed expression that extracts the distribution release number from the /etc/system-release file. This information is used to generate the text names for each kernel release that appear in the GRUB menu, such as "Fedora". Due to variations in the structure of the data in the system-release file between distributions, this sed expression may be different on your system.
- GRUB_DEFAULT Determines which kernel is booted by default. That is the "saved" kernel which is the most recent kernel. Other options here are a number which represents the index of the list of kernels in grub.cfg. Using an index such as 3, however, to load the fourth kernel in the list will always load the fourth kernel in the list even after a new kernel is installed. So using an index will load a different kernel after a new kernel is installed. The only way to ensure that a specific kernel release is booted is to set the value of GRUB_DEFAULT to the name of the desired kernel, like 4.8.13-300.fc25.x86_64.
- GRUB_SAVEDEFAULT Normally, this option is not specified in the grub defaults file. Normal operation when a different kernel is selected for boot, that kernel is booted only that one time. The default kernel is not changed. When set to "true" and used with GRUB_DEFAULT=saved this option saves a different kernel as the default. This happens when a different kernel is selected for boot.
- GRUB_DISABLE_SUBMENU Some people may wish to create a hierarchical menu structure of kernels for the GRUB menu screen. This key, along with some additional configuration of the kernel stanzas in grub.cfg allow creating such a hierarchy. For example, the one might have the main menu with "production" and "test" sub-menus where each sub-menu would contain the appropriate kernels. Setting this to "false" would enable the use of sub-menus.
- GRUB_TERMINAL_OUTPUT In some environments it may be desirable or necessary to redirect output to a different display console or terminal. The default is to send output to the default terminal, usually the "console" which equates to the standard display on an Intel class PC. Another useful option is to specify "serial" in a data center or lab environment in which serial terminals or Integrated Lights Out (ILO) terminal connections are in use.
- GRUB_TERMINAL_INPUT As with GRUB_TERMINAL_OUTPUT, it may be desirable or necessary to redirect input from a serial terminal or ILO device rather than the standard keyboard input.
- GRUB_CMDLINE_LINUX This key contains the command line arguments that will be passed to the kernel at boot time. Note that these arguments will be added to the kernel line of grub.cfg for all installed kernels. This means that all installed kernels will have the same arguments when booted. I usually remove the "rhgb" and "quiet" arguments so that I can see all of the very informative messages output by the kernel and systemd during the boot and startup.
- GRUB_DISABLE_RECOVERY When the value of this key is set to "false," a recovery entry is created in the GRUB menu for every installed kernel. When set to "true" no recovery entries are created. Regardless of this setting, the last kernel entry is always a "rescue" option. However, I encountered a problem with the rescue option, which I'll talk more about below.
There are other keys that I have not covered here that you might find useful. Their descriptions are located in Section 5.1 of the GRUB Manual 2.
After completing the desired configuration it is necessary to generate the /boot/grub2/grub.cfg file. This is accomplished with the following command.
grub2-mkconfig > /boot/grub2/grub.cfg
This command takes the configuration files located in /etc/grub.d in sequence to build the grub.cfg file, and uses the contents of the grub defaults file to modify the output to achieve the final desired configuration. The grub2-mkconfig command attempts to locate all of the installed kernels and creates an entry for each in the 10_Linux section of the grub.cfg file. It also creates a "rescue" entry to provide a method for recovering from significant problems that prevent Linux from booting.
It is strongly recommended that you do not edit the grub.cfg file manually because any direct modifications to the file will be overwritten the next time a new kernel is installed or grub2-mkconfig is run manually.
I encountered one problem with GRUB2 that could have serious consequences if you are not aware of it. The rescue kernel does not boot, instead, one of the other kernels boots. I found that to be the kernel at index 1 in the list, i.e., the second kernel in the list. Additional testing showed that this problem occurred whether using the original grub.cfg configuration file or one that I generated. I have tried this on both virtual and real hardware and the problem is the same on each. I only tried this with Fedora 25 so it may not be an issue with other Fedora releases.
Note that the "recovery" kernel entry that is generated from the "rescue" kernel does work and boots to a maintenance mode login.
I recommend changing GRUB_DISABLE_RECOVERY to "false" in the grub defaults file, and generating your own grub.cfg. This will generate usable recovery entries in the GRUB menu for each of the installed kernels. These recovery configurations work as expected and boot to runlevel 1—according to the runlevel command—at a command line entry that requests a password to enter maintenance mode. You could also press Ctrl-D to continue a normal boot to the default runlevel.
GRUB is the first step after BIOS in the sequence of events that boot a Linux computer to a usable state. Understanding how to configure GRUB is important to be able to recover from or to circumvent various types of problems.
I have had to boot to recovery or rescue mode many times over the years to resolve many types of problems. Some of those problems were actual boot problems due to things like improper entries in /etc/fstab or other configuration files, and others were due to problems with application or system software that was incompatible with the newest kernel. Hardware compatibility issues might also prevent a specific kernel from booting.
I hope this information will help you get started with GRUB configuration.