Skip to content

Instantly share code, notes, and snippets.

@vixalien
Last active May 13, 2022 16:03
Show Gist options
  • Save vixalien/482eee203808290b2181c9960225a8f5 to your computer and use it in GitHub Desktop.
Save vixalien/482eee203808290b2181c9960225a8f5 to your computer and use it in GitHub Desktop.
Add kernels to efi directory for systemd boot
#!/bin/bash
# this script generates a kernel hook to populate systemd-boot entries whenever
# kernels are added or removed
DEFAULT_NAME="Ubuntu"
DEFAULT_UUID="e46e8ef1-c78f-4652-ad6a-51b0b313e39c"
DEFAULT_BOOT_DIR="/boot"
DEFAULT_ESD="/boot/efi"
DEFAULT_CMDLINE="quiet splash resume=UUID=ea1497af-8f02-414f-b533-9434d70cd407"
# the number of items in prompt
I="6"
read -e -p "[1/$I] Enter the name of your OS: " -i $DEFAULT_NAME NAME
NAME_LOWERCASE=$(echo "$NAME" | tr '[:upper:]' '[:lower:]')
DEFAULT_EFI_DIR="/Linux/${NAME_LOWERCASE}"
read -e -p "[2/$1] Enter the UUID of the directory that contains your installation: " -i $DEFAULT_UUID UUID
read -e -p "[3/$I] Enter the directory that contains your initrd and kernel: " -i $DEFAULT_BOOT_DIR BOOT_DIR
read -e -p "[4/$I] Where is your ESD?: " -i $DEFAULT_ESD ESD
read -e -p "[5/$I] Enter the path on ESD that will contain the initrd and kernel: " -i $DEFAULT_EFI_DIR EFI_DIR
read -e -p "[6/$I] Add additional kernel parameters? " -i "${DEFAULT_CMDLINE}" CMDLINE
# we add `-auto` to the EFI directory to allow other entries to exists without
# being affected by this script
EFI_DIR+="-auto"
cat << EOF > zz-update-systemd-boot
#!/bin/bash
# this file is at /etc/kernel/postinst.d/zz-update-systemd-boot
#
# This is a simple kernel hook to populate the systemd-boot entries whenever
# kernels are added or removed.
# the following variables were set automatically, change if you really know what
# you are doing
NAME="${NAME}"
UUID="${UUID}"
BOOT_DIR="${BOOT_DIR}"
EFI_DIR="${EFI_DIR}"
ESD="${ESD}"
NAME_LOWERCASE="${NAME_LOWERCASE}"
CMDLINE="${CMDLINE}"
EOF
cat << \EOL >> zz-update-systemd-boot
function getfilesize {
if [ -f $1 ]; then
FSIZE=$(du -k $1 | cut -f1 | sed 's/[^0-9]//g')
else
FSIZE=0
fi
}
# Our kernels.
KERNELS=()
FIND="find ${BOOT_DIR} -maxdepth 1 -name 'vmlinuz-*' -type f -print0 | sort -rz"
while IFS= read -r -u3 -d $'\0' LINE; do
KERNEL=$(basename "${LINE}")
KERNELS+=("${KERNEL:8}")
done 3< <(eval "${FIND}")
# There has to be at least one kernel.
if [ ${#KERNELS[@]} -lt 1 ]; then
echo -e "\e[2msystemd-boot\e[0m \e[1;31mNo kernels found.\e[0m"
exit 1
fi
# Perform a nuclear clean to ensure everything is always in perfect sync.
rm -f $ESD/loader/entries/${NAME_LOWERCASE}-auto*.conf 2> /dev/null
rm -rf $ESD$EFI_DIR 2> /dev/null
mkdir -p $ESD$EFI_DIR
mkdir -p $ESD/loader/entries
SPACE_LEFT=$(df -k ${ESD} | awk '/[0-9]%/{print $(NF-2)}')
# Copy the latest kernel files to a consistent place so we can keep using the
# same loader configuration.
FILES=(config initrd.img System.map vmlinuz)
LATEST="${KERNELS[@]:0:1}"
echo $LATEST
echo -e "\e[2mFound kernel\e[0m \e[1;32m${LATEST}\e[2m (Default)\e[0m"
# Checking if there is space available the +1 in the if statement is for
# adjusting for the loader
TOTAL_SIZE=0
for FILE in ${FILES[@]}; do
getfilesize "${BOOT_DIR}/${FILE}-${LATEST}"
((TOTAL_SIZE=TOTAL_SIZE+FSIZE))
done
if (( SPACE_LEFT > (TOTAL_SIZE+1) )); then
for FILE in ${FILES[@]}; do
cp "${BOOT_DIR}/${FILE}-${LATEST}" "${ESD}${EFI_DIR}/${FILE}"
done
cat << EOF > $ESD/loader/entries/${NAME_LOWERCASE}-auto.conf
title ${NAME}
linux ${EFI_DIR}/vmlinuz
initrd ${EFI_DIR}/initrd.img
options root=UUID=${UUID} ro ${CMDLINE}
EOF
# optional: sign kernels
sbctl sign "${ESD}${EFI_DIR}/vmlinuz"
(( SPACE_LEFT=SPACE_LEFT-TOTAL_SIZE))
else
echo -e "\e[1;31mCannot copy kernel because there is no space left on EFI\e[0m \e[1;32m${LATEST}\e[2m (Default)\e[0m"
fi
# Copy any legacy kernels over too, but maintain their version-based names to
# avoid collisions.
if [ ${#KERNELS[@]} -gt 1 ]; then
LEGACY=("${KERNELS[@]:1}")
for VERSION in "${LEGACY[@]}"; do
echo -e "\e[2mFound kernel\e[0m \e[1;32m${VERSION}\e[0m"
TOTAL_SIZE=0
for FILE in ${FILES[@]}; do
getfilesize "${BOOT_DIR}/${FILE}-${LATEST}"
((TOTAL_SIZE=TOTAL_SIZE+FSIZE))
done
if (( SPACE_LEFT > (TOTAL_SIZE+1) )); then
for FILE in ${FILES[@]}; do
cp "${BOOT_DIR}/${FILE}-${VERSION}" "${ESD}${EFI_DIR}/${FILE}-${VERSION}"
done
cat << EOF > $ESD/loader/entries/${NAME_LOWERCASE}-auto-${VERSION}.conf
title ${NAME} ${VERSION}
linux ${EFI_DIR}/vmlinuz-${VERSION}
initrd ${EFI_DIR}/initrd.img-${VERSION}
options root=UUID=${UUID} ro ${CMDLINE}
EOF
# optional: sign kernels
sbctl sign "${ESD}/${EFI_DIR}/vmlinuz-${VERSION}"
(( SPACE_LEFT=SPACE_LEFT-TOTAL_SIZE))
else
echo -e "\e[1;31mCannot copy kernel because there is no space left on EFI\e[0m \e[1;32m${VERSION}\e[0m"
fi
done
fi
# Success!
exit 0
EOL
chmod +x zz-update-systemd-boot
#!/bin/bash
# this script generates a hook, runs it and then install it
if [ "$EUID" -ne 0 ]
then echo "Please run as root"
exit
fi
source ./gen-script.sh
source ./zz-update-systemd-boot
source ./ubuntu-install-hook.sh
#!/bin/bash
# this files generates a link of generated kernel hook in the hooks directory
chown root: zz-update-systemd-boot
chmod 0755 zz-update-systemd-boot
[ -d "/etc/initramfs/post-update.d" ] || mkdir -p /etc/initramfs/post-update.d
rm -f /etc/{kernel/postrm.d,kernel/postinst.d,initramfs/post-update.d}/zz-update-systemd-boot
FILE="$(pwd)/zz-update-systemd-boot"
LINK="$( eval echo /etc/{kernel/postrm.d,kernel/postinst.d,initramfs/post-update.d}/zz-update-systemd-boot)"
rm -f $LINK
ln -s $FILE /etc/kernel/postrm.d/zz-update-systemd-boot
ln -s $FILE /etc/kernel/postinst.d/zz-update-systemd-boot
ln -s $FILE /etc/kernel/post-update.d/zz-update-systemd-boot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment