4th July, updated with BTRFS installations.
There’s also a more recent and simpler version of this post.
Besides Windows (which I rarely use) on my computers, I have a few Linux distributions. Grub 2 does a good job booting Windows and Linux, especially thanks to os-prober, in autodetecting other operating systems in other partitions of the same computer. However, there are a few “buts” in this strategy:
- Typically, the last installed Linux distribution, say L1, installs its own grub as the main one, and when you upgrade the kernel in another Linux distribution, say L2, you have to boot into L1 and “update-grub” so that the main grub configuration learns about the new kernel of L2. Only then can you boot the new kernel of L2. Of course, you can change the main grub by reordering the EFI entries, e.g., by using the computer’s BIOS, but again, that’s far from optimal.
- Not all Linux distributions’ grub configurations can boot other Linux distributions. For example, Arch-based distros like EndeavourOS and Manjaro can boot Ubuntu-based distros, but not the other way around (unless you fix a few things in the grub configuration of Ubuntu)! Recently, I also started to use Fedora. I found out that os-prober in Ubuntu and EndeavourOS does not detect the configurations correctly to boot Fedora: recently, Fedora switched to “blscfg” (https://fedoraproject.org/wiki/Changes/BootLoaderSpecByDefault), and as a result, Ubuntu and EndeavourOS create grub configurations that do not consider the changes you made in Fedora’s /etc/default/grub.
That’s why I started to experiment with grub configurations. I still have a “main grub” in a Linux installation, which simply “delegates” to the grub configurations of the other Linux installations. This way, I can solve both the problems above!
In this blog post, I’ll show how I did that. Note that this assumes you use EFI to boot.
I have Windows 10, Kubuntu, EndeavourOS, and Fedora on the same computer in this example. I will configure the grub installation of Fedora so that it delegates to Windows, Kubuntu, and EndeavourOS without relying on os-prober.
This is the disk layout of my computer so that you understand the numbers in the grub configuration that I’ll show later (I omit other partitions like Windows recovery).
1 2 3 4 5 6 |
/dev/nvme0n1p1 650M EFI System /dev/nvme0n1p3 139G Microsoft basic data /dev/nvme0n1p7 20G Linux swap /dev/nvme0n1p8 87,9G Linux filesystem FEDORA /dev/nvme0n1p10 68,9G Linux filesystem ENDEAVOUROS /dev/nvme0n1p11 70,2G Linux filesystem KUBUNTU |
The key point is modifying the file /etc/grub.d/40_custom. I guess you already know that you should not modify directly grub.cfg, because a system update or a grub update (e.g., “update-grub”) will overwrite that file.
The file /etc/grub.d/40_custom already has some contents that must be left as they are: you add your lines after the existing ones. For example, in Fedora, you have:
1 2 3 4 5 |
#!/usr/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. |
We will use the option configfile of grub configuration (see https://www.gnu.org/software/grub/manual/grub/grub.html#configfile): “Load file as a configuration file. If file defines any menu entries, then show a menu containing them immediately.” The Arch wiki also explains it well:
If the other distribution has already a valid /boot folder with installed GRUB, grub.cfg, kernel and initramfs, GRUB can be instructed to load these other grub.cfg files on-the-fly during boot.
The idea is to put in /etc/grub.d/40_custom an entry for each Linux distribution, pointing to the grub.cfg of that distribution after setting the root partition. Thus, the path to the grub.cfg must be intended as an absolute path in that partition. If you look at the partition numbers above, these are the two entries for booting EndeavourOS and Kubuntu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
menuentry "EndeavourOS" { insmod part_gpt insmod btrfs insmod ext2 rmmod tpm set root='hd0,gpt10' configfile /boot/grub/grub.cfg } menuentry "Kubuntu" { insmod part_gpt insmod btrfs insmod ext2 rmmod tpm set root='hd0,gpt11' configfile /boot/grub/grub.cfg } |
NOTE: the “rmmod tpm” is required to avoid TPM errors when booting those systems (“Unknown TPM error”, “you need to load the kernel first”). It happened on my Dell XPS 13, for example. Adding that line (i.e., not loading the module “tpm”) solved the problem.
Remember that the path assumes that the /boot directory is not mounted on a separate partition. If, instead, that’s the case, you probably have to remove “/boot”, but I haven’t tried that.
Concerning the entry for Windows, here it is:
1 2 3 4 5 6 7 |
menuentry "Windows" { savedefault insmod part_gpt insmod fat set root=(hd0,gpt1) chainloader (${root})/EFI/Microsoft/Boot/bootmgfw.efi } |
In this entry, the root must correspond to the EFI partition, NOT to the partition of Windows.
Save the file and regenerate the grub configuration. In other Linux distributions, it would be a matter of running “update-grub,” but in Fedora, it is:
1 |
sudo grub2-mkconfig -o /boot/grub2/grub.cfg |
Now reboot, and you should see the grub menu of Fedora and then, at the bottom, the entries for EndeavourOS, Kubuntu, and Windows. Choosing “EndeavourOS” or “Kubuntu” will NOT boot directly in these systems: it will show the grub menu of “EndeavourOS” or “Kubuntu.”
If you upgrade the kernel on one of these two systems, their grub configuration will be correctly updated. There’s no need to boot into Fedora to update its grub configuration 🙂
If you want to configure the grub in another Linux distribution, please remember that Fedora stores the grub.cfg in /boot/grub2 instead of /boot/grub, so you should write the entry for Fedora with the right path. However, if you plan to boot Fedora with this mechanism, you should disable “blscfg” in the Fedora grub configuration, or you will not be able to boot Fedora (errors “increment.mod” and “blscfg.mod” not found).
Now that we verified that it works, we can remove the entries generated by os-prober. In /etc/default/grub add the line:
1 |
GRUB_DISABLE_OS_PROBER=true |
and regenerate the grub configuration.
If you want Grub to remember the last choice, you can look at this post.
On a side note, due to the way Fedora uses grub (https://fedoraproject.org/wiki/Changes/HiddenGrubMenu), without os-prober, you will not see the grub menu unless you press ESC. After the timeout, it will simply boot on the default entry. To avoid that and see the grub menu, just run:
1 |
sudo grub2-editenv - unset menu_auto_hide |
And the grub menu will get back as usual.
Then, you can also remove os-prober from the other Linux installations since it is useless now.
These were the original grub menus of Fedora and EndeavourOS before applying the modifications described in this post:
Pretty crowded!
This is the result after the procedure described in this post (note that from the Fedora grub menu, you select EndeavourOS to land its grub menu and Kubuntu to land its grub menu):
Much better! 🙂
If you need to boot an installation in a BTRFS filesystem (which also includes the /boot directory and the grub.cfg), things are slightly more complex. In fact, BTRFS installations are typically based on subvolumes. The root subvolume is typically denoted by the label “@”. This must be taken into consideration when creating the menu entry.
For example, I’ve also installed Arch on my computer using BTRFS, and the root subvolume is denoted by “@”. The menu entry is as follows:
1 2 3 4 5 6 7 8 9 |
menuentry "Arch" { insmod gzio insmod part_gpt insmod btrfs insmod ext2 rmmod tpm set root='hd0,gpt13' configfile /@/boot/grub/grub.cfg } |
Note the presence of “/@” in the configfile specification.
That’s not all. If the GRUB configuration specified in configfile has submenus, for example, automatically generated by grub-btrfs, you also must define the prefix variable appropriately (in fact, grub-btrfs generates entries relying on such a variable):
1 2 3 4 5 6 7 8 9 10 |
menuentry "Arch" { insmod gzio insmod part_gpt insmod btrfs insmod ext2 rmmod tpm set root='hd0,gpt13' set prefix="/@/boot/grub" configfile "${prefix}/grub.cfg" } |
Pingback: Testing the new Fedora 36 | Lorenzo Bettini
Pingback: Timeshift and grub-btrfs in Linux Arch | Lorenzo Bettini
Pingback: My notes on the Grub incident in Linux Arch | Lorenzo Bettini
Pingback: Installing Ubuntu Linux on an Acer Aspire Vero | Lorenzo Bettini
Hi Lorenzo,
Thank you for this post, it helped me.
I have Fedora as my main OS (this is the main GRUB) and Manjaro is located on another disk. On Manjaro, i use BTRFS as filesystem and btrfs-grub to populate some menu-entries in order to be able to boot on any snapshot.
Well, i didn’t use the prefix variable in the file /etc/grub.d/40_custom
I directly put :
menuentry “Manjaro” {
insmod gzio
insmod part_gpt
insmod btrfs
set root=’hd1,gpt6′
configfile “/@/boot/grub/grub.cfg”
}
I can boot on my Manjaro OS from Fedora. (I do not see any “prefix variable” in my grub-btrfs.cfg though).
Then, i have an issue i can’t resolve for now. When i am in Manjaro grub menu, i can’t do back to Fedora grub menu. Indeed, when i press ESC key, my computer is stuck, the only way is to do a hard reset….
Yet on the archwiki https://wiki.archlinux.org/title/GRUB#GNU/Linux
They say : “When choosing this entry, GRUB loads the grub.cfg file from the other volume and displays that menu. Any environment variable changes made by the commands in file will not be preserved after configfile returns. Press Esc to return to the first GRUB menu.”
So it should work…do you have any idea ?
Thanks you
Regards
Hi
I remember I had the same problem as well: when pressing ESC, things did not work as expected.
If I remember correctly, I had this problem when the main configuration was Fedora, which I don’t use anymore.
I did not investigate further because it’s just a matter of rebooting.
Hi Lorenzo
Great post, learnt a lot…
One question, you use
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
to update the configuration, and I did the same… everything works, but I remember I read somewherem this should be used on UEFI-based machines
sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
I see /boot/efi/EFI/redhat/grub.cfg in my PC is quite simple, and the last statement is indeed
configfile $prefix/grub.cfg
and $prefix being resolved to /boot/grub2/grub.cfg, so everything works as expected, but just curious if this would work even if I use the “suggested” command, i.e. grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
IIRC, the second method you mention is the old one, which can still be found on old articles. In fact, as you noted, that file simply refers to the new one.
Pingback: LG GRAM 16 (16Z90P): Adding a second SSD | Lorenzo Bettini
Pingback: Dell OptiPlex 5040 MiniTower: upgrading SSD | Lorenzo Bettini