Ubuntu grub config management
For some time now in Informatics we have occasionally seen problems with Ubuntu desktop machines not successfully rebooting. It hasn’t been a widespread problem, affecting something like just 1% of machines whenever package updates require a reboot, so diagnosis has been difficult. We think we may finally have a proper solution …
A while back we tracked down the issue to the way in which the grub configuration was updated when certain packages (e.g. grub-pc, memtest86+ and systemd-sysv on my machine) are upgraded.
The standard way of updating the grub configuration on Debian and Ubuntu is to run the /usr/sbin/update-grub
script and that is usually done from the post-install script when a relevant package is upgraded. The problem we have is that this can (and often does) generate a configuration that doesn’t fit with the way we currently want to manage it using the LCFG grub2 component. In an attempt to ensure the grub configuration is correct, the apt component calls the grub2 component configure method whenever a package is updated that requires a reboot. We also always regenerate the grub configuration when the grub2 component is stopped which usually only happens when the system is rebooted or powered-off. The problem is that this can leave a window of some time when the configuration is in an incorrect state, if the machine crashes or is uncleanly forced off then it won’t be fixed before the next reboot.
Having tried various solutions, including package triggers, it eventually became clear that the only option was to replace the standard update-grub
script, which is provided in the grub2-common package, with a local LCFG-aware equivalent. That poses the challenge of replacing the script in such a way that when the grub2-common package is upgraded at some later time the local version is not overwritten. Debian supports this approach with diversions which are managed using the dpkg-divert command. This creates a situation where effectively both the grub2-common and lcfg-grub2 packages simultaneously provide the /usr/sbin/update-grub
file (which would normally be considered a file conflict) with the original being diverted to another location.
The diversion is created in the pre-install script for the lcfg-grub2 package (lcfg-grub2.preinst
) like this:
if [ upgrade != "$1" ] || dpkg --compare-versions "$2" lt 0.15.0-1; then dpkg-divert --package lcfg-grub2 --rename \ --divert "/usr/sbin/update-grub-debian" \ --add "/usr/sbin/update-grub" fi
Where 0.15.0-1
is the first version of the lcfg-grub2 package which provided the file. The original file is renamed to /usr/sbin/update-grub-debian
and can still be used if necessary.
For correctness, support should also be added to the pre-removal script (lcfg-grub2.postrm
) in case the lcfg-grub2 package is ever completely removed. That way the original from grub2-common package would be restored to the standard location. That is done like this:
if [ remove = "$1" -o abort-install = "$1" -o disappear = "$1" ] ; then dpkg-divert --no-rename --package lcfg-grub2 --rename \ --remove "/usr/sbin/update-grub" fi if [ abort-upgrade = "$1" ] && dpkg --compare-versions "$2" lt 0.15.0; then dpkg-divert --no-rename --package lcfg-grub2 --rename \ --remove "/usr/sbin/update-grub" fi
This handles various cases beyond just full removal, such as failure to upgrade to the new version.
The script itself is quite simple:
if om grub2 isstarted -q; then echo "Configuring grub using LCFG component" om grub2 configure else # Call the standard script if component is not running /usr/sbin/update-grub-debian "$@" fi
If the component is started, the configure method will be called otherwise the standard script (in its diverted location) will be run.
See the lcfg-grub2 code in our subversion repository for complete details. For further examples see the Debian wiki.
Dpkg diversions are a powerful tool but they do have some limitations, in particular, they don’t work well with configuration files (typically things in the /etc
directory) which are managed with other tools (e.g. debconf or ucf). There are also risks associated with replacing files from essential packages where a failure might make it impossible to fix the system.
Recent comments