Skip to content

Instantly share code, notes, and snippets.

@dreamcat4
Last active October 16, 2020 06:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreamcat4/b175c96dfefd82aa73aef06926e7aaff to your computer and use it in GitHub Desktop.
Save dreamcat4/b175c96dfefd82aa73aef06926e7aaff to your computer and use it in GitHub Desktop.
For luks zfs root pool on ubuntu. Patches for - dual disks, v1.04, for ubuntu 19.04+
#!/bin/sh
#
# /usr/local/bin/update-boot2
#
# Summary:
#
# For luks zfs root pool on ubuntu. Patches for - dual disks, v1.04, for ubuntu 19.04+
#
# a) This patches initrd to remove certain error messages at boot time, that would otherwise
# interfere and prevent the system booting correctly.
# b) Regenerates the contents /boot2 on the 2nd boot drive, for example after kernel updates.
#
# Details:
#
# * patch the 'cryptroot' script in initramfs
# * in the event of a failed boot drive, attempt to continue booting off the other good disk
# * enabled with a new boot arg 'cryptroot_nofail', does not check the existing crypttab 'nofail'
# * does not fail if other boot disk is also missing, it assumes they don't fail simultaneously
#
# * patch 'grub-mkconfig' script. when generating 'grub.cfg' menu file
# * do not always assume the target boot partition is mounted to /boot (might be /boot2 etc)
# * instead get the boot partition from the target directory where 'grub.cfg' is being written to
# * grub.cfg is then generated with correct boot disk uuids, for grub booting off 2nd boot disk
#
# * copy over new kernel files to /boot2
#
# * update-initramfs
#
# * grub-mkconfig -o /boot2/grub/grub.cfg
#
#
unset _not_patched
_home="$(eval echo ~$USER)"
cat_patch_cryptroot ()
{
# cd /tmp
# mkdir -p a/usr/share/initramfs-tools/scripts/local-top
# mkdir -p b/usr/share/initramfs-tools/scripts/local-top
# cp /usr/share/initramfs-tools/scripts/local-top/cryptroot a/usr/share/initramfs-tools/scripts/local-top/cryptroot
# cp /usr/share/initramfs-tools/scripts/local-top/cryptroot b/usr/share/initramfs-tools/scripts/local-top/cryptroot
# nano b/usr/share/initramfs-tools/scripts/local-top/cryptroot
# diff -crB a/usr/share/initramfs-tools/scripts/local-top/cryptroot b/usr/share/initramfs-tools/scripts/local-top/cryptroot > cryptroot.patch
# cat cryptroot.patch
cat <<- "EOF"
diff -crB a/usr/share/initramfs-tools/scripts/local-top/cryptroot b/usr/share/initramfs-tools/scripts/local-top/cryptroot
*** a/usr/share/initramfs-tools/scripts/local-top/cryptroot 2019-05-20 11:31:59.904908630 +0100
--- b/usr/share/initramfs-tools/scripts/local-top/cryptroot 2019-05-22 20:52:45.612925860 +0100
***************
*** 86,91 ****
--- 86,96 ----
crypttab_parse_options --export --missing-path=fail || return 1
if ! wait_for_source; then
+ if [ "${CRYPTROOT_NOFAIL}" -o "${cryptroot_nofail}" ]; then
+ cryptsetup_message "ERROR: Skipping target $CRYPTTAB_NAME: device not found, and cryptroot_nofail=true"
+ return 1
+ fi
+
# we've given up
if [ -n "$panic" ]; then
panic "ALERT! encrypted source device $CRYPTTAB_SOURCE does not exist, can't unlock $CRYPTTAB_NAME."
EOF
}
_patch_cryptroot ()
{
_cryptroot=/usr/share/initramfs-tools/scripts/local-top/cryptroot
if ! grep -q -i 'cryptroot_nofail' $_cryptroot; then
cat_patch_cryptroot | patch -p1 --forward --directory=/ --ignore-whitespace --reject-file=- $_cryptroot
_not_patched=true
if [ -e "${_cryptroot}.orig" ]; then
echo "Moving ${_cryptroot}.orig to ${_home}/"
mv "${_cryptroot}.orig" $_home
fi
if [ -e "${_cryptroot}.rej" ]; then
echo "Moving ${_cryptroot}.rej to ${_home}/"
mv "${_cryptroot}.rej" $_home
fi
else
echo "cryptroot: already patched"
fi
}
cat_patch_cryptroot_hooks ()
{
# cd /tmp
# mkdir -p a/usr/share/initramfs-tools/hooks
# mkdir -p b/usr/share/initramfs-tools/hooks
# cp /usr/share/initramfs-tools/hooks/cryptroot a/usr/share/initramfs-tools/hooks/cryptroot
# cp /usr/share/initramfs-tools/hooks/cryptroot b/usr/share/initramfs-tools/hooks/cryptroot
# nano b/usr/share/initramfs-tools/hooks/cryptroot
# diff -crB a/usr/share/initramfs-tools/hooks/cryptroot b/usr/share/initramfs-tools/hooks/cryptroot > cryptroot.patch
# cat cryptroot.patch
cat <<- "EOF"
diff -crB a/usr/share/initramfs-tools/hooks/cryptroot b/usr/share/initramfs-tools/hooks/cryptroot
*** a/usr/share/initramfs-tools/hooks/cryptroot 2019-05-22 18:34:12.116097472 +0100
--- b/usr/share/initramfs-tools/hooks/cryptroot 2019-05-22 20:13:02.159138688 +0100
***************
*** 70,88 ****
# take the last mountpoint if used several times (shadowed)
unset -v devnos
spec="$(printf '%b' "$spec")"
- resolve_device "$spec" || continue # resolve_device() already warns on error
fstype="$(printf '%b' "$fstype")"
! if [ "$fstype" = "btrfs" ]; then
! # btrfs can span over multiple devices
! if uuid="$(device_uuid "$DEV")"; then
! for dev in "/sys/fs/$fstype/$uuid/devices"/*/dev; do
! devnos="${devnos:+$devnos }$(cat "$dev")"
! done
! else
! cryptsetup_message "ERROR: $spec: Couldn't determine UUID"
fi
- elif [ -n "$fstype" ]; then
- devnos="$MAJ:$MIN"
fi
fi
done </proc/mounts
--- 70,97 ----
# take the last mountpoint if used several times (shadowed)
unset -v devnos
spec="$(printf '%b' "$spec")"
fstype="$(printf '%b' "$fstype")"
! if [ "$fstype" = "zfs" ]; then
! # zfs can span over multiple devices
! for dev in $(zpool status -L -P | grep -o "/dev/[^ ]*"); do
! MAJ="$(printf "%d\n" 0x$(stat -L -c"%t" -- "$dev"))"
! MIN="$(printf "%d\n" 0x$(stat -L -c"%T" -- "$dev"))"
! devnos="${devnos:+$devnos }$MAJ:$MIN"
! done
! else
! resolve_device "$spec" || continue # resolve_device() already warns on error
! if [ "$fstype" = "btrfs" ]; then
! # btrfs can span over multiple devices
! if uuid="$(device_uuid "$DEV")"; then
! for dev in "/sys/fs/$fstype/$uuid/devices"/*/dev; do
! devnos="${devnos:+$devnos }$(cat "$dev")"
! done
! else
! cryptsetup_message "ERROR: $spec: Couldn't determine UUID"
! fi
! elif [ -n "$fstype" ]; then
! devnos="$MAJ:$MIN"
fi
fi
fi
done </proc/mounts
EOF
}
_patch_cryptroot_hooks ()
{
_cryptroot_hooks=/usr/share/initramfs-tools/hooks/cryptroot
if ! grep -q -i 'zpool status -L -P | grep -o' $_cryptroot_hooks; then
cat_patch_cryptroot_hooks | patch -p1 --forward --directory=/ --ignore-whitespace --reject-file=- $_cryptroot_hooks
_not_patched=true
if [ -e "${_cryptroot_hooks}.orig" ]; then
echo "Moving ${_cryptroot_hooks}.orig to ${_home}/cryptroot_hooks.orig"
mv "${_cryptroot_hooks}.orig" ${_home}/cryptroot_hooks.orig
fi
if [ -e "${_cryptroot_hooks}.rej" ]; then
echo "Moving ${_cryptroot_hooks}.rej to ${_home}/cryptroot_hooks.rej"
mv "${_cryptroot_hooks}.rej" ${_home}/cryptroot_hooks.rej
fi
else
echo "cryptroot_hooks: already patched"
fi
}
cat_patch_grub_mkconfig ()
{
# cd /tmp
# mkdir -p a/usr/sbin
# mkdir -p b/usr/sbin
# cp /usr/sbin/grub-mkconfig a/usr/sbin/grub-mkconfig
# cp /usr/sbin/grub-mkconfig b/usr/sbin/grub-mkconfig
# nano b/usr/sbin/grub-mkconfig
# diff -crB a/usr/sbin/grub-mkconfig b/usr/sbin/grub-mkconfig > grub-mkconfig.patch
# cat grub-mkconfig.patch
cat <<- "EOF"
*** a/usr/sbin/grub-mkconfig 2017-04-28 20:29:30.444342042 +0100
--- b/usr/sbin/grub-mkconfig 2017-04-28 20:31:03.388384589 +0100
***************
*** 139,146 ****
GRUB_DEVICE="`${grub_probe} --target=device /`"
GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
! # Device containing our /boot partition. Usually the same as GRUB_DEVICE.
! GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true
# Filesystem for the device containing our userland. Used for stuff like
--- 139,153 ----
GRUB_DEVICE="`${grub_probe} --target=device /`"
GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
! if [ "x${grub_cfg}" = "x" ]; then
! # Device containing our /boot partition. Usually the same as GRUB_DEVICE.
! GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
! else
! # Device where we are outputting our grub configuration file
! grub_cfg_dir="`dirname ${grub_cfg}`"
! GRUB_DEVICE_BOOT="`${grub_probe} --target=device $grub_cfg_dir`"
! fi
!
GRUB_DEVICE_BOOT_UUID="`${grub_probe} --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`" || true
# Filesystem for the device containing our userland. Used for stuff like
EOF
}
_patch_grub_mkconfig ()
{
_grub_mkconfig=/usr/sbin/grub-mkconfig
if ! grep -q '${grub_probe} --target=device $grub_cfg_dir' $_grub_mkconfig; then
cat_patch_grub_mkconfig | patch -p1 --forward --directory=/ --ignore-whitespace --reject-file=- $_grub_mkconfig
_not_patched=true
if [ -e "${_grub_mkconfig}.orig" ]; then
echo "Moving ${_grub_mkconfig}.orig to ${_home}/"
mv "${_grub_mkconfig}.orig" ${_home}
fi
if [ -e "${_grub_mkconfig}.rej" ]; then
echo "Moving ${_grub_mkconfig}.rej to ${_home}/"
mv "${_grub_mkconfig}.rej" ${_home}
fi
else
echo "grub_mkconfig: already patched"
fi
}
_update_initrd ()
{
if [ "$_not_patched" ]; then
update-initramfs -c -k all
update-grub
# reinstall grub
[ -d /boot/efi ] && _grub_args_boot_efi="--efi-directory=/boot/efi"
grub-install --target=x86_64-efi --recheck --no-floppy --boot-directory=/boot $_grub_args_boot_efi
fi
}
_sync_boot2 ()
{
_boot2_folder="/boot2"
_mounts="$(mount)"
_boot2_drive="$(echo $_mounts | grep "on $_boot2_folder " | cut -d' ' -f1 | sed -e 's/[0-9]*$//')"
if [ "$_boot2_drive" ]; then
echo "$0: syncing /boot to $_boot2_folder"
rsync -avu --delete "/boot/" "$_boot2_folder"
# update-initramfs -b ${_boot2_folder} -c -k all
# generate a /boot2 tailored version of grub.cfg
grub-mkconfig -o ${_boot2_folder}/grub/grub.cfg
# reinstall grub
[ -d ${_boot2_folder}/efi ] && _grub_args_boot2_efi="--efi-directory=${_boot2_folder}/efi"
grub-install --target=x86_64-efi --recheck --no-floppy --boot-directory=${_boot2_folder} $_grub_args_boot2_efi $_boot2_drive
else
echo "$0: warning: couldn't find any $_boot2_folder to update. Skipping."
fi
}
# Begin:
echo "$0: updating..."
_patch_cryptroot;
_patch_cryptroot_hooks;
_patch_grub_mkconfig;
_update_initrd;
_sync_boot2;
echo "$0: done."
# End.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment