#!/bin/sh
# $Id: select-kernel,v 1.29 2012/01/17 11:16:29 cetus Exp $
# Copyright (C) 2004 Vitaly Lipatov <lav@etersoft.ru>
# Copyright (C) 2005-2010 Anatoly Kitaykin <cetus@newmail.ru>
# Copyright (C) 2008 Vladimir V. Kamarzin <vvk@altlinux.org>
#
# 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.

PROG="${0##*/}"

message() {
	printf %s\\n "$PROG: $*" >&2
}

debug() {
	echo "$@" >> /tmp/$PROG.dbg
}

show_help() {
cat << EOF

$PROG is a kernel maintenance tool. It helps to install, remove,
and switch kernels with related module infrastructures.

Usage:

	$PROG [options] [flavour] [release]

Both, flavour and release, are patterns to filter full kernel list.

	flavour is one of well-known suffixes, like "std-def",
		"std-pae", "ovz-smp" etc.

	release is somewhat more flexible, like "alt6" or "2.6.22"
		or so.

Valid options are:

	-f | -y | --yes | --assume-yes
		to force apt-get --yes option

	-n | --num
		to use numeric sort order

	-h | --help
		to display this text

EOF
}

yes=
numeric=
RELEASE=.
FLAVOUR=.

CACHE=/tmp/$PROG.$$
trap "rm -f $CACHE" EXIT SIGHUP SIGINT SIGQUIT SIGTERM

while [ -n "$1" ]; do
	if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
		show_help
		exit
	fi
	if [ "$1" = "-n" ] || [ "$1" = "--num" ]; then
		numeric=yes
		shift
		continue
	fi
	if [ "$1" = "-f" ] || [ "$1" = "-y" ] || [ "$1" = "--yes" ] || [ "$1" = "--assume-yes" ]; then
		yes=--yes
		shift
		continue
	fi
	if [ "$RELEASE" != "." ]; then
		[ -z "$FLAVOURS" ] && FLAVOURS=`apt-cache pkgnames kernel-image | sed -e "s/kernel-image-//g" | sed -e "s/#.*$//" | sort -u`
		for foo in $FLAVOURS; do
			if [ "$foo" = "$RELEASE" ]; then
				FLAVOUR="$RELEASE"
				RELEASE="$1"
				break
			fi
			if [ "$foo" = "$1" ]; then
				FLAVOUR="$1"
				break
			fi
		done
		if [ "$foo" != "$FLAVOUR" ]; then
			RELEASE="$1"
		fi
	else
		RELEASE="$1"
	fi
	shift
done

# use sudo(1) if running as unprivileged user
[ "$UID" = "0" ] && SUDO= || SUDO=sudo

KERNELS=(`$SUDO apt-get install kernel 2>&1 | grep '#' | grep $FLAVOUR | grep $RELEASE |\
	sed -e 's/^  //' | sort -k2 | while read n v s ; do echo $n ${s:-[+]} ; done`)
[ ${#KERNELS[*]} = 0 ] && { message "Kernel list with filter ($FLAVOUR,$RELEASE) is empty" ; exit ; }

# resort by kernel version
#echo was:
#for ((i=0; i<${#KERNELS[*]}; i+=2)); do
#	echo ${KERNELS[$i]}
#done
#echo due:
if [ -z $(which rpmvercmp) ]; then
	rpmvercmp () {
		if [ "$1" '<' "$2" ]; then
			printf "%d\n" -1
		elif [ "$1" '>' "$2" ]; then
			printf "%d\n" 1
		else
			printf "%d\n" 0
		fi
	}
fi
for ((s=2; s<${#KERNELS[*]}; s+=2)); do
	for ((t=s; t>=2; t-=2)); do
		if [ "$numeric" = "yes" ]; then
			foo=${KERNELS[$((t-2))]#*#}
			foo=${foo#*:}
			bar=${KERNELS[$t]#*#}
			bar=${bar#*:}
		else
			foo=${KERNELS[$((t-2))]%#*}
			bar=${KERNELS[$t]%#*}
		fi
		comparison="$(rpmvercmp $foo $bar)"
		if [ "$comparison" -lt 0 ]; then
			#echo $foo lesser than $bar
			break
		fi
		if [ "$comparison" -eq 0 ]; then
			#echo $foo equal $bar
			if [ "$numeric" = "yes" ]; then
				foo=${KERNELS[$((t-2))]%#*}
				bar=${KERNELS[$t]%#*}
			else
				foo=${KERNELS[$((t-2))]#*#}
				foo=${foo#*:}
				bar=${KERNELS[$t]#*#}
				bar=${bar#*:}
			fi
			comparison="$(rpmvercmp $foo $bar)"
			if [ "$comparison" -le 0 ]; then
				#echo $foo less or equal $bar
				break
			fi
		fi
		#echo $foo swapped by $bar
		foo=${KERNELS[$((t-2))]}
		bar=${KERNELS[$((t-1))]}
		KERNELS[$((t-2))]=${KERNELS[$t]}
		KERNELS[$((t-1))]=${KERNELS[$((t+1))]}
		KERNELS[$((t))]=$foo
		KERNELS[$((t+1))]=$bar
	done
done
#echo now:
#for ((i=0; i<${#KERNELS[*]}; i+=2)); do
#	echo ${KERNELS[$i]}
#done

CURRENT_FLAVOUR=`uname -r | cut -d "-" -f2,3`
CURRENT_VERSION=`uname -r | cut -d "-" -f1`
CURRENT_BUILD=`uname -r | cut -d "-" -f4`
#CURRENT_KERNEL="kernel-image-$CURRENT_FLAVOUR#$CURRENT_VERSION-$CURRENT_BUILD"
for ((i=0; i<${#KERNELS[*]}; i+=2)); do
	foo=${KERNELS[$i]%#*}
	bar=${KERNELS[$i]#*#}
	bar=${bar#*:}
	if [ "$foo" = "kernel-image-$CURRENT_FLAVOUR" ]\
	&& [ "$bar" = "$CURRENT_VERSION-$CURRENT_BUILD" ]; then
		CURRENT_KERNEL=${KERNELS[$i]}
	fi
done 

dialog --default-item "$CURRENT_KERNEL" --menu "Choose a kernel:" "" "" "" "${KERNELS[@]}" 2>$CACHE
KERNEL=$(<$CACHE)

if [ -z "$KERNEL" ]; then
	clear
	message No kernel selected
	exit
fi

FLAVOUR=`echo $KERNEL | sed -e 's/#/-/' | cut -d '-' -f3,4`
VERSION=`echo $KERNEL | sed -e 's/#/-/' | sed -e 's/[0-9]\+://' | cut -d '-' -f5`
BUILD=`echo $KERNEL | sed -e 's/#/-/' | cut -d '-' -f6`
INSTVER=$VERSION-$FLAVOUR-$BUILD

if rpm -q `echo $KERNEL | sed -e 's/#/-/' | sed -e 's/[0-9]\+://'`; then
	dialog --menu "$KERNEL" "" "" ""\
		"upgrade modules for"	"$KERNEL"\
		"reinstall"	"$KERNEL"\
		"remove"	"$KERNEL"\
		"switch to"	"$KERNEL"\
		2>$CACHE
	VERB=$(<$CACHE)
	case $VERB in
		"switch to")
			$SUDO installkernel $INSTVER
			exit
			;;
		"reinstall")
			$SUDO apt-get install --reinstall $KERNEL
			exit
			# or not exit?
			;;
		"upgrade modules for")
			message Please wait
			;;
		"remove")
			[ $(uname -r) = "$INSTVER" ] && { message It is a bad idea to remove current kernel. Try it once after reboot!; exit; }
			dialog --colors --yesno "[$KERNEL]\n\nTry to \Z1REMOVE\Z0 this kernel and modules? Are you sure?" "" "" || exit
			$SUDO apt-get remove $KERNEL
			exit
			;;
		"")
			clear
			message Nothing to do
			exit
			;;
		*)
			message Menu and case items mismatch. Please report a bug!
			exit
			;;
	esac
else
	dialog --colors --yesno "[$KERNEL]\n\nTry to \Z2install\Z0 this kernel and modules?" "" "" || exit
	$SUDO apt-get install $KERNEL
fi

# try to install kernel headers for module builds
if rpm -qa | grep ^kernel-headers-modules > /dev/null; then
	message try install kernel-headers-modules
	$SUDO apt-get install $yes kernel-headers-modules-$FLAVOUR=$VERSION-$BUILD ||\
	$SUDO apt-get install $yes kernel-headers-modules-$FLAVOUR
fi

ALLMODULES=`rpm -qa --qf "%{NAME}\n" | grep '^kernel-modules-' | sed -e 's/-[^-]\+-[^-]\+$//' | sort -u`
for PKGNAME in $ALLMODULES; do
	message Try to install $PKGNAME
	$SUDO apt-get install $yes "$PKGNAME-$INSTVER"
done

# try to run x11setupdrv if might need that (e.g. for nvidia_glx updates)
X11SETUPDRV=/usr/bin/x11setupdrv

case "$ALLMODULES" in
	*drm*|*fglrx*|*nvidia*)
		[ ! -x "$X11SETUPDRV" ] && \
		message "You might need to run x11setupdrv, video drivers updated but it's missing" \
		|| $SUDO "$X11SETUPDRV"
		# see bug #19107
        ;;
esac


