#!/bin/sh
#
#  apt-upgrade-kernel
#
#  Helper for upgrading Linux kernel image and kernel-related modules via APT:
#  displays list of packages for passing to 'apt-get install' command.
#
#  Works under ordinal account and doesn't requires superuser privileges.
#
#  Requires: apt-cache, egrep, sed, awk, xargs, rpmquery, rpmvercmp
#
#  Uses packages naming conventions from ALTLinux Kernel Policy 1.2.
#
#  Tested on ALTLinux Master 2.4:
#      kernel-build-tools-0.7-alt1, apt-0.5.15cnc6-alt6,
#      rpm-4.0.4-alt40, rpm-utils-0.8.1-alt1(rpmvercmp).
#
#  Todo: how to be with kernel-complete package and empty apt-kernel-images list?
#
#  Written at Apr,May 2005 by evseev@altlinux.ru
#  Distributed under terms of GNU GPL
#

echo_stderr() {
	echo "$@" 1>&2
}

usage() {
	echo "\
$fname0 $version
Purpose: Update Linux kernel and installed kernel modules via APT
Usage: [VAR=value] $fname0 [options]

Options:
    -V, --version  Show version string
    -h, --help     Show complete usage
    -q, --quiet    Silent mode (turn off messages)
    -v, --verbose  Detailed mode (turn on messages)
    -k, --keep     Dont remove temporary working directory at finish
    --debug        Enable debugging mode, see below

Variables for explicit selection of currently installed kernel to be upgraded
(by default they are detected automatically via 'uname -r'):
    KERNEL_FLAVOUR (examples: std-up, vs-smp, ...)
    KERNEL_VERSION (for example, 2.4.33-std-smp-alt9)

Debugging mode:
    Use static data directory instead of temporary,
    dont overwrite already existing files in data directory
    (use previously created if they are not removed manually),
    use more verbose output.

Examples:
    sudo apt-get update;
    export KERNEL_FLAVOUR=std-smp;
    $fname0 -q | xargs sudo -H apt-get -y install 
"
}

main()
{

local fname0=$(basename $0)
local version="0.1 (May 2005)"

local is_debug
local debug_echo=":"
local info_echo="echo_stderr"
local error_echo="echo_stderr ERROR:"
local echo_passed="echo ...already exists, passed..."
local keepwd

local used_commands="apt-cache egrep sed awk xargs rpmquery rpmvercmp"

while [ "$1" != "" ]; do
   case "$1" in
	-V | --version ) echo "$fname0 $version"; return 0 ;;
	-h | --help    ) usage; return 0 ;;
	-k | --keep    ) keepwd=yes;;
	--debug        ) is_debug=yes; info_echo="echo_stderr"; debug_echo="echo_stderr DEBUG:" ;;
	-v | --verbose )               info_echo="echo_stderr"; debug_echo="echo_stderr DEBUG:" ;;
	-q | --quiet | --silent )      info_echo=":";           debug_echo=":"; echo_passed=":" ;;
	* ) $error_echo "invalid option $1, run '$0 --help' for usage info"; return 1 ;;
   esac
   shift
done

#-----------------------------------------------------------------------

for c in $used_commands; do
	[ "$(which $c)" = "" ] || continue
	$error_echo "Error: missing program: $c"
	return 1
done

$debug_echo "Create temprorary directory..."
if [ -z "$is_debug" ]; then
	local workdir=$(mktemp -dt $fname0.XXXXXXXX)
	$debug_echo "...created $workdir"
else
	local workdir=$HOME/tmp/$fname0
	mkdir -p $workdir
	$debug_echo "...using $workdir"
fi
if [ -z "$workdir" ]; then
	$error_echo "mktemp failed, abort"
	return 1
fi
[ -n "$is_debug" ] && keepwd=yes
[ -z "$keepwd" ] && trap "rm -rf $workdir" 0 1 2 5 15

#-----------------------------------------------------------------------

$debug_echo "Detect kernel flavour..."
if [ -z "$KERNEL_FLAVOUR" ]; then
	[ -z "$KERNEL_VERSION" ] && local KERNEL_VERSION=$(uname -r)
	local ktmp=${KERNEL_VERSION#*-}
	local KERNEL_FLAVOUR=${ktmp%-*}
	$debug_echo "...found $KERNEL_FLAVOUR, KERNEL_VERSION = $KERNEL_VERSION"
else
	$debug_echo "...use predefined = $KERNEL_FLAVOUR"
	local KERNEL_VERSION="$(rpmquery --qf '%{VERSION}-xxx-%{RELEASE}\n' kernel-image-$KERNEL_FLAVOUR)"
	if [ -z "$KERNEL_VERSION" ]; then
		$error_echo "Cannot find kernel-image-$KERNEL_FLAVOUR, failed."
		return 1
	fi
	$debug_echo "...found KERNEL_VERSION = $KERNEL_VERSION"
fi
local KERNEL_BASEVER=${KERNEL_VERSION%%-*}
local KERNEL_RELEASE=${KERNEL_VERSION##*-}
$debug_echo "Installed kernel version = $KERNEL_BASEVER, release = $KERNEL_RELEASE, flavour = $KERNEL_FLAVOUR"

#return 0

#-----------------------------------------------------------------------

$info_echo "Get list of kernel images available to install..."
if [ -e $workdir/apt-kernel-images ]; then $echo_passed; else
	apt-cache showpkg "kernel-image-$KERNEL_FLAVOUR" \
	| egrep "^kernel-image-$KERNEL_FLAVOUR" > $workdir/apt-kernel-images
fi

local kmaxname kmaxver=""
if [ -s $workdir/apt-kernel-images ]; then
	while read kname kver; do
		$debug_echo "...check $kname ($kver)"
		if [ "$(rpmvercmp \"$kmaxver\" $kver)" = "-1" ]; then
			kmaxver=$kver
			kmaxname=$kname
			$debug_echo "....is newest"
		fi
	done < $workdir/apt-kernel-images
	if [ -z "$kmaxver" -o -z "$kmaxname" ]; then
		$error_echo "Cannot find any kernel-image-$KERNEL_FLAVOUR in APT repository, failed"
		return 1
	fi
	$info_echo "Found newest kernel version = $kmaxver, name = $kmaxname"
else
	$error_echo "??? apt-kernel-images: empty"
	return 1
fi

#return 0

#-----------------------------------------------------------------------

$info_echo "Get full list of package depending from kernel to be installed..."
[ -e $workdir/apt-whatdepends ] && $echo_passed "(whatdepends)" || \
	apt-cache whatdepends "$kmaxname" \
	| egrep '^  [^ ]' | sed -e 's/^  //' \
	> $workdir/apt-whatdepends
if [ -e $workdir/apt-whatdepends-vpackages ]; then $echo_passed "(vpackages)"; else
	grep '#' $workdir/apt-whatdepends \
	| sed -e 's/\(#.*-.*\)-.*-.*$/\1/' \
	> $workdir/apt-whatdepends-vpackages
fi
if [ -e $workdir/apt-whatdepends-vnamesonly ]; then $echo_passed "(names only)"; else
	sed -e 's/#.*$//' $workdir/apt-whatdepends-vpackages \
	> $workdir/apt-whatdepends-vnamesonly
fi
if [ -e $workdir/apt-whatdepends-packages ]; then $echo_passed "(remaining packages)"; else
	grep -v '#' $workdir/apt-whatdepends \
	> $workdir/apt-whatdepends-packages
fi

#return 0

#-----------------------------------------------------------------------

$info_echo "Get list of packages depending from current kernel..."
if [ -e "$workdir/rpm-whatdepends-namesonly" ]; then $echo_passed; else
#	rpmquery --whatrequires "kernel-image-$KERNEL_FLAVOUR" --qf '%{NAME}-%{VERSION}-%{RELEASE}\n' | uniq > $workdir/rpm-whatdepends
	rpmquery --whatrequires "kernel-image-$KERNEL_FLAVOUR" --qf '%{NAME}\n' | uniq > $workdir/rpm-whatdepends-namesonly
fi

$info_echo "Build list of package vnames to be installed..."
[ -e "$workdir/apt-toinstall-namesonly" ] && $echo_passed "(vnames)" || \
	grep -xf $workdir/rpm-whatdepends-namesonly $workdir/apt-whatdepends-vnamesonly > $workdir/apt-toinstall-namesonly

$info_echo "Build list of vpackages to be installed..."
[ -e "$workdir/apt-toinstall" ] && $echo_passed "(vpackages)" || \
	grep -f $workdir/apt-toinstall-namesonly $workdir/apt-whatdepends-vpackages > $workdir/apt-toinstall

$info_echo "Build list of remaining packages to be installed..."
if [ -e "$workdir/apt-toinstall2" ]; then $echo_passed "(packages)"; else
	sed -e 's/-[^-]*-[^-]*$//' $workdir/apt-whatdepends-packages \
	| xargs rpmquery --qf '%{NAME}\n' 2>/dev/null \
	> $workdir/apt-toinstall2
fi

#return 0

$info_echo "This list should be passed to \"apt-get install\" command:"
echo $kmaxname
cat $workdir/apt-toinstall $workdir/apt-toinstall2

[ -z "$keepwd" ] && rm -rf $workdir
return 0

}

main "$@"

## EOF ##
