#!/bin/bash
#
# Copyright (C) Voltaire Ltd. 2006.  ALL RIGHTS RESERVED.
#
# This program 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., 59 Temple
# Place, Suite 330, Boston, MA 02111-1307 USA
#
# Author: Erez Zilber <erezz@voltaire.com>

TMP_DIR=/tmp

K_VER=$(uname -r)

RPM=rpm
MV=mv
MKDIR=mkdir
NULL=/dev/null

BCKP_DIR=/usr/voltaire/backup

RPM_DIR_DFT="/var/tmp/${PACKAGE}RPM"
RPM_DIR=${RPM_DIR:-"${RPM_DIR_DFT}"}
if [ -d $RPM_DIR ]; then
    find $RPM_DIR -type d | sort -r | xargs rmdir > $NULL 2>&1
fi
mkdir -p $RPM_DIR/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

# Source path definitions
PKG_SOURCE_DIR=${PWD}

# Set Distribuition dependency environment
dist_rpm=""
if [ -f /etc/SuSE-release ]; then
    dist_rpm=$($RPM -qf /etc/SuSE-release)
    DISTRIBUTION="SuSE"
elif [ -f /etc/fedora-release ]; then
    dist_rpm=$($RPM -qf /etc/fedora-release)
    DISTRIBUTION="fedora"
elif [ -f /etc/rocks-release ]; then
    dist_rpm=$($RPM -qf /etc/rocks-release)
    DISTRIBUTION="Rocks"
elif [ -f /etc/redhat-release ]; then
    dist_rpm=$($RPM -qf /etc/redhat-release)
    DISTRIBUTION="redhat"
else
    dist_rpm="Unknown"
    DISTRIBUTION=$(ls /etc/*-release | head -n 1 | xargs -iXXX basename XXX -release 2> $NULL)
    [ -z "${DISTRIBUTION}" ] && DISTRIBUTION="Unknown"
fi

SUSE_OPEN_ISCSI_PKG_NAME="open-iscsi"
REDHAT_OPEN_ISCSI_PKG_NAME="iscsi-initiator-utils"

# Voltaire uses kernel version and not dist_rpm
RPMS=${PKG_SOURCE_DIR}/RPMS/`uname -r`
SRPMS=${PKG_SOURCE_DIR}/SRPMS

build_arch=$(rpm --eval '%{_target_cpu}')

if [ ! -d ${RPMS} ]; then
    $MKDIR -p ${RPMS} || exit 1
fi

usage="Usage: $0 -i|-u"

install_open_iscsi()
{
        # Build (if necessary) and install open-iscsi userspace package
	open_iscsi_usr_binary_rpm=$(find $RPMS -name "$SUSE_OPEN_ISCSI_PKG_NAME-[[:digit:]]*.rpm")
	if ! [ -f  "$open_iscsi_usr_binary_rpm" ]; then
		open_iscsi_usr_src_rpm=$(find $SRPMS -name "open-iscsi-generic-[[:digit:]]*.src.rpm")
		echo "Building open-iscsi userspace package"
		rpmbuild --rebuild --define "_rpmdir ${RPMS}" ${open_iscsi_usr_src_rpm}
		open_iscsi_usr_binary_rpm=$(find ${RPMS} -name "$SUSE_OPEN_ISCSI_PKG_NAME-[[:digit:]]*.rpm")
	fi

	# Leave only the binary rpm that is relevant for the current distro
	case $DISTRIBUTION in
	SuSE)
                find ${RPMS} -name "$REDHAT_OPEN_ISCSI_PKG_NAME-[[:digit:]]*.rpm" -exec rm '{}' \;
		;;
	redhat)
                find ${RPMS} -name "$SUSE_OPEN_ISCSI_PKG_NAME-[[:digit:]]*.rpm" -exec rm '{}' \;
		;;
	*)
		echo "$DISTRIBUTION distribution is not supported"
		exit 1
		;;
	esac
	
	echo "Installing open-iscsi userspace package"
	$RPM --nodeps -ihv ${open_iscsi_usr_binary_rpm}

	# Set the dependencies between /etc/init.d/open-iscsi & /etc/init.d/gridstack
	echo "Setting dependencies between open-iscsi and GridStack"
	awk '/Required-Start/{print $0 " gridstack"} !/Required-Start/{print $0}' /etc/init.d/open-iscsi > $TMP_DIR/open-iscsi
	mv $TMP_DIR/open-iscsi /etc/init.d

	awk '/Required-Stop/{print $0 " iscsi"} !/Required-Stop/{print $0}' /etc/init.d/gridstack > $TMP_DIR/gridstack
	mv $TMP_DIR/gridstack /etc/init.d

	# Make sure that gridstack & open-iscsi startup scripts are executable
	chmod +x /etc/init.d/gridstack

	case $DISTRIBUTION in
	SuSE)
		chmod +x /etc/init.d/open-iscsi
		;;
	redhat)
		chmod +x /etc/init.d/iscsi
		;;
	*)
		echo "$DISTRIBUTION distribution is not supported"
		exit 1
		;;
	esac

	case $DISTRIBUTION in
	SuSE)
		insserv /etc/init.d/gridstack
		insserv /etc/init.d/open-iscsi
		;;
	redhat)
		chkconfig --add /etc/init.d/gridstack
		chkconfig --add /etc/init.d/iscsi
		;;
	*)
		echo "$DISTRIBUTION distribution is not supported"
		exit 1
		;;
	esac

	# Build (if necessary) and install open-iscsi kernel package
	if ! ( $($RPM -q open-iscsi-kernel > $NULL 2>&1) ); then
		if ! [ -f  $RPMS/$build_arch/open-iscsi-kernel*${build_arch}.rpm ]; then
			open_iscsi_kernel_src_rpm=$(find ${SRPMS} -name open-iscsi-kernel*.src.rpm)
			echo "Building open-iscsi kernel package"
			rpmbuild --rebuild --define "_rpmdir ${RPMS}" ${open_iscsi_kernel_src_rpm}
		fi
		echo "Installing open-iscsi kernel package"
		$RPM --nodeps -ihv $RPMS/$build_arch/open-iscsi-kernel*${build_arch}.rpm
	fi
}

install_open_iscsi_devel()
{
        # Build (if necessary) and install open-iscsi devel package
	if ! ( $($RPM -q open-iscsi-devel > $NULL 2>&1) ); then
		if ! [ -f  $RPMS/$build_arch/open-iscsi-devel*${build_arch}.rpm ]; then
			open_iscsi_devel_src_rpm=$(find ${SRPMS} -name open-iscsi-devel*.src.rpm)
			echo "Building open-iscsi devel package"
			rpmbuild --rebuild --define "_rpmdir ${RPMS}" ${open_iscsi_devel_src_rpm}
		fi
		echo "Installing open-iscsi devel package"
		$RPM --nodeps -ihv $RPMS/$build_arch/open-iscsi-devel*${build_arch}.rpm
	fi
}

fix_symbol_crc()
{
	echo "Fixing CRC for packages"
	rm -f $TMP_DIR/syms

	n_mods=0

	until [ -z "$1" ]
	do
		pkg_kernel_modules=$pkg_kernel_modules" "$($RPM -ql $1 | grep .ko)
		shift
	done

	for mod in $pkg_kernel_modules ; do
		echo "fixing CRC for $mod in packages"
		nm -o $mod | grep __crc >> $TMP_DIR/syms
		n_mods=$((n_mods+1))
	done
   
	n_syms=$(wc -l $TMP_DIR/syms |cut -f1 -d" ")
	echo found $n_syms symbols in $n_mods modules
	n=1
   
	MOD_SYMVERS_PKG=$TMP_DIR/Module.symvers.pkg
	MOD_SYMVERS_PATCH=$TMP_DIR/Module.symvers.patch

	# make sure that we use a new patch file
	rm -f $MOD_SYMVERS_PATCH

	# find Module.symvers file
	if [ -f /lib/modules/`uname -r`/build/Module.symvers ] ; then
		MOD_SYMVERS_KERNEL=/lib/modules/`uname -r`/build/Module.symvers
	else
		echo file Module.symvers not found
	fi
   
	if [ ! -z $MOD_SYMVERS_KERNEL ] ; then
   
		rm -f $MOD_SYMVERS_PKG
   
		# Build the new symbols
		while [ $n -le $n_syms ] ; do
			line=$(head -$n $TMP_DIR/syms|tail -1)
			mod_path=$(echo $line|cut -f1 -d:)
			symbol_crc=$(echo $line|cut -f2 -d:)
			file=$(echo $mod_path|cut -f5- -d/)
			file=$(echo $file|cut -f1 -d.)

			crc=$(echo $symbol_crc|cut -f1 -d" ")
			crc=${crc:8}
			sym=$(echo $symbol_crc|cut -f3 -d" ")
			sym=${sym:6}
			echo -e  "0x$crc\t$sym\t$file" >> $MOD_SYMVERS_PKG
			if [ -z $allsyms ] ; then
				allsyms=$sym
			else
				allsyms="$allsyms|$sym"
			fi
			n=$((n+1))
		done

		# Add all other kernel symbols
		egrep -v "$allsyms" $MOD_SYMVERS_KERNEL >> $MOD_SYMVERS_PKG
		
		diff -u $MOD_SYMVERS_KERNEL $MOD_SYMVERS_PKG > $MOD_SYMVERS_PATCH
		patch -d $(dirname $MOD_SYMVERS_KERNEL) < $MOD_SYMVERS_PATCH
		mkdir -p $BCKP_DIR
		mv $MOD_SYMVERS_PATCH $BCKP_DIR
	fi
}

restore_symbol_crc()
{
	echo "Restoring CRC"
	if [ -f /lib/modules/`uname -r`/source/Module.symvers ] ; then
		MOD_SYMVERS_KERNEL=/lib/modules/`uname -r`/source/Module.symvers
	elif [ -f /lib/modules/`uname -r`/build/Module.symvers ] ; then
		MOD_SYMVERS_KERNEL=/lib/modules/`uname -r`/build/Module.symvers
	else
		echo file Module.symvers not found
	fi

	# apply the backward patch and delete it
	patch -d $(dirname $MOD_SYMVERS_KERNEL) -R  < $BCKP_DIR/Module.symvers.patch
        rm $BCKP_DIR/Module.symvers.patch

	# if the backup dir is empty, delete it
	if [ `ls -A $BCKP_DIR | wc -l` -eq 0 ] ; then
		echo "removing $BCKP_DIR"
		rm -rf $BCKP_DIR
	fi
}

install_iser()
{
        # Build (if necessary) and install iSER kernel package
	if ! ( $($RPM -q iser > $NULL 2>&1) ); then
		if ! [ -f  $RPMS/$build_arch/iser*${build_arch}.rpm ]; then
			iser_src_rpm=$(find ${SRPMS} -name iser*.src.rpm)
			rpmbuild --rebuild --define "_rpmdir ${RPMS}" ${iser_src_rpm}
		fi
		$RPM --nodeps -ihv $RPMS/$build_arch/iser*${build_arch}.rpm
	fi
}

install()
{
	# Do not install if open-iscsi (userpsace) is already installed
	if ( $($RPM -q open-iscsi > $NULL 2>&1) ) ; then
		echo "open-iscsi is already installed. Exiting."
		echo "If you want to install this version of open-iscsi with iSER, please uninstall open-iscsi first."
		exit 1
	fi

	# Check the kernel version (currently supporting only SLES 10)
	case $(echo $K_VER | sed "s/-ppc64\|-smp//") in
	2.6.16.21-0.8)
		;;
	*)
		echo "This kernel version (${K_VER})is not supported."
		exit 1
		;;
	esac

	# Install userspace programs and kernel modules for open-iscsi
	install_open_iscsi

	# decide if open-iscsi-devel should be installed
	open_iscsi_devel=1
        if ( $(rpm --showrc | grep " _vendor" | grep suse > /dev/null 2>&1) ) ; then
            if ! ( $(rpm -q kernel-source > /dev/null 2>&1) ) ; then
		echo "Not installing open-iscsi-devel because the kernel-source package is not installed."
		open_iscsi_devel=0
	    fi    
        else if ( $(rpm --showrc | grep " _vendor" | grep redhat > /dev/null 2>&1) ) ; then
            if ! ( $(rpm -q kernel-devel > /dev/null 2>&1) ) ; then
		echo "Not installing open-iscsi-devel because the kernel-devel package is not installed."
		open_iscsi_devel=0
	    fi
        else
            echo "This distribution is not supported. Not installing open-iscsi-devel."
            open_iscsi_devel=0
        fi
        fi

        if [ $open_iscsi_devel == 1 ] ; then
            install_open_iscsi_devel
        fi

	# fix the symbols crc before building iSER
	fix_symbol_crc open-iscsi-kernel kernel-ib

	install_iser
}

uninstall()
{
	# Remove the dependencies between open-iscsi startup script & /etc/init.d/gridstack
	case $DISTRIBUTION in
	SuSE)
		insserv -r /etc/init.d/gridstack
		insserv -r /etc/init.d/open-iscsi
		;;
	redhat)
		chkconfig --del /etc/init.d/gridstack
		chkconfig --del /etc/init.d/iscsi
		;;
	*)
		echo "$DISTRIBUTION distribution is not supported"
		exit 1
		;;
	esac
	
	# uninstall all packages
	for open_iscsi_pkg in iser open-iscsi open-iscsi-kernel open-iscsi-devel ; do
		if ( $RPM -q ${open_iscsi_pkg} > $NULL 2>&1 ); then
			$RPM -e ${open_iscsi_pkg}
		else
			echo "could not find package ${open_iscsi_pkg}"
		fi
	done

	# restore the symbols crc
	restore_symbol_crc
}

while getopts "iu" opt
do
	case ${opt} in
	i) install
		if [ $? != 0 ] ; then
			echo "error: open-iscsi over iSER installation failed"
			exit 1
		else
			exit 0
		fi
		;;
	u) uninstall
		if [ $? != 0 ] ; then
			echo "error: open-iscsi over iSER uninstall failed"
			exit 1
		else
			exit 0
		fi
		;;
	*)
		echo $usage
		exit 1
	esac
done

echo ${usage}


