#!/bin/ksh
#< Highly detailed Solaris system information gathering script
# Description:
#   Display various groups of system inforamtion. The script is designed to be
#   easily extendable by adding process_command "command" directives, and appending
#   filenames to the list of FILES to check
#
# Kevin Waldron 2006

BASENAME="/usr/bin/basename"
CAT="/usr/bin/cat"
CENTRE_STRING="/home/kevin/bin/centre_string"
DATE="/usr/bin/date"
ECHO="/usr/bin/echo"
GREP="/usr/bin/grep"
HOSTNAME="/usr/bin/hostname"
LAST="/usr/bin/last"
TR="/usr/bin/tr"
HEAD="/usr/bin/head"
UNAME="/usr/bin/uname"
PRTDIAG="/usr/platform/$( ${UNAME} -i )/sbin/prtdiag"
EEPROM="/usr/platform/$( ${UNAME} -i )/sbin/eeprom"
ISAINFO="/usr/bin/isainfo"
PSRINFO="/usr/sbin/psrinfo"
PRTCONF="/usr/sbin/prtconf"
SYSDEF="/usr/sbin/sysdef"
WHO="/usr/bin/who"
WHODO="/usr/sbin/whodo"
W="/usr/bin/w"
IFCONFIG="/usr/sbin/ifconfig"
NETSTAT="/usr/bin/netstat"
NDD="/usr/sbin/ndd"
LS="/usr/bin/ls"
SED="/usr/bin/sed"
AWK="/usr/bin/awk"
PRINTF="/usr/bin/printf"
WHOAMI="/usr/ucb/whoami"
FORMAT="/usr/sbin/format"
SWAP="/usr/sbin/swap"
DF="/usr/sbin/df"
PRSTAT="/usr/bin/prstat"
IOSTAT="/usr/bin/iostat"
MPSTAT="/usr/bin/mpstat"
VMSTAT="/usr/bin/mpstat"
PS="/usr/bin/ps"
EGREP="/usr/bin/egrep"
DMESG="/usr/sbin/dmesg"
SHOWREV="/usr/bin/showrev"
PKGINFO="/usr/bin/pkginfo"
UPTIME="/usr/bin/uptime"
METASTAT="/usr/sbin/metastat"
METADB="/usr/sbin/metadb"
VXDISK="/usr/sbin/vxdisk"
VXPRINT="/usr/sbin/vxprint"
VXDG="/usr/sbin/vxdg"
PRTVTOC="/usr/sbin/prtvtoc"
SVCS="/usr/bin/svcs"
INETADM="/usr/sbin/inetadm"

THISPROG=$( ${BASENAME} $0 )

VERBOSE=0
CS_WIDTH=80
CS_CHAR_1="-"
CS_CHAR_2="*"
HTML=0
VALID_GROUPS="all system network disk vxvm capacity files logs snapshot user software"
MAJOR_VERSION=0
MINOR_VERSION=1
VERSION="${MAJOR_VERSION}.${MINOR_VERSION}"

echo_debug() {
   echo "-[debug]- $@" >&2
}

echo_stderr() {
   echo "$@" >&2
}

usage() {
   echo_stderr "${THISPROG} [-v] [-g group_1[,group_2,...]] [-H]"
   echo_stderr "   -g group_1,group_2   Display specific info groups"
   echo_stderr "   -l                   List available info groups then exit"
   echo_stderr "   -H                   Output in HTML"
   echo_stderr "   -v                   Print development debug messages"
   exit 1
}

list_info_groups() {
   echo_stderr "Valid info groups are: ${VALID_GROUPS}"
   exit 6
}

display_header() {
   (( HTML )) && {
      HEADER=$( ${ECHO} "$1" | ${SED} -e 's/\&/\&amp;/' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' )
      ${ECHO} "<h2>${HEADER}</h2>"
   } || {
      ${ECHO}
      ${CENTRE_STRING} ${CS_WIDTH} "${CS_CHAR_2}" ""
      ${CENTRE_STRING} ${CS_WIDTH} "${CS_CHAR_1}" "$1"
      ${CENTRE_STRING} ${CS_WIDTH} "${CS_CHAR_2}" ""
      ${ECHO}
   }
}

display_command_syntax() {
   (( HTML )) && {
      ${ECHO} "<h3><tt>$@</tt></h3>"
   } || {
      ${ECHO}
      ${ECHO} "###### $@"
      ${ECHO}
   }
}

display_intro() {
   (( HTML )) && {
      ${ECHO} "<html>"
      ${ECHO} "<head>"
      ${ECHO} "<title>SYSTEM INFORMATION REPORT FOR $( ${HOSTNAME} )</title>"
      ${ECHO} "</head>"
      ${ECHO} "<body>"
      ${ECHO} "<h2>SYSTEM INFORMATION REPORT FOR $( ${HOSTNAME} )<br>$( ${DATE} )</h2>"
   } || {
      display_header " SYSTEM INFORMATION REPORT FOR $( ${HOSTNAME} ) - $( ${DATE} ) "
   }
}

process_command() {
   COMMAND_BUFFER="$@"
   display_command_syntax "${COMMAND_BUFFER}"
   BINARY=$( ${ECHO} "${COMMAND_BUFFER}" | ${AWK} '{print $1}' )
   if [ ! -e "${BINARY}" ]; then
      echo_stderr "Error: ${BINARY} does not exist"
   elif [ ! -x "${BINARY}" ]; then
      echo_stderr "Error: ${BINARY} is not executable"
   else
      (( HTML )) && echo "<pre>"
      (( HTML )) && {
         eval ${COMMAND_BUFFER} | ${SED} -e 's/\&/\&amp;/' -e 's/</\&lt;/g' -e 's/>/\&gt;/g'
      } || {
         eval ${COMMAND_BUFFER}
      }
      (( HTML )) && echo "</pre>"
   fi
}

display_system_info() {
   (( VERBOSE )) && echo_debug "display_system_info()"
   display_header "< SYSTEM INFORMATION >"

   process_command "${UNAME} -a"
   display_command_syntax "${ECHO} \$TZ"
   COMMAND_BUFFER="${ECHO} ${TZ}"
   eval ${COMMAND_BUFFER}
   process_command "${UPTIME}"
   process_command "${WHO} -r"
   process_command "${PRTDIAG} -v"
   process_command "${EEPROM}"
   process_command "${ISAINFO} -kv"
   process_command "${PSRINFO}"
   process_command "${PSRINFO} -v"
   process_command "${PRTCONF} -v"
   process_command "${PRTCONF} -V"
   process_command "${SYSDEF}"

   RELEASE=$( ${UNAME} -r )
   if [ "${RELEASE}" = "5.10" ]; then
      process_command "${SVCS} -a"
      process_command "${INETADM}"
   fi
}

display_network_info() {
   (( VERBOSE )) && echo_debug "display_network_info()"
   display_header "< NETWORK INFORMATION >"

   process_command "${IFCONFIG} -a"
   process_command "${NETSTAT} -ivn"
   process_command "${NETSTAT} -rn"
   process_command "${NETSTAT} -an"

   if [ "$( ${WHOAMI} )" = "root" ]; then
      ${LS} /etc/hostname* | ${SED} 's/^[^.]*\.\([^.]*\)$/\1/' | while read INTERFACE; do
         ${ECHO} ${INTERFACE} | ${GREP} ":" >/dev/null 2>&1
         if [ "$?" -eq "0" ]; then
            echo_stderr "Skipping interface ${INTERFACE}"
         else
            ${ECHO} ${INTERFACE} | grep "bge" >/dev/null 2>&1
            if [ "$?" -ne "0" ]; then
               instance=`${ECHO} ${INTERFACE} | ${SED} 's/^[a-z][a-z]*\([0-9]\)$/\1/'`
               INTERFACE=`${ECHO} ${INTERFACE} | ${SED} 's/^\([a-z][a-z]*\)[0-9]$/\1/'`
               process_command "${NDD} -set /dev/${INTERFACE} instance ${instance}"
            fi
            (( HTML )) && {
               ${ECHO} "<pre>"
            }
            ${NDD} -get /dev/${INTERFACE} \? |\
                ${AWK} '/^adv/ {print $1}' | while read param; do
                    setting=`${NDD} -get /dev/${INTERFACE} ${param}`
                    ${PRINTF} "%25s:\t%s\n" "${param}" "${setting}"
                done
            (( HTML )) && {
               ${ECHO} "</pre>"
            }
          fi
       done
    fi
}

display_disk_info() {
   (( VERBOSE )) && echo_debug "display_disk_info()"
   display_header "< DISK INFORMATION >"

   if [ "$( ${WHOAMI} )" = "root" ]; then
      process_command "${FORMAT} < /dev/null"
      ${LS} /dev/rdsk | ${GREP} "s2" | while read RAW; do
         process_command "${PRTVTOC} /dev/rdsk/${RAW}"
      done
   fi
   process_command "${METASTAT}"
   process_command "${METASTAT} -p"
   process_command "${METADB}"
   process_command "${IOSTAT} -En"
}

display_vxvm_info() {
   (( VERBOSE )) && echo_debug "display_vxvm_info()"
   display_header "< VXVM INFORMATION >"
   if [ ! -d "/etc/vx" ]; then
      echo_stderr "Error: It doesn't look like Veritas Volume Manager is installed!"
      return
   fi
   if [ "$( ${WHOAMI} )" = "root" ]; then
      process_command "${VXDISK} list"
      ${VXDISK} list | ${SED} '1d' | ${AWK} '{print $3}' | while read DISK; do
         process_command "${VXDISK} list ${DISK}"
      done
      process_command "${VXDG} list"
      ${VXDG} list | ${SED} '1d' | ${AWK} '{print $3}' | while read DISK; do
         process_command "${VXDG} list ${DISK}"
      done
   fi
   process_command "${VXPRINT}"
}

display_capacity_info() {
   (( VERBOSE )) && echo_debug "display_capacity_info()"
   display_header "< CAPACITY INFORMATION >"

   process_command "${SWAP} -l"
   process_command "${DF} -k"
}

display_files_info() {
   (( VERBOSE )) && echo_debug "display_files_info()"
   display_header "< SYSTEM FILES INFORMATION >"

   HOSTNAME_FILES=`eval ${ECHO} /etc/hostname*`
   FILES="/etc/release /etc/hosts ${HOSTNAME_FILES} /etc/defaultrouter /etc/netmasks /etc/vfstab /etc/system /etc/inet/ntp.
conf"
   FILES="${FILES} /etc/inittab"
   for FILENAME in ${FILES}; do
      if [ -e "${FILENAME}" ]; then
         COMMAND_BUFFER="${CAT} ${FILENAME}"
         display_command_syntax "${COMMAND_BUFFER}"
         (( HTML )) && ${ECHO} "<pre>"
         eval ${COMMAND_BUFFER} | ${SED} -e 's/\&/\&amp;/' -e 's/</\&lt;/g' -e 's/>/\&gt;/g'
         (( HTML )) && ${ECHO} "</pre>"
      else
         echo_stderr "Error: ${FILENAME} does not exist"
      fi
   done
}

display_logs_info() {
   (( VERBOSE )) && echo_debug "display_logs_info()"
   display_header "< LOGFILE INFORMATION >"

   MESSAGES="/var/adm/messages"
   process_command "${EGREP} -i 'error|warn' ${MESSAGES}"
   process_command "${DMESG}"
}

display_user_info() {
   (( VERBOSE )) && echo_debug "display_user_info()"
   display_header "< USER INFORMATION >"

   process_command "${WHO}"
   process_command "${W}"
   process_command "${WHODO}"
   process_command "${LAST} | ${HEAD} -50"
   process_command "${CAT} /etc/passwd"
   process_command "${CAT} /etc/group"
}

display_software_info() {
   (( VERBOSE )) && echo_debug "display_user_info()"
   display_header "< SOFTWARE INFORMATION >"

   process_command "${PKGINFO}"
   process_command "${SHOWREV} -p"
}

display_snapshot() {
   (( VERBOSE )) && echo_debug "display_snapshot()"
   display_header "< SYSTEM ACTIVITY SNAPSHOT >"

   process_command "${PRSTAT} 1 1"
   process_command "${VMSTAT} 1 10"
   process_command "${MPSTAT} 1 10"
   process_command "${IOSTAT} 1 10"
   process_command "${PS} -ef"
}

display_all_info() {
   (( VERBOSE )) && echo_debug "display_all_info()"
   display_system_info
   display_network_info
   display_disk_info
   display_vxvm_info
   display_capacity_info
   display_files_info
   display_logs_info
   display_user_info
   display_snapshot
   display_software_info
}

while getopts ":lg:Hvh" ARG; do
   case "${ARG}" in
      "g")    INFO_GROUPS="${OPTARG}"
              ;;
      "l")    list_info_groups
              ;;
      "v")    VERBOSE=1
              ;;
      "H")    HTML=1
              ;;
      "h"|*)  usage
              ;;
   esac
done

shift $(( ${OPTIND} - 1 ))

if [ "$#" -ne "0" ]; then
   usage
fi

if [ ! -e "${CENTRE_STRING}" ]; then
   echo_stderr "Error: centre_string cannot be found!"
   exit 3
fi

if [ "$( ${UNAME} -s )" != "SunOS" ]; then
   echo_stderr "Error: this script is designed to run on Solaris systems only!"
   # no solaris 10 functionality yet, alas!
   exit 4
fi

if [ -z "${INFO_GROUPS}" ]; then
   INFO_GROUPS="all"
fi

COUNTER=0

${ECHO} "${INFO_GROUPS}" | tr "," "\n" | while read TMP_GROUP; do
   INFO_GROUP[${COUNTER}]=${TMP_GROUP}
   (( COUNTER = COUNTER + 1 ))
done

COUNTER=0
NUM_GROUPS=${#INFO_GROUP[@]}

display_intro

while [[ "${COUNTER}" -lt "${NUM_GROUPS}" ]]; do
   ${ECHO} "${VALID_GROUPS}" | ${GREP} "${INFO_GROUP[${COUNTER}]}" >/dev/null 2>&1
   if [ "$?" -ne "0" ]; then
      echo_stderr "Error: ${INFO_GROUP[${COUNTER}]} is not a valid info group"
      echo_stderr "Valid info groups are: ${VALID_GROUPS}"
      exit 2
   fi
   ACTION_GROUP="${INFO_GROUP[${COUNTER}]}"
   case "${ACTION_GROUP}" in
      "all")      display_all_info      ;;
      "system")   display_system_info   ;;
      "network")  display_network_info  ;;
      "disk")     display_disk_info     ;;
      "vxvm")     display_vxvm_info     ;;
      "capacity") display_capacity_info ;;
      "files")    display_files_info    ;;
      "logs")     display_logs_info     ;;
      "user")     display_user_info     ;;
      "snapshot") display_snapshot      ;;
      "software") display_software      ;;
   esac
   (( COUNTER = COUNTER + 1 ))
done

(( HTML )) && {
  echo "</body>"
  echo "</html>"
}

exit 0