#!/bin/bash
#
# cs_sum_base_config
#
# (c) 2011-2017 SUSE Linux GmbH, Germany.
# (c) 2018-2021 SUSE LLC
# Author: L.Pinne.
# GNU General Public License v2. No warranty.
# http://www.gnu.org/licenses/gpl.html
#
# Version: 2021-02-21 SLE12, SLE15
#
# shellcheck disable=SC1090
#

EXE="$0"

CFG="/etc/ClusterTools2/cs_sum_base_config"
test -s $CFG && source $CFG

CFGVAR="
TEMP
CONF_FILES
CONF_CALLS
APPS_FILES
APPS_CALLS
CLONE_FILES
"

test -z "${TEMP}" &&\
	TEMP="/dev/shm/cltl.$RANDOM"

test -z "${CONF_FILES}" &&\
	 CONF_FILES="
/etc/os-release
/etc/zypp/zypp.conf
/etc/zypp/zypper.conf
/etc/zypp/repos.d/*.repo
/etc/products.d/*.prod
/boot/vmlinuz-.*default
/boot/initrd-.*default
/boot/vmlinuz-.*xen
/boot/initrd-.*xen
/proc/cmdline
/proc/sys/kernel/tainted
/etc/auto.{master,misc,net,smb}
/etc/auto.master.d/*
/etc/ld.so.conf
/etc/ld.so.conf.d/*
/etc/hosts
/etc/host.conf
/etc/resolv.conf
/etc/ntp.conf
/etc/adjtime
/etc/passwd
/etc/group
/etc/sudoers
/etc/sudoers.d/*
/etc/services
/etc/ldap.conf
/etc/openldap/ldap.conf
/etc/logevent.conf
/etc/krb5.conf
/etc/drbd.conf
/etc/drbd.d/*
/etc/lvm/lvm.conf
/etc/multipath.conf
/etc/multipath.bind*
/etc/multipath/*
/etc/mdadm.conf*
/etc/*mdadm.*.conf
/clusterconf/*/mdadm.conf
/clusterconf/mdadm.*.conf
/etc/CLUSTER
/etc/init.d/boot.local
/etc/init.d/after.local
/etc/iscsi/iscsid.conf
/etc/iscsi/initiatorname.iscsi
/etc/sysstat/*
/etc/systemd/*.conf
/etc/systemd/system/*.service
/etc/systemd/system/*/*
/etc/security/limits.conf
/etc/sysconfig/kernel
/etc/sysconfig/bootloader
/etc/sysconfig/kdump
/etc/sysconfig/sbd
/etc/sysconfig/ulimit
/etc/sysconfig/uuidd
/etc/sysconfig/security
/etc/sysconfig/language
/etc/sysconfig/clock
/etc/sysconfig/ntp
/etc/sysconfig/lvm
/etc/sysconfig/o2cb
/etc/sysconfig/bravo
/etc/sysconfig/customfw
/etc/sysconfig/saptune
/var/lib/saptune/*
/var/lib/saptune/*/*
/etc/sysconfig/sapconf
/var/lib/sapconf/last_profile
/etc/sysconfig/saprouter
/etc/sysconfig/hana-firewall
/etc/sysconfig/network/config
/etc/sysconfig/network/routes
/etc/default/*
/etc/ocfs2/cluster.conf
/etc/pam.d/login
/etc/opt/bravo/*.conf
/etc/opt/bravo/profiles/two-sets/*/*
/etc/opt/bravo/profiles/three-sets/*/*
/etc/sysctl.d/*.conf
/etc/sysctl.conf
/etc/saptune/*/*
/etc/tuned/active_profile
/etc/modprobe.conf.local
/etc/modprobe.d/*
/etc/modules-load.d/*
/etc/cron.d/*
/etc/logrotate.d/corosync
/etc/corosync/corosync.conf
/etc/corosync/logd.cf
/etc/corosync/authkey
/etc/xen/xend-config.sxp
/etc/xen/vm/*.xml
/etc/hp/*
/etc/hp*.conf
/etc/patrol.d/*.conf
/etc/vmware-tools/tools.conf
/etc/vmware-tools/plugins/*/*
/etc/pam.d/vmtoolsd
"
# TODO: exact grep patterns
test -z "${CONF_CALLS}" &&\
	 CONF_CALLS="
'/usr/sbin/dmidecode -t system | /usr/bin/grep -v \"UUID:\" | /usr/bin/grep -v \"Serial.Number:\"'
'/sbin/lspci'
'/usr/bin/grep \"model.name\" /proc/cpuinfo'
'/usr/bin/grep -e \"MemTotal:\" -e \"SwapTotal:\" -e \"VmallocTotal:\" /proc/meminfo'
'/bin/dmesg | /usr/bin/grep -e governor -e cpupower -e cpuidle'
'/bin/cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor'
'/bin/cat /sys/kernel/mm/transparent_hugepage/enabled'
'/usr/bin/grep -v \"^#\" /etc/sysctl.conf'
'/usr/bin/grep -v \"^#\" /etc/security/limits.conf'
'/usr/bin/grep -v \"^#\" /etc/systemd/system.conf'
'/usr/bin/lsscsi --kname'
'/bin/uname -s -r -v -m -p -i -o'
'/bin/lsmod | awk °{print %1}° | sort'
'/bin/ls -l /boot/vmlinuz | colrm 27 39'
'/bin/ls -l /boot/initrd | colrm 27 39'
'/bin/ls -l /boot/vmlinuz-xen | colrm 27 39'
'/bin/ls -l /boot/initrd-xen | colrm 27 39'
'/usr/bin/xz -dc /boot/initrd | cpio -itv 2>/dev/null | colrm 43 54'
'/bin/fuser -u /dev/watchdog'
'/usr/sbin/cs_make_sbd_devices -d'
'/bin/rpm -qa'
'/bin/rpm -Va'
'/usr/bin/zypper -n lr'
'/usr/bin/zypper -n lu'
'/usr/bin/zypper -n se -t pattern | grep \"^i\"'
'/bin/cat /proc/mounts'
'/usr/bin/find /sys/devices/ -name \"scheduler\" -exec grep -e '\[deadline\]' -e '\[no..\]' {} \;'
'/sbin/multipath -ll'
'/sbin/dmsetup table | sort'
'/usr/bin/grep -v \"^#\" /etc/lvm/lvm.conf'
'/usr/bin/grep -v \"^#\" /etc/multipath.conf'
'/sbin/chkconfig -A'
'/usr/bin/systemctl list-units --no-pager'
'/usr/bin/systemctl list-unit-files --no-pager'
'/usr/bin/systemctl list-sockets --no-pager'
'/usr/bin/systemctl list-timers --no-pager | awk °{print %NF}°'
'/usr/bin/systemd-delta --no-pager'
'/bin/ip route'
'/usr/sbin/iptables -L'
'/bin/ip a s | /usr/bin/grep \"^[123456789]\:\"'
'/usr/bin/grep -v \"IPADDR=\" /etc/sysconfig/network/ifcfg-* | /usr/bin/grep -v \"UNIQUE=\"'
'/usr/bin/cset set -l'
'/usr/bin/numactl -H | /usr/bin/grep -v free; /usr/bin/numactl -s'
'/usr/bin/timedatectl --no-pager status | /usr/bin/tail -4'
'/usr/bin/chronyc sources | awk -F\" \" °{print $1,$2,$3}°'
'/usr/sbin/saptune daemon status'
'/usr/sbin/saptune solution list'
'/usr/sbin/saptune solution verify | /usr/bin/grep -v °^#°'
'/usr/bin/find /opt/'
'/usr/bin/find /usr/'
'/usr/bin/find /etc/'
'/bin/ls -al /etc/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /etc/*/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /home/ | awk °{print %1,%2,%3,%4,%5,%9}°'
"
#
test -z "${APPS_FILES}" &&\
	 APPS_FILES="
/etc/oratab
/etc/oraInst.loc
/etc/sysconfig/oracle
/etc/tnsnames.ora
/opt/oracle/product/*/*/dbs/*.ora
/opt/oracle/product/*/*/network/admin/*.ora
/etc/sysconfig/postgresql
/var/lib/pgsql/data/postgresql.conf
/var/run/cron/tabs/*
/etc/sysconfig/rhn/*
/etc/rhn/rhn.conf
/etc/nocpulse/*
/etc/opt/novell/eDirectory/conf/nds.conf
/etc/logevent.conf
/etc/opt/novell/nici*
/etc/profile.d/ndssource.sh
/etc/pam.d/sapstartsrv
/etc/rc.d/sapinit
/usr/sap/sapservices
/usr/sap/*/SYS/profile/???_*_*
/usr/sap/*/SYS/global/hdb/custom/config/global.ini
/hana/shared/myHooks/SAPHanaSR.py
/etc/opt/sdb
/etc/db2nodes.conf
/etc/sysconfig/saphaws
/etc/sysconfig/spock
/etc/sysconfig/ctdb
/etc/samba/*
"
#
test -z "${APPS_CALLS}" &&\
	 APPS_CALLS="
'/bin/ls -al /usr/spool/sql/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /sapdb/programs/lib/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /sapdb/programs/runtime/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /sapdb/clients/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /var/lib/sdb/dbm/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /sapmnt/[A-Z]??/profile/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /usr/sap/[A-Z]??/SYS/profile/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /usr/sap/*/[0-9][0-9]/work/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /hana/log/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /hana/data/ | awk °{print %1,%2,%3,%4,%5,%9}°'
'/bin/ls -al /hana/shared/ | awk °{print %1,%2,%3,%4,%5,%9}°'
"
# TODO: samba
# TODO: ndstat and other edir checking
# TODO: generic script to strip "#" from conf files 
# TODO: generic script for directory listing 
# TODO: better network listing 
# TODO: calc diff between hwclock and Linux time, fe. based on hwclock --debug --test

# TODO: function to collect relevant files and output
# TODO: find reason for error on repos.d/ (line 136 ?)
# TODO: generic function for sum_calls and sum_files


function help(){
	echo "usage:	$(basename "$EXE")"
	echo "	$(basename "$EXE") [OPTION]"
	echo
	echo " --help		show help."
	echo " --version	show version."
	echo " --writecfg	show some internal variables."
	echo " --files	checksum base files only."
	echo " --calls	checksum base calls only."
	echo " --apps 	checksum apps config files and calls only."
	echo " --might 	checksum files than might not be cloned."
	echo
	test $UID -gt 0 && echo "please call as root."
}


function writecfg(){
	echo -e "# $CFG \n# For SLES11.\n#"
	for c in $CFGVAR; do
		case $c in
		*_CALLS)
			echo "${c}=\""
			# shellcheck disable=SC2086,SC2001
			echo ${!c} | sed s/\'\ \'/\'\\n\'/g
			echo "\""
			echo "#"
		;;
		*_FILES)
			echo "${c}=\""
			# shellcheck disable=SC2086
			echo ${!c} | tr " " "\n"
			echo "\""
			echo "#"
		;;
		esac
	done
}


function sum_config(){
	S="NA"
	test -r "$f" && S=$(md5sum "$f" | awk '{print $1}')
	echo "$f = $S"
}


function sum_files(){
	nf=1
	f=$CFG
	sum_config
	# TODO: better loop
	for f in ${CONF_FILES}; do
		(( nf++ ))
		S="NA"
		test -r "$f" && S=$(md5sum "$f" | awk '{print $1}')
        	echo "$f = $S"
	done
	echo "INFO: $nf files" >>/dev/stderr
}


function sum_might(){
	nf=1
	CFIL="/etc/ClusterTools2/cs_list_clone_file"
	test -s $CFIL && source $CFIL
	test -z "${CLONE_FILES}" &&\
	CLONE_FILES="
/boot/grub/menu.lst
/etc/HOSTNAME
/etc/udev/rules.d/70-persistent-net.rules
/etc/sysconfig/network/ifcfg-*
/etc/fstab
/etc/iscsi/initiatorname.iscsi
/etc/machine-id
/etc/rhn/rhn.conf
/etc/sysconfig/rhn/systemid
/etc/sshd/ssh_host_*
/etc/SUSEConnect
/etc/zmd/deviceid
/etc/zmd/secret
/etc/zypp/credentials.d/*credentials
/etc/zypp/services.d/*
/root/.ssh/*
/var/cache/SuseRegister/lastzmdconfig.cache
"
	CONF_FILES="${CLONE_FILES}"
	for f in ${CONF_FILES}; do
		(( nf++ ))
		S="NA"
		test -r "$f" && S=$(md5sum "$f" | awk '{print $1}')
        	echo "$f = $S"
	done
	echo "INFO: $nf files" >>/dev/stderr
}


function sum_calls(){
	# TODO: replace errors by "$REPLY = NA" as above
	# TODO: array instead of list, to avoid ugly "'" handling
	mkdir "$TEMP"
	nc=0
	f=$CFG
	sum_config
	# shellcheck disable=SC2162
	echo "${CONF_CALLS}" |\
		 tr "'" "\n" | tr -s "\n" | tr -s "°" "'" | tr "%" "$" |\
	while read; do
		# Modification of REPLY is local, caused by subshell grouping ()
		# so line may be removed next time
		# shellcheck disable=SC2030
		REPLY=$(echo "${REPLY}" | tr -s "'")
		echo -n "'${REPLY}' = "
		eval "${REPLY}" | sort | md5sum - | awk '{print $1}'
		(( nc++ ))
		echo "$nc" >"${TEMP}"/nc
	done | grep -v "'.*d41d8cd98f00b204e9800998ecf8427e"
	nc=$(cat "${TEMP}"/nc); nc=$((nc/2))
	echo "INF0: $nc calls" >>/dev/stderr
	rm -rf "$TEMP"
}


function sum_apps(){
	nf=1
	f=$CFG
	sum_config
	# TODO: better loop
	for f in ${APPS_FILES}; do
		(( nf++ ))
		S="NA"
		test -r "$f" && S=$(md5sum "$f" | awk '{print $1}')
        	echo "$f = $S"
	done
	echo "INFO: $nf files" >>/dev/stderr

	mkdir "$TEMP"
	nc=0
	f=$CFG
	sum_config
	# shellcheck disable=SC2162
	echo "${APPS_CALLS}" |\
		 tr "'" "\n" | tr -s "\n" | tr "°" "'" | tr "%" "$" |\
	while read; do
		# Modification of REPLY is local, caused by subshell grouping ()
		# so line may be removed next time
		# shellcheck disable=SC2031
		REPLY=$(echo "${REPLY}" | tr -s "'")
		echo -n "'${REPLY}' = "
		eval "${REPLY}" | sort | md5sum - | awk '{print $1}'
		(( nc++ ))
		echo "$nc" >"${TEMP}"/nc
	done | grep -v "'.*d41d8cd98f00b204e9800998ecf8427e"
	nc=$(cat "${TEMP}"/nc); nc=$((nc/2))
	rm -rf "$TEMP"
}


# main()
case $1 in
	-v|--version)
		echo -n "$(basename "$EXE") "
		head -11 "$EXE" | grep "^# Version: "
		exit
	;;
	-h|--help)
		help
		exit
	;;
	-w|--writecfg)
		writecfg
		exit
	;;
	-f|--files)
		test $UID -gt 0 && echo "please call as root." && exit
		sum_files
		exit
	;;
	-c|--calls)
		test $UID -gt 0 && echo "please call as root." && exit
		sum_calls
		exit
	;;
	-a|--apps)
		test $UID -gt 0 && echo "please call as root." && exit
		sum_apps
		exit
	;;
	-m|--might)
		test $UID -gt 0 && echo "please call as root." && exit
		sum_might
		exit
	;;
	*)
		test $UID -gt 0 && echo "please call as root." && exit
		sum_files
		sum_calls
		exit		
	;;
esac
#
