#!/bin/bash
# Description: Displays basic system information
# Modified:    2018 Feb 06

##############################################################################
#  Copyright (C) 2018 SUSE LLC
##############################################################################
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; version 2 of the License.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, see <http://www.gnu.org/licenses/>.
#
#  Authors/Contributors:
#     Jason Record (jason.record@suse.com)
#
##############################################################################

##############################################################################
# Variables
##############################################################################
SVER='1.5.2'
PAD=25
QUIET=0
FORMAT_OUT="%-${PAD}s %s\n"

if [[ -s /etc/hostinforc ]]
then
	. /etc/hostinforc
else
	echo "Error: Missing /etc/hostinforc"
	exit 2
fi

##############################################################################
# Functions
##############################################################################
showHelp()
{
	echo "hostinfo - Gathers host information"
	echo
	echo "USAGE: hostinfo [OPTIONS]"
	echo "OPTIONS"
	echo " -h This help screen"
	echo " -n Ignore network address output"
	echo " -m Ignore memory output"
	echo " -d Ignore disk output"
	echo " -u Ignore updates output"
	echo " -q Quiet mode"
	echo " -v View the current root-motd"
	echo
}

exit_code() {
	XC=$1
	shift
	MSG="$@"
	[[ -n "$MSG" ]] && echo "$MSG"
	exit $XC
}

showHostname()
{
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" "Hostname:" "$(hostname)" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" "Hostname:" "$(hostname)" | tee -a $FILE_ROOT_MOTD
	fi
}

hrLine()
{
	if (( QUIET ))
	then
		echo '-----------------------------------------------------------' >> $FILE_ROOT_MOTD
	else
		echo '-----------------------------------------------------------' | tee -a $FILE_ROOT_MOTD
	fi
}

emptyLine()
{
	if (( QUIET ))
	then
		echo >> $FILE_ROOT_MOTD
	else
		echo | tee -a $FILE_ROOT_MOTD
	fi
}

showDate()
{
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" "Current As Of:" "$(date '+%c')" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" "Current As Of:" "$(date '+%c')" | tee -a $FILE_ROOT_MOTD
	fi
}

showDistribution()
{
	RELEASE_FILE='/etc/os-release'
	PRETTY_NAME=$(cat ${RELEASE_FILE} | grep PRETTY_NAME | cut -d\= -f2 | tr -d '"')
	DIST=$(sed -e "s/ SP.//g" <<< $PRETTY_NAME)
	SPSTR="0"
	if echo $PRETTY_NAME | grep SP &>/dev/null; then
		SPTMP=$(echo $PRETTY_NAME | awk '{print $NF}')
		SPSTR=${SPTMP##SP}
	fi
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" "Distribution:" "$DIST" >> $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Service Pack:" "$SPSTR" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" "Distribution:" "$DIST" | tee -a $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Service Pack:" "$SPSTR" | tee -a $FILE_ROOT_MOTD
	fi
}

showKernel()
{
	KERNEL_STR=$(uname -r)
	KERNEL_TYPE=$(awk -F- '{print $NF}' <<< $KERNEL_STR)
	KERN_RPM="kernel-${KERNEL_TYPE}"
	KERN_RPM_VERSION="${KERN_RPM}-${KERNEL_STR%%-$KERNEL_TYPE}*"
	KERN_DATE=$(rpm -q --queryformat "%{INSTALLTIME:date}" $KERN_RPM_VERSION 2>/dev/null)
	if [[ -n "$KERN_DATE" ]]; then
		KERN_DATE_STR="$KERN_DATE"
	else
		KERN_DATE_STR="Unknown"
	fi
	TAINT=$(cat /proc/sys/kernel/tainted)
	TAINTED=0
	if (( ${#TAINT} > 1 )); then
		TAINTED=1
	elif (( ${TAINT} > 0 )); then
		TAINTED=1
	fi
	if (( TAINTED )); then
		KERN_TAINT_STR="Tainted: ${TAINT}"
	else
		KERN_TAINT_STR="Not Tainted"
	fi

	if (( QUIET ))
	then
		printf "$FORMAT_OUT" "Architecture:" "$(uname -i)" >> $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" "Kernel Version:" "$KERNEL_STR" >> $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Installed:" "$KERN_DATE_STR" >> $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Status:" "$KERN_TAINT_STR" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" "Architecture:" "$(uname -i)" | tee -a $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" "Kernel Version:" "$KERNEL_STR" | tee -a $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Installed:" "$KERN_DATE_STR" | tee -a $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Status:" "$KERN_TAINT_STR" | tee -a $FILE_ROOT_MOTD
	fi
}

showNetAddr() {
	NET_LIST="$(ip address)
"
	MASTER=''
	IFACE=''
	ADDR4=''
	ADDR6=''
	STR_LABEL=''
	STR_ADDR=''
	RE_START='^[0-9]'
	RE_IPV4='inet '
	RE_IPV6='inet6 '
	echo "$NET_LIST" | while read LINE
	do
#		echo "Pre:    MASTER=$MASTER IFACE=$IFACE #ADDR4=${#ADDR4} #ADDR6=${#ADDR6} #LINE=${#LINE} : $LINE"
		if (( ${#LINE} < 1 )); then
#			echo "Line0:  MASTER=$MASTER IFACE=$IFACE #ADDR4=${#ADDR4} #ADDR6=${#ADDR6} #LINE=${#LINE} : $LINE"
			if (( ${#ADDR4} > 0 )); then
				STR_LABEL='IPv4 Address:'
				STR_ADDR="$IFACE $ADDR4"
			elif (( ${#MASTER} > 0 )); then
				STR_LABEL='Bonded Interface:'
				STR_ADDR="$IFACE (Slave to $MASTER)"
			else
				STR_LABEL='Interface:'
				STR_ADDR="$IFACE (Unconfigured)"
			fi
			if (( QUIET )); then
				printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" >> $FILE_ROOT_MOTD
			else
				printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" | tee -a $FILE_ROOT_MOTD
			fi
			if (( ${#ADDR6} > 0 )); then
				STR_LABEL='IPv6 Address:'
				STR_ADDR="$IFACE $ADDR6"
				if (( QUIET )); then
					printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" >> $FILE_ROOT_MOTD
				else
					printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" | tee -a $FILE_ROOT_MOTD
				fi
			fi
		elif [[ "$LINE" =~ $RE_START ]]; then
			if (( ${#IFACE} > 0 )); then
				if (( ${#ADDR4} > 0 )); then
					STR_LABEL='IPv4 Address:'
					STR_ADDR="$IFACE $ADDR4"
				elif (( ${#MASTER} > 0 )); then
					STR_LABEL='Bonded Interface:'
					STR_ADDR="$IFACE (Slave to $MASTER)"
				else
					STR_LABEL='Interface:'
					STR_ADDR="$IFACE (Unconfigured)"
				fi
				if (( QUIET )); then
					printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" >> $FILE_ROOT_MOTD
				else
					printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" | tee -a $FILE_ROOT_MOTD
				fi
				if (( ${#ADDR6} > 0 )); then
					STR_LABEL='IPv6 Address:'
					STR_ADDR="$IFACE $ADDR6"
					if (( QUIET )); then
						printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" >> $FILE_ROOT_MOTD
					else
						printf "$FORMAT_OUT" "$STR_LABEL" "$STR_ADDR" | tee -a $FILE_ROOT_MOTD
					fi
				fi
				MASTER=''
				ADDR4=''
				ADDR6=''
				IFACE=''
			fi
			LINE_ARRAY=($LINE)
			IFACE=${LINE_ARRAY[1]//:/}
			if [[ "$IFACE" == "lo" ]]; then
				IFACE=''
			else
				MASTER_IDX=$(echo ${LINE_ARRAY[@]/master//} | cut -d/ -f1 | wc -w | tr -d ' ')
				if (( $MASTER_IDX != ${#LINE_ARRAY[@]} )); then
					(( MASTER_IDX++ ))
					MASTER=${LINE_ARRAY[$MASTER_IDX]}
				fi
			fi
		elif [[ "$LINE" =~ $RE_IPV4 ]]; then
			LINE_ARRAY=($LINE)
			ADDR4=${LINE_ARRAY[1]}
		elif [[ "$LINE" =~ $RE_IPV6 ]]; then
			LINE_ARRAY=($LINE)
			ADDR6=${LINE_ARRAY[1]}
		fi
#		echo "Post:   MASTER=$MASTER IFACE=$IFACE #ADDR4=${#ADDR4} #ADDR6=${#ADDR6} #LINE=${#LINE} : $LINE"
	done
}

showUpdates()
{
	LIP_ALL=$(rpm -qa --last | head -1)
	LIP_NAME=$(echo $LIP_ALL | cut -d' ' -f1)
	LIP_DATE=$(echo $LIP_ALL | sed -e "s/${LIP_NAME}[[:space:]]*//g")
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" "Last Updated Package:" "$LIP_DATE" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" "Last Updated Package:" "$LIP_DATE" | tee -a $FILE_ROOT_MOTD
	fi

	REPOS=$(zypper --non-interactive --no-gpg-checks repos 2>/dev/null | grep '^[ ]\{0,1\}[[:digit:]]' | wc -l)
	if (( REPOS > 1 ))
	then
		PATCH_STRING=$(zypper --non-interactive --no-gpg-checks patch-check 2>/dev/null | tail -1 | grep -i patches 2>/dev/null)
		if [[ -n "$PATCH_STRING" ]]
		then
			PATCH_COUNT_NEEDED=$(echo $PATCH_STRING | cut -d' ' -f1)
			PATCH_COUNT_SECURITY=$(echo $PATCH_STRING | cut -d\( -f2 | cut -d' ' -f1)
		else
			PATCH_COUNT_NEEDED='Pending'
			PATCH_COUNT_SECURITY='Pending'
		fi
	else
		PATCH_COUNT_NEEDED='Not Registered'
		PATCH_COUNT_SECURITY='Not Registered'
	fi
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" " -Patches Needed:" "$PATCH_COUNT_NEEDED" >> $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Security:" "$PATCH_COUNT_SECURITY" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" " -Patches Needed:" "$PATCH_COUNT_NEEDED" | tee -a $FILE_ROOT_MOTD
		printf "$FORMAT_OUT" " -Security:" "$PATCH_COUNT_SECURITY" | tee -a $FILE_ROOT_MOTD
	fi

	COUNT_NVR=$(rpm -qa --queryformat "%{VENDOR}|%{NAME}\n" | egrep -iv "^SUSE LLC|^SUSE Linux Enterprise|gpg-pubkey$" | wc -l)
	if (( QUIET ))
	then
		printf "$FORMAT_OUT" " -3rd Party Packages:" "$COUNT_NVR" >> $FILE_ROOT_MOTD
	else
		printf "$FORMAT_OUT" " -3rd Party Packages:" "$COUNT_NVR" | tee -a $FILE_ROOT_MOTD
	fi
}

showMemory()
{
	if [[ -x /usr/bin/free ]]
	then
		FREE=$(free -h | grep "^Mem")
		FREE_ARRAY=($FREE)
		MEM_TOTAL=${FREE_ARRAY[1]}
		MEM_FREE=${FREE_ARRAY[3]}
		MEM_AVAIL=${FREE_ARRAY[-1]}
		FREE=$(free -b | grep "^Mem")
		FREE_ARRAY=($FREE)
		CALC_TOTAL=${FREE_ARRAY[1]}
		CALC_AVAIL=${FREE_ARRAY[-1]}
		MEM_PERCENT=$(printf "%i" $(( CALC_AVAIL * 100 / CALC_TOTAL )))
		if (( QUIET ))
		then
			printf "$FORMAT_OUT" "Total/Free/Avail Memory:" "${MEM_TOTAL}/${MEM_FREE}/${MEM_AVAIL} (${MEM_PERCENT}% Avail)" >> $FILE_ROOT_MOTD
		else
			printf "$FORMAT_OUT" "Total/Free/Avail Memory:" "${MEM_TOTAL}/${MEM_FREE}/${MEM_AVAIL} (${MEM_PERCENT}% Avail)" | tee -a $FILE_ROOT_MOTD
		fi
	else
		MEM_TOTAL=$(cat /proc/meminfo | grep MemTotal: | awk '{printf "%i", $2/1024}')
		MEM_FREE=$(cat /proc/meminfo | grep MemFree: | awk '{printf "%i", $2/1024}')
		if (( QUIET ))
		then
			printf "$FORMAT_OUT" "Total/Free Memory:" "${MEM_TOTAL}/${MEM_FREE} MB" >> $FILE_ROOT_MOTD
		else
			printf "$FORMAT_OUT" "Total/Free Memory:" "${MEM_TOTAL}/${MEM_FREE} MB" | tee -a $FILE_ROOT_MOTD
		fi
	fi
}

showDisks()
{
	DISK_SIZES=$(egrep '[s,h,xv,c][0-9]?d[a-z,0-9]$' /proc/partitions | awk '{printf "%s %u %s\n", "/dev/"$4, $3*1024/1000^3, "GB"}')
	if [[ -z "$DISK_SIZES" ]]; then
		DISK_SIZES=Unknown
	fi
	echo "$DISK_SIZES" | while read DISK_INFO
	do
		THIS_DISK=$(echo $DISK_INFO | awk '{printf "%s %u %s\n", $1, $2, $3}')
		if (( QUIET ))
		then
			printf "$FORMAT_OUT" "Hard Disk:" "$THIS_DISK" >> $FILE_ROOT_MOTD
		else
			printf "$FORMAT_OUT" "Hard Disk:" "$THIS_DISK" | tee -a $FILE_ROOT_MOTD
		fi
	done
}

displayCurrentDate()
{
	if ! (( QUIET ))
	then
		echo
		printf "$FORMAT_OUT" "Current Date:" "$(date '+%c')"
	fi
}

showRootMotd()
{
	if [[ -s $FILE_ROOT_MOTD ]]
	then
		if grep "Hostname:" $FILE_ROOT_MOTD &> /dev/null
		then
			displayCurrentDate
			DATE_NEEDED=0
			cat $FILE_ROOT_MOTD
			exit 0
		fi
	fi
}

##############################################################################
# main
##############################################################################
DATE_NEEDED=1
while getopts :hnmdquv TMPOPT
do
	case $TMPOPT in
	\:)	showHelp
			case $OPTARG in
			*) echo "ERROR: Missing Argument -$OPTARG"
				;;
			esac
			echo; exit 1 ;;
	\?)	showHelp
			case $OPTARG in
			*) echo "ERROR: Invalid Option -$OPTARG"
				;;
			esac
			echo; exit 1 ;;
	n) IGNORE_NET=1 ;;
	m) IGNORE_MEM=1 ;;
	d) IGNORE_DISK=1 ;;
	u) IGNORE_UPDATES=1 ;;
	h) showHelp; exit 0 ;;
	q) QUIET=1 ;;
	v) showRootMotd ;;
	esac
done

(( DATE_NEEDED )) && displayCurrentDate
> $FILE_ROOT_MOTD
hrLine
showHostname
showDate
showDistribution
showKernel
(( IGNORE_UPDATES )) || showUpdates
(( IGNORE_NET )) || showNetAddr
(( IGNORE_MEM )) || showMemory
(( IGNORE_DISK )) || showDisks
hrLine
emptyLine

