#!/bin/bash
# Written by Didier Spaier this script is dedicated to the public domain.
#
# This script is called by slapt-get --upgrade like this:
# 
# Its main purpose is to  perform specific actions when upgrading kernels
# Rationale: we want to make sure that a working kernel be always installed, but
# we don't want to keep more kernels than necessary, to save space on disk and
# not clutter the GRUB boot menu. In that aim:
# 1. When installing a new kernel, we will keep the running one.
# 2. When the new kernel runs, we remove the one that was running when
#    installing it.
# Additionally, this script uses spkg -i then spkg -d for packages that ship
# many files, namely kernel-modules and kernel-source, to save time removing
# them as spkg -d is faster that removepkg. This could be used to upgrade other
# packages with many files that do not need a pre-installation. In case of
# packages kernel-generic or kernel-modules it calls update-portable that will
# make a specific initrd and grub.cfg case occuring, else make an initrd and
# update grub directly.
# Incidentally, we plan to not upgrade the huge kernel anymore. As soon as a
# generic one will be running we will remove the one initially installed upon
# next upgrade of a generic kernel.
TMP=/tmp/wrapupgradepkg
mkdir -p $TMP
rm -f $TMP/log
RUNNINGVERSION=$(uname -r)
# We are called with the patch to the new package as $2
NEWKERNELPATH=$2
NEWPKGNAME="$(basename $NEWKERNELPATH)"
FRAG='[^-]\{1,\}'
NEWSHORTNAME=$(echo $NEWPKGNAME|sed "s/\(.*\)-$FRAG-$FRAG-$FRAG$/\1/")
NEWVERSION=$(echo $NEWPKGNAME|sed "s/.*-\($FRAG\)-$FRAG-$FRAG$/\1/")
NEWBUILD=$(echo $NEWPKGNAME|sed "s/.*-$FRAG-$FRAG-\($FRAG$\)/\1/")

# We assume that only one kernel package at a given version is installed. As a
# consequence, if we need to reconfigure a kernel, better wait for a new version
# or at least do not do that twice in a row, else we won't know which kernel
# package to remove short of checking the oldest installed according to
# "stat -c %Y $i" that you could insert below, probably an overkill.
usepkgtools() {
	if [ "$NEWSHORTNAME" = "kernel-generic" ]; then  
		INSTALLED=$(ls -1 /var/log/packages|grep -e "kernel-generic" -e "kernel-huge")
	else 
		INSTALLED=$(ls -1 /var/log/packages|grep -e "$NEWSHORTNAME")
	fi
	installpkg $NEWKERNELPATH
	echo "$INSTALLED"|while read i; do
		iVERSION=$(echo $i|sed "s/.*-\($FRAG\)-$FRAG-$FRAG$/\1/")
		if [ "$iVERSION" = "$RUNNINGVERSION" ]; then
			echo "not removing $i" >>$TMP/log
			continue
		fi
		echo "removepkg $i" >>$TMP/log
		removepkg $i
		if [ -f /boot/initrd-$iVERSION ]; then
			rm /boot/initrd-$iVERSION
		fi
	done
	# Remove the symlinks we won't use any more
	( cd /boot
	rm -f System.map config config-generic vmlinuz{,-generic,-huge}
	)
}
usespkg() {
	INSTALLED=$(ls -1 /var/log/packages|grep ${NEWSHORTNAME}-[[:digit:]])
	installpkg $NEWKERNELPATH
	echo "$INSTALLED"|while read i; do
		iVERSION=$(echo $i|sed "s/.*-\($FRAG\)-$FRAG-$FRAG$/\1/")
		if [ "$iVERSION" = "$RUNNINGVERSION" ]; then
			echo "not removing $i" >>$TMP/log
			continue
		fi
		echo "spkg -d $i" >>/$TMP/log
		spkg -d $i
	done
}
initrdandgrub() {
	MODULESINSTALLED=$(ls -1 /var/log/packages/|grep ^kernel-modules-$NEWVERSION)
	KERNELINSTALLED=$(ls -1 /var/log/packages/|grep ^kernel-generic-$NEWVERSION)
	# Remove the huge kernel and the symlinks we won't use
	if [ -f /boot/vmlinuz-huge-* ]; then
		removepkg kernel-huge 
	fi
	( cd /boot
		rm -f System.map config config-generic vmlinuz{,-generic,-huge}
	)
	if  [ ! "$MODULESINSTALLED" = "" ] && [ ! "$KERNELINSTALLED" = "" ]; then
			if [ ! -f /boot/grub/grub.cfg ] && grep -q "# This grub.cfg is part of a portable Slint." /boot/grub/grub.cfg; then
				updateportable
			else
				echo "/usr/sbin/geninitrd" >>$TMP/log
				/usr/sbin/geninitrd >>$TMP/log
				updategrub
			fi
	fi
}
updateportable() {
	ROOTDELAY=10
	ROOTUUID="$(findmnt -no uuid /)"
	FSTYPE="$(findmnt -no fstype /)"
	SLINTVERSION=$(</etc/slint-version)
	. /etc/default/grub
	HOST_AND_STORAGE=$(find /lib/modules/$NEWVERSION/kernel/drivers/ -name "*.ko"|grep -e "/storage/" -e "/host/"|grep -v /staging/|sed "s,.*/,,;s/.ko//;s/$/:/"|tr -d '\n')
	FS="btrfs:ext2:ext4:f2fs:jfs:reiserfs:xfs:
	MODULES="$HOST_AND_STORAGE${FS}usbhid
	mkinitrd -c -k $NEWVERSION	 -f $FSTYPE -r UUID=$ROOTUUID -m $MODULES -w $ROOTDELAY -u -o /boot/initrd-$NEWVERSION 1>/dev/null 2>/dev/null

	cat << EOF > /boot/grub/grub.cfg
# This grub.cfg is part of a portable Slint.
# Do NOT remove or modify the line above, as it indicates to the script
# wrapupgradepkg that it should run the function updateportable.
set menu_color_normal=white/black
set menu_color_highlight=white/blue

terminal_output console
set timeout=10
set menu_color_normal=white/black
set menu_color_highlight=white/blue

terminal_output console
set timeout=10
play 480 262 1 330 1 392 1 523 1
EOF

	# We put the entry for the new kernel version on top the menu. 
	cat <<EOF >> /boot/grub/grub.cfg

menuentry '$SLINTVERSION kernel $NEWVERSION' {
	echo "Starting $SLINTVERSION kernel $NEWVERSION.  Please wait..."
	insmod part_gpt
	insmod part_msdos
	insmod btrfs
	insmod ext2
	insmod f2fs
	insmod jfs
	insmod reiserfs
	insmod xfs
    insmod all_video
	search --fs-uuid --set=root $ROOTUUID
	linux /boot/vmlinuz-$NEWVERSION root=UUID=$ROOTUUID vga=normal ro $GRUB_CMDLINE_LINUX_DEFAULT
	initrd /boot/initrd-$NEWVERSION
}
EOF
	# Now append boot entries for other installed kernels. We will make an
	# initrd for each if it doesn't exist.
	INSTALLED=$(ls -1 /var/log/packages|grep "kernel-generic")
	echo "$INSTALLED"|while read i; do
		iVERSION=$(echo $i|sed "s/.*-\($FRAG\)-$FRAG-$FRAG$/\1/")
		iNAME=$(echo $i|sed "s/\(.*\)-$FRAG-$FRAG-$FRAG$/\1/")
		if [ "$iVERSION" = "$NEWVERSION" ]; then
			continue
		fi
		HOST_AND_STORAGE=$(find /lib/modules/$iVERSION/kernel/drivers/ -name "*.ko"|grep -e "/storage/" -e "/host/"|grep -v /staging/|sed "s,.*/,,;s/.ko//;s/$/:/"|tr -d '\n')
		MODULES="$HOST_AND_STORAGE${FS}usbhid"
		mkinitrd -c -k $NEWVERSION	 -f $FSTYPE -r UUID=$ROOTUUID -m $MODULES -w $ROOTDELAY -u -o /boot/initrd-$NEWVERSION 1>/dev/null 2>/dev/null
		cat <<EOF >> /boot/grub/grub.cfg

menuentry '$SLINTVERSION kernel $iVERSION' {
	echo "Starting $SLINTVERSION kernel $iVERSION.  Please wait..."
	insmod part_gpt
	insmod part_msdos
	insmod btrfs
	insmod ext2
	insmod f2fs
	insmod jfs
	insmod reiserfs
	insmod xfs
    insmod all_video
	search --fs-uuid --set=root $ROOTUUID
	linux /boot/${iNAME}-$iVERSION root=UUID=$ROOTUUID vga=normal ro $GRUB_CMDLINE_LINUX_DEFAULT
	initrd /boot/initrd-$iVERSION
}
EOF
	done
	# Get rid of initrd.gz if still there
	rm -f /boot/initrd.gz
}
updategrub() {
	if [ ! -f /boot/grub/grub.cfg ]; then
		echo
		gettext "It seems that you didn't install grub in Slint. If you installed it from
another distribution you should now run update-grub from this other
distribution, else Slint won't boot from the grub menu. If you used
another boot manager that grub we suggest that you install grub now."
		echo
	elif grep -q "# This grub.cfg is part of a portable Slint." /boot/grub/grub.cfg; then
		echo
		gettext "This is a portable Slint, updating the initrd and grub config files.
Please wait..."
		updateportable
	else
		gettext "Updating GRUB..."
		echo
		update-grub
		echo "update-grub" >>$TMP/log 
		echo
	fi
}
case $NEWSHORTNAME in
	kernel-generic) usepkgtools;initrdandgrub;;
	kernel-modules) usespkg;initrdandgrub;;
	kernel-headers) usepkgtools;;
	kernel-source|libreoffice|mozilla-firefox|mozilla-thunderbird) usespkg;;
	*)              upgradepkg --reinstall $NEWKERNELPATH;;
esac
