#!/bin/bash # SPDX-License-Identifier: GPL-3.0-or-later # PLONK - PLONK Leaves Only Needed Kernels # # This script removes old Debian kernels # It also purges old kernel packages left in "rc" state # # In short: old kernels go plonk. # # Author: bisco # Script inspired by the following cyberciti post: # https://www.cyberciti.biz/faq/debian-ubuntu-linux-delete-old-kernel-images-command/ set -euo pipefail ### Variables APT_GET="$(command -v apt-get || true)" DPKG_QUERY="$(command -v dpkg-query || true)" KERNELVER="$(uname -r)" KEEP_KERNELS="2" ACTION="" ASSUME_YES="no" KERNELS_TO_KEEP=() ABIS_TO_KEEP=() OLD_KERNELS=() RC_KERNELS=() PKGS_TO_PURGE=() ### End Variables ### Code. ### Please don't edit below unless if you know what you're doing. ### Check if something went wrong check_error(){ echo "====> ERROR!" echo "====> Script failed on line ${BASH_LINENO[0]}" exit 1 } ### Run check_error function on errors trap check_error ERR ### Show help and exits usage(){ echo "PLONK - PLONK Leaves Only Needed Kernels" echo "" echo "Old kernels go plonk." echo "" echo "Usage: $0 [option]" echo "" echo "-l | --list : list old kernel packages" echo "-n | --dry-run : simulate old kernel packages removal" echo "-r | --remove : remove old kernel packages" echo "-k | --keep NUM : number of kernels to keep. Default: ${KEEP_KERNELS}" echo "-y | --yes : assume yes when removing packages" echo "-h | --help : show this help and exits" echo "" echo "Examples:" echo "$0 --list" echo "$0 --dry-run" echo "sudo $0 --remove" echo "sudo $0 --remove --keep 3" echo "" } ### Check if all binaries are properly installed on target system check_binary(){ if [ "${APT_GET}" == "" ] || [ "${DPKG_QUERY}" == "" ]; then echo "[FAIL] Some binaries not found." echo "[INFO] Please make sure you have: apt-get, dpkg-query" exit 1 else echo "[OK] All binaries are properly installed. Let's go on!" fi } ### Check if the script has been run by root when removing packages check_root(){ if [ "${ACTION}" != "remove" ]; then return fi if [ "$(id -u)" == "0" ]; then echo "[OK] Check root permissions" else echo "[FAIL] Check root permissions" echo "[INFO] Run this script as root or sudo" exit 1 fi } ### Extract kernel version from package name pkg_to_kernel_version(){ local PKG="${1%%:*}" case "${PKG}" in linux-image-unsigned-*) echo "${PKG#linux-image-unsigned-}" ;; linux-image-*) echo "${PKG#linux-image-}" ;; linux-headers-*) echo "${PKG#linux-headers-}" ;; *) return 1 ;; esac } ### Extract Debian kernel ABI from kernel package version kernel_abi_from_version(){ local VERSION="$1" case "${VERSION}" in *-cloud-amd64) echo "${VERSION%-cloud-amd64}" ;; *-rt-amd64) echo "${VERSION%-rt-amd64}" ;; *-amd64) echo "${VERSION%-amd64}" ;; *-686-pae) echo "${VERSION%-686-pae}" ;; *-686) echo "${VERSION%-686}" ;; *-cloud-arm64) echo "${VERSION%-cloud-arm64}" ;; *-rt-arm64) echo "${VERSION%-rt-arm64}" ;; *-arm64) echo "${VERSION%-arm64}" ;; *-common) echo "${VERSION%-common}" ;; *) echo "${VERSION%-*}" ;; esac } ### List installed Debian kernel packages list_installed_kernel_packages(){ { "${DPKG_QUERY}" -W -f='${db:Status-Abbrev}\t${binary:Package}\n' \ 'linux-image-[0-9]*' \ 'linux-image-unsigned-[0-9]*' \ 'linux-headers-[0-9]*' \ 2>/dev/null || true } | awk '$1 == "ii" { print $2 }' | sort -u } ### List residual Debian kernel packages in rc state list_rc_kernel_packages(){ { "${DPKG_QUERY}" -W -f='${db:Status-Abbrev}\t${binary:Package}\n' \ 'linux-image-[0-9]*' \ 'linux-image-unsigned-[0-9]*' \ 'linux-headers-[0-9]*' \ 2>/dev/null || true } | awk '$1 == "rc" { print $2 }' | sort -u } ### List installed Debian kernel image versions list_installed_kernel_versions(){ { "${DPKG_QUERY}" -W -f='${db:Status-Abbrev}\t${binary:Package}\n' \ 'linux-image-[0-9]*' \ 'linux-image-unsigned-[0-9]*' \ 2>/dev/null || true } | awk '$1 == "ii" { print $2 }' \ | while read -r PKG; do pkg_to_kernel_version "${PKG}" done \ | sort -V -u } ### Build the list of kernels that should be kept build_keep_list(){ local INSTALLED_KERNELS=() local VERSION="" local ABI="" local I="" mapfile -t INSTALLED_KERNELS < <(list_installed_kernel_versions) KERNELS_TO_KEEP=("${KERNELVER}") for (( I=${#INSTALLED_KERNELS[@]}-1; I>=0 && ${#KERNELS_TO_KEEP[@]}