2022-04-03 03:12:12 +03:00
#!/bin/bash
2008-12-28 15:20:56 +03:00
# Copyright (C) 2008 Vladimir V. Kamarzin <vvk@altlinux.org>
#
# Remove all kernels except current
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
2022-04-06 02:09:07 +03:00
PROG=${0##*/}
message() {
echo >&2 "$PROG: $*"
}
fatal() {
message "$@"
exit 1
}
show_usage()
{
[ -z "$*" ] || message "$*"
echo >&2 "Try \`$PROG --help' for more information."
exit 1
}
2016-01-23 06:56:45 +03:00
show_help()
{
cat <<EOF
Usage: $PROG [options]
Valid options are:
2022-06-26 07:37:42 +03:00
-f, -y, --force do not ask for removal confirmation (default is to ask)
2016-01-23 06:56:45 +03:00
-n, --dry-run just simulate removal
2022-06-26 08:31:47 +03:00
-t, --type remove old kernels for the specified flavour (un-def, std-def, etc)
-a, --all remove old kernels for all flavours
-A remove all kernels of other (than current or -t) flavours
Note: currently booted and backup kernels won't be removed in any case.
Backup kernel is the latest kernel with uptime more than day.
2016-01-23 06:56:45 +03:00
-h, --help show this text and exit
EOF
2022-06-26 04:10:25 +03:00
exit 0
2016-01-23 06:56:45 +03:00
}
#parse command line options
2022-06-26 08:31:47 +03:00
TEMP=$(getopt -n "$PROG" -o f,y,n,t:,h,a,A,v -l force,dry-run,type:,help,all,verbose -- "$@") || show_help
2016-01-23 06:56:45 +03:00
eval set -- "$TEMP"
while :; do
case "$1" in
--) shift; break
;;
2018-08-22 16:44:27 +03:00
-f|-y|--force) force="-y"
2016-01-23 06:56:45 +03:00
;;
-n|--dry-run) dryrun="--no-remove"
;;
2016-04-24 03:42:48 +03:00
-t|--type) shift ; kernel_flavour="$1"
;;
2019-12-19 16:13:08 +03:00
-a|--all) all=1
;;
2022-06-26 08:31:47 +03:00
-A) all=2
;;
2022-06-26 02:24:38 +03:00
-v|--verbose) verbose=1
;;
2016-01-23 06:56:45 +03:00
-h|--help) show_help
esac
shift
done
2022-06-26 02:24:38 +03:00
if [ -n "$verbose" ]; then
V() { echo >&2 "+ $*"; "$@"; }
else
V() { "$@"; }
fi
2022-06-26 07:05:52 +03:00
cr=$'\n'
2022-06-26 07:30:25 +03:00
# set colors on tty
if [ -t 1 ]; then
RED=$'\e[1;31m'
GREEN=$'\e[1;32m'
MAGENTA=$'\e[1;35m'
BRIGHT=$'\e[1m'
NORM=$'\e[0m'
else
RED=
GREEN=
MAGENTA=
BRIGHT=
NORM=
fi
2022-06-26 07:05:52 +03:00
2022-06-26 01:15:45 +03:00
uname_r=$(uname -r)
2016-04-24 03:42:48 +03:00
# get running kernel version
2022-06-26 01:15:45 +03:00
current_kernel_package=$(rpmquery -qf "/lib/modules/$uname_r/kernel" 2>/dev/null)
2016-04-24 03:42:48 +03:00
if [ -n "$current_kernel_package" ] ; then
2022-06-26 06:06:03 +03:00
current_kernel_pkgname=$(rpmquery --queryformat "%{NAME}-%{VERSION}-%{RELEASE}\n" -q "$current_kernel_package")
2022-06-26 07:30:25 +03:00
echo "Currently booted kernel package: $BRIGHT$current_kernel_pkgname$NORM"
2022-06-26 06:06:03 +03:00
unset current_kernel_pkgname
2016-04-24 03:42:48 +03:00
else
2022-06-26 07:30:25 +03:00
echo "Running kernel version: $BRIGHT$uname_r$NORM (package not found)"
2016-04-24 03:42:48 +03:00
fi
# set kernel flavour. if not defined with -t option, use current
2022-06-26 01:15:45 +03:00
current_kernel_flavour="$uname_r"
2020-02-12 16:30:43 +03:00
current_kernel_flavour="${current_kernel_flavour#*-}"
current_kernel_flavour="${current_kernel_flavour%-*}"
2019-12-19 16:13:08 +03:00
if [ -n "$all" ] ; then
2022-06-26 01:37:52 +03:00
flavours="$(rpm -qa --queryformat '%{NAME}\n' 'kernel-image-*' | grep -v -w -e domU -e debuginfo | sort -u | cut -d- -f3-)"
2019-12-19 16:13:08 +03:00
else
flavours="${kernel_flavour:-$current_kernel_flavour}"
fi
2016-04-24 03:42:48 +03:00
2022-06-26 07:22:53 +03:00
# Get the latest kernel with uptime >=1 day
good_kernel=$(LC_ALL=C last -a reboot | awk '$ 10 ~ /+/ {print $10,$11; exit }')
good_kernel_days=${good_kernel%% *}
good_kernel=${good_kernel##* }
good_kernel_days=${good_kernel_days#(}
good_kernel_days=${good_kernel_days%%+*}
good_kernel_package=
2022-06-26 09:27:50 +03:00
if [ -n "$good_kernel" ]; then
if [ "$good_kernel" != "$uname_r" ]; then
tver=${good_kernel%%-*}
trel=${good_kernel##*-}
tflv=${good_kernel#"$tver"-}
tflv=${tflv%-"$trel"}
good_kernel=kernel-image-$tflv-$tver-$trel
good_kernel_package=$(rpm -q "$good_kernel" 2>/dev/null)
unset tver trel tflv
echo "Previous kernel with uptime $good_kernel_days days: $BRIGHT$good_kernel$NORM (backup)"
if [ -z "$good_kernel_package" ]; then
echo "${RED}Warning: Package for the backup kernel not found.$NORM"
fi
else
echo "Backup kernel is the same as booted kernel (uptime $good_kernel_days days)."
fi
else
echo "${RED}Warning: Backup kernel is not determined.$NORM"
2022-06-26 07:22:53 +03:00
fi
2022-06-26 07:05:52 +03:00
# Sort the kernels
2022-06-26 08:31:47 +03:00
[ -z "$kernel_flavour" ] && kernel_flavour=$current_kernel_flavour
other_flavours=
2022-06-26 07:05:52 +03:00
keep_kernels=
2022-06-26 08:31:47 +03:00
for flavour in $flavours; do
all_kernels="$(rpm -qa "kernel-image-$flavour" | sort -V)"
2022-06-26 07:05:52 +03:00
newest_kernel=$(echo "$all_kernels" | tail -1)
for kernel in $all_kernels; do
reason=
2022-06-26 08:31:47 +03:00
if [ "$all" = "2" ] && [ "$kernel_flavour" != "$flavour" ]; then
:
elif [ "$kernel" = "$newest_kernel" ]; then
reason="$reason, latest for $flavour"
[ "$kernel_flavour" != "$flavour" ] && other_flavours=y
2022-06-26 07:05:52 +03:00
fi
if [ "$kernel" = "$current_kernel_package" ]; then
2022-06-26 07:22:53 +03:00
reason="$reason, currently booted"
fi
if [ "$kernel" = "$good_kernel_package" ]; then
reason="$reason, with uptime $good_kernel_days days"
2022-06-26 07:05:52 +03:00
fi
if [ -n "$reason" ]; then
2022-06-26 07:30:25 +03:00
keep_kernels="$keep_kernels $GREEN$kernel$NORM (${reason#, })$cr"
2022-06-26 07:05:52 +03:00
else
2022-06-26 07:30:25 +03:00
remove_kernels="$remove_kernels $MAGENTA$kernel$NORM$cr"
2022-06-26 07:05:52 +03:00
apt_args_list="$apt_args_list $(rpm -q --queryformat '%{NAME}=%{EPOCH}:%{VERSION}-%{RELEASE}\n' "$kernel" \
| sed -e "s,(none):,,g")"
fi
2019-12-19 16:13:08 +03:00
done
2008-12-28 15:41:11 +03:00
done
2022-06-26 07:37:42 +03:00
howmuch=$(echo "$keep_kernels" | grep -c .)
[ "$howmuch" -eq 1 ] && phrase="this kernel" || phrase="these $BRIGHT$howmuch$NORM kernels"
2022-06-26 09:32:50 +03:00
echo "Not removing $phrase (with the reason why):"
2022-06-26 08:31:47 +03:00
printf "%s" "$keep_kernels"
[ -n "$other_flavours" ] && echo "Specify -A to remove all kernels of other flavours than $kernel_flavour."
echo
2019-12-20 14:48:28 +03:00
if [ -z "$apt_args_list" ] ; then
echo "Nothing to remove."
exit 0
fi
2022-06-26 09:02:42 +03:00
howmuch=$(echo "$remove_kernels" | grep -c .)
[ "$howmuch" -eq 1 ] && phrase="this kernel" || phrase="these $BRIGHT$howmuch$NORM kernels"
2022-06-26 09:32:50 +03:00
echo "Will be removing $phrase:"
2022-06-26 09:02:42 +03:00
echo "$remove_kernels"
2021-07-10 10:30:51 +03:00
if [ "$UID" != "0" ]; then
2022-06-26 07:30:25 +03:00
echo >&2 "${RED}Warning: This program requires root privileges.$NORM"
2021-07-10 10:30:51 +03:00
fi
2008-12-28 15:20:56 +03:00
2022-06-26 07:37:42 +03:00
echo -n "Confirm" ${dryrun:+--dry-run} "uninstall action for $phrase [Y/n]? "
if [ -n "$force" ]; then
echo "yes"
else
while true; do
read -r || { echo "Aborting"; exit 1; }
shopt -s nocasematch
case "$REPLY" in
n|no|q) exit 0 ;;
y|ye|yes|'') break ;;
*) ;;
esac
echo -n "[Y/n] "
shopt -u nocasematch
done
fi
2022-04-03 03:12:12 +03:00
# shellcheck disable=SC2086
2022-06-26 07:37:42 +03:00
V apt-get -y $dryrun remove $apt_args_list
2016-01-23 06:56:45 +03:00
# Mask non-zero apt exit code on dry run:
if [ -n "$dryrun" ]; then
exit 0
fi