Regenerating `initramfs` from another snapshot with `mkinitcpio`
I was hit by an unfortunate
bug
recently, in which a bundled ssl
library overrode the system wide version
rendering my system unbootable. I could not even get into early userspace
because the initramfs
generated with this library could not cryptsetup open
my encrypted root partition.
This is usually a moment in whch those who have a (btrfs/zfs/lvm) system
rollback solution in place can calmly rollback their system and go on with their
day. (/boot
along with the initramfs
files should be kept under rollback
control, otherwise snapshots using older kernels would not be bottable).
However, suppose we want to fix the issue directly: we need to know how to
regenerate an initramfs from a system root that is not the current one (/
).
Suppose our snapshots look like this
/btrfs/@root
/btrfs/snapshots/@good_snapshot-1
/btrfs/snapshots/@good_snapshot-2
/btrfs/snapshots/@good_snapshot-3
After the update, /btrfs/@root
is broken (because
/btrfs/@root/boot/initramfs-linux.img
are broken) and suppose we are currently
booted into /btrfs/snapshots/@good_snapshot-3
. What it means for us to be
“booted into” /btrfs/snapshots/@good_snapshot-3
is that the subvolume
/btrfs/snapshots/@good_snapshot-3
is mounted to /
just after the root
partition is unlocked in the boot process.
Reading the manual of mkinitcpio
we see that we need the options
-g, --generate filename
Generate a CPIO image as filename. Default: no; this means nothing will
be written to the filesystem unless this option is specified.
-r, --moduleroot root
Specifies the root directory to find modules in, defaulting to /
-k, --kernel kernelversion
Use kernelversion, instead of the current running kernel. This may be a
path to a kernel image (only supported for x86-based architectures), a
specific kernel version or the special keyword none. In the latter case,
no kernel modules are added to the image.
The option -g
will tell mkinitcpio
where to save the initramfs, we want this
to be generated in the root of the currently broken snapshot
/btrfs/@root/boot/initramfs-linux.img
. Moreover, we want mkinitcpio
to read
all module information from /btrfs/@root
and not /
(which is currently
mounted to /btrfs/snasphots/@good_snapshot-3
), so we pass this to the -r
option. Finally, we want mkinitcpio
to read the correct kernel version (image)
from disk to create the initramfs
, so we need to pass -k /btrfs/@root/boot/vmlinuz-linux
to mkinitcpio
. Now that the initramfs
has
been regenerated, we can re-install our bootloader entries and boot into
/btrfs/@root
as usual.
This is another example where Unified Kernel Images (UKI’s) can really save ones
bacon: after regenerating the initramfs
, we can sipmly re-create a bootable
UKI and create a new EFI entry if necessary with efibootmgr
to create a
bootable system. We need not worry about bootloaders getting confused with
archived snapshots and live systems.