#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
#  
#  
# Licensed Materials - Property of IBM 
#  
# (C) COPYRIGHT International Business Machines Corp. 2000,2007 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
###################################################################
#
# Description:
#     The csmsnap command gathers configuration, log and trace information
#     about the Cluster Systems Management (CSM) components that
#     are installed. This command only collects
#     the data on the local node on which this command is run.
#
#     This command is typically executed when a problem is encountered with
#     any of these components in order to provide service information to the
#     IBM Support Center.
#
#     This command should only be executed at the instruction of the IBM
#     Support Center.

# Syntax:
#       csmsnap [-h] [-d output_directory]
#
# Flags:
#       -h writes the usage of this command to standard output
#       -d is used to specify the output directory (absolute path)
#          default is /tmp/csmsnap
#
# Ouputs:
#     tar file : csmsnap.host_name.nnnnnnnn.tar.Z
#     log file : csmsnap.host_name.nnnnnnnn.log
#     (where host_name is the base name of the host name of the
#     node on which the command is running; nnnnnnnn is a timestamp).
#     By default these files are placed in the /tmp/csmsnap directory.
#
# Exit Status:
#     0 - run successfully
#     1 - error occured
#
# Security:
#     This command can only be run by a root user.
#
####################################################################
# @(#)82   1.1   src/csm/core/cmds/csmsnap, csmcore, csm_rfish, rfishs001b 6/5/06 17:02:27

export LANG=C

ROOTDIR=/
LOGDIR=/tmp/csmsnap
total_bytes=0

#####################################################################
# FUNCTIONs
#####################################################################

usage () {
  echo "Usage: csmsnap [-h] [-d output_directory]"
  echo "    -h Display this usage statement."
  echo "    -d Directory to put information (default : /tmp/csmsnap)."
} # End of usage

valid_dir () {
  case "$1" in
        /*) ;;
        *)  echo "Invalid argument for -d. Please specify an absolute path."
            exit 1
            ;;          # Not valid path.
  esac
} # End of valid_dir

function check_space {

  echo "Checking for necessary space ......." >> $LOGFILE
  echo "Checking for necessary space ......."

  # adding an extra 20 kbytes into total number of bytes needed in order to
  # keep filesystem from being 100 percent full on systems tight on space

  total_bytes=`expr $total_bytes + 20`
  echo "Required space: $total_bytes kbytes" >> $LOGFILE
  echo "Required space: $total_bytes kbytes"

  if [ "$BASEOS" = "AIX" ]
  then
      free_space=`df -k ${LOGDIR} | tail -n +2 | awk '{print $3}'`
  else
      free_space=`df -k ${LOGDIR} | tail -n +2 | awk '{print $4}'`
  fi
  echo "Free space: $free_space kbytes" >> $LOGFILE
  echo "Free space: $free_space kbytes"

  if [ "$free_space" -lt "$total_bytes" ]
  then
    echo "Not enough space in ${LOGDIR}." >> $LOGFILE
    echo "Not enough space in ${LOGDIR}."
    echo "Exiting..." >> $LOGFILE
    echo "Exiting..."
    exit 1
  else
    echo "Sufficient space is present to proceed." >> $LOGFILE
    echo "Sufficient space is present to proceed."
  fi

} # End of check_space

function check_and_tar_symbolic_dirs {
  i=0
  circular=0
  fulldir=$file
  pre_dir=$file

  while [[ -L $fulldir ]]
    do
      if (( $i > $max_link_count )) # after max_link_count stop searching
      then
          echo "The symbolic link count exceeds max_link_count of $max_link_count." >> $LOGFILE
          break 1
      fi
      #get the real directory name to tar
      fulldir=$(ls -ld $fulldir |awk '{print $NF}')

      # check if it is a relative dir and get the absolute path without ..
      # so that it is easy for comparison for checking circular link
      if (( $i > 0 ))
      then
          ((ii=$i-1))
          pre_dir=${dir_array[$ii]}
      fi
      if [[ $fulldir = ..* ]]
      then
          abdir=${pre_dir%/*}
          while [[ $fulldir = ..* ]]
          do
            fulldir=${fulldir#../}
            abdir=${abdir%/*}
          done
          fulldir=$abdir/$fulldir
      elif [[ $fulldir = .* ]]
      then
          fulldir=${fulldir#.}
          abdir=${pre_dir%/*}
          fulldir=$abdir$fulldir
      elif [[ $fulldir != /* ]]
      then
          abdir=${pre_dir%/*}
          fulldir=$abdir/$fulldir
      fi
      dir_array[$i]=$fulldir

      # check circular link since now they are all absolute paths
      j=0
      while (( $j < $i ))
        do
          if [[ ${dir_array[$i]} = ${dir_array[$j]} ]]
          then
              echo "${dir_array[$i]} is a circular link." >> $LOGFILE
              circular=1
              break 2
          fi
          ((j=$j+1))
      done
      flist=".$fulldir $flist" # keep the original middle dirs structure
                                   # so that we can trace the links
      ((i=$i+1))
  done
  if [[ $circular != 1 ]]
  then
      if [[ -e ${TARFILE} ]]
      then
          tar -uf ${TARFILE} .$fulldir 2>/dev/null
      else
          tar -cf ${TARFILE} .$fulldir 2>/dev/null
      fi
  fi
} # End of check_and_tar_symbolic_dirs

function timeout_cmd {
    typeset sleepTime=$1 # sleep for $1 secs
    typeset timeOut=$2   # timeout in $2 secs
    typeset waitTime=0   # increment value
    typeset pid=""

    # run the cmd
    eval $cmd > .${OUTDIR}/$comp.out 2>&1 &
    pid=$!

    while [[ $waitTime -lt $timeOut ]]
    do
      waitTime=$(($waitTime + $sleepTime))

      if ! kill -s 0 $pid 2>/dev/null
      then
        isTimeOut=0
        break
      fi
      sleep $sleepTime
    done
    if [[ $waitTime -ge $timeOut ]]
    then
        kill $pid 2>/dev/null
        isTimeOut=1
        echo "Command $cmd timed out." >> $LOGFILE
    fi

} # end of timeout_cmd

function run_cmd {
  exec 2>/dev/null
  echo "    $cmd > $comp.out" >> $LOGFILE
  echo "    $cmd > $comp.out"
  echo "      Executing: $cmd" >> $LOGFILE
  echo "      Executing: $cmd"
  echo "$cmd" | egrep "lsrsrc|lsrpnode|lscomg"  >/dev/null 2>/dev/null
  if [ "$?" = 0 ]
  then
      timeout_cmd 5 30
  else
      eval $cmd > .${OUTDIR}/$comp.out 2>&1
  fi

  echo "      Execution Complete: $cmd" >> $LOGFILE
  echo "      Execution Complete: $cmd"

  exec 2>/dev/null
} # end of run_cmd

function gather_files {
  exec 2>/dev/null
  indent=1
  echo "    $files" >> $LOGFILE
  echo "    $files"
  echo "      Processing Files: $files" >> $LOGFILE
  echo "      Processing Files: $files"
  file_list=`ls $files`
  for i in $file_list
  do
    file=$i
    gather_file
  done
  echo "      Files Processed: $files" >> $LOGFILE
  echo "      Files Processed: $files"
  indent=0
  exec 2>/dev/null
} # end gather_files

function gather_file {
  exec 2>/dev/null
  if [[ indent -eq 1 ]]
  then
    echo "        $file" >> $LOGFILE
    echo "        $file"
    echo "          Processing File: $file" >> $LOGFILE
    echo "          Processing File: $file"
  else
    echo "    $file" >> $LOGFILE
    echo "    $file"
    echo "      Processing File: $file" >> $LOGFILE
    echo "      Processing File: $file"
  fi
  if [[ -L $file ]]
  then
      check_and_tar_symbolic_dirs #handle symbolic link
  fi
  flist=".$file $flist"  # keep the original dir structure but
                             # if it is a symbolic link then it's
                             # only a symbolic link when tarred
                             # so there is no duplication
                             #  If it's not a symbolic link then
                             # get the file list for archive

  if [[ indent -eq 1 ]]
  then
    echo "          File Processed: $file" >> $LOGFILE
    echo "          File Processed: $file"
  else
    echo "      File Processed: $file" >> $LOGFILE
    echo "      File Processed: $file"
  fi
  exec 2>/dev/null
} # end of gather_file

##############################################################################
# Function: doit
#
# To utilize this facility and add new function to collect more data from a
# system you must use one of three methods :
#
# 1) single redirection in the form of " > "
#     Notice the spaces surrounding the greater than sign
# 2) append redirection in the form of "  >> "
#     Notice the spaces surrounding the greater than signs
# 3) The ls command in the form of "ls xxxx"
#     Notice the xxxx can be either a file name or a directory name
#     (but no wildcard)
#
#   All of these forms are very important for supporting conversion of commands
#   to forms that will pipe their output to the "wc -c" command to count the
#   number of bytes for the particular operation.
#   If the commands are not in this form, you will get an error message.
#   Again, this is important to understand when adding new functionality into
#   the script for collecting more documentation
#
#   For the first (with ">") and the second (with ">>") methods you must use
#   the following 3-line sequence to perform the appropriate space checking.
#
#   for example, for collecting "errpt -a" information :
#           comp=errpt
#           cmd="errpt -a > ./errpt.out 2>&1"
#           run_cmd
#
#    comp    => This is the component name that will be used as the output
#               file name. This output file will be save in log directory.
#               There is no need to specify the component for the ls command.
#    cmd     => This is the actual command you would like to run in one of the
#               three appropriate formats as noted above.  Notice the " > " in
#               this form of the command.
#    run_cmd => This is just the function call to take appropriate action
#               depending on which pass we are on.
#
#   For the third (ls) method, there is no need to specify the component name,
#   only cmd and run_cmd lines are needed.
#
##############################################################################
function doit {

  #1. collect files

  echo "  Collecting Files..." >> $LOGFILE
  echo "  Collecting Files..."
  echo >> $LOGFILE
  echo

  files="/csminstall/csm/scripts/data/*"
  gather_files

  files="/csminstall/csm/scripts/update/*"
  gather_files

  files="/etc/*-release"
  gather_files

  file="/etc/db_file.cr"
  gather_file

  file="/etc/dhcpd.cfg"
  gather_file

  file="/etc/dhcp.conf"
  gather_file

  file="/etc/dhcpsd.cnf"
  gather_file

  file="/etc/hosts"
  gather_file

  file="/etc/nsswitch.conf"
  gather_file

  file="/etc/opt/conserver/conserver.cf"
  gather_file

  files="/opt/csm/install/*tmpl*"
  gather_files

  files="/opt/csm/install/*.xml*"
  gather_files

  files="/tftpboot/*"
  gather_files

  files="/tmp/spot.out.*"
  gather_files

  file="/var/adm/ras/nimlog"
  gather_file

  file="/var/log/conserver"
  gather_file

  files="/var/log/consoles/*"
  gather_files

  file="/var/log/messages"
  gather_file

  files="/var/log/csm/*"
  gather_files

  echo >> $LOGFILE
  echo
  echo "  File Collection Complete." >> $LOGFILE
  echo "  File Collection Complete."
  echo >> $LOGFILE
  echo

  #2. output of commands:

  echo "  Capturing System Configuration Information..." >> $LOGFILE
  echo "  Capturing System Configuration Information..."
  echo >> $LOGFILE
  echo

  comp=arp_-a
  cmd="/usr/sbin/arp -a"
  run_cmd

  comp=csmconfig
  cmd="/opt/csm/bin/csmconfig"
  run_cmd

  comp=csmstat
  cmd="/opt/csm/bin/csmstat"
  run_cmd

  comp=DSH_LIST
  cmd="/bin/echo \$DSH_LIST"
  run_cmd

  comp=errpt_-a
  cmd="/bin/errpt -a"
  run_cmd

  comp=frame_-l
  cmd="/opt/csm/bin/frame -l"
  run_cmd

  comp=ifconfig_-a
  cmd="/etc/ifconfig -a"
  run_cmd

  comp=instfix_-i
  cmd="/usr/sbin/instfix -i"
  run_cmd

  comp=cfmroot
  cmd="/bin/ls -lR /cfmroot"
  run_cmd

  comp=lshwdev_-a_Mode
  cmd="/opt/csm/bin/lshwdev -a Mode"
  run_cmd

  comp=lslpp_-hac
  cmd="/bin/lslpp -hac"
  run_cmd

  comp=lsmod
  cmd="/sbin/lsmod"
  run_cmd

  comp=lsnim_-l
  cmd="/usr/sbin/lsnim -l"
  run_cmd

  comp=lsnode_-i
  cmd="/opt/csm/bin/lsnode -i"
  run_cmd

  comp=lsnode_-F
  cmd="/opt/csm/bin/lsnode -F"
  run_cmd

  comp=lsnode_-p
  cmd="/opt/csm/bin/lsnode -p"
  run_cmd

  comp=lspci
  cmd="/sbin/lspci"
  run_cmd

  comp=lsrhws_-e
  cmd="/opt/csm/bin/lsrhws -e"
  run_cmd

  comp=lsrhws_-f
  cmd="/opt/csm/bin/lsrhws -f"
  run_cmd

  comp=lsrhws_-m
  cmd="/opt/csm/bin/lsrhws -m"
  run_cmd

  comp=lsrhws_-s_.Frame_BPA_MTMS==..TM*MS_of_BPA..._-L
  cmd="/opt/csm/bin/lsrhws -s 'Frame_BPA_MTMS=="TM*MS_of_BPA"' -L"
  run_cmd

  comp=lsrsrc_IBM.ManagedNode
  cmd="/bin/lsrsrc IBM.ManagedNode"
  run_cmd

  comp=lsrsrc_IBM.ManagementServer
  cmd="/bin/lsrsrc IBM.ManagementServer"
  run_cmd

  comp=lsrsrc_IBM.MNNetworkInterface_Name_IPAddress_Status
  cmd="/bin/lsrsrc IBM.MNNetworkInterface Name IPAddress Status"
  run_cmd

  comp=lssrc_-a
  cmd="/bin/lssrc -a"
  run_cmd

  comp=lssrc_-l_-s_dhcpsd
  cmd="/bin/lssrc -l -s dhcpsd"
  run_cmd

  comp=monitorinstall
  cmd="/opt/csm/bin/monitorinstall"
  run_cmd

  comp=netstat_-A
  cmd="/bin/netstat -A"
  run_cmd

  comp=netstat_-in
  cmd="/bin/netstat -in"
  run_cmd

  comp=netstat_-rn
  cmd="/bin/netstat -rn"
  run_cmd

  comp=nodegrp
  cmd="/opt/csm/bin/nodegrp"
  run_cmd

  comp=rmcdomainstatus_-s_ctrmc
  cmd="/usr/sbin/rsct/bin/rmcdomainstatus -s ctrmc"
  run_cmd

  comp=rpm_-qa
  cmd="/bin/rpm -qa"
  run_cmd

  comp=rpower_-av_cec_query
  cmd="/opt/csm/bin/rpower -av cec_query"
  run_cmd

  comp=rpower_-av_query
  cmd="/opt/csm/bin/rpower -av query"
  run_cmd

  comp=systemid
  cmd="/opt/csm/bin/systemid"
  run_cmd

  echo >> $LOGFILE
  echo
  echo "  System Configuration Information Captured." >> $LOGFILE
  echo "  System Configuration Information Captured."
  echo >> $LOGFILE
  echo

} # End of doit

#############################################
# MAIN
#############################################


logdate=`date +\%m\%d\%H\%M`

userid=`id -ru`
if [ "$userid" != 0 ]
then
  echo "You must be a root user to use this utility. Exiting..."
  exit 1
fi
while getopts "ahvd:" flag
do
    case $flag in
    h)   usage
         exit 0
         ;;
    d)   d_argument=$OPTARG
         LOGDIR=$d_argument
         valid_dir $LOGDIR
         ;;
    :)   echo "You forgot to enter argument to $OPTARG"
         usage
         exit 1
         ;;
    \?)  usage
         exit 1
         ;;
    esac
done

HOST=`hostname -s`
TARFILE=${LOGDIR}/csmsnap.${HOST}.${logdate}.tar
LOGFILE=${LOGDIR}/csmsnap.${HOST}.${logdate}.log

mkdir -p ${LOGDIR}
exec 3> $LOGFILE

echo "csmsnap Executing..." >> $LOGFILE
echo "csmsnap Executing..."
echo >> $LOGFILE
echo
echo "  Preparing for data collection..." >> $LOGFILE
echo "  Preparing for data collection..."
echo >> $LOGFILE
echo

cd $ROOTDIR
flist=""
tmp_file_list="csmsnap_out"
out_file=""
delete_list=""
max_link_count=32

OUTDIR=${LOGDIR}/csmsnap_out
if [[ -e $OUTDIR ]]
then
  rm -rf $OUTDIR
fi
mkdir -p ${OUTDIR}

echo "    Time Stamp: `date`" >> $LOGFILE
echo "    Time Stamp: `date`"
echo "    Log Directory: ${LOGDIR}" >> $LOGFILE
echo "    Log Directory: ${LOGDIR}"
echo >> $LOGFILE
echo
echo "  Preparation Complete." >> $LOGFILE
echo "  Preparation Complete."
echo >> $LOGFILE
echo

doit

echo "  Compiling Information..." >> $LOGFILE
echo "  Compiling Information..."

flist="$flist"
set $flist

if [[ -e ${TARFILE} ]]
then
    tar -uf ${TARFILE}  -C $LOGDIR $tmp_file_list  -C $ROOTDIR "$@" 2>/dev/null
else
    tar -cf ${TARFILE}  -C $LOGDIR $tmp_file_list  -C $ROOTDIR "$@" 2>/dev/null
fi

if [[ -e ${TARFILE} ]]
then
    which gzip  > /dev/null 2>&1
    if [[ "$?" = 0 ]]
    then
        gzip -f ${TARFILE}
    else
        which compress  > /dev/null 2>&1
        if [[ "$?" = 0 ]]
        then
            compress -f ${TARFILE}
        else
            echo "    gzip and compress commands do not exist. The tar file ${TARFILE} will not be compressed." >> $LOGFILE
            echo "    gzip and compress commands do not exist. The tar file ${TARFILE} will not be compressed."
        fi
    fi
fi

GZFILE=${TARFILE}.gz
ZFILE=${TARFILE}.Z
out_file=".$OUTDIR $delete_list"
set $out_file
if [[ -e ${TARFILE} || -e ${GZFILE} || -e ${ZFILE} ]]
then
    rm -rf "$@"
fi

echo "  Information Compiled." >> $LOGFILE
echo "  Information Compiled."
echo >> $LOGFILE
echo
echo "csmsnap Execution Complete." >> $LOGFILE
echo "csmsnap Execution Complete."

chmod 400 $LOGFILE
if [[ -e ${GZFILE} ]]
then
    chmod 400 ${GZFILE}
elif [[ -e ${ZFILE} ]]
then
    chmod 400 $ZFILE
elif [[ -e ${TARFILE} ]]
then
    chmod 400 $TARFILE
else
    chmod 400 $out_file
fi
exit 0
