1

I am running ubuntu 20.04, and have a number of kernels installed ranging from the default ones to custom kernels I'm compiling locally. When I run sudo update-grub, the kernel I'm fiddling with currently (I.E. last compiled) is always magically chosen as the default option to boot into.

How does that work? How does update-grub know which kernel it should set as the default one? I have found the documentation on the subject is annoyingly anaemic:

It works by looking in /boot for all files which start with "vmlinuz-". They will be treated as kernels, and grub menu entries will be created for each.

That's nice, but how?

  • 1
    grub selects the kernel with the highest version to be default. It is very simple. – Pilot6 Jun 29 at 12:17
  • @Pilot6 OK. And how is it determining "highest version"? Just filename based on the numbers after "vmlinuz-" or some system flag somwhere or something? – Dan Scally Jun 29 at 12:21
  • 1
    Each kernel has it's version. The text after "vmlinuz-" is the version. – Pilot6 Jun 29 at 12:35
  • If you get down into custom names appended, then it I agree it doesn't seem to follow any logical sort order at that level. I never bothered to try to figure out why. – Doug Smythies Jun 29 at 12:40
  • @Pilot6 I know that the kernel has a version number and that the text after "vmlinuz-" is that version number, I just want to confirm that what you're saying is "update-grub reads the names of the files in /boot, parses the version numbers out of any file beginning vmlinuz- and uses those parsed numbers to determine which kernel to boot". If that's the case, post an answer and you get a green tick :) – Dan Scally Jun 29 at 12:46
3

update-grub calls grub-mkconfig, which in turn runs shell scripts in /etc/grub.d. One of them is /etc/grub.d/10_linux, which uses the shell function version_find_latest to keep iterating through the list of remaining Linux kernels, from latest to oldest.

The shell function version_find_latest is defined in /usr/share/grub/grub-mkconfig_lib, using helper function version_test_gt (also defined in the same file). This function uses a mix of sed regular expressions to detect prereleases, git versions, etc., and finally resorts to dpkg --compare-versions to compare two point revision strings.

You can actually try it out in the shell without compiling any kernels or changing any grub configuration:

$ source /usr/share/grub/grub-mkconfig_lib
$ version_find_latest vmlinuz-5.6.7-aaa vmlinuz-5.1.12 vmlinuz-5.6.7-git
vmlinuz-5.6.7-aaa
| improve this answer | |
New contributor
dubek is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
1

This is not an authoritative answer and will be deleted if a better one is posted.

The order of kernels on the grub menu is largely sorted by version. However grub does seem to know the difference between a release candidate and the final version. It also seems to treat the "-" character as a separator, in addtion to ".".

Example (edited, after grep menuentry /boot/grub.cfg):

    menuentry 'Ubuntu, with Linux 5.8.0-050800-lowlatency' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-050800-lowlaten>
    menuentry 'Ubuntu, with Linux 5.8.0-050800-lowlatency (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp-ps2' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-qp-sp-ps2-advan>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp-ps2 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp-powersave' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-qp-sp-pow>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp-powersave (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-qp-sp-advanced-0ac3>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-qp-sp (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-qp->
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-stock' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-stock-advanced-0ac3>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-stock (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-sto>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-spv2' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-spv2-advanced-0ac356>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-spv2 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-spv2>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds4' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds4-advanced-0ac356c1>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds4 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds4-r>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds3' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds3-advanced-0ac356c1>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds3 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds3-r>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds1' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds1-advanced-0ac356c1>
    menuentry 'Ubuntu, with Linux 5.8.0-rc1-ds1 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.8.0-rc1-ds1-r>
    menuentry 'Ubuntu, with Linux 5.7.0-doug-hwp' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.7.0-doug-hwp-advanced-0ac356>
    menuentry 'Ubuntu, with Linux 5.7.0-doug-hwp (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.7.0-doug-hwp>
    menuentry 'Ubuntu, with Linux 5.7.0-050700rc6-lowlatency' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.7.0-050700rc6-lo>
    menuentry 'Ubuntu, with Linux 5.7.0-050700rc6-lowlatency (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.>
    menuentry 'Ubuntu, with Linux 5.7.0-050700rc3-lowlatency' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.7.0-050700rc3-lo>
    menuentry 'Ubuntu, with Linux 5.7.0-050700rc3-lowlatency (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.>
    ...

In the above list 5.8.0-rc1-ds4 is actually the most recently compiled, but is 7th in the list. The first in the list is actually rc1 from the mainline PPA, with an incorrect file name, because it is actually -rc1. The 5.8.0-rc1-qp-sp-ps2 one is actually quite old, and I assume it is the extra "-" separator that contributed to its position in the list.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.