#!/bin/bash
#
# Description: Setup, capture or report on Java and C/C++ code coverage.
#
# Change Activity:
#   06/25/2007 P. Callaghan   - Initial version

#Function to freshen regular files in one directory with that from
# another if the file exists. Note, symbolic links in the directory to
# freshen are not freshened.
freshen() {
  directoryToFreshen=$1
  directoryToFreshenWith=$2
  cd $directoryToFreshen
  files=$(find . -maxdepth 1 -type f)
  cd -
  #echo $files
  for currentFile in $files
  do
    if [ -e "${directoryToFreshenWith}${currentFile}" ] ; then
      cp "${directoryToFreshenWith}${currentFile}" "${directoryToFreshen}"
    fi
  done
}

# Function to setup for Java and C/C++ code coverage.
# Arguments - None
doSetup() {

   ##Determine if we are on an HMC or a SE
   #temp=$(ps -Afww | grep 'bbrdhal' | grep -v 'grep bbrdhal')
   #if [ -n "$temp" ] ; then
   #   # On a SE
   #   onSE=1
   #else
   #   # On an HMC
   #   onSE=0
   #fi

   # Do emma setup.
   if [ -e /ffdc/emma.jar ] ; then
      echo 'Doing java coverage setup.'
      #cd /console
      jars=$(find /console/jars -type f -name '*.jar' | grep -v '/console/jars/framework/auiml/')
      #echo $jars
      for i in $jars
      do
        if [ -z "$jarlist" ] ; then
          jarlist=$i
        else
          jarlist=$jarlist:$i
        fi
      done
      rm -Rf /ffdc/ccov_out
      rm /console/coverage.em > /dev/null 2>&1
      java -cp /ffdc/emma.jar emma instr -ix com.ibm.hwmca*,com.ibm.ui*,com.ibm.aui* -ip /console/:$jarlist -d /ffdc/ccov_out/ -verbose -out /console/coverage.em
      chown hmcmanager:nobody /ffdc/ccov_out -R
      chown hmcmanager:nobody /console/coverage.em
      stringToWrite='/ffdc/ccov_out/:/ffdc/emma.jar'
      echo "$stringToWrite" > /console/first_in_classpath
      chown hmcmanager:nobody /console/first_in_classpath
      touch /console/coverage.ec
      chown hmcmanager:nobody /console/coverage.ec
   else
      echo 'The /ffdc/emma.jar file does not exist so java coverage setup is skipped.'
   fi

   # Do gcov setup.

   # Overlay the existing executables and shared libraries with the instrumented versions
   # but after moving the existing so as to be less disruptive to the running system.
   binSuccess=0
   libSuccess=0
   if [ -e /ffdc/bin.tgz ] ; then
      if [ ! -d /console/bin_staging_area ] ; then
         if [ ! -d /console/bin_orig ] ; then
            if [ ! -d /console/bin_temp ] ; then
               echo 'Doing executable coverage setup.'

               # Create a new directory structure with the existing executables in it.
               cp -Rp /console/bin /console/bin_staging_area

               # Extract the tar file to a temporary location.
               mkdir /console/bin_temp/
               cd /console/bin_temp/
               tar -zxf /ffdc/bin.tgz
               cd /

               # Overlay this new directory with instrumented executables but
               # keeping the ownership and permissions as the existing
               # destination files.
               freshen /console/bin_staging_area/base/ /console/bin_temp/
               freshen /console/bin_staging_area/framework/ /console/bin_temp/
               freshen /console/bin_staging_area/zseries/ /console/bin_temp/
               freshen /console/bin_staging_area/test/ /console/bin_temp/
               freshen /console/bin_staging_area/tmp/ /console/bin_temp/
               rm -Rf /console/bin_temp/

               # Move the existing executables
               mv /console/bin /console/bin_orig

               # Move the staging area.
               mv /console/bin_staging_area /console/bin

               binSuccess=1
            else
               echo 'The directory /console/bin_temp already exists so executable coverage setup is skipped.'
            fi
         else
            echo 'The directory /console/bin_orig already exists so executable coverage setup is skipped.'
         fi
      else
         echo 'The directory /console/bin_staging_area already exists so executable coverage setup is skipped.'
      fi
   else
      echo 'The /ffdc/bin.tgz file does not exist so executable coverage setup is skipped.'
   fi
   if [ -e /ffdc/lib.tgz ] ; then
      if [ ! -d /console/lib_staging_area ] ; then
         if [ ! -d /console/lib_orig ] ; then
            if [ ! -d /console/lib_temp ] ; then

               echo 'Doing shared library coverage setup.'

               # Create a new directory structure with the existing shared libraries in it.
               cp -Rp /console/lib /console/lib_staging_area

               # Extract the tar file to a temporary location.
               mkdir /console/lib_temp/
               cd /console/lib_temp/
               tar -zxf /ffdc/lib.tgz
               cd /

               # Overlay this new directory with instrumented shared libraries but
               # keeping the ownership and permissions as the existing
               # destination files.
               freshen /console/lib_staging_area/base/ /console/lib_temp/
               freshen /console/lib_staging_area/framework/ /console/lib_temp/
               freshen /console/lib_staging_area/zseries/ /console/lib_temp/
               freshen /console/lib_staging_area/test/ /console/lib_temp/
               freshen /console/lib_staging_area/tmp/ /console/lib_temp/
               rm -Rf /console/lib_temp/

               # Move the existing shared libraries
               mv /console/lib /console/lib_orig

               # Move the staging area.
               mv /console/lib_staging_area /console/lib

               libSuccess=1
            else
               echo 'The directory /console/lib_temp already exists so shared library coverage setup is skipped.'
            fi
         else
            echo 'The directory /console/lib_orig already exists so shared library coverage setup is skipped.'
         fi
      else
         echo 'The directory /console/lib_staging_area already exists so shared library coverage setup is skipped.'
      fi
   else
      echo 'The /ffdc/lib.tgz file does not exist so shared library coverage setup is skipped.'
   fi

   # If using gcov profiling, ensure that hmcmanager can write to the gcda files
   # that root will be creating by adding the root group to hmcmanager.
   if [[ $binSuccess -eq 1 || $libSuccess -eq 1 ]] ; then
      theGroups0=$(groups hmcmanager)
      theGroups=$(echo "$theGroups0" | cut -f 2 -d : --output-delimiter="," )
      groupsToAdd=""
      addedGroup=0
      rootGroupPresent=0
      for aGroup in $theGroups; do
         if [ !  "$aGroup" == "root" ] ; then
            if [ $addedGroup -eq 1 ] ; then
               groupsToAdd="${groupsToAdd},${aGroup}"
            else
               groupsToAdd=$aGroup
               addedGroup=1
            fi
         else
            rootGroupPresent=1
            break
         fi
      done
      if [ $rootGroupPresent -eq 0 ] ; then
         usermod -G${groupsToAdd},root hmcmanager
         touch /console/addedRootGroup
      fi
   fi
}

# Function to capture Java code coverage.
# Arguments - None
doCapture() {
   #echo '->doCapture'

   # Request Java code coverage.
   java -cp /ffdc/emma.jar emma ctl -connect 127.0.0.1:47653 -command coverage.dump

   # Request C/C++ code coverage
   requestGCDAFiles
}

# Function to report on Java code coverage.
# Arguments - None
doReport() {
   #echo '->doReport'
   java -cp /ffdc/emma.jar emma report -r html -in /console/coverage.ec -in /console/coverage.em -Dreport.depth=method -sp /console
   #firefox /console/coverage/index.html
}

# Function to display usage syntax.
# Arguments - None
displayUsage() {
   echo 'Usage : ccov [setup | capture | report | cleanup]'
}

# Function to cleanup Java and C/C++ code coverage.
# Arguments - None
doCleanup() {
   #echo '->doCleanup'

   echo 'Cleaning up Java code coverage files'
   rm -Rf /ffdc/ccov_out > /dev/null 2>&1
   rm /console/coverage.em > /dev/null 2>&1
   rm /console/coverage.ec > /dev/null 2>&1

   stringToWrite='/ffdc/ccov_out/:/ffdc/emma.jar'
   if [ -e /console/first_in_classpath ] ; then
      contents=$(cat /console_first_in_classpath)
      if [ -n "$contents" ] ; then
         if [ "$stringToWrite" = "$contents" ] ; then
            echo 'Removing instrumented classes from the classpath'
            rm /console/first_in_classpath
         fi
      fi
   fi

   # If we added the root group to hmcmanager, remove it.
   if [ -e /console/addedRootGroup ] ; then
      theGroups0=$(groups hmcmanager)
      theGroups=$(echo "$theGroups0" | cut -f 2 -d : --output-delimiter="," )
      groupsToAdd=""
      addedGroup=0
      rootGroupPresent=0
      for aGroup in $theGroups; do
         if [ !  "$aGroup" == "root" ] ; then
            if [ $addedGroup -eq 1 ] ; then
               groupsToAdd="${groupsToAdd},${aGroup}"
            else
               groupsToAdd=$aGroup
               addedGroup=1
            fi
         else
            rootGroupPresent=1
         fi
      done
      if [ $rootGroupPresent -eq 1 ] ; then
         echo 'Removing the root group from the hmcmanager userid'
         usermod -G${groupsToAdd} hmcmanager
      fi
      rm /console/addedRootGroup
   fi

   binSuccess=0
   libSuccess=0
   if [ -d /console/bin_orig ] ; then
      echo 'Restoring executables to their original state'
      mv /console/bin /console/bin_new
      mv /console/bin_orig /console/bin
      binSuccess=1
   else
      echo 'Did not restore executables to their original state because the /console/bin_orig/ directory could not be found'
   fi

   if [ -d /console/lib_orig ] ; then
      echo 'Restoring shared libraries to their original state'
      mv /console/lib /console/lib_new
      mv /console/lib_orig /console/lib
      libSuccess=1
   else
      echo 'Did not restore shared libaries to their original state because the /console/lib_orig/ directory could not be found'
   fi

   if [ $binSuccess -eq 1 ] ; then
      if [ $libSuccess -eq 1 ] ; then
         echo 'reboot the system and after reboot, logon root and issue "rm -Rf /console/bin_new" and "rm -Rf /console/lib_new"'
      else
         echo 'reboot the system and after reboot, logon root and issue "rm -Rf /console/bin_new"'
      fi
   else
      if [ $libSuccess -eq 1 ] ; then
         echo 'reboot the system and after reboot, logon root and issue "rm -Rf /console/lib_new"'
      fi
   fi
}

requestGCDAFiles() {

   # Setup our main classpath to the base tower classes.
   CCFW_CLASSPATH=/opt/ccfw/ccfw.jar
   CONSOLE_CLASSPATH=/console/
   if [ -f $CCFW_CLASSPATH ]; then
      OUR_CLASSPATH=$CCFW_CLASSPATH
   elif [ -n "$CONSOLE_PATH" ]; then
      # CONSOLE_PATH is set so use it.
      OUR_CLASSPATH=$CONSOLE_PATH
   elif [ -d $CONSOLE_CLASSPATH ]; then
      OUR_CLASSPATH=$CONSOLE_CLASSPATH
   else
      echo 'Cannot locate classpath for the CCFW base tower.'
   fi

   java -cp $OUR_CLASSPATH com.ibm.hwmca.base.monitor.DumpCCOV all
}

if [ $# -ne 1 ]; then
   displayUsage
   exit 1
fi

# Make sure we're root
me=$(whoami)                # Current user's login name
if [ $me != "root" ]; then
   echo "You must be logged in as root to run this script; you are currently logged in as $me."
   exit 3
fi

if [ "${1}" == "setup" ]; then
   doSetup
elif [ "${1}" == "capture" ]; then
   doCapture
elif [ "${1}" == "report" ]; then
   doReport
elif [ "${1}" == "cleanup" ]; then
   doCleanup
else
   displayUsage
   exit 2
fi

exit 0
