Skip to content

Instantly share code, notes, and snippets.

@anonyco
Last active May 31, 2024 20:48
Show Gist options
  • Save anonyco/ec7c1d69b2ddde23fc1bdade017a0ad0 to your computer and use it in GitHub Desktop.
Save anonyco/ec7c1d69b2ddde23fc1bdade017a0ad0 to your computer and use it in GitHub Desktop.
Shellscript grub.d hook to automatically fixup /boot selected kernels for vmlinuz and initrd.img. Primarily targets ubuntu/derivatives but should work anywhere that uses grub.d
#!/bin/sh
# DESCRIPTION: fixes up /boot selected kernels for vmlinuz and initrd.img
#
# INSTALLATION: sudo wget 'https://gist.githubusercontent.com/anonyco/ec7c1d69b2ddde23fc1bdade017a0ad0/raw' \
# -O/etc/grub.d/01_fixup_boot_kernel && sudo chmod +x /etc/grub.d/01_fixup_boot_kernel
#
# ERROR HANDLING: Run this program with peace of mind knowing that any serious/critical error (that would likely bork
# your computer if you were to reboot) will alert you with a graphical popup error dialog to catch your attention:
# * IF either no initrd.img or no vmlinuz was found. This could happen if your system uses a different model
# and is most likely indicative of this script being incompatible with your system's boot setup
# * IF there's a version mismatch between the latest initrd.img/vmlinuz. This can happen, for example, if the
# there's no disk space left on /boot and only of these is successfully copied to /boot by update-initramfs
# * BOTH these errors will appear no matter what! Even if you run update-grub as a background automated task,
# this script will seek out and hook into whatever graphical display it can find and show an error box on it
#
# BEHAVIOR:
# 1. Chooses the latest available kernel version for vmlinuz and initrd.img
# 2. IF you are current running an older kernel than the latest, then this script makes sure vmlinuz.old and
# initrd.img.old point to the ones for your current running kernel (so you have a solid working backup option.)
# 3. IF vmlinuz.old and initrd.img.old are left as-is IF they are not at the latest kernel AND are not dead links.
# 4. Otherwise, vmlinuz.old and initrd.img.old are autoset to the oldest available vmlinuz and initrd.img.old
# 5. All checks make sure the version of vmlinuz.old and initrd.img.old are matching versions and non-zero size and
# you won't be notified if the versions don't match; this script will just skip choosing that version and search
# for the next working verison-matching non-zero-size vmlinuz and initrd.img pair to use.
#
# SPDX-License-Id: GPL-3.0-only
OLDDIR="$(pwd)"
if cd /boot 2>/dev/null ; then
OLDIFS="$IFS"
oldestinitrd=""
newestinitrd=""
oldestvmlinuz=""
newestvmlinuz=""
thisscript="$0"
runAsUserSourceFromPID() (
thepid="$1"
theuser="$2"
thegroup="$3"
shift 3
if cdtopwd="$(/usr/bin/grep -m1 -zahe PWD= "/proc/$thepid/environ" 2>/dev/null)" ; then
cd -- "${cdtopwd#"PWD="}" 2>/dev/null || true
elif test -d "/home/$theuser" ; then
cd -- "/home/$theuser" 2>/dev/null || true
elif test -d "/home/$thegroup" ; then
cd -- "/home/$thegroup" 2>/dev/null || true
fi
# shellcheck disable=SC2016
cdtopwd='$cdtopwd'
sudo -i -A -u "$theuser" -g "$thegroup" <<EOL
cdtopwd=''
$(
# shellcheck disable=SC2016
env -i xargs -r0a"/proc/$thepid/environ" sh -c 'export "$@"; test "$PWD" != "/boot" && export cdtopwd="$PWD"; export -p' --
)
test -z "$cdtopwd" || cd -- "$cdtopwd"
$(
IFS="'"
for a in "$@"; do
a="$a "
# shellcheck disable=SC2086
o="$(printf "%s'\\\''" $a)"
printf "'%s' " "${o%" '\\''"}"
done
)
EOL
)
showCriticalMessageGUI() (
msg="FATAL ERROR WHILST GENERATING GRUB: $thisscript: $1! System might be borked and you should investigate this before restarting!"
wall "$msg" >/dev/null 2>&1 || true
# First, we only search non-root seated session leaders. Then, we exaustively search the non-session-leaders for any x processes who might have our needed variables
for psargs in -dNo -eo; do
IFS='
'
# shellcheck disable=SC2009
for l in $(ps "$psargs" pid,euid,seat,euser,egroup 2>/dev/null | grep -ve ' 0 ' -e ' - ' -e ' EUSER '); do
IFS=' '
# shellcheck disable=SC2086
set -- $l
if test "x$*" = "x" ; then
continue
fi
# notice the "-s" flag, which suppresses outputting any read errors, which will happen for processes we dont have permission to read their environment of
if grep -asqe 'XAUTHORITY=/' "/proc/$1/environ" >/dev/null 2>&1 ; then
#eval "$(printf "sudo -u '$2' -g '$3' /usr/bin/env "; xargs -0a"/proc/$1/environ" /usr/bin/printf "%q "; printf "-- gnome-terminal")"
#if test "x' '" = "x$(/usr/bin/printf "%q" " " 2>/dev/null)"; then
# printf "%s\n" eval "$(xargs -0a"/proc/$1/environ" /usr/bin/printf "%q\n")"
#else
# printf "%s\n" eval "$(xargs -r0a"/proc/$1/environ" sh -c 'IFS="'\''"; for a in "$@"; do o="$(printf "%s'"'\\\''"'" $a)"; printf "'\''%s'\''\n" "${o%"'"'\\\''"'"}"; done' --)"
#fi
#eval "$(env -i xargs -r0a"/proc/$1/environ" sh -c 'export "$@"; test "$PWD" != "/boot" && export cdtopwd="$PWD"; export -p' --)"
#test -z "$cdtopwd" || cd -- "$cdtopwd"
#/bin/bash -i
#runAsUserSourceFromPID "$1" "$4" "$5" /usr/bin/gnome-terminal
runAsUserSourceFromPID "$1" "$4" "$5" xmessage -default ok -geometry 300x200 -nearmouse "$(printf "%s\n" "$msg" | fold -sw 36)"
return 0
fi
done
done
)
IFS='
'
for file in $( printf "%s\n" initrd.img-* vmlinuz-* | sort -nt- -k2,2 )
do
test -s "$file" || continue
if test "${file#vmlinuz-}" = "$file" ; then
oldestinitrd="${oldestinitrd:-$file}"
newestinitrd="$file"
else
oldestvmlinuz="${oldestinitrd:-$file}"
newestvmlinuz="$file"
fi
done
IFS="$(printf "\t\n ")"
if test "/$newestinitrd" = "/" -o "/$newestvmlinuz" = "/" ; then
xmessage "FATAL ERROR WHILST GENERATING GRUB: $thisscript: could not find vmlinuz or initrd in /boot! System might be borked and you should investigate this before restarting!" -default ok -geometry 300x200 -nearmouse
exit 1
fi
if test "${newestinitrd#initrd.img-}" != "${newestvmlinuz#vmlinuz-}" ; then
xmessage "FATAL ERROR WHILST GENERATING GRUB: $thisscript: version mismatch between $newestvmlinuz and $newestinitrd in /boot! System might be borked and you should investigate this before restarting!" -default ok -geometry 300x200 -nearmouse
exit 1
fi
#ln -sfT "$newestinitrd" initrd.img
echo "[INFO] $thisscript: linked /boot/initrd.img -> $newestinitrd" >&2
#ln -sfT "$newestvmlinuz" vmlinuz
echo "[INFO] $thisscript: linked /boot/vmlinuz -> $newestvmlinuz" >&2
alreadyerrored=0
if test "${oldestinitrd#initrd.img-}" != "${oldestvmlinuz#vmlinuz-}" ; then
if test -s "vmlinuz-${oldestinitrd#initrd.img-}" ; then
oldestvmlinuz="vmlinuz-${oldestinitrd#initrd.img-}"
elif test -s "initrd.img-${oldestvmlinuz#vmlinuz-}" ; then
oldestinitrd="initrd.img-${oldestvmlinuz#vmlinuz-}"
else
alreadyerrored=1
echo "[WARN] $thisscript: could not match old vmlinuz and initrd.img versions $oldestinitrd and $oldestvmlinuz as neither verisons have eachother. The old may be unavailable and this should be looked into." 1>&2
fi
fi
didMatchRepl=n
if runningkernelver="$(uname -r >/dev/null 2>&1)" && test "initrd.img-$runningkernelver" != "$newestinitrd"
then
for file in initrd.img-*"$runningkernelver" vmlinuz-*"$runningkernelver"
do
test -s "$file" -a "$file" != "$newestvmlinuz" -a "$file" != "$newestinitrd" || continue
if test "${file#vmlinuz}" = "$file" -a -s "vmlinuz-${file#initrd.img-}" ; then
oldestinitrd="$file"
oldestvmlinuz="vmlinuz-${file#initrd.img-}"
didMatchRepl=y
break
elif test -s "initrd.img-${file#vmlinuz-}" ; then
oldestinitrd="initrd.img-${file#vmlinuz-}"
oldestvmlinuz="$file"
didMatchRepl=y
break
fi
done
test "$didMatchRepl" = "n" && echo "[WARN] $thisscript: the currently running kernel version does not exist in /boot. This shouldnt be an issue as theres another kernel to boot but proceed carefully." 1>&2
fi
if test "$alreadyerrored" -eq 1
then
: ;
elif test "$didMatchRepl" = "n" -a -s "$(readlink initrd.img.old >/dev/null 2>&1)" -a -s "$(readlink vmlinuz.old >/dev/null 2>&1)" -a "$newestinitrd" != "$(basename "$(readlink initrd.img.old >/dev/null 2>&1)" >/dev/null 2>&1)"
then
echo "[INFO] $thisscript: the existing initrd.img.old and vmlinuz.old are fine as-is and left unmodified" 1>&2
elif test "$oldestinitrd" != "$newestinitrd"
then
#oldinitrdlink="$(basename "$(readlink initrd.img.old 2>/dev/null)" 2>/dev/null)"
#if test "/$oldinitrdlink" = "/" -o "/$oldinitrdlink" = "/$newestinitrd" -o \! -s "$oldinitrdlink"
#then
#ln -sfT "$oldestinitrd" initrd.img.old
echo "[INFO] $thisscript: linked /boot/initrd.img.old -> $oldestinitrd" >&2
#ln -sfT "$oldestvmlinuz" vmlinuz.old
echo "[INFO] $thisscript: linked /boot/vmlinuz.old -> $oldestvmlinuz" >&2
#fi
else
echo "[WARN] $thisscript: could not update vmlinuz.old and initrd.img.old as the oldest found versions ($oldestinitrd and $oldestvmlinuz) either were the same as the latest version or they mismatched" 1>&2
fi
cd -- "$OLDDIR" 2>/dev/null || true
IFS="$OLDIFS"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment