#!/bin/bash -u
#*****************************************************************************
# Copyright 2004-2005 Engenio Information Technologies, Inc.
#
# 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,  version 2 of the License.
# 
# 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.
#*****************************************************************************
#
#  Script %name:	setupSuseBoot %
#  Instance:		WIC_2
#  %version:		2 %
#  Description:		Make the /boot/initrd points to the mpp ramdisk and add additional
#                   backup menu entry in /boot/grub/menu.lst
#  %created_by:		jwendel %
#  %date_created:	Fri Dec 14 21:03:11 2007 %

###############################################################################
#
###############################################################################
# The function "mppLnx_suse_setup_boot" should be called at the mpp driver installation
# time.
#
# The function "mppLnx_suse_cleanup_boot" should be invoked at the mpp driver un-installation
# time
#
###############################################################################
#
#
#################################################################################
# Function:mppLnx_suse_init_variables
# Description:set up common environment variables for all functions in this file
##################################################################################
RUNNING_KERNEL=$(uname -r)
MPPLNX_RDAC_BUILD_VERSION="MPPLNX_REPLACE_THIS_WITH_BUILD_VERSION"
MPPLNX_RDAC_BUILD_ARCH="MPPLNX_REPLACE_THIS_WITH_BUILD_ARCH"
mppLnx_suse_init_variables()
{
   
   BACKUP_BEGIN_TOKEN="###BEGIN of Linux System Original Boot Entry. Do not edit ###"
   BACKUP_END_TOKEN="###END of Linux System Original Boot Entry. Do not edit ###"
   MPP_RAMDISK_NAME="mpp-${MPPLNX_RDAC_BUILD_VERSION}.img"
   MPP_RAMDISK_FILE="/boot/${MPP_RAMDISK_NAME}"
   DEFAULT_KERNEL_IMG="/boot/vmlinuz"
   export BACKUP_END_TOKEN="${BACKUP_END_TOKEN}"
   export BACKUP_BEGIN_TOKEN="${BACKUP_BEGIN_TOKEN}"
   export MPP_RAMDISK_FILE="${MPP_RAMDISK_FILE}"
   export MPP_RAMDISK_NAME="${MPP_RAMDISK_NAME}"
   export DEFAULT_KERNEL_IMG="${DEFAULT_KERNEL_IMG}"
}

#####################################################
# Function:mppLnx_suse_vmlinuz_version
# Description: Get the version of the installed kernel from /boot/vmlinuz
#
# Scope: private to this file.
#
#   Error condition:
#       If the /boot/vmlinuz is not a symbolic link to a proper kernel image file, 
#       this function will print an installation error message and terminate the 
#       pre-installation process 
#####################################################
mppLnx_suse_vmlinuz_version()
{
   DEFAULT_KERNEL_IMG="/boot/vmlinuz"
   #/boot/vmlinuz should be a link
   if [ -h ${DEFAULT_KERNEL_IMG} ]
   then
      VMLINUZ_IMAGE=$(ls -l ${DEFAULT_KERNEL_IMG}|awk -F'>' '{print $2}'|sed 's/^ //g'|sed 's/ $//g')
   else
      echo -e "
   ###### I N S T A L L A T I O N    E R R O R #######
   /boot/vmlinuz is not a symbolic link. The /boot directory has been modified.
   Cannot proceed... Please make the "vmlinuz" link to a proper kernel image file
   " >&2
      exit 3
   fi

   echo "$(strings /boot/${VMLINUZ_IMAGE}|egrep '^2.6.*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) {1,2}(0{0,1}[1-9]|[1-2][0-9]|3[0-1]) ([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]'|awk '{print $1}')"
}

#####################################################
#check the kernel versions
# returns 
#   1 if the rpm build kernel version is same as the current running 
#       kernel version and is same as the /boot/vmlinuz image kernel version
#   2 if the rpm build kernel version is same as the current running kernel 
#       version but is different from the /boot/vmlinuz image kernel version
#   3 if the rpm build kernel version is different from the current running
#       kernel version but is same as the /boot/vmlinuz image kernel version 
#   4 if the rpm build kernel version is different from the current running 
#       kernel version and is not same as the /boot/vmlinuz image kernel version
#
#####################################################
mppLnx_suse_version_check()
{
   if [ "${MPPLNX_RDAC_BUILD_VERSION}" = "${RUNNING_KERNEL}"  -a "${MPPLNX_RDAC_BUILD_VERSION}" = "${VMLINUZ_VERSION}" ]
   then
      echo "1"
   elif  [ "${MPPLNX_RDAC_BUILD_VERSION}" = "${RUNNING_KERNEL}"  -a "${MPPLNX_RDAC_BUILD_VERSION}" != "${VMLINUZ_VERSION}" ]
   then
      echo "2"
   elif [ "${MPPLNX_RDAC_BUILD_VERSION}" != "${RUNNING_KERNEL}"  -a "${MPPLNX_RDAC_BUILD_VERSION}" = "${VMLINUZ_VERSION}" ]
   then
      echo "3"
   elif [ "${MPPLNX_RDAC_BUILD_VERSION}" != "${RUNNING_KERNEL}"  -a "${MPPLNX_RDAC_BUILD_VERSION}" != "${VMLINUZ_VERSION}" ]
   then
      echo "4"
   fi
}

#################################################################################
# Function:mppLnx_suse_inst_ramdisk
# Description:save the original initrd to initrd.orig and make the initrd points to
#             the mpp ramdisk
#
# Scope: private to this file.
#
#  termination - if the kernel image doesn't exist, the function will be terminated
##################################################################################
mppLnx_suse_inst_ramdisk()
{
   found_kernel=no
   bootpart=boot
   if [ -e "/boot/vmlinuz" ]; then
      found_kernel=yes;
   fi


   if [ "${found_kernel}" = "yes" ]; then
   
      bootpart=boot

      if [ ! -f ${MPP_RAMDISK_FILE} ]
      then
         echo "The file ${MPP_RAMDISK_FILE} doesn't exist. Cannot proceed..."
          exit 5
      fi
 

      if [ -h /${bootpart}/initrd ]
      then
        #the initrd exists and it is a link
        #we must check whether or not the initrd links to mpp ramdisk
        if [ "$(ls -l /boot/initrd |grep -c mpp)" = 1 ]
        then
            #why the /boot/initrd links to mpp ramdisk
            #we must link it to the initrd-kernel-version
            if [ -f /boot/initrd-${MPPLNX_RDAC_BUILD_VERSION} ]
            then
                cd /boot
                ln -sf initrd-${MPPLNX_RDAC_BUILD_VERSION} initrd.orig
            fi
            #let's link the initrd.orig link to the build kernel image
            if [ -h /${bootpart}/initrd.orig ]
            then 
                rm /${bootpart}/initrd.orig
            fi
            if [ -f /${bootpart}/initrd-${MPPLNX_RDAC_BUILD_VERSION} ]
            then
                 ln -sf /${bootpart}/initrd-${MPPLNX_RDAC_BUILD_VERSION} /${bootpart}/initrd.orig
            fi
         else
                
            cd /boot
            #Saving initrd in initrd.orig
            mv initrd initrd.orig
         fi
      fi

      if [ -e /${bootpart}/initrd.shipped ]; then
         #Saving initrd.shipped in initrd.shipped.orig
         cd /boot
         mv initrd.shipped initrd.shipped.orig
      fi

      if [ -e /${bootpart}/initrd.suse ]; then
         # Saving initrd.suse in initrd.suse.orig
         cd /boot
         mv initrd.suse initrd.suse.orig
      fi

      cd /boot
      ln -sf "${MPP_RAMDISK_NAME}" initrd
   else
      echo -e "Did not detect kernel image. Exiting ..."
      exit 2
   fi
}

#################################################################################
# Function:mppLnx_suse_add_backup_menu
# Description:add backup menu entry to the /boot/grub/menu.lst. The backup menu entry
#             is used to boot the system to the original condition in the case where
#             the mpp ramdisk is corrupted
#
# Scope: private to this file.
#
##################################################################################
mppLnx_suse_add_backup_menu()
{
   mppLnx_suse_init_variables
   MENU_LIST_FILE="/boot/grub/menu.lst"

   #parsing the /boot/grub/menu.lst file and find the default boot menu
   cat ${MENU_LIST_FILE}|awk \
                             -v BACKUP_BEGIN_TOKEN="${BACKUP_BEGIN_TOKEN}"\
                             -v BACKUP_END_TOKEN="${BACKUP_END_TOKEN}"  '
   BEGIN{
       lnOfDefault=0
       totalLine=0
       noOfEntrys=0
  }
  {
      if( /^default/ )
      {
          lnOfDefault=NR
      }
      if( /^title/)
      {
          titleLn[noOfEntrys]=NR
          noOfEntrys++
      }
      fileContent[NR]=$0
      totalLine++
  }
END{
   #searching for the default boot menu entry
   #the default menu entry line could be in the formats of
   #default=0 or default 0
   if(fileContent[lnOfDefault] ~ "=")
   {
       split(fileContent[lnOfDefault], defaultLn,"=")
   }
   else
   {
       split(fileContent[lnOfDefault], defaultLn," ")
   }
   defaultBootEntry=defaultLn[2]
   #the default menu entry line could be in the formats of
   #default=0 or default 0
   

   for(i=titleLn[defaultBootEntry]; i<totalLine; i++)
   {
         if(fileContent[i] ~ "title" )
         {
            #print the comments and the new title
            print BACKUP_BEGIN_TOKEN
            print "title Linux Original Boot Entry"
         } else if( fileContent[i] ~ "initrd")
         {
            #put the orig initrd for initrd line
            split(fileContent[i],initrdFields,"/")
            printf("%s/%s/initrd.orig\n",initrdFields[1],initrdFields[2])
            print BACKUP_END_TOKEN
            i=totalLine++
         }
         else
         {
            #do not touch the boot/root/command option line
            if (fileContent[i] ~ /^ *$/ )
            {
               #do not add the blank line
            }
            else
            {
               print fileContent[i]
            }
         }
      }
   }
' >>${MENU_LIST_FILE}
}
#################################################################################
# Function:mppLnx_suse_uninst_ramdisk
# Description: restore the files in /boot that were modified by mppLnx_suse_inst_ramdisk 
#
# Scope: private to this file.
#
##################################################################################
mppLnx_suse_uninst_ramdisk()
{
   #remove the mpp ramdisk
   if [ -f /boot/${MPP_RAMDISK_NAME} ]
   then
       rm -f /boot/${MPP_RAMDISK_NAME}
   fi
   
   case ${SUSE_VERSION_CHECKING} in 
        3)
            if [ -L /boot/initrd ]
            then
                rm /boot/initrd
            fi
            if [ -L /boot/initrd.orig ]
            then
                rm /boot/initrd.orig
                cd /boot
                ln -s initrd-${VMLINUZ_VERSION} initrd
            else
                cd /boot
                ln -s initrd-${VMLINUZ_VERSION} initrd
            fi
                        
            ;;
        *)
            if [ -e /boot/initrd.orig ]
            then

                #remove the link of /boot/initrd
                if [ -e /boot/initrd ]
                then
                    rm -f /boot/initrd
                fi

                #move the /boot/initrd.orig back to /boot/initrd
                mv  /boot/initrd.orig  /boot/initrd
            fi
         ;;
   esac
  
}
#################################################################################
# Function:mppLnx_suse_remove_backup_menu
# Description: remove the bakc up menu entry in /boot/grub/menu.lst that was added
#              by mppLnx_suse_add_backup_menu
#
# Scope: private to this file.
#
##################################################################################
mppLnx_suse_remove_backup_menu()
{
   MENU_LIST_FILE="/boot/grub/menu.lst"
   TEMP_MENU_LIST_FILE="/tmp/menu.lst_tmp_$$"
   cat ${MENU_LIST_FILE}|awk -v BACKUP_END_TOKEN="${BACKUP_END_TOKEN}"\
                             -v BACKUP_BEGIN_TOKEN="${BACKUP_BEGIN_TOKEN}"  '
   BEGIN {
      begin_token_start = 0
      end_token_start = 0
   }
   {
      if($0 ~ BACKUP_BEGIN_TOKEN)
      {
          begin_token_start = 1
      }
      else if($0 ~ BACKUP_END_TOKEN)
      {
          end_token_start = 1
      } 
      else if(begin_token_start == 0)
      {
          print $0
      }else if(end_token_start == 1 && begin_token_start == 1)
      {
          print $0
      }
    }
   
'>${TEMP_MENU_LIST_FILE}
   cp ${TEMP_MENU_LIST_FILE} ${MENU_LIST_FILE}
   rm -f ${TEMP_MENU_LIST_FILE}
}

#################################################################################
# Function:mppLnx_suse_is_mpp_initrd
# Description: Check whether or not mpp ramdisk is the default initrd image
# Scope: public
#
# output: return 1 if it is.
#
##################################################################################
mppLnx_suse_is_mpp_initrd()
{
    INITRD_LINK="/boot/initrd"

    if [ -h ${INITRD_LINK} ]
    then

        INITRD_FILE=$(ls -l ${INITRD_LINK}|grep -c mpp)
        if [ "${INITRD_FILE}" = 1 ]
        then
            echo "1"
        else
            echo "0"
        fi
    fi
}
#################################################################################
# Function:mppLnx_suse_setup_boot
# Description: Make the system could be rebooted from the mpp ramdisk. This function 
#              can be invoked by the mpp driver installation operation
#
# Scope: public
#
# Termination: if the function detects that the running kernel is not the same kernel
#              as the /boot/vmlinuz kernel image
# input: install or update
#
##################################################################################
mppLnx_suse_setup_boot()
{
   setup_opt="$1"
   mppLnx_suse_init_variables
   
   if [ "${setup_opt}" = "install" ]
   then
        mppLnx_suse_inst_ramdisk
        mppLnx_suse_add_backup_menu
   else
        #the option is update
        #We should do any thing here except the kernel is just updated by Yast2.
        #if this is the case, we must re-install the ramdisk

        case ${SUSE_VERSION_CHECKING} in 
            1)
                mppLnx_suse_inst_ramdisk
                ;;
            3)
                mppLnx_suse_inst_ramdisk
                ;;
            *)
                ;;
        esac
   fi
        
}

#################################################################################
# Function:mppLnx_suse_cleanup_boot
# Description: Restore the system boot menu and /boot directory to its previous condition
#              This function can be invoked by the mpp driver un-installation operation
#
# Scope: public
#
# Termination: if the function detects that the running kernel is not the same kernel
#              as the /boot/vmlinuz kernel image
#
# input: uninstall or update
##################################################################################
mppLnx_suse_cleanup_boot()
{
   cleanup_opt="$1"
   mppLnx_suse_init_variables

   if [ "${cleanup_opt}" = "uninstall" ]
   then
        #the uninstallation case
        if [ "$(mppLnx_suse_is_mpp_initrd)" = 1 ]
        then
            mppLnx_suse_uninst_ramdisk
        fi
        
        if [ -e /boot/initrd.orig ]
        then
           rm /boot/initrd.orig
        fi

        mppLnx_suse_remove_backup_menu
   fi
   #we don't need to do any thing for the update case
}

##################################################################################
# main - testing driver
# $0 setup -- invoke the mppLnx_suse_setup_boot function
# $0 cleanup -- invoke the mppLnx_suse_cleanup_boot function
##################################################################################

VMLINUZ_VERSION=$(mppLnx_suse_vmlinuz_version)
SUSE_VERSION_CHECKING=$(mppLnx_suse_version_check)
   
if [ "$1" = "setup" ]
then 
   echo "set up"
   mppLnx_suse_setup_boot
fi

if [ "$1" = "cleanup" ]
then
   echo "clean up"
   mppLnx_suse_cleanup_boot
fi
