#!/bin/sh
#
#	Collect LINUX system info
#
#	Optional parameter:  name
#		If present, <name> will be used to generate the output 
#               directory/file:/tmp/netapp/netapp_linux_name
#		compressed tar file will be called /tmp/netapp_linux_name.tar.gz
#
#	If <name> is not specified, output will be in
#       /tmp/netapp_linux_info.tar.gz and so on.
#
#	$Id: //depot/prod/san_host/main/support/linux_info#16 $
#
# Copyright (C) 2002-2005 Network Appliance, Inc., All Rights Reserved
#

USAGE="linux_info fcp|iscsi|all [-d <directory>] [-f] [ -n <name>]"

HELP1="\nCollects LINUX configuration information.\n"
HELP2="This creates a tar file ready to be sent to\n"
HELP3="Network Appliance	 Customer Support.\n\n"
HELP4="\tfcp\tcollects information for FCP enabled hosts\n"
HELP5="\tiscsi\tcollects information for iSCSI enabled hosts\n"
HELP6="\tall\tcollects information for both FCP and iSCSI enabled hosts\n"
HELP7="\t-d <directory>\tgives the directory to place the files in\n"
HELP8="\t-f force overwriting of output files if they already exist\n"
HELP9="\t\t\t(default is /tmp/netapp)\n\n"
HELPA="\t-n <name>\tgives a name string to be used in the output\n"
HELPB="\t\t\tfile and directory names\n"
HELP="$HELP1$HELP2$HELP3$HELP4$HELP5$HELP6$HELP7$HELP8$HELP9$HELPA$HELPB"


CD=cd
CP="/bin/cp -p"
CAT=/bin/cat
COMPRESS=/usr/bin/gzip
DATE=/bin/date
DF=/bin/df
ECHO="/bin/echo -e"
FDISK=/sbin/fdisk
GREP=/bin/grep
LSMOD=/sbin/lsmod
LSPCI=/sbin/lspci
MKDIR=/bin/mkdir
MOUNT=/bin/mount
MV=/bin/mv
RM=/bin/rm
RPM=/bin/rpm
SANSURFER=/opt/QLogic_Corporation/SANsurferCLI/scli
LPUTIL=/usr/sbin/lpfc/lputil
STRINGS=/usr/bin/strings
SYSCTL=/sbin/sysctl
TAR=/bin/tar
UNAME=/bin/uname
WHOAMI=/usr/bin/whoami
PSCMD=/bin/ps
LSOF_REDHAT=/usr/sbin/lsof
LSOF_SUSE=/usr/bin/lsof
UPTIME=/usr/bin/uptime
LS=/bin/ls
AWK=/bin/awk
DMSETUP=/sbin/dmsetup
MULTIPATH=/sbin/multipath

FSTAB=/etc/fstab
MCONF=/etc/modules.conf
MCONF2=/etc/modprobe.conf
MCONF3=/etc/modprobe.conf.local

SAN_UTIL_DIR=/opt/netapp/santools
SAN_UTIL_PROG=sanlun
SANLUN=$SAN_UTIL_DIR/$SAN_UTIL_PROG

QLREMOTE=/usr/local/bin/qlremote

# save a copy of the command line
CMDLINE="$0 $@"

# set default arguements/options
directory=/tmp/netapp
name="info"
FFLAG=0
FCPFLAG=0
ISCSIFLAG=0

#
# save_sysfs_info
#
# args:
# $1 - sysfs dir to save
# $2 - base output directory to copy info to
#
save_sysfs_info () {
    if [ -d $1 ]; then
        for i in $( ls $1 ); do
            tmp_dir=$2/$i
            $MKDIR -p $tmp_dir
            for j in $( ls $1/$i ); do
                if [ $j = uevent ] || [ $j = device ]; then
                    continue
                fi
                if [ -f $1/$i/$j ] && [ -r $1/$i/$j ]; then
                    $CP $1/$i/$j $tmp_dir 2>&1
                fi
            done
        done
    fi
    return 0
}

#
# cpio_sysfs
#
# args:
# $1 - sysfs dir to save (no trailing slash)
# $2 - base output directory to copy info to (no trailing slash)
# $3 - maximum depth
#
cpio_sysfs () {
     $MKDIR $2
     find $1 -depth -print0 -maxdepth $3 | cpio -0dmaup --no-preserve-owner $2 >& /dev/null
     $MV $2$1/* $2/
     rm -rf $2/sys
     echo "usage of 'cat' command may be necessary in order to view file contents" > $2/README.txt 
     return 0
}

# process the first arguement
# at least one parameter from {fcp|isci|all} is required
case "$1" in
	fcp)	FCPFLAG=1
		shift;;
	iscsi)	ISCSIFLAG=1
		shift;;
	all)	ISCSIFLAG=1
		FCPFLAG=1
		shift;;
	*)	$ECHO $USAGE
                exit 1;;
esac

# process remaining options
while getopts d:n:f opt
do
        case $opt in
        d)      directory=$OPTARG;;
	f)	FFLAG=1;;
        n)      name=$OPTARG;;
        \?)     $ECHO $USAGE
		$ECHO $HELP
                exit 1;;
        esac
done

outdir=$directory/netapp_linux_$name
outfile=$directory/netapp_linux_$name.tar
final_file=$outfile.gz

ME=`$WHOAMI`
if [ "$ME" != "root" ]; then
	$ECHO "You must be root to run this script \(current user: $ME\)"
	exit 1
fi

if [ -f $directory ] ; then
	$ECHO "Argument to -d option, $directory, exists as a file."
	$ECHO "Please select a different directory or delete the file, then re-run this script"
	exit 1
fi
# make sure the directory exists; re-use it if it's already there 
if [ ! -d $directory ] ; then
	$MKDIR -p $directory
fi

if [ $FFLAG -eq 0 ]; then
   if [ -d $outdir -o -f $outdir ]; then
      $ECHO "$outdir already exists; please delete it or specify a different name from \"$name\""
      exit 1
   fi

   if [ -f $outfile ]; then
      $ECHO "$outfile already exists; please delete it or specify a different name from \"$name\""
      exit 1
   fi

   if [ -f $final_file ]; then
      $ECHO "$final_file already exists; please delete it or specify a different name from \"$name\""
      exit 1
   fi
else
   $RM -rf $outdir
   $RM -f $final_file
fi

printf "Gathering RPM information..."
$MKDIR -m 777 $outdir

# Collect _BRAND_SHORT_STRING_ package information
#$RPM -qa | grep $SAN_UTIL_RPM > $outdir\$SAN_UTIL_RPM.rpminfo
$RPM -qa > $outdir/packages
printf "...DONE\n"

# 
#	Get the version info for the kit
#
$SAN_UTIL_DIR/san_version -v > $outdir/san_version 2>&1

#
#	Double check the version in the sanlun binary
#
$SANLUN version > $outdir/sanlun_version 2>&1

printf "Gathering general Linux information..."
#
# 	Get config files from /etc
#
$CP $FSTAB  $outdir/fstab	 2>&1
# 2.4 kernels 
if [ -f $MCONF ]; then
    $CP $MCONF  $outdir/modules.conf 2>&1
fi
# 2.6 kernels 
if [ -f $MCONF2 ]; then
    $CP $MCONF2  $outdir/modprobe.conf 2>&1
fi
if [ -f $MCONF3 ]; then
    $CP $MCONF3  $outdir/modprobe.conf.local 2>&1
fi

#	
#	Get the partition and filesystem information
#
$FDISK -l		> $outdir/fdisk_l	  2>&1
$MOUNT 			> $outdir/mount		  2>&1
$CAT /proc/partitions	> $outdir/proc.partitions 2>&1
$DF -h			> $outdir/df_h		  2>&1

#
#	Get the current scsi mid layer view of the world
#
$CAT /proc/scsi/scsi > $outdir/proc.scsi.scsi 2>&1

#
# Get raw and SCSI disk device info
#
raw -qa > $outdir/raw_qa 2>&1
ls -l /dev/sd* > $outdir/dev_sd 2>&1

#
#	Get the latest kernel messages
#	Scheme is as follows:
#	1. Grab up to 3 files, based on most recent modification times
#	2. Grab up to 1MB of log messages
#
# 	This scheme should work for both RHEL and SLES.  This was
#	changed from a simpler scheme of just copying one file because
#	the logs rotate and there's a reasonable chance the interesting
#	messages are not in the latest messages file.  The main reason
#	_not_ to copy all messages file is because of file size (and
#	SLES gzips the files, so there may be a lot of them).
#
ze=0
mcount=1
for file in `$LS -t /var/log/messages*`
do
        $CP $file $outdir 2>&1
	#
        # break out if we get at least 3 files or 500k of data
	#
        mcount=$(($mcount+1))
        if [ "$mcount" -gt 3 ]
        then
                break
        fi
        msize=$(($msize + `$LS -sk $file | $AWK '{print $1}'`))
        if [ "$msize" -gt 1000 ]
        then
                break
        fi
done

#
#	Collect OS version and uptime
#
$UNAME -a > $outdir/uname_a 2>&1
$CP /etc/issue.net $outdir/issue.net 2>&1
$UPTIME > $outdir/uptime 2>&1
if [ -f /etc/redhat-release ]; then
    $CP /etc/redhat-release $outdir/redhat-release
fi
if [ -f /etc/UnitedLinux-release ]; then
    $CP /etc/UnitedLinux-release $outdir/UnitedLinux-release
fi
if [ -f /etc/SuSE-release ]; then
    $CP /etc/SuSE-release $outdir/SuSE-release
fi

#
#	Get the full hardware configuration of the system
#
$ECHO "lspci basic info\n===================="		>  $outdir/lspci 2>&1
$LSPCI							>> $outdir/lspci 2>&1
$ECHO "\n\nlspci verbose info\n===================="	>> $outdir/lspci 2>&1
$LSPCI -v						>> $outdir/lspci 2>&1

$CAT /proc/cpuinfo > $outdir/proc.cpuinfo 2>&1
$CAT /proc/meminfo > $outdir/proc.meminfo 2>&1

#
# Get current process and open file information
#
$PSCMD -efl > $outdir/ps_efl 2>&1
if [ "`grep -i suse /etc/issue.net`" ]; then 
	$LSOF_SUSE > $outdir/lsof 2>&1
elif [ "`grep -i \"Red Hat\" /etc/issue.net`" ]; then 
	$LSOF_REDHAT > $outdir/lsof 2>&1
else
	$LSOF_REDHAT > $outdir/lsof 2>&1
fi

#
#	Get the kernel boot parameters and modules info
#
$CAT /proc/cmdline > $outdir/proc.cmdline 2>&1
$SYSCTL -a	   > $outdir/sysctl_a	  2>&1
$LSMOD		   > $outdir/lsmod	  2>&1
printf "...DONE\n"


#
# ----- FCP information section -----
#	Get data that pertains to FCP 
#
if [ $FCPFLAG -eq 1 ]; then
   printf "Gathering FCP information..."

   # Check for qlogic in general
   #
   if [ -d /proc/scsi/qla2xxx ]; then
      #
      #		Get info from proc if possible 
      #
      for i in `ls -1 /proc/scsi/qla2xxx | grep -v HbaApiNode`; do
         $CP /proc/scsi/qla2xxx/$i $outdir/qla2xxx.$i 2>&1
      done

      #
      #		Get info from sysfs if possible
      #
      if [ -d /sys/module/qla2xxx ]; then
          cpio_sysfs /sys/module/qla2xxx $outdir/sys_module_qla2xxx 2
      fi

      if [ ! -d /opt/QLogic_Corporation/SANsurferCLI ]; then
	  $ECHO "NOTICE: SANsurfer cli not installed in default location" > $outdir/sansurfer.X 2>&1
      else
	  # retrieve target info
  	  $SANSURFER -t > $outdir/sansurfer_target_info
	  # retrieve host settings
	  $SANSURFER -c all > $outdir/sansurfer_host_settings
      fi

      #
      #		Get info from the qlremote agent:
      #
      if [ ! -f $QLREMOTE ]; then
         $ECHO "NOTICE: qlremote agent not installed in default location" > $outdir/qlremote.X 2>&1
      else
         $QLREMOTE -v > $outdir/qlremote_v
      fi
   else
      $ECHO "NOTICE:qla2xxx driver not loaded" > $outdir/qla2xxx.X 2>&1
   fi

   #
   # Collect Emulex related info
   #   
   if [ -d /proc/scsi/lpfc ]; then
   #                                                           
   #  Get info from proc and sys directories
   #                                                           
   	for i in `ls /proc/scsi/lpfc`; do
            $CP /proc/scsi/lpfc/$i $outdir/lpfc.$i 2>&1
      	    cpio_sysfs /sys/class/scsi_host/host$i $outdir/sys_class_lpfc_host$i 1       
   	done                                                        

   	if [ ! -f $LPUTIL ]; then
   		$ECHO "NOTICE: lputil not installed in default location" > $outdir/lputil.X 2>&1
   	else
		$CAT /proc/devices | $GREP -q "lpfcdfc"
      	        if [ $? -eq 0 ]; then
			#Collect lputil info for the Emulex HBA
            	        $LPUTIL listhbas > $outdir/lputil_listhbas
            	        $LPUTIL shownodes all > $outdir/lputil_shownodes
            	        $LPUTIL fcpmap all > $outdir/lputil_fcpmap 
		else
			$ECHO "NOTICE:lpfcdfc driver not loaded" > $outdir/lpfcdfc.X 2>&1
      	        fi
        fi
   else
   	$ECHO "NOTICE:lpfc driver not loaded" > $outdir/lpfc.X 2>&1
   fi	
   #
   #	Get the info from the sanlun utility:
   #
   if [ -d /proc/scsi/qla2xxx -o -d /proc/scsi/lpfc ];then
      $SANLUN lun show -v all         > $outdir/luns 2>&1
      $SANLUN fcp show adapter -v all > $outdir/adapters 2>&1
      $SAN_UTIL_DIR/$SAN_UTIL_PROG lun show -v all         > $outdir/luns 2>&1
      $SAN_UTIL_DIR/$SAN_UTIL_PROG fcp show adapter -v all > $outdir/adapters 2>&1
   fi

   printf "...DONE\n"
fi

#
# ----- iSCSI information section -----
#	Get data that pertains to iSCSI
#
if [ $ISCSIFLAG -eq 1 ]; then

   # make sure the directory exists; re-use it if it's already there 
   if [ ! -d $outdir/iscsi ] ; then
      $MKDIR -p $outdir/iscsi
   fi
   #
   # Get general TCP/IP info: netstat -an, netstat -rn, ifconfig -a
   #
   printf "Gathering iSCSI networking information..."
   netstat -an > $outdir/iscsi/netstat_an 2>&1
   netstat -rn > $outdir/iscsi/netstat_rn 2>&1
   ifconfig -a > $outdir/iscsi/ifconfig_a 2>&1
   printf "...DONE\n"

   #
   # Get specific iscsi information
   #
   printf "Gathering iSCSI configuration information..."
   if [ -f /var/log/iscsi.log ]; then
       $CP /var/log/iscsi.log $outdir/iscsi 2>&1
   fi
   if [ -d /var/lib/open-iscsi ]; then
       $CP /var/lib/open-iscsi/*.db $outdir/iscsi 2>&1
   fi
   if [ -f /usr/sbin/iscsi-ls ]; then
      /usr/sbin/iscsi-ls -l > $outdir/iscsi/iscsi-ls_l 2>&1
      /usr/sbin/iscsi-ls -c > $outdir/iscsi/iscsi-ls_c 2>&1
      /usr/sbin/iscsi-ls    > $outdir/iscsi/iscsi-ls 2>&1
   elif [ -f /sbin/iscsi-ls ]; then
      /sbin/iscsi-ls -l > $outdir/iscsi/iscsi-ls_l 2>&1
      /sbin/iscsi-ls -c > $outdir/iscsi/iscsi-ls_c 2>&1
      /sbin/iscsi-ls    > $outdir/iscsi/iscsi-ls 2>&1
   elif [ -f /usr/local/sbin/iscsi-ls ]; then
      /usr/local/sbin/iscsi-ls -l > $outdir/iscsi/iscsi-ls_l 2>&1
      /usr/local/sbin/iscsi-ls -c > $outdir/iscsi/iscsi-ls_c 2>&1
      /usr/local/sbin/iscsi-ls    > $outdir/iscsi/iscsi-ls 2>&1
   fi
   $CAT /proc/scsi/iscsi/* > $outdir/iscsi/proc_scsi_iscsi 2>&1
   if [ -f /etc/iscsi.conf ]; then
       $CP /etc/iscsi.conf $outdir/iscsi/iscsi.conf 2>&1
   elif [ -f /etc/iscsid.conf ]; then
       $CP /etc/iscsid.conf $outdir/iscsi/iscsid.conf 2>&1
   fi
   $CP /etc/initiatorname.iscsi $outdir/iscsi/initiatorname.iscsi 2>&1
   if [ -f /etc/fstab.iscsi ]; then
      $CP /etc/fstab.iscsi $outdir/iscsi/fstab.iscsi 2>&1
   fi
   #
   # For 3-4 linux-iscsi versions, grab /dev/iscsi/... symlinks
   #
   if [ -d /dev/iscsi ]; then
      ls -lR /dev/iscsi > $outdir/iscsi/dev_iscsi_ls_lR 2>&1
   elif [ -d /dev/disk/by-id ]; then
      # 
      # For SLES9, get device persistency links
      #
      if [ "`grep -i suse /etc/issue.net`" ]; then 
         ls -l /dev/disk/by-id/iscsi* > $outdir/iscsi/dev_disk_by-id_symlinks 2>&1
      fi
   fi

   #
   # Open-iscsi (sles10, etc)
   #
   save_sysfs_info /sys/class/iscsi_connection \
                   $outdir/iscsi/sys_class_iscsi_connection
   save_sysfs_info /sys/class/iscsi_session \
                   $outdir/iscsi/sys_class_iscsi_session
   save_sysfs_info /sys/class/iscsi_host \
                   $outdir/iscsi/sys_class_iscsi_host
   save_sysfs_info /sys/class/iscsi_transport \
                   $outdir/iscsi/sys_class_iscsi_transport

   # 
   # For RHEL4 and other 2.6 versions that use sysfs, grab sysfs stuff
   #
   if [ -d /sys/class/scsi_host ]; then
       for i in $( ls /sys/class/scsi_host ); do
           if [ "`grep -i iscsi /sys/class/scsi_host/$i/proc_name`" ]; then 
               tmp_dir=$outdir/iscsi/sys_class_scsi_host/$i
               $MKDIR -p $tmp_dir
               for j in $( ls /sys/class/scsi_host/$i ); do
                   #
                   # Skip open-iscsi read-only attributes (not sure why
                   # bash '-r' test passes while cp fails)
                   #
                   if [ $j = uevent ] || [ $j = scan ] || [ $j = device ]; then
                       continue
                   fi
                   #
                   # Skip RHEL4 (linux-iscsi) read-only attributes (not
                   # sure why bash '-r' test passes while cp fails)
                   #
                   if [ $j = shutdown ] || [ $j = drop_session ]; then
                       continue
                   fi
                   #
                   # Skip SLES9 (linux-iscsi) read-only attributes (not
                   # sure why bash '-r' test passes while cp fails)
                   #
                   if [ $j = log ] || [ $j = failover ]; then
                       continue
                   fi
                   if [ -r /sys/class/scsi_host/$i/$j ]; then
                       $CP /sys/class/scsi_host/$i/$j $tmp_dir 2>&1
                   fi
               done
           fi
       done
   fi

   if [ -f /var/lib/iscsi/bindings ]; then
     $CP /var/lib/iscsi/bindings $outdir/iscsi/bindings 2>&1
   fi
   printf "...DONE\n"

   #
   # sanlun
   #
   printf "Gathering iSCSI sanlun information..."
   $SANLUN lun show -v all         > $outdir/iscsi/sanlun_luns 2>&1
   printf "...DONE\n"
fi

#
#	Device mapper multipathing (dm-multipath)
#
# RHEL4 U3
# make sure the directory exists; re-use it if it's already there 
printf "Gathering dm-multipath information..."
if [ ! -d $outdir/dm-multipath ] ; then
   $MKDIR -p $outdir/dm-multipath
fi
if [ -f /etc/multipath.conf ]; then
   $CP /etc/multipath.conf $outdir/dm-multipath/multipath.conf 2>&1
fi
if [ -f /var/lib/multipath/bindings ]; then
   $CP /var/lib/multipath/bindings $outdir/dm-multipath/bindings 2>&1
fi
#
# Unfortunately we can't run "multipath -l" unless we want to risk it hanging if a path
# is down (not unlikely if there's a support case).  Just dump kernel table, which seems
# to be non-blocking in the case of path failure.
#
if [ -f $DMSETUP ]; then
   $DMSETUP table --verbose 99 > $outdir/dm-multipath/dm_setup_table 2>&1
   $DMSETUP status --verbose 99 > $outdir/dm-multipath/dm_status_target_multipath 2>&1
fi
if [ -f $MULTIPATH ]; then
   $MULTIPATH -l -v3 -d > $outdir/dm-multipath/multipath_v3 2>&1
fi
# RHEL4
if [ -d /dev/mpath/ ]; then
   ls -lR /dev/mpath > $outdir/dm-multipath/dev_mpath_ls 2>&1
elif [ -d /dev/disk/by-name ]; then    # SLES9
   ls -lR /dev/disk/by-name > $outdir/dm-multipath/dev_mpath_ls 2>&1
fi
printf "...DONE\n"


printf "Done gathering information\n"
#
#	Save the runtime params for this invocation of linux_info
#
$ECHO "Run on `date`"			>  $outdir/linux_info.runtime
$ECHO "Command line was:\n\n\t$CMDLINE"	>> $outdir/linux_info.runtime

$TAR -cf $outfile -C $directory netapp_linux_$name
$COMPRESS $outfile
#
#	Print out what's where, and exit
#
$ECHO "\n\nLINUX system info is in directory $outdir"
$ECHO "\tCompressed file is $final_file"
$ECHO "\tPlease send this file to Network Appliance	 for analysis"
exit 0
