#!/bin/bash # Brian K. White - b.kenyon.w@gmail.com # Update xfs.mod and grub.cfg on the EFI partition. # Run at shutdown to ensure the EFI partition will be bootable. # Work-around for https://bugs.launchpad.net/ubuntu/+source/grub2/+bug/1652822 # Copies xfs.mod to the ESP (efi system partition) and prepends "insmod xfs" to grub.cfg # Also generates 3 other versions of grub.cfg: emergency.cfg, old.cfg, static.cfg # * grub.cfg - is automatically generated any time grub2 is installed or updated, # This script takes the grub.cfg that was automatically generated, and prepends "insmod /path/to/xfs.mod" to that. # * emergency.cfg - is a copy of the latest grub.cfg # * old.cfg - is a copy of the most recent emergency.cfg before the current one # * static.cfg - is an ultimate emergency backup, totally static hardcoded version of grub.cfg that doesn't derive from the package manager auto-generated grub.cfg at all, and doesn't use the search for uuid method to find the root fs. # TO USE # When booting fails, you will normally be left at a "grub>" prompt. # At the grub> prompt type this: # # configfile $cmdpath/emergency.cfg # # if that doesn't work, try either old.cfg or static.cfg # # configfile $cmdpath/old.cfg # or # configfile $cmdpath/static.cfga # # Then after booting, run this script, which will fix the normal grub.cfg, and booting will be normal again until the next time a grub package update breaks it again. set -f ESP_DIR=/boot/efi/EFI/ubuntu XFS_MOD=/boot/grub/x86_64-efi/xfs.mod pr () { echo "$@" >&2 ; } abrt () { echo "$0: $@" >&2 ; exit 1 ; } pr "Checking for broken grub + efi + xfs config..." pr pr "EFI System Partition ESP_DIR=${ESP_DIR}" ls -l ${ESP_DIR} >&2 pr pr "Grub-* package's xfs.mod XFS_MOD=${XFS_MOD}" ls -l ${XFS_MOD} >&2 pr # If it doesn't already exist, generate a fully static config file just as an # extra alternative emergency backup. # It's commented-out because this must be manually customized for your actual # disk layout. # This is the actual correct example for my particular laptop, which still has # the original factory partitions including uefi boot and Win10. To install # Linux I only defragged and resized the Win10 C: partition, and created a new # partition in the freed space. The uefi partition is original. Win10 was not # wiped or reinstalled. In order for grub to be able to boot the xfs root fs, # all it really needs is xfs.mod, and since there already is a FAT filesystem # for UEFI, you can place a copy of xfs.mod on the EFI filesystem, and tell # the initial grub.cfg where to find it, and then grub can get everything else # from /boot on "/", without needing /boot to be a separate ext2 filesystem. #[[ -s ${ESP_DIR}/static.cfg ]] || cat >${ESP_DIR}/static.cfg <<-"%%EOF" # insmod (hd0,gpt1)/EFI/ubuntu/xfs.mod # root=hd0,gpt5 # prefix=($root)/boot/grub # configfile $prefix/grub.cfg #%%EOF # If the copy of xfs.mod on the root fs is newer than the one on the esp # then update the copy on the esp. # This single line does the same thing but no messages #[[ ! -s xfs.mod ]] || [[ ${XFS_MOD} -nt xfs.mod ]] && cp -f ${XFS_MOD} xfs.mod pr "Checking xfs.mod ..." UPDATE_XFS_MOD=false [[ -s ${ESP_DIR}/xfs.mod ]] && { pr "${ESP_DIR}/xfs.mod is present" [[ ${XFS_MOD} -nt ${ESP_DIR}/xfs.mod ]] && { ls -l ${XFS_MOD} >&2 ls -l ${ESP_DIR}/xfs.mod >&2 pr "${ESP_DIR}/xfs.mod is older than ${XFS_MOD}" UPDATE_XFS_MOD=true } || { pr "${ESP_DIR}/xfs.mod is up to date" } } || { pr "${ESP_DIR}/xfs.mod is missing" UPDATE_XFS_MOD=true } ${UPDATE_XFS_MOD} && { pr "Updating ${ESP_DIR}/xfs.mod" cp -vf ${XFS_MOD} ${ESP_DIR}/xfs.mod >&2 : } || { pr "No update needed for ${ESP_DIR}/xfs.mod" } pr # If the efi partition's grub.cfg doesn't have some form of "insmod xfs", # (sample possible values: "insmod xfs", "insmod $cmdpath/xfs.mod") pr "Checking ${ESP_DIR}/grub.cfg ..." grep '^insmod .*xfs.*' ${ESP_DIR}/grub.cfg >&2 && { pr "${ESP_DIR}/grub.cfg contains insmod xfs" pr "No update needed for ${ESP_DIR}/grub.cfg" } || { pr "${ESP_DIR}/grub.cfg does not contain insmod xfs" pr "(A grub-* package update has generated a new ${ESP_DIR}/grub.cfg incorrectly)" # Copy the current existing emergency.cfg to old.cfg [[ -s ${ESP_DIR}/emergency.cfg ]] && { pr "emergency.cfg exists" pr "Copying current emergency.cfg to old.cfg" cp -vf ${ESP_DIR}/emergency.cfg ${ESP_DIR}/old.cfg >&2 } # Generate a new emergency.cfg by writing the insmod line followed by the new grub.cfg pr "Generating a new emergency.cfg by prepending insmod xfs to the new grub.cfg" echo 'insmod $cmdpath/xfs.mod' > ${ESP_DIR}/emergency.cfg cat ${ESP_DIR}/grub.cfg >> ${ESP_DIR}/emergency.cfg # Copy the new emergency.cfg over grub.cfg pr pr "Summary:" pr "${ESP_DIR}/grub.cfg before apt upgrade:" cat ${ESP_DIR}/old.cfg >&2 pr pr "${ESP_DIR}/grub.cfg after apt upgrade:" cat ${ESP_DIR}/grub.cfg >&2 pr pr "${ESP_DIR}/emergency.cfg we just generated:" cat ${ESP_DIR}/emergency.cfg >&2 pr pr "Copying new emergency.cfg over grub.cfg" cp -vf ${ESP_DIR}/emergency.cfg ${ESP_DIR}/grub.cfg >&2 } pr pr "Finished" pr pr "This is the ${ESP_DIR}/grub.cfg currently in effect for the next boot:" pr "---" cat ${ESP_DIR}/grub.cfg >&2 pr "---"