#!/bin/bash
#
# Name:
#	mcinfo 
#
# Description:
#	This script gets the machine information which is useful for support 
#	team to analyze an obstacle.
#
# Authors: 
# 	Tatsuo Ito <tito@miraclelinux.com>
#	Jun YOSHIDA <jun@miraclelinux.com>
#	OGAWA Hirofumi <hogawa@miraclelinux.com>
#	Mika Kamei <mika.kamei@miraclelinux.com>
#	YOSHIFUJI Hideaki <hideaki.yoshifuji@miraclelinux.com>
#
# Copyright:
#	(C) 2001-2016 MIRACLE LINUX CO.
#
# This file is subject to the GNU General Public License.
# It comes with NO WARRANTY.
#

export LANG=C
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
: ${TMPDIR:=/tmp}

CMDNAME=mcinfo

get_block_devices()
{
    if [ -r /proc/partitions ]; then
	DEVS=""
	PARTITION=""
	while read major minor blocks name; do
	    if [ -z "$name" -o "$name" = "name" ]; then
		continue
	    fi

	    case "$(echo $name | sed -e 's/[0-9]\+$//')" in
		# partition
		"$PARTITION")
		    ;;
		# whole device
		*)
		    DEVS="$DEVS /dev/$name"
		    case "$name" in
			*[0-9])
			    PARTITION="${name}p"
			    ;;
			*)
			    PARTITION="$name"
			    ;;
		    esac
		    ;;
	    esac
	done < /proc/partitions
    else
	for base in hd sd i2o/hd; do
	    DEVS="$DEVS /dev/$base[a-z]"
	done
	for base in md; do
	    DEVS="$DEVS /dev/$base[0-9] /dev/$base[0-9][0-9]"
	done
	for base in rd cciss ida; do
	    DEVS="$DEVS /dev/$base/c[0-9]d[0-9] c[0-9]d[0-9][0-9]"
	done
    fi

    echo $DEVS
}

do_cp()
{
    SRC="$1"

    if [ $LOG_STDOUT = 0 ]; then
	if [ -d "$SRC" ]; then
	    echo "=== ${CMDNAME}: cp $SRC ===" >&2
	    cp -x --parent -pRL $SRC $LOG_TEMP
	    find $LOG_TEMP/$SRC -type b -o -type c | xargs rm -f 2> /dev/null
	fi
	if [ -f "$SRC" ]; then
	    echo "=== ${CMDNAME}: cp $SRC ===" >&2
	    cp --parent -pRL $SRC $LOG_TEMP
	fi
    else
	for i in `find "$SRC" -xtype f 2> /dev/null`; do
	    echo "=== ${CMDNAME}: $i ==="
	    cat "$i" 2>&1
	    echo
	done
    fi
}

do_cmd_with_logname()
{
    if [ "$1" = "-e" ] ; then
        CMD_LOG_DIR="$LOG_TEMP/extra"
        shift 1
    else
        CMD_LOG_DIR="$LOG_TEMP/cmdlog"
    fi
    CMD_LOG_NAME="$1"
    CMD="$2"
    shift 2

    if [ "$(type -t $CMD)" = "builtin" -o -x "$(type -p $CMD)" ]; then
	if [ $LOG_STDOUT = 0 ]; then
	    if [ ! -d "$CMD_LOG_DIR" ]; then
		mkdir $CMD_LOG_DIR
	    fi

	    if [ -z "$CMD_LOG_NAME" ]; then
		# decode command to file name
		CMD_LOG_NAME=$(echo $CMD "$@" | tr ' /' '_#')
	    fi

	    echo "=== ${CMDNAME}: $CMD $@ ===" >&2
	    eval `echo "$CMD $@"` >> $CMD_LOG_DIR/$CMD_LOG_NAME 2>&1
	else
	    echo "=== ${CMDNAME}: $CMD $@ ==="
	    eval `echo "$CMD $@"` 2>&1
	    echo
	fi
    fi
}

do_cmd()
{
    do_cmd_with_logname "" "$@"
}

LOG_NAME=cmd.log
LOG_DIR="$CMDNAME-$(hostname -s)-$(date '+%Y%m%d%H%M%S')"
LOG_TEMP=$TMPDIR/$LOG_DIR
LOG_STDOUT=0
HARDWARE=0

# Isn't stdout the terminal?
if [ ! -t 1 ]; then
    LOG_STDOUT=1
fi

NOLOG=0
ABRT=0

if [ -f /etc/mcinfo.conf ]; then
    . /etc/mcinfo.conf
fi

while getopts "c:dnahHt:o:W:" OPT; do
    case "$OPT" in
	n)
	    NOLOG=1
	    ;;
	c)
	    if [ "$OPTARG" = "1" ]; then
		LOG_STDOUT=1
	    else
		LOG_STDOUT=0
	    fi
	    ;;
	d)
	    HARDWARE=1
	    ;;
	a)
	    ABRT=1
	    ;;
	t)
	    ARCHIVE_TYPE="$OPTARG"
	    ARCHIVE_ON="true"
	    ;;
	o)
	    OUTPUTDIR="$OPTARG"
	    OUTPUTDIR_ON="true"
	    ;;
	W)
	    case "$OPTARG" in
	    force-ipmitool|enable-ipmitool)
		ENABLE_IPMITOOL=yes
		;;
	    disable-ipmitool)
		ENABLE_IPMITOOL=no
		;;
	    *)
		echo "Invalid -W option"
		exit
	    esac
	    ;;
	H)
	    echo "Long options (with -W)"
	    echo "    force-ipmitool, enable-ipmitool, disable-ipmitool"
	    exit
	    ;;
	h|*)
	    echo "Usage: $CMDNAME [-n][-a][-c MODE][-d][-t compress_type][-o out_directory][-h][-H][-W long-option]"
	    echo
	    echo "    -h               This help"
	    echo "    -H               Show -W options"
	    echo "    -n               Don't collect /var/log"
	    echo "    -c MODE          MODE=0: Force output to file"
	    echo "                     MODE=1: Force output to stdout"
	    echo "    -d               Only collect hardware informations"
	    echo "    -a               Collect ABRT information when abrt daemon works"
	    echo "    -t compress_type Set tar compression from 'bz2', 'gz', 'xz', or" 
	    echo "                     'none' (default 'bz2')."
	    echo "    -o out_directory Set output directory"
	    echo "    -W options...    Set various options; see -H"
	    echo ""
	    echo "For more information on mcinfo-extension, see mcinfo(1)."
	    echo ""
	    exit
	    ;;
    esac
done
shift $(($OPTIND - 1))

if [ "$(id -u)" != "0" ]; then
    echo "Error: you must run \"$CMDNAME\" as root" >&2
    exit 1
fi

if [ $LOG_STDOUT = 0 ]; then
    if ! mkdir $LOG_TEMP; then
	echo "Error: couldn't create temporary directory" >&2
	exit 1
    fi
    trap "rm -rf $LOG_TEMP" EXIT
fi

if [ $HARDWARE -eq 0 ]; then
# commands
do_cmd date
do_cmd_with_logname "rpm_-qa" rpm -qa --qf \"%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\\n\" \| sort
do_cmd uname -a
do_cmd sysctl -a

# systemd
do_cmd systemctl get-default
do_cmd systemctl -at service --no-pager
do_cmd systemctl list-unit-files
do_cmd systemctl list-units --all
do_cmd systemctl list-units --failed
do_cmd systemctl show --all

do_cmd df -aT
do_cmd df -aiT
for i in $(get_block_devices); do
    do_cmd fdisk -l "$i";
    do_cmd udevadm info --query=all --name="$i";
done
do_cmd parted -l -s
do_cmd blkid
do_cmd lsblk
do_cmd mount -l
do_cmd vgdisplay -vvv
do_cmd raw -qa
do_cmd uptime

do_cmd w
do_cmd ulimit -Ha
do_cmd ulimit -Sa
do_cmd ipcs -l
do_cmd ipcs -a
do_cmd ipcs -u
do_cmd_with_logname "ps_-eo" ps -eo user,stat,pid,ppid,pgid,pri,ni,tname,%cpu,%mem,vsz,rss,wchan,stime,bsdtime,cmd 
do_cmd ps auxwwwf
do_cmd sar -A
do_cmd lsof -n

do_cmd hostnamectl 
do_cmd ip n
do_cmd ip a
do_cmd ip link
do_cmd ip -s link
do_cmd ip route
do_cmd ip maddr
do_cmd ss
do_cmd rpcinfo -p
do_cmd exportfs -v
do_cmd firewall-cmd --list-all-zones
do_cmd firewall-cmd --list-all-zones --permanent
if [ -r /proc/modules ]; then
    for n in filter mangle nat raw; do
	if grep -q "iptable_$n" /proc/modules; then
	    do_cmd iptables -t "$n" -nvL
	fi
    done
    for n in filter mangle raw; do
	if grep -q "ip6table_$n" /proc/modules; then
	    do_cmd ip6tables -t "$n" -nvL
	fi
    done
fi
if [ -r /proc/net/dev ]; then
    while read -r line; do
	dev="${line%%:*}"
	if [ "$dev" != "$line" ]; then
	    do_cmd ethtool "$dev"
	    do_cmd ethtool -k "$dev"
	    do_cmd ethtool -S "$dev"
	fi
    done < /proc/net/dev
fi

do_cmd netstat -s
do_cmd ss -aneop

do_cmd lsmod
do_cmd lspci -vvvxxx
do_cmd lspci -n
do_cmd dmesg -s 1000000
do_cmd_with_logname "ls_#dev#disk#by-uuid" ls -l /dev/disk/by-uuid
do_cmd_with_logname "ls_#dev#disk#by-path" ls -l /dev/disk/by-path
do_cmd_with_logname "ls_#sys#class#net" ls -l /sys/class/net
do_cmd_with_logname "ls_#var#crash" ls -l /var/crash


if [ x"$ENABLE_IPMITOOL" != x"no" ]; then
	# IPMI information
	IPMIDEV=`ls -d /dev/ipmi* 2> /dev/null`
	if [ -f /usr/bin/ipmitool ] && [ "$IPMIDEV" != "" ]; then
	    do_cmd ipmitool fru list
	    do_cmd ipmitool sdr list
	    do_cmd ipmitool sel list
	fi
fi

# /var/crash
while read -d $'\0' file; do
        do_cp ${file}/vmcore-dmesg.txt
done < <((find /var/crash -mindepth 1 -maxdepth 1 -print0) 2>/dev/null)

# /boot/grub
do_cp /boot/grub2/default
do_cp /boot/grub2/device.map
do_cp /boot/grub2/grub.cfg

# EFI
do_cp /boot/efi/EFI/redhat/grub.conf

# /proc
do_cp /proc/buddyinfo
do_cp /proc/cgroups
do_cp /proc/cmdline
do_cp /proc/crypto
do_cp /proc/diskstats
do_cp /proc/iomem
do_cp /proc/mdstat
do_cp /proc/modules
do_cp /proc/mounts
do_cp /proc/mtrr
do_cp /proc/net/bonding
do_cp /proc/pci
do_cp /proc/schedstat
do_cp /proc/scsi/scsi
do_cp /proc/slabinfo
do_cp /proc/swaps
do_cp /proc/vmstat
do_cp /proc/zoneinfo

do_cp /usr/lib/sysctl.d

# /etc
for f in /etc/*-release /etc/cron*; do
    do_cp "$f"
done
do_cp /etc/X11/xorg.conf
do_cp /etc/depmod.d
do_cp /etc/dracut.conf
do_cp /etc/exports
do_cp /etc/fstab
do_cp /etc/hosts
do_cp /etc/inittab
do_cp /etc/kdump.conf
do_cp /etc/ld.so.conf
do_cp /etc/ld.so.conf.d
do_cp /etc/mdadm.conf
do_cp /etc/modprobe.conf
do_cp /etc/modprobe.d
do_cp /etc/modules.conf
do_cp /etc/raidtab
do_cp /etc/security/limits.conf
do_cp /etc/sysconfig/i18n
do_cp /etc/sysconfig/ip6tables
do_cp /etc/sysconfig/ip6tables-config
do_cp /etc/sysconfig/iptables
do_cp /etc/sysconfig/iptables-config
do_cp /etc/sysconfig/network
do_cp /etc/sysconfig/network-scripts
do_cp /etc/sysconfig/selinux
do_cp /etc/sysctl.conf
do_cp /etc/systemd
do_cp /etc/yaboot.conf
do_cp /etc/yum.conf
do_cp /etc/yum.repos.d
# /var/spool/cron
do_cp /var/spool/cron

# ABRT
if [ $ABRT = 1 ] ; then
  do_cp /var/spool/abrt-upload
  do_cmd abrt-cli list
fi

# axtsn-client-tools
do_cp /var/lib/axtu
do_cp /var/log/yum.log
do_cp /var/log/up2date
fi

#HARDWARE
do_cp /proc/bus
do_cp /proc/chandev
do_cp /proc/cpuinfo
do_cp /proc/dasd
do_cp /proc/dma
do_cp /proc/devices
do_cp /proc/driver/rtc
do_cp /proc/ide
do_cp /proc/interrupts
do_cp /proc/ioports
do_cp /proc/meminfo
do_cp /proc/partitions
do_cp /proc/scsi
do_cp /proc/net/netstat
do_cp /proc/net/netlink
do_cp /proc/net/snmp
do_cp /proc/net/snmp6
do_cp /etc/stinit.def
do_cp /etc/sysconfig/hwconf
do_cmd lspci
do_cmd lspci -nvv
do_cmd lsusb
do_cmd lsusb -t 
do_cmd lsusb -v
do_cmd lshal
do_cmd dmidecode
do_cmd multipath -ll
do_cmd_with_logname "" dmesg \| grep -e 'e820.' -e 'agp.'
tmpreg=""
for hwmodule in `cat /proc/modules | cut -d " " -f 1 | grep "[[:alpha:]]" | sort -u`
do
	if [ -z "$tmpreg" ]; then
		tmpreg=$hwmodule
	else
		[ -n "$hwmodule" ] && tmpreg="$tmpreg|$hwmodule"
	fi
done
do_cmd_with_logname "dmesg_drivers" dmesg \| egrep '$tmpreg'

if [ "$NOLOG" != "1" ]; then
    # /var/log
    do_cp /var/log/Xorg.*.log
    for f in /var/log/cron*; do
	do_cp "$f"
    done
    do_cp /var/log/dmesg
    for f in /var/log/messages*; do
	do_cp "$f"
    done
    do_cp /var/log/sa
    do_cmd journalctl --all --this-boot --no-pager
    do_cmd journalctl --all --this-boot --no-pager -o verbose 
fi

# waagent.log
if [ -e "/etc/waagent.conf" ] ; then
    do_cp /etc/waagent.conf
fi

if [ -e "/var/log/waagent.log" ] ; then
    for f in /var/log/waagent.log*; do
        do_cp "$f"
    done
fi

# mcinfo-extension
SCRIPTS_DIR=/etc/mcinfo.d
SCRIPTS_LIST=$SCRIPTS_DIR/mcinfo-extension
OUTFILES=/var/tmp/mcinfo/outfiles

NUM_LINES=`cat $SCRIPTS_LIST | grep -Evc '^#|^$'`
NUM_SCRIPTS=0
NUM_FILES=0

if [ ! -d "$OUTFILES" ]; then
    mkdir -p $OUTFILES
fi

for file in "$SCRIPTS_DIR"/*
do
    if [ "$file" = $SCRIPTS_LIST ] ; then
        continue
    fi
    if [ -x "$file" ] ; then
        NUM_SCRIPTS=`expr "$NUM_SCRIPTS" + 1`
    else
        if cat $file | grep -E '#!/bin/.*sh' > /dev/null ; then
	    chmod +x $file
    	    NUM_SCRIPTS=`expr "$NUM_SCRIPTS" + 1`
        fi
    fi
done

if [ ! "$NUM_LINES" -eq 0 ] && [ ! "$NUM_SCRIPTS" -eq 0 ] ; then
    while read line
    do
        if echo $line | grep -E '^#|^$' > /dev/null
        then
            continue
        fi

        scriptname=`echo $line | sed -e 's/ \(.*$\)//'`

        if [ ! -e "$SCRIPTS_DIR"/"$scriptname" ] ; then
            echo "$SCRIPTS_DIR/$scriptname does not exist!"
            continue
        fi
        if [ -x "$SCRIPTS_DIR"/"$scriptname" ] ; then
            do_cmd_with_logname -e "$scriptname" $SCRIPTS_DIR/$line || continue
        fi
    done < $SCRIPTS_LIST

    NUM_FILES=`find $OUTFILES -type f | wc -l`
    if [ $NUM_FILES -ge 1 ] ; then
        if [ $LOG_STDOUT = 0 ]; then
            echo "=== ${CMDNAME}: cp $OUTFILES ===" >&2
            cp -x -pRL $OUTFILES $LOG_TEMP/extra
        else
            for i in `find "$OUTFILES" -xtype f 2> /dev/null`; do
                echo "=== ${CMDNAME}: $i ==="
                cat "$i" 2>&1
                echo
            done
        fi
	rm -rf $OUTFILES/*
    fi
    find "$LOG_TEMP/extra" -type f -empty | xargs rm -rf 2> /dev/null
fi

# end of mcinfo-extension

if [ $LOG_STDOUT = 0 ]; then
    # make the log archive
    SUFFIX="tar.bz2"
    ARCHIVER="bzip2"
    if [ "$ARCHIVE_TYPE" = "bz2" ]; then
	SUFFIX="tar.bz2"
	ARCHIVER="bzip2"
    elif [ "$ARCHIVE_TYPE" = "gz" ]; then
	SUFFIX="tar.gz"
	ARCHIVER="gzip"
    elif [ "$ARCHIVE_TYPE" = "xz" ]; then
        SUFFIX="tar.xz"
        ARCHIVER="xz"
    elif [ "$ARCHIVE_TYPE" = "none" ]; then
        SUFFIX="tar"
        ARCHIVER=""
    fi
    echo >&2

    # check ARCHIVER
    if [ -n "$ARCHIVER" ]; then
	which $ARCHIVER 2>&1 >/dev/null
	if [ $? -ne 0 ]; then
	    echo "Fall back to \"none\"." >&2
	    SUFFIX="tar"
	    ARCHIVER=""
	fi
    fi
    if [ "$OUTPUTDIR_ON" = "true" ]; then
        if [ -d "$OUTPUTDIR" ]; then
            echo -n "Making \"${OUTPUTDIR}/$LOG_DIR.$SUFFIX\"...   " >&2
            if [ -z "$ARCHIVER" ]; then
                (cd $TMPDIR && tar cf - $LOG_DIR) > ${OUTPUTDIR}/$LOG_DIR.$SUFFIX
            else
                (cd $TMPDIR && tar cf - $LOG_DIR) | $ARCHIVER -9c > ${OUTPUTDIR}/$LOG_DIR.$SUFFIX
            fi
        else
            echo "=== ${OUTPUTDIR} is not exist ===" >&2
        fi
    else
        echo -n "Making \"$LOG_DIR.$SUFFIX\"...   " >&2
        if [ -z "$ARCHIVER" ]; then
            (cd $TMPDIR && tar cf - $LOG_DIR) > $LOG_DIR.$SUFFIX
        else
            (cd $TMPDIR && tar cf - $LOG_DIR) | $ARCHIVER -9c > $LOG_DIR.$SUFFIX
        fi
    fi
    echo "Done" >&2
fi
