#!/bin/sh # EFI related vars EFI_BASE_LABEL="Debian unified" EFI_MOUNT_PATH="/boot/efi" temp_efi_list_file="/tmp/efibootmgr.label.entry.temp" # OS related vars ROOT_UUID=$(findmnt --kernel --noheadings --output UUID -- /) ROOT_FSTYPE=$(findmnt --kernel --noheadings --output FSTYPE -- /) CRYPT_PART_UUID=$(blkid | sed --silent 's;/dev/.*_crypt.*UUID="\(.*\)".*TYPE=.*;\1;p') temp_kernel_list_file="/tmp/kernel.list.temp" temp_kernel_command_file="/tmp/kernel.command.temp" # Clean old entries {{{ ## Install efibootmgr tool if not available command -v efibootmgr > /dev/null || aptitude install --assume-yes -- efibootmgr ## Get all old entries list with base label rm --force -- "${temp_efi_list_file}" ; touch "${temp_efi_list_file}" efibootmgr | grep --extended-regexp -- ".*${EFI_BASE_LABEL}.*" | cut --characters=5-8 > "${temp_efi_list_file}" ## Remove all matching entries while IFS= read -r OLD_EFI_ENTRY; do printf "%s\n" "Deleting efiboot entry ${OLD_EFI_ENTRY}" efibootmgr --delete-bootnum --bootnum "${OLD_EFI_ENTRY}" > /dev/null || exit 1 #printf "%s\n" "efibootmgr --delete-bootnum --bootnum ${EFI_ENTRY}" done < "${temp_efi_list_file}" # }}} # Clean old kernels {{{ ## Rename last version of generic kernel for backup mv -- "${EFI_MOUNT_PATH}/EFI/debian/linux.debian.efi" "${EFI_MOUNT_PATH}/EFI/debian/backup.debian.efi.$(date +%Y%m%d-%H%M)" ## Keep only the 4 more recent backup kernels find "${EFI_MOUNT_PATH}/EFI/debian" -type f -iname "backup.debian.efi.*" | sort --reverse --numeric-sort -- | tail --lines=+5 -- | xargs --replace={} rm -- {} ## Remove all previous unified kernels with version in filename find "${EFI_MOUNT_PATH}/EFI/debian" -type f -iname "linux.debian.*.efi" -delete # }}} # Create unified kernels blob and efiboot entries {{{ ## Install objcopy tool if not available command -v objcopy > /dev/null || aptitude install --assume-yes -- binutils ## Put Kernel command line in temp file rm --force -- "${temp_kernel_command_file}" ; touch "${temp_kernel_command_file}" printf "%s" "root=UUID=${ROOT_UUID} rootfstype=${ROOT_FSTYPE} add_efi_memmap \ ro cryptdevice=UUID=${CRYPT_PART_UUID}:lvm" >> "${temp_kernel_command_file}" ## Get all kernel versions starting with the oldest rm --force -- "${temp_kernel_list_file}" ; touch "${temp_kernel_list_file}" ls -1tr -- /boot/vmlinuz-* >> "${temp_kernel_list_file}" ## For each version of the kernel {{{ while IFS= read -r KERNEL; do ### Get kernel version KERNEL_VERSION=$(printf "%s" "${KERNEL}" | sed 's;.*vmlinuz-\(.*\);\1;') ### Ensure EFI device is mounted (excluding systemd-automount line) if ! mount | grep --invert-match -- "autofs" | grep --quiet -- "${EFI_MOUNT_PATH}"; then mount "${EFI_MOUNT_PATH}" || exit 2 fi ESP=$(findmnt -kno SOURCE "${EFI_MOUNT_PATH}" | grep --invert-match -- systemd | sed s-/dev/--) ESP_DISK=$(lsblk /dev/"${ESP}" -no pkname) ESP_PART=$(cat /sys/class/block/"${ESP}"/partition) ### Calculate address values to use for each section osrel_offs=$(objdump --section-headers -- "/usr/lib/systemd/boot/efi/linuxx64.efi.stub" | awk 'NF==7 {size=strtonum("0x"$3); offset=strtonum("0x"$4)} END {print size + offset}') cmdline_offs=$((osrel_offs + $(stat --dereference --format=%s -- "/usr/lib/os-release"))) linux_offs=$((cmdline_offs + $(stat --dereference --format=%s -- "${temp_kernel_command_file}"))) initrd_offs=$((linux_offs + $(stat --dereference --format=%s -- "/boot/vmlinuz-${KERNEL_VERSION}"))) ### Create a unified kernel printf "%s\n" "Creating unified kernel for version ${KERNEL_VERSION}..." objcopy \ --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ --add-section .cmdline="${temp_kernel_command_file}" --change-section-vma .cmdline=$(printf 0x%x $cmdline_offs) \ --add-section .linux="/boot/vmlinuz-${KERNEL_VERSION}" --change-section-vma .linux=$(printf 0x%x $linux_offs) \ --add-section .initrd="/boot/initrd.img-${KERNEL_VERSION}" --change-section-vma .initrd=$(printf 0x%x $initrd_offs) \ /usr/lib/systemd/boot/efi/linuxx64.efi.stub "${EFI_MOUNT_PATH}/EFI/debian/linux.debian.${KERNEL_VERSION}.efi" ### Create a efiboot entry printf "%s\n" "Creating efiboot entry for kernel ${KERNEL_VERSION}" efibootmgr --disk /dev/"${ESP_DISK}" --part "${ESP_PART}" --create --label "${EFI_BASE_LABEL} ${KERNEL_VERSION}" --loader "\\EFI\\debian\\linux.debian.${KERNEL_VERSION}.efi" #printf "%s\n" "efibootmgr --disk /dev/\"${ESP_DISK}\" --part \"${ESP_PART}\" --create --label \"${EFI_BASE_LABEL} ${KERNEL_VERSION}\" --loader \"\\EFI\\debian\\linux.${KERNEL_VERSION}.efi\"" done < "${temp_kernel_list_file}" ## }}} ## Create generic entry for the last version of the kernel {{{ ### Create a unified kernel printf "%s\n" "Creating unified generic kernel for the last version (${KERNEL_VERSION})..." objcopy \ --add-section .osrel="/usr/lib/os-release" --change-section-vma .osrel=$(printf 0x%x $osrel_offs) \ --add-section .cmdline="${temp_kernel_command_file}" --change-section-vma .cmdline=$(printf 0x%x $cmdline_offs) \ --add-section .linux="/boot/vmlinuz-${KERNEL_VERSION}" --change-section-vma .linux=$(printf 0x%x $linux_offs) \ --add-section .initrd="/boot/initrd.img-${KERNEL_VERSION}" --change-section-vma .initrd=$(printf 0x%x $initrd_offs) \ /usr/lib/systemd/boot/efi/linuxx64.efi.stub "${EFI_MOUNT_PATH}/EFI/debian/linux.debian.efi" ### Create a efiboot entry printf "%s\n" "Creating efiboot generic entry for the last version (${KERNEL_VERSION})" efibootmgr --disk /dev/"${ESP_DISK}" --part "${ESP_PART}" --create --label "${EFI_BASE_LABEL}" --loader "\\EFI\\debian\\linux.debian.efi" #printf "%s\n" "efibootmgr --disk /dev/\"${ESP_DISK}\" --part \"${ESP_PART}\" --create --label \"${EFI_BASE_LABEL} ${KERNEL_VERSION}\" --loader \"\\EFI\\debian\\linux.efi\"" ## }}} # }}} ## Remove temp files rm --force -- "${temp_efi_list_file}" "${temp_kernel_list_file}" "${temp_kernel_command_file}" exit 0