#!/bin/sh
# $Copyright$
# Copyright 2015-2017 FUJITSU LIMITED
# All rights reserved
#############################################################################
#
# eecd_mods:	ServerView Agent Linux eecd modules.
#               The modules will be first compiled if necessary.
#
# chkconfig: 2345 20 20
# processname: eecd_mods_src
# description: Inserts and removes the eecd modules
#
### BEGIN INIT INFO
# Provides: eecd_mods
# Required-Start: $local_fs
# Required-Stop:
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Description: Inserts and removes the eecd modules
### END INIT INFO
#
#
# Exit status codes (see LSB 3 spec, ch. 20) are :
# 0     OK
# 1     generic or unspecified error
# 2     invalid or excess argument(s)
# 3     unimplemented feature (e.g. "reload")
# 4     user had insufficient privileges
# 5     program is not installed
# 6     program is not configured
# 7     program is not running
# 8+    reserved (see LSB Core Spec 3.1, ch. 20)

# Set up a decent path.
PATH="/sbin:/usr/sbin:/bin:/usr/bin"
export PATH

# Use LSB function library for convenience.

[ -f /lib/lsb/init-functions ] && . /lib/lsb/init-functions

# Source ServerView configuration file and function library

. /etc/srvmagt/config
. /etc/srvmagt/functions
exportConfVars  

export INTF_NUM=0 # number for IPMI device node

# Do nothing in a VM or ESX 4 where the native IPMI module is already loaded.
machType=$(isVM) && exit 0
vmware -v 2>/dev/null | fgrep "ESX 4" >/dev/null && exit 0  # SV_NICKNAME not yet available


module_loaded()
# module_loaded - check the status of ipmi module 
# $1    ipmi module 
# Returns 0 or 1 if module IS or IS NOT loaded
{
	if /sbin/lsmod | grep $1 >/dev/null 2>&1 ; then
		return 0
	elif [ -d "/sys/module/$1" ]; then
		return 0
	elif [ "$1" == "ipmi_msghandler" ]; then
		if [ -d "/sys/module/ipmi_si" ]; then
			return 0
		fi
	fi
	return 1
}

[ "$1" = stop ] &&  {
	(
		flock -n  500
		if [ $? -eq 1 ]; then
			mylog_failure_msg "Service locked. Try $0 $1 later on"
			exit 1
		fi

		# Unload all ServerView modules, but DO NOT unload native IPMI unless on XenServer

		if isXenServer; then
			/sbin/modprobe -q -r ipmi_si > /dev/null 2>&1
			/sbin/modprobe -q -r ipmi_devintf > /dev/null 2>&1
			/sbin/modprobe -q -r ipmi_msghandler > /dev/null 2>&1
			/sbin/modprobe -q -r ipmi__watchdog > /dev/null 2>&1

			if [ ! -x /sbin/udevd ]; then
				rm -f /dev/ipmi${INTF_NUM} 2> /dev/null
			fi

		fi

		error=0
		module=smbus
		lsmod | grep "$module " > /dev/null 2>&1
		if [ $? -ne 0 ]; then
			mylog_success_msg "Stopping ServerView modules: $module not loaded"
		else
			# Since the module is loaded, failure to unload indicates it is in use.
			rmmod $module 2>/dev/null >/dev/null
			if [ $? -eq 0 ]; then
				mylog_success_msg "Stopping ServerView modules: $module"
				rm -f /dev/pci/$module
			else
				mylog_failure_msg "Stopping ServerView modules: $module still in use"
				error=1
			fi
		fi

		[ $error -eq 0 ] && [ -d /dev/pci ] && rmdir /dev/pci

		# If necessary, reestablish EDAC kernel modules
		[ -d "/etc/modprobe.d/" ] && {
			edac_enable
			rc=$?
			case $rc in
			0)	mylog_success_msg "Stopping ServerView modules: Reenable EDAC";;
			1)	mylog_failure_msg "Stopping ServerView modules: Reenable EDAC";;
			esac
		}

		flock -u 500
		exit $error
	) 500>/var/log/srvmagt/lock.srvmagt-etc

	SubshellStatus=$?
	exit $SubshellStatus
}

# perform SetSvEnv only if not yet done
[ -z "$SV_NICKNAME" ] && SetSvEnv

# SV_MODULES is the complete set of SV kernel modules to build/load,
# a subset from {ipmi, smbus}.
# The SV IPMI module is in the set, if the native IPMI module is not configured.

SV_MODULES=""
isPRIMEQUEST || SV_MODULES="smbus"

THIS_RELEASE=$(uname -r)	# e.g. "2.6.5-7.97-default"
MOD_SUFFIX="o"
[[ ${THIS_RELEASE%%-*} > "2.6" ]] && MOD_SUFFIX="ko"

umask 0066

logger -t $MYNAME "$*: $(uname -a)"
mode="$1"

case "$mode" in
start|trace)
	(
		flock -n  500
		if [ $? -eq 1 ]; then
			mylog_failure_msg "Service locked. Try $0 $mode later on"
			exit 1
		fi

		# Remove /etc/srvmagt/srvmagtCronOn if it exists to avoid that eecd is started twice after system crash
		# SA 233464492
		[ -f /etc/srvmagt/srvmagtCronOn ] &&
			rm /etc/srvmagt/srvmagtCronOn

		# Changes to kernel modules might crash a running eecd

		[ -x /usr/sbin/eecd ] && pid=$(mypidof "/usr/sbin/eecd") && {
			mylog_failure_msg "Starting ServerView modules: stop service eecd first!"
			flock -u 500
			exit 1
		}

		# Remove the EDAC kernel modules if it exists
		[ -d "/etc/modprobe.d/" ] && { 
			edac_disable
			rc=$?
			case $rc in
			0)	mylog_success_msg "Starting ServerView modules: disable EDAC";;
			1)	mylog_failure_msg "Starting ServerView modules: disable EDAC";;
			esac
		}

		# 1. Load the native IPMI module
		# The native IPMI module might or might not have an init script.

		logger -t $MYNAME "Starting native IPMI modules..."

		if [ $SV_NICKNAME == "SLES12" ]; then
			cat >/etc/modprobe.d/ipmi_devintf.conf <<EOF
alias acpi*:IPI0001:* ipmi_devintf 
alias acpi*:IPI0001:* ipmi_si 
# alias acpi:IPI000*:* ipmi_msghandler
EOF
			systemctl start ipmi.service
			rc=$?
			case $rc in
			0)	logger -t $MYNAME "Native IPMI modules are loaded.";;
			1)	logger -t $MYNAME "Starting ServerView modules: native IPMI modules were not loaded (rc=$rc).";;
			esac

		else

			if [ -f  /usr/lib/systemd/system/ipmi.service ]; then
				systemctl start ipmi.service
				rc=$?
				case $rc in
				0)	logger -t $MYNAME "Native IPMI modules are loaded.";;
				1)	logger -t $MYNAME "Starting ServerView modules: native IPMI modules were not loaded (rc=$rc).";;
				esac

			elif [ -x "/etc/init.d/ipmi" ]; then
				# OpenIPMI init script exists
				/etc/init.d/ipmi status >/dev/null 2>&1 || /etc/init.d/ipmi start >/dev/null 2>&1
				rc=$?		# last failure status MUST be from "ipmi start"
				if /etc/init.d/ipmi status >/dev/null 2>&1; then
					logger -t $MYNAME "Native IPMI modules are loaded."
				else
					logger -t $MYNAME "Starting ServerView modules: native IPMI modules were not loaded (rc=$rc)."
				fi
			else
				# No OpenIPMI init script, the IPMI modules must be loaded "manually".

				/sbin/modprobe ipmi_msghandler > /dev/null 2>&1

				if ( ! module_loaded ipmi_msghandler ) ; then
					logger -t $MYNAME "Module 'ipmi_msghandler' cannot be loaded. All IPMI driver modules unloaded."
					# flock -u 500
					# exit 1  # Log only, but don't abort anymore on non-IPMI systems.
				else
					/sbin/modprobe ipmi_devintf > /dev/null 2>&1

					if ( ! module_loaded ipmi_devintf ) ; then
						logger -t $MYNAME "Module 'ipmi_devintf' cannot be loaded. All IPMI driver modules unloaded."
						/sbin/modprobe -r ipmi_msghandler > /dev/null 2>&1
						# flock -u 500
						# exit 1  # Log only, but don't abort anymore on non-IPMI systems.
					else
						/sbin/modprobe ipmi_si > /dev/null 2>&1

						if ( ! module_loaded ipmi_devintf ) ; then
							logger -t $MYNAME "Module 'ipmi_si' cannot be loaded. All IPMI driver modules unloaded."
							/sbin/modprobe -r ipmi_devintf > /dev/null 2>&1
							/sbin/modprobe -r ipmi_msghandler > /dev/null 2>&1
							# flock -u 500
							# exit 1  # Log only, but don't abort anymore on non-IPMI systems.
						else
							# Now ipmi modules are loaded
							if [ ! -x /sbin/udevd ]; then
								DEVMAJOR=`cat /proc/devices | awk '/ipmidev/{print $1}'`
								rm -f /dev/ipmi${INTF_NUM}
								/bin/mknod -m 0600 /dev/ipmi${INTF_NUM} c ${DEVMAJOR} 0 
							fi

							# udev can take several seconds to create /dev/ipmi0,
							# but it happens asynchronously, so delay here
								locdelay=20
							while [ ! -e /dev/ipmi${INTF_NUM} -a ${locdelay} -gt 0 ]; do
								locdelay=$((locdelay - 1))
								sleep 1
							done

							if [ ! -e /dev/ipmi${INTF_NUM} ]; then
								logger -t $MYNAME "Node '/dev/ipmi0' has not been created. All IPMI driver modules unloaded."
								/sbin/modprobe -r ipmi_si > /dev/null 2>&1
								/sbin/modprobe -r ipmi_devintf > /dev/null 2>&1
								/sbin/modprobe -r ipmi_msghandler > /dev/null 2>&1
								# flock -u 500
								# exit 1 Log only, but don't abort anymore on non-IPMI systems.
							else
								# Start the IPMI Watchdog.
								/sbin/modprobe ipmi__watchdog > /dev/null 2>&1
								if /sbin/lsmod | grep ipmi__watchdog >/dev/null 2>&1 ; then
									logger -t $MYNAME "Module 'ipmi_watchdog' cannot be loaded."
								fi
							fi
						fi
					fi
				fi
			fi
		fi

		[ "${SV_NICKNAME:0:2}" = "XS" -o "${SV_NICKNAME:0:1}" = "O" -o "${SV_NICKNAME:0:3}" = "TLX" ] && {
			mylog_success_msg "Starting ServerView modules: Note that $SV_NICKNAME Server does not offer smbus."
			flock -u 500
			exit 0
		}

		# 2. Validate SV modules and recompile if necessary unless PLDP or DUP are present.
		# Note: The release of the RUNNING kernel is within the searched folder name!

		# OL!!!
		[ "${SV_NICKNAME:0:5}" = "SLES1" -o "${SV_NICKNAME:0:4}" = "RHEL" ]  && {
			# In (valid) presence of PLDP or DUP required modules should exist

			errors=0
			for module in $SV_MODULES; do
				flags=
				[ "$mode" = trace ] && flags="${module}Debug=3"

				logger -t $MYNAME "loading (modprobe) module $module $flags"
				/sbin/modprobe -q $module $flags 2>/dev/null
				insrc=$?

				[ $insrc -eq 0 ] && {
					# Recreate the module's special file

					rm -f /dev/pci/$module
					major=$(grep $module /proc/devices) && {
						major=${major%% *}
						[ -e /dev/pci ] || {
							mkdir /dev/pci
							chmod 755 /dev/pci
							chown root /dev/pci
							chgrp root /dev/pci
						}
						mknod -m 644 /dev/pci/$module c $major 0 2>&1 | logger -t $MYNAME
					}

					[ -c /dev/pci/$module ] && {
						logger -t $MYNAME "created $(ls -l /dev/pci/$module)"
						mylog_success_msg "Starting ServerView modules: $module $flags"
						continue
					}
				}

				logger -t $MYNAME "Starting ServerView modules: no KMP for $module. Own $module is used"
				let errors++

			done
			[ $errors -eq 0 ] && {
				flock -u 500
				exit 0
			}

		}

		# Compile any missing and necessary SV modules.
		# PLDP and DUP module DON'T exist here 

		compileModules=0
		for module in $SV_MODULES; do
			path=/lib/modules/$THIS_RELEASE/srvmagt/$module.$MOD_SUFFIX

			[ -f $path ] && {
				logger -t $MYNAME "Starting ServerView modules: found $path"
				continue;
			}
			logger -t $MYNAME "Starting ServerView modules: make $path"
			let compileModules++
		done

		[ $compileModules -gt 0 ] && {
			/etc/srvmagt/StartupScripts/eecd_mods makemods || {
				mylog_failure_msg "Starting ServerView modules: cannot make modules"
				flock -u 500
				exit 1
			}
		}

		# 3. (Re)load each ServerView module in turn

		errors=0
		for module in $SV_MODULES; do
			res=$(lsmod | grep "$module ") && {
				mylog_success_msg "Starting ServerView modules: $module already loaded"
				continue
			}

			path=/lib/modules/$THIS_RELEASE/srvmagt/$module.$MOD_SUFFIX
			[ -f $path ] && {
				flags=
				[ "$mode" = trace ] && flags="${module}Debug=3"

				# create temporary file with randomized name for logging
				Eecd_modsLog=$(mktemp /tmp/eecd_mods_XXXXXXXX)

				logger -t $MYNAME "loading (insmod) module $module $flags"
				insmod $path $flags >$Eecd_modsLog 2>&1
				insrc=$?
				logger -t $MYNAME -f $Eecd_modsLog
				rm -f $Eecd_modsLog

				[ $insrc -eq 0 ] && {
					# Recreate the module's special file

					rm -f /dev/pci/$module
					major=$(grep $module /proc/devices) && {
						major=${major%% *}
						[ -e /dev/pci ] || {
							mkdir /dev/pci
							chmod 755 /dev/pci
							chown root /dev/pci
							chgrp root /dev/pci
						}
						mknod -m 644 /dev/pci/$module c $major 0 2>&1 | logger -t $MYNAME
					}

					[ -c /dev/pci/$module ] && {
						logger -t $MYNAME "created $(ls -l /dev/pci/$module)"
						mylog_success_msg "Starting ServerView modules: $module $flags"
						continue
					}
				}

				# The module will not load. Missing HW is not an error, other causes are.
				# Since distinction is impossible, just log this event to /var/log/messages.

				logger -t $MYNAME "Starting ServerView modules: cannot load $module (missing HW?)"
				continue
			}

			mylog_failure_msg "Starting ServerView modules: $path does not exist"
			let errors++
		done

		[ $errors -eq 0 ] && {
			flock -u 500
			exit 0
		}

		flock -u 500
		exit 1
	) 500>/var/log/srvmagt/lock.srvmagt-etc

	SubshellStatus=$?
	exit $SubshellStatus ;;
	
force-reload)
	# Reload configuration, if the service supports this,
	# otherwise start the service if it is not running

	$0 start
	exit $? ;;

restart)
	$0 stop  $*
	$0 start $*
	exit $? ;;

status)
	# Status codes in this case are:
	# 0     all agents are running [OK]
	# 1     service is dead /var/run/<pid file> exists
	# 2     service is dead and /var/lock/<lock file> ecists
	# 3     one or more agents are not running
	# 4     service status is unknown
	# 5+    reserved (see LSB Core Spec 3.1, ch. 20)

	echo "ServerView modules packages:"
	rpm -q \
		--queryformat '\tinstalled %{INSTALLTIME:date} %{NAME}-%{VERSION}-%{RELEASE}\n' \
		srvmagt-mods_src

	pkgs=$(rpm -qa | egrep "primergy-ipmi|primergy-smbus|kmod-ipmi|kmod-smbus")
	for pkg in $pkgs; do
		rpm -q \
			--queryformat '\tinstalled %{INSTALLTIME:date} %{NAME}-%{VERSION}-%{RELEASE}\n' \
		$pkg
	done

	# Show SV modules status including native IPMI module

	echo ""
	lsmod | head -1
	if [ ${SV_NICKNAME:0:2} = "XS" ]; then
		res=$(lsmod | grep "ipmi_")
		
		if [ -n "$res" ]; then
			printf "$res"
			exit 0
		fi
		exit 3
	fi

	no_n_ipmi=0
	theLine=$(lsmod | grep "ipmi_")
	if [ $? -eq 0 ]; then
		echo "$theLine"
	else
		echo "Native IPMI module(s) not loaded"
		no_n_ipmi=1
	fi
	
	no_smbus=0
	theLine=$(lsmod | grep "smbus")
	if [ $? -eq 0 ]; then
		echo "$theLine"
	else
		echo "ServerView smbus module not loaded"
		
		# On ESX4, OL and OVM a missing smbus is OK.
		[ ${SV_NICKNAME} = "ESX4" -o ${SV_NICKNAME:0:2} = "OL" -o ${SV_NICKNAME:0:3} = "OVM" ] || no_smbus=1
	fi
	
	[ $no_n_ipmi -eq 0 -a $no_smbus -eq 0 ] || exit 3
	
	exit 0 ;;

makemods)
	# Only in the package's "src" incarnation
	# Compile ServerView modules for the RUNNING kernel
	# Make sure suitable kernel source is installed for module compilation

	[ $MYNAME = "eecd_mods_bin" ] && exit 1

	kdir=$(checkKernelSource $SV_NICKNAME $SV_ARCH)
	case $? in 
	0)
		 ;;
	1)
		mylog_failure_msg "Compiling found no $SV_NICKNAME kernel $THIS_RELEASE source"
		logger -t $MYNAME "$mode found no $SV_NICKNAME kernel $THIS_RELEASE source [${kdir%%:*}]"
		exit 1 ;;
	2)
		mylog_failure_msg "kernel source $SV_PKG_ARCH and processor architecture $SV_ARCH mismatch"		
		exit 1 ;;
	esac

	logger -t $MYNAME "$mode compiles with $SV_NICKNAME kernel $THIS_RELEASE source: ${kdir%%:*}"

	echo "Compiling ServerView modules for $SV_NICKNAME kernel $THIS_RELEASE..."
	logger -t $MYNAME "Compiling ServerView modules for $SV_NICKNAME kernel $THIS_RELEASE..."
	
	# create temporary file with randomized name for logging
	Eecd_modsLog=$(mktemp /tmp/eecd_mods_XXXXXXXX)
	cd /etc/srvmagt/sources;make -s -C /etc/srvmagt/sources all >$Eecd_modsLog 2>&1
	makerc=$?
	logger -t $MYNAME -f $Eecd_modsLog
	rm -f $Eecd_modsLog
	if [ $makerc -eq 0 ]; then
		mylog_success_msg "Compiling ServerView modules"
		logger -t $MYNAME "$mode succeeded"
		exit 0
	else
		mylog_failure_msg "Compiling ServerView modules"
		echo "See /var/log/messages for details!"
		logger -t $MYNAME "$mode failed"
		exit 1
	fi ;;

showlog)
	# Display my log file

	grep $MYNAME /var/log/messages | more
	exit 0 ;;

try-restart|reload|*)
	echo "Usage: $0 {start|stop|trace|status|makemods|showlog}"
	exit 1 ;;
esac

exit 1
# EOF
