#!/bin/bash
#
# This script represents an interface between the postinstall and postuninstall
# scripts of kernel rpms and the update-bootloader script.
# 
# Interface:
# ----------
# /usr/lib/bootloader/bootloader_entry [add|remove] <kernel-flavor> <kernel-release> <image-name> <initrd-name>
#
# Call Semantics:
# ---------------
# [ -x $cmd ] && $cmd <parameters>
#
#
# Author: aosthof@suse.de
#


# Print how to use this script correctly
function usage()
{
	echo "Unknown or missing parameter."
	echo "Usage: $0 [add|remove] <kernel-flavor> <kernel-release> <image-name> <initrd-name> [force-default]"
	echo
	echo "The old interface with 4 parameters is still supported, but deprecated."
	echo "This interface will be dropped in the near future."
	echo "Usage: $0 [add|remove] <kernel-package-name> <image-name> <initrd-name>"
	exit 1
}


# Get all command line arguments
function getargs()
{
	# old interface with 4 parameters
	if [ $# -eq 4 ] ; then
		action=${1}		# contains the action to be executed, e.g. "add" or "remove"
		flavor=${2#*-}		# contains the kernel-flavor, e.g. "default" or "xen"
		flavor=${flavor%%-*}
		release=${2#*-*-}	# contains the kernel-release, e.g. "2.6.18-4-default"
		release=${release%.*.*}
		release="${release}-${flavor}"
		image=${3}		# contains the full image name, e.g. "vmlinuz-2.6.18-4-default"
		initrd=${4}		# contains the full initrd name, e.g. "initrd-2.6.18-4-default"
		
	# new interface with 5 or 6 parameters, depends whether option
	# "force-default" is used or not
	else
		action=${1}		# contains the action to be executed, e.g. "add" or "remove"
		flavor=${2}		# contains the kernel-flavor, e.g. "default" or "xen"
		release=${3}		# contains the kernel-release, e.g. "2.6.18-4-default"
		image=${4}		# contains the full image name, e.g. "vmlinuz-2.6.18-4-default"
		initrd=${5}		# contains the full initrd name, e.g. "initrd-2.6.18-4-default"
		forcedefault=${6}	# contains action which forces corresponding boot entry beeing the
					# default boot entry, enabled by given parameter "force-default"
	fi
}


# Wrapper for the update-bootloader function
function update_bootloader() 
{
        echo "bootloader_entry: This is (wrapper) function update_bootloader" >> $logname

	[ -x /sbin/update-bootloader ] || return 0
	    # call update-bootloader and also append stderr to the log file
	    ((/sbin/update-bootloader "$@") 3>&1 1>&2 2>&3 3>&- | tee -a \
	    $logname ) 3>&1 1>&2 2>&3 3>&-
}


##############################
# Add a new bootloader entry #
##############################
function add_entry()
{
        echo "bootloader_entry: This is function add_entry()" >> $logname

	# If running in instsys, write command(s) to be executed in a file
	# which will be executed by yast2-bootloader after installation of
	# packages is finished.
	#
	# This is to prevent inconsistencies triggered by libata migration.

	if [ "$YAST_IS_RUNNING" == instsys -a "$DELAYED_RUN_UPDATE_BOOTLOADER" != yes ]; then
		cat - >> $delayed_exec_file <<-EOF
		#!/bin/sh

		export DELAYED_RUN_UPDATE_BOOTLOADER=yes

		/usr/lib/bootloader/bootloader_entry $@

		EOF

		chmod 755 $delayed_exec_file
	else
		# Set up the new kernel
		if [ -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/sysconfig/bootloader ] &&
		   [ -f $PERL_BOOTLOADER_TESTSUITE_PATH/boot/grub/menu.lst -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/lilo.conf      -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/elilo.conf     -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/zipl.conf ]; then
			case $flavor in
				(kdump|um)
				;;
				(xen*)
					opt_xen_kernel=
					set -- $flavor
					set -- ${1#xen}
					opt_xen_kernel=--xen-kernel=/boot/xen${1:+-$1}.gz

				if [ "$forcedefault" == "force-default" ]; then
					# Add the new bootloader entry (xen kernel)
					# and force it beeing the default entry
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --default \
							  --force-default \
							  --add \
							  --force $opt_xen_kernel \
							  --name "$release" \
                                                          || exit 1
				else
					# Add the new bootloader entry (xen kernel)
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --default \
							  --add \
							  --force $opt_xen_kernel \
							  --name "$release" \
                                                          || exit 1
				fi

					# Run the bootloader (e.g., lilo).
					update_bootloader --refresh || exit 1
				;;

				(debug)
				if [ "$forcedefault" == "force-default" ]; then
					# Add the new bootloader entry (debug kernel)
					# and force it beeing the default entry
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --force-default \
							  --add \
							  --force \
							  --name "$release" \
                                                          || exit 1
				else
					# Add the new bootloader entry (debug kernel)
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --add \
							  --force \
							  --name "$release" \
                                                          || exit 1
				fi

					# Run the bootloader (e.g., lilo).
					update_bootloader --refresh || exit 1
				;;

				(*)
				if [ "$forcedefault" == "force-default" ]; then
					# Add the new bootloader entry
					# and force it beeing the default entry
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --default \
							  --force-default \
							  --add \
							  --force \
							  --name "$release" \
                                                          || exit 1
				else
					# Add the new bootloader entry
					update_bootloader --image /boot/$image \
							  --initrd /boot/$initrd \
							  --default \
							  --add \
							  --force \
							  --name "$release" \
                                                          || exit 1
				fi

					# Run the bootloader (e.g., lilo).
					update_bootloader --refresh || exit 1
				;;
			esac
		fi
	fi
}


#######################################
# Remove an existing bootloader entry #
#######################################
function remove_entry()
{
        echo "bootloader_entry: This is function remove_entry()" >> $logname

	# If running in instsys, write command(s) to be executed in a file
	# which will be executed by yast2-bootloader after installation of
	# packages is finished.
	#
	# This is to prevent inconsistencies triggered by libata migration.

	if [ "$YAST_IS_RUNNING" == instsys -a "$DELAYED_RUN_UPDATE_BOOTLOADER" != yes ]; then
		cat - >> $delayed_exec_file <<-EOF
		#!/bin/sh

		export DELAYED_RUN_UPDATE_BOOTLOADER=yes

		/usr/lib/bootloader/bootloader_entry $@

		EOF

		chmod 755 $delayed_exec_file
	else
		if [ -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/sysconfig/bootloader ] &&
		   [ -f $PERL_BOOTLOADER_TESTSUITE_PATH/boot/grub/menu.lst -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/lilo.conf      -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/elilo.conf     -o \
		     -f $PERL_BOOTLOADER_TESTSUITE_PATH/etc/zipl.conf ]; then
		# Do not specify the name of a bootloader entry when removing it, thus
		# removing all sections matching the kernel image and initrd names
		# (either both a "linux" and a "failsafe" section, or a section
		# installed with the kernel postinstall script).
		#
		# Rationale: we do not know whether the old entry has
		#    - the product name as its name (when installed with
		#      yast-bootloader) or
		#    - "Kernel-<version>" (when installed with the kernel package's
		#      postinstall script and perl-Bootloader).
		#
		#  So we cannot use the name to find the correct section.
		#  This is safe, because on grub, this does still not match other
		#  sections on other partitions with the same name for the kernel
		#  image and initrd (because they will still have the (hdx,y) prefix
		#  in perl-Bootloader). Other bootloaders do not specify other
		#  sections at all, or do only chainload them (BootLILO.ycp), and
		#  thus do not match either. (#223030)


		if [[ "$flavor" =~ xen ]]; then
			update_bootloader --image /boot/$image \
					  --initrd /boot/$initrd \
					  --xen \
					  --remove \
					  --force \
                                          || exit 1
		else
			update_bootloader --image /boot/$image \
					  --initrd /boot/$initrd \
					  --remove \
					  --force \
                                          || exit 1
		fi

		# Run the bootloader (e.g., lilo).
		update_bootloader --refresh || exit 1
                fi
	fi
}



#####################  M A I N  ###############################################

# Log how program was called
logname=$PERL_BOOTLOADER_TESTSUITE_PATH"/var/log/YaST2/perl-BL-standalone-log"
echo "bootloader_entry was called as: $*" >> $logname

# Log parts of the current system configuration
(
echo "/proc/mounts:"
cat /proc/mounts
echo

echo "/sys:"
ls -l /sys
echo

fstab="/etc/fstab"
if [ -e $fstab ] ; then
	echo "fstab:"
	cat $fstab
	echo
fi

echo "excerpts of /dev:"
#if doesn't find anything you can be on strange architecture (like ps3) and dump all block devices
ls -l /dev/{[hs]d[ab]?,md[0-3],.udev,disk/by-*} 2>/dev/null || ls -l /dev | grep ^b
echo

device_map="/boot/grub/device.map"
if [ -e $device_map ] ; then
	echo "device.map:"
	cat $device_map
	echo
fi
) >> $logname

if [ `grep -c "^[^[:space:]]\+[[:space:]]\+/boot" /etc/fstab` -ne `grep -c "^[^[:space:]]\+[[:space:]]\+/boot" /etc/mtab` ]; then
  echo "/boot directory is not mounted";
  exit 1;
fi

# File containing commands for later execution
delayed_exec_file="/boot/perl-BL_delayed_exec"

# Checks if correct amount of arguments is given
if [ "$#" -lt "4" -o "$#" -gt "6" ] ; then
	usage
fi

# Get all given arguments
getargs $@

# Find out which action should be executed
case $action in
	add)
		# Add a new bootloader entry
		add_entry "$@"
	;;
	remove) 
		# Remove an existing bootloader entry
		remove_entry "$@"
	;;
	*)
		# Unknown argument
		usage
	;;
esac