#!/bin/bash
#
# SVN Info:
#       $Id: instsvcdrv 14 2008-01-16 09:18:10Z bas $
#
###############################################################################
#
#          Dell Inc. PROPRIETARY INFORMATION
# This software is supplied under the terms of a license agreement or
# nondisclosure agreement with Dell Inc. and may not
# be copied or disclosed except in accordance with the terms of that
# agreement.
#
# Copyright (c) 2000-2006 Dell Inc. All Rights Reserved.
#
# Module Name:
#
#   instsvcdrv
#
# Abstract/Purpose:
#
#   Systems Management Device Drivers init script
#
# Environment:
#
#   Linux
#
# Notes:
#
#   dcdbas needs to remain started at runlevel 0 for host control.
#   dell_rbu needs to remain started at runlevel 6 for BIOS Update.
#
# Following two lines used by chkconfig utility:
# chkconfig: 345 96 04
# description: Systems Management Device Drivers
#
### BEGIN INIT INFO
# Provides: instsvcdrv
# Required-Start: $localfs $remotefs $syslog
# Required-Stop: $localfs $remotefs $syslog
# Default-Start: 0 3 4 5 6
# Default-Stop: 1 2
# Short-Description: Systems Management Device Drivers
# Description: Systems Management Device Drivers
### END INIT INFO
#
###############################################################################

# SARA hack
#
# Stupid bash shell does not expand aliases in a shell
#
shopt -s expand_aliases


ISVCDD_PROD_NAME="Systems Management Device Drivers"
ISVCDD_SCRIPT_NAME="instsvcdrv"
ISVCDD_DEFAULT_INSTALL_DIR="/opt/dell/srvadmin/hapi"
ISVCDD_DEFAULT_VARDATA_DIR="/opt/dell/srvadmin/hapi"

# Flag to turn on verbose logging
VERBOSE_LOGGING=false
VERBOSE_TARGET=/dev/stderr

# OS information
OS_DEVICE_DIR="/dev"
OS_INITSCRIPT_DIR="/etc/init.d"
OS_MODULES_DIR="/lib/modules"
OS_VARLOG_DIR="/var/log"
OS_SCRIPT_FUNCTIONS_LSB="/lib/lsb/init-functions"
OS_SCRIPT_FUNCTIONS_RH="/etc/init.d/functions"
OS_SCRIPT_FUNCTIONS_NONE="none"

# Check for supported OS script functions
if [ -f ${OS_SCRIPT_FUNCTIONS_RH} ];
then
	OS_SCRIPT_FUNCTIONS=${OS_SCRIPT_FUNCTIONS_RH}
elif [ -f ${OS_SCRIPT_FUNCTIONS_LSB} ];
then
	OS_SCRIPT_FUNCTIONS=${OS_SCRIPT_FUNCTIONS_LSB}
else
	OS_SCRIPT_FUNCTIONS=${OS_SCRIPT_FUNCTIONS_NONE}
fi

# Include OS script functions if available
if [ ${OS_SCRIPT_FUNCTIONS} != ${OS_SCRIPT_FUNCTIONS_NONE} ];
then
	. ${OS_SCRIPT_FUNCTIONS}
fi

# Make sure standard bin directories are in path
PATH="${PATH}:/sbin:/usr/sbin:/bin:/usr/bin"

# Get running kernel
RUNNING_KERNEL=$(uname -r)

# HAPI config file and variables
HAPICFG_PATHFILENAME="/etc/hapi.cfg"
HAPICFG_PROJECT_NAME_HAPI="hapi"
HAPICFG_HAPI_LOADDRIVERS_KEY="${HAPICFG_PROJECT_NAME_HAPI}.loaddrivers"
HAPICFG_HAPI_LOADDBAS_KEY="${HAPICFG_PROJECT_NAME_HAPI}.loaddbas"
HAPICFG_HAPI_LOADDRBU_KEY="${HAPICFG_PROJECT_NAME_HAPI}.loaddrbu"
HAPICFG_HAPI_FORCEKERMATCH_KEY="${HAPICFG_PROJECT_NAME_HAPI}.forcekernelmatch"
HAPICFG_HAPI_OI_INITFAIL_OK_KEY="${HAPICFG_PROJECT_NAME_HAPI}.allow.user.mode"
HAPICFG_HAPI_OI_LOAD="${HAPICFG_PROJECT_NAME_HAPI}.loadopenipmi"

# Supported values for "loaddrivers" variable
HAPICFG_HAPI_LOADDRIVERS_ACTIVE="active"
HAPICFG_HAPI_LOADDRIVERS_ALL="all"
HAPICFG_HAPI_LOADDRIVERS_BASEONLY="baseonly"
HAPICFG_HAPI_LOADDRIVERS_NONE="none"
HAPICFG_HAPI_LOADDRIVERS_SELECTED="selected"

# omreg config file variables
OMREG_PATHFILENAME="/etc/omreg.cfg"
OMREG_PROJECT_NAME_HAPI="hapi"
OMREG_HAPI_INSTALLPATH_KEY="${OMREG_PROJECT_NAME_HAPI}.installpath"
OMREG_HAPI_VARDATAPATH_KEY="${OMREG_PROJECT_NAME_HAPI}.vardatapath"

# OpenIPMI-specific variables
OPENIPMI_SCRIPT="${OS_INITSCRIPT_DIR}/ipmi"
if [ ! -f "${OPENIPMI_SCRIPT}" ];
then
	OPENIPMI_SCRIPT="${OS_INITSCRIPT_DIR}/dsm_sa_ipmi"
	if [ ! -f "${OPENIPMI_SCRIPT}" ];
	then
		OPENIPMI_SCRIPT=
	fi
fi
OPENIPMI_DSM_SCRIPT="${OS_INITSCRIPT_DIR}/dsm_sa_ipmi"
OPENIPMI_FILEVER="ipmi_msghandler"
OPENIPMI_GETVER_MOD="modinfo ${OPENIPMI_FILEVER}"
OPENIPMI_GETVER_FILE="/lib/modules/${RUNNING_KERNEL}/kernel/drivers/char/ipmi/${OPENIPMI_FILEVER}"

OPENIPMI_DISPLAY_NAME="ipmi driver"
OPENIPMI_INITFAIL_OK_MSG="(override enabled)"
OPENIPMI_RHEL3_VERMAJ_DEFAULT=35
OPENIPMI_RHEL3_VERMIN_DEFAULT=12
OPENIPMI_RHEL4_VERMAJ_DEFAULT=33
OPENIPMI_RHEL4_VERMIN_DEFAULT=12
OPENIPMI_SLES9_VERMAJ_DEFAULT=36
OPENIPMI_SLES9_VERMIN_DEFAULT=7
OPENIPMI_KERNEL_VERMAJ_DEFAULT=2
OPENIPMI_KERNEL_VERMIN_DEFAULT=6
OPENIPMI_KERNEL_VERPCH_DEFAULT=15

OPENIPMI_RHEL3_VERMAJ_CONFIG_KEY="openmanage.openipmi.rhel3.ver_min_major"
OPENIPMI_RHEL3_VERMIN_CONFIG_KEY="openmanage.openipmi.rhel3.ver_min_minor"
OPENIPMI_RHEL4_VERMAJ_CONFIG_KEY="openmanage.openipmi.rhel4.ver_min_major"
OPENIPMI_RHEL4_VERMIN_CONFIG_KEY="openmanage.openipmi.rhel4.ver_min_minor"
OPENIPMI_SLES9_VERMAJ_CONFIG_KEY="openmanage.openipmi.sles9.ver_min_major"
OPENIPMI_SLES9_VERMIN_CONFIG_KEY="openmanage.openipmi.sles9.ver_min_minor"
OPENIPMI_KERNEL_VERMAJ_CONFIG_KEY="openmanage.openipmi.kernel.ver_min_major"
OPENIPMI_KERNEL_VERMIN_CONFIG_KEY="openmanage.openipmi.kernel.ver_min_minor"
OPENIPMI_KERNEL_VERPCH_CONFIG_KEY="openmanage.openipmi.kernel.ver_min_patch"

# Determine install and variable data paths
if [ -f ${OMREG_PATHFILENAME} ];
then
	# Get install path from omreg config file
	ISVCDD_INSTALLPATH=$(
		grep "^${OMREG_HAPI_INSTALLPATH_KEY}=" ${OMREG_PATHFILENAME} |
		sed "s/^${OMREG_HAPI_INSTALLPATH_KEY}=//")
	if [ -z "${ISVCDD_INSTALLPATH}" ];
	then
		echo "Unable to get install path from file: ${OMREG_PATHFILENAME}"
		exit 1
	fi

	# Get variable data path from omreg config file
	ISVCDD_VARDATAPATH=$(
		grep "^${OMREG_HAPI_VARDATAPATH_KEY}=" ${OMREG_PATHFILENAME} |
		sed "s/^${OMREG_HAPI_VARDATAPATH_KEY}=//")
	if [ -z "${ISVCDD_VARDATAPATH}" ];
	then
		echo "Unable to get variable data path from file: ${OMREG_PATHFILENAME}"
		exit 2
	fi
else
	# Set defaults if not specified by user
	if [ -z "${INSTALL_DIR}" ];
	then
		ISVCDD_INSTALLPATH="${ISVCDD_DEFAULT_INSTALL_DIR}"
	else
		ISVCDD_INSTALLPATH=${INSTALL_DIR}
	fi

	if [ -z "${VARDATA_DIR}" ];
	then
		ISVCDD_VARDATAPATH="${ISVCDD_DEFAULT_VARDATA_DIR}"
	else
		ISVCDD_VARDATAPATH=${VARDATA_DIR}
	fi
fi

ISVCDD_SCRIPT_LOCKFILE="${ISVCDD_VARDATAPATH}/${ISVCDD_SCRIPT_NAME}.lock"

# Determine bit size of application modules supported by product
# Check the config tool module to make the determination
if [ -f ${ISVCDD_INSTALLPATH}/bin/dchcfg64 ];
then
	ISVCDD_APP_BIT_SIZE="64"
else
	ISVCDD_APP_BIT_SIZE="32"
fi

# Determine target processor architecture, and the bit size, for device drivers
if [ ${HOSTTYPE} = "ia64" ];
then
	ISVCDD_PROC_ARCH="ia64"
	ISVCDD_DRV_BIT_SIZE="64"
elif [ ${HOSTTYPE} = "x86_64" ];
then
	ISVCDD_PROC_ARCH="x86_64"
	ISVCDD_DRV_BIT_SIZE="64"
else
	ISVCDD_PROC_ARCH="x86"
	ISVCDD_DRV_BIT_SIZE="32"
fi

# Install directories
ISVCDD_BIN_DIR="${ISVCDD_INSTALLPATH}/bin"
if [ -z "${ISVCDD_ROOT_DIR}" ];
then
	ISVCDD_DRIVERS_DIR="${ISVCDD_INSTALLPATH}/drivers/${ISVCDD_PROC_ARCH}"
else
	ISVCDD_DRIVERS_DIR="${ISVCDD_ROOT_DIR}"
fi

# Status directories
ISVCDD_STATUS_DIR="${ISVCDD_VARDATAPATH}/drivers/status"
if [ ! -d ${ISVCDD_STATUS_DIR} ];
then
	mkdir -p ${ISVCDD_STATUS_DIR}
fi
ISVCDD_STATUS_KERNEL_DIR="${ISVCDD_STATUS_DIR}/${RUNNING_KERNEL}"
if [ ! -d ${ISVCDD_STATUS_KERNEL_DIR} ];
then
	mkdir -p ${ISVCDD_STATUS_KERNEL_DIR}
fi

# Application filenames
ISVCDD_DCHCFG_EXE="dchcfg${ISVCDD_APP_BIT_SIZE}"

# Device driver names
ISVCDD_DRIVER_NAME_BASE="dcdbas"
ISVCDD_DRIVER_NAME_RBU="dell_rbu"

# Disabled by Bas van der Vlies & Sander Keemink, not needed
#
ISVCDD_DRIVER_NAME_RBU=""

# Create list of device driver module names
ISVCDD_DRIVER_LIST_ALL=""
ISVCDD_DRIVER_LIST_ALL="${ISVCDD_DRIVER_LIST_ALL} ${ISVCDD_DRIVER_NAME_BASE}"
ISVCDD_DRIVER_LIST_ALL="${ISVCDD_DRIVER_LIST_ALL} ${ISVCDD_DRIVER_NAME_RBU}"

# Systems Management Data Engine information
DENG_PROD_NAME="Systems Management Data Engine"
DENG_SCRIPT="${OS_INITSCRIPT_DIR}/dataeng"
DENG_WAS_RUNNING=0

# Standard status codes for commands other than "status"
STATUS_NO_ERROR=0
STATUS_GENERIC_ERROR=1
STATUS_INVALID_ARG=2
STATUS_NOT_IMPLEMENTED=3
# Device Drivers status codes for commands other than "status"
STATUS_SYSTEM_NOT_SUPPORTED=150
STATUS_NO_KERNEL_SOURCE=151
STATUS_DKS_COMPILE_ERROR=152
STATUS_DKS_LINK_ERROR=153
STATUS_INSMOD_UNRESOLVED_SYMBOL=154
STATUS_INSMOD_ERROR=155
STATUS_RMMOD_ERROR=156
STATUS_DKS_FILES_NOT_FOUND=157
STATUS_GCC_NOT_FOUND=158
STATUS_BUILTIN_KERNEL=159

# Standard status codes for "status" command
STATUS_RUNNING=0
STATUS_NOT_RUNNING=3
# Device Drivers status codes for "status" command
STATUS_INVALID_STATUS_ARG=180

# System types
SYS_TYPE_NONE=0
SYS_TYPE_TVM=1
SYS_TYPE_ESM=2
SYS_TYPE_IPMI=4

# Flag to force start of all users
# changed by: HvB and Sander Keemink
#
FORCE_START_USERS=1

# OpenIPMI to HAPI configuration
OIHAPICFG_PATHFILENAME="${ISVCDD_INSTALLPATH}/ini/dchipm${ISVCDD_APP_BIT_SIZE}.ini"
OIHAPICFG_KEYPREFIX="${HAPICFG_PROJECT_NAME_HAPI}.openipmi"
OIHAPICFG_KEY_DRIVERSTARTED="${OIHAPICFG_KEYPREFIX}.driverstarted"
OIHAPICFG_KEY_ISSUPPORTEDVERSION="${OIHAPICFG_KEYPREFIX}.issupportedversion"
OIHAPICFG_KEY_ISPOWEROFFCAPABLE="${OIHAPICFG_KEYPREFIX}.ispoweroffcapable"
OIHAPICFG_KEY_POWERCYCLECOMMAND="${OIHAPICFG_KEYPREFIX}.powercyclecommand"
OIHAPICFG_KEY_POWEROFFMODULE="${OIHAPICFG_KEYPREFIX}.poweroffmodule"
OIHAPICFG_KEY_POWERCYCLEMODULE="${OIHAPICFG_KEYPREFIX}.powercyclemodule"
OIHAPICFG_KEY_BASEDRIVERPREFIX="${OIHAPICFG_KEYPREFIX}.basedriverprefix"
OIHAPICFG_KEY_DRIVERPATTERN="${OIHAPICFG_KEYPREFIX}.driverpattern"
OIHAPICFG_KEY_DEVICENODENAME="${OIHAPICFG_KEYPREFIX}.devicenodename"
OIHAPICFG_KEY_ALLOWUSERMODE="${HAPICFG_HAPI_OI_INITFAIL_OK_KEY}"
OIHAPICFG_HEADER="\
# Automatically generated file: please don't edit\n\
# Copyright (c) 1995-2006 Dell Inc. - All Rights Reserved\n\
# This file is in config (not INI) format\
"


###############################################################################
# Function:    debugprint
# Description: Print debugging messages
# Returns:     none
###############################################################################
debugprint()
{
	if [ `echo ${VERBOSE_LOGGING} | grep -Ec "(0|no|NO|No|false|False|FALSE)"` -eq 0 ];
	then
		echo $1 >${VERBOSE_TARGET} 2>&1
	fi
}

###############################################################################
# Function:    openipmi_check_version
# Description: Check for minimum version of OpenIPMI supported
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
openipmi_check_version()
{
	local l_fname="CheckOpenIPMIVersion"
	local l_os_supported
	local l_ver_min_major l_ver_min_minor l_ver_min_patch
	local l_modext l_major l_minor l_patch
	local l_maj_ckey l_maj_dflt 
	local l_min_ckey l_min_dflt 
	local l_pat_ckey l_path_dflt

	## get supported operating systems
	l_os_supported=1

	## check if operating system is RHEL3
	if [ ! "`grep 'Taroon' /etc/redhat-release 2>/dev/null`" == "" ];
	then
		debugprint "${l_fname}: OS is RHEL3"
		l_maj_ckey=${OPENIPMI_RHEL3_VERMAJ_CONFIG_KEY}
		l_maj_dflt=${OPENIPMI_RHEL3_VERMAJ_DEFAULT}
		l_min_ckey=${OPENIPMI_RHEL3_VERMIN_CONFIG_KEY}
		l_min_dflt=${OPENIPMI_RHEL3_VERMIN_DEFAULT}
		l_modext=".o"
	## check if operating system is RHEL4
	elif [ ! "`grep 'Nahant' /etc/redhat-release 2>/dev/null`" == "" ];
	then
		debugprint "${l_fname}: OS is RHEL4"
		l_maj_ckey=${OPENIPMI_RHEL4_VERMAJ_CONFIG_KEY}
		l_maj_dflt=${OPENIPMI_RHEL4_VERMAJ_DEFAULT}
		l_min_ckey=${OPENIPMI_RHEL4_VERMIN_CONFIG_KEY}
		l_min_dflt=${OPENIPMI_RHEL4_VERMIN_DEFAULT}
		l_modext=".ko"
	## check if operating system is SLES9
	elif [ "`grep 'VERSION' /etc/SuSE-release 2>/dev/null | sed 's#[^0-9]##g'`" == "9" ];
	then
		debugprint "${l_fname}: OS is SLES9"
		l_maj_ckey=${OPENIPMI_SLES9_VERMAJ_CONFIG_KEY}
		l_maj_dflt=${OPENIPMI_SLES9_VERMAJ_DEFAULT}
		l_min_ckey=${OPENIPMI_SLES9_VERMIN_CONFIG_KEY}
		l_min_dflt=${OPENIPMI_SLES9_VERMIN_DEFAULT}
		l_modext=".ko"
	else
		debugprint "${l_fname}: FAILED to determine OS"
		l_maj_ckey=${OPENIPMI_KERNEL_VERMAJ_CONFIG_KEY}
		l_maj_dflt=${OPENIPMI_KERNEL_VERMAJ_DEFAULT}
		l_min_ckey=${OPENIPMI_KERNEL_VERMIN_CONFIG_KEY}
		l_min_dflt=${OPENIPMI_KERNEL_VERMIN_DEFAULT}
		l_pat_ckey=${OPENIPMI_KERNEL_VERPCH_CONFIG_KEY}
		l_pat_dflt=${OPENIPMI_KERNEL_VERPCH_DEFAULT}
		l_os_supported=0
	fi

	## extract major version base value
	l_ver_min_major=$(grep "${l_maj_ckey}" ${OMREG_PATHFILENAME} \
		| cut -d= -f2 | sed 's/[\t ]*//g')
	[ -z "${l_ver_min_major}" ] && l_ver_min_major=${l_maj_dflt}

	## extract minor version base value
	l_ver_min_minor=$(grep "${l_min_ckey}" ${OMREG_PATHFILENAME} \
		| cut -d= -f2 | sed 's/[\t ]*//g')
	[ -z "${l_ver_min_minor}" ] && l_ver_min_minor=${l_min_dflt}

	## check if a supported operating system is found
	if [ ${l_os_supported} -eq 0 ];
	then
		## check if kernel version otherwise meets a minimum kernel 
		## version (if so, then it is assumed that the system should 
		## have an OpenIPMI driver installed that meets or exceeds the 
		## minimum version of OpenIPMI required by Systems Management)

		## extract patch version base value
		l_ver_min_patch=$(grep "${l_pat_ckey}" ${OMREG_PATHFILENAME} \
			| cut -d= -f2 | sed 's/[\t ]*//g')
		[ -z "${l_ver_min_patch}" ] && 
			l_ver_min_patch=${l_pat_dflt}

		debugprint "${l_fname}: kernel version minimum is: ${l_ver_min_major}.${l_ver_min_minor}.${l_ver_min_patch}"
		debugprint "${l_fname}: running kernel version is: ${RUNNING_KERNEL}"

		## now check if running kernel version meets the minimum kernel version
		l_major=$(echo ${RUNNING_KERNEL} | cut -d. -f1)
		if [ ${l_major} -gt ${l_ver_min_major} ]; 
		then
			debugprint "${l_fname}: kernel major version > minimum"
			## good at this point
			return ${STATUS_NO_ERROR}
		elif [ ${l_major} -eq ${l_ver_min_major} ];
		then
			l_minor=$(echo ${RUNNING_KERNEL} | cut -d. -f2)
			if [ ${l_minor} -gt ${l_ver_min_minor} ]; 
			then
				debugprint "${l_fname}: kernel minor version > minimum"
				## good at this point
				return ${STATUS_NO_ERROR}
			elif [ ${l_minor} -eq ${l_ver_min_minor} ];
			then
				l_patch=$(echo ${RUNNING_KERNEL} | cut -d. -f3 | cut -d- -f1)
				if [ ${l_patch} -gt ${l_ver_min_patch} ]; 
				then
					debugprint "${l_fname}: kernel patch version > minimum"
					## good at this point
					return ${STATUS_NO_ERROR}
				elif [ ${l_patch} -eq ${l_ver_min_patch} ];
				then
					debugprint "${l_fname}: kernel version == minimum"
					## good at this point
					return ${STATUS_NO_ERROR}
				else
					debugprint "${l_fname}: failed: kernel patch version < minimum"
					return ${STATUS_GENERIC_ERROR}
				fi
			else
				debugprint "${l_fname}: failed: kernel minor version < minimum"
				return ${STATUS_GENERIC_ERROR}
			fi
		else
			debugprint "${l_fname}: failed: kernel major version < minimum"
			return ${STATUS_GENERIC_ERROR}
		fi
	fi

	## check version using modprobe
	debugprint "${l_fname}: minimum version is ${l_ver_min_major}.${l_ver_min_minor}"
	l_minor=0
	l_major=$(${OPENIPMI_GETVER_MOD} 2>/dev/null \
		| grep '^version:' | awk -F'version:' '{ print $2 }' \
		| cut -d. -f1 | sed -e 's/[ \t]*//g' -e 's/v//g')
	[ -z "${l_major}" ] && l_major=0
	if [ ${l_major} -eq ${l_ver_min_major} ]; 
	then
		## major version == minimum
		l_minor=$(${OPENIPMI_GETVER_MOD} 2>/dev/null \
			| grep '^version:' | awk -F'version:' '{ print $2 }' \
			| awk -F'.' '{ print $2 }' | sed -e 's/\([0-9]*\).*/\1/')
		[ -z "${l_minor}" ] && l_minor=0
		if [ ${l_minor} -ge ${l_ver_min_minor} ]; 
		then
			debugprint "${l_fname}: version >= minimum"
			## good at this point
			return ${STATUS_NO_ERROR}
		fi
	else
		if [ ${l_major} -gt ${l_ver_min_major} ]; 
		then
			debugprint "${l_fname}: major version > minimum"
			## good at this point
			return ${STATUS_NO_ERROR}
		fi
	fi

	## form the path file name
	l_modext="${OPENIPMI_GETVER_FILE}${l_modext}"

	## check version using strings in the kernel module file
	debugprint "${l_fname}: failed version check using modinfo"
	debugprint "${l_fname}: trying ${l_modext}"
	l_minor=0
	l_major=$(grep -a ' version ' ${l_modext} 2>/dev/null \
		| awk -F' version ' '{ print $2 }' \
		| cut -d. -f1 | sed -e 's/[ \t]*//g' -e 's/v//g')
	[ -z "${l_major}" ] && l_major=0
	if [ ${l_major} -eq ${l_ver_min_major} ]; 
	then
		## major version == minimum
		l_minor=$(grep -a ' version ' ${l_modext} 2>/dev/null \
			| awk -F' version ' '{ print $2 }' \
			| awk -F'.' '{ print $2 }' | sed -e 's/\([0-9]*\).*/\1/')
		[ -z "${l_minor}" ] && l_minor=0
		if [ ${l_minor} -ge ${l_ver_min_minor} ]; 
		then
			debugprint "${l_fname}: version >= minimum"
			## good at this point
			return ${STATUS_NO_ERROR}
		fi
	else
		if [ ${l_major} -gt ${l_ver_min_major} ]; 
		then
			debugprint "${l_fname}: major version > minimum"
			## good at this point
			return ${STATUS_NO_ERROR}
		fi
	fi
	
	debugprint "${l_fname}: failed: found version: ${l_major}.${l_minor}"
	return ${STATUS_GENERIC_ERROR}
} # openipmi_check_version


###############################################################################
# Function:    instsvcdrv_initfailok_openipmi
# Description: Check configuration settings for init fail override
# Returns:     LSB status codes
#              STATUS_NO_ERROR if init failure is not allowed
#              STATUS_GENERIC_ERROR if init failure is allowed
###############################################################################
instsvcdrv_initfailok_openipmi()
{
	local l_val

	## check configuration file for overrides
	if [ -f "${OMREG_PATHFILENAME}" ]; 
	then
		l_val=$(grep "^${HAPICFG_HAPI_OI_INITFAIL_OK_KEY}" \
			${OMREG_PATHFILENAME} | sed "s/^.*=//")
		if [ ! -z "${l_val}" ] && 
		   [ `echo ${l_val} | grep -Ec "(0|no|NO|No|false|False|FALSE)"` -eq 0 ];
		then
			return ${STATUS_GENERIC_ERROR}
		fi
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_initfailok_openipmi


###############################################################################
# Function:    instsvcdrv_oihapicfg_validate_addheader
# Description: Check security state of OpenIPMI-HAPI configuration file
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_oihapicfg_validate_addheader()
{
	local l_fname="OItoHAPIconfig"

	debugprint "instsvcdrv_oihapicfg_validate_addheader()"
	## check file security before making changes
#	[ ! -e "${OIHAPICFG_PATHFILENAME}" ] &&
#		debugprint "${l_fname}: error: file does not exist" &&
#		return ${STATUS_GENERIC_ERROR}
	if [ ! -e "${OIHAPICFG_PATHFILENAME}" ];
	then
		if [ "`id -u`" = "0" ];
		then
			## create the path and file only if user root
			l_path=$(basename ${OIHAPICFG_PATHFILENAME})
			l_path=$(echo ${OIHAPICFG_PATHFILENAME} | sed "s/\/${l_path}//")
			if [ ! -e "${l_path}" ];
			then
				debugprint "${l_fname}: creating ${l_path}"
				mkdir ${l_path} >/dev/null
				chmod 700 ${l_path} >/dev/null
			fi
			debugprint "${l_fname}: creating ${OIHAPICFG_PATHFILENAME}"
			touch ${OIHAPICFG_PATHFILENAME} >/dev/null
			chmod 600 ${OIHAPICFG_PATHFILENAME} >/dev/null
		fi
		## check again
		if [ ! -e "${OIHAPICFG_PATHFILENAME}" ];
		then
			debugprint "${l_fname}: error: file does not exist" &&
			return ${STATUS_GENERIC_ERROR}
		fi
	fi

	[ -h "${OIHAPICFG_PATHFILENAME}" ] &&
		debugprint "${l_fname}: error: file is a symbolic link" &&
		return ${STATUS_GENERIC_ERROR}

	[ ! "`id -u`" = "0" -o ! -O "${OIHAPICFG_PATHFILENAME}" ] &&
		debugprint "${l_fname}: error: file is not owned by root" &&
		return ${STATUS_GENERIC_ERROR}

	[ ! -w "${OIHAPICFG_PATHFILENAME}" ] &&
		debugprint "${l_fname}: error: file is not writable" &&
		return ${STATUS_GENERIC_ERROR}

	## add standard header
	echo -e $"#\n${OIHAPICFG_HEADER}" > ${OIHAPICFG_PATHFILENAME}
	echo -e $"# Generated on `date`\n#" >> ${OIHAPICFG_PATHFILENAME}

	return ${STATUS_NO_ERROR}
} # instsvcdrv_oihapicfg_validate_addheader


###############################################################################
# Function:    instsvcdrv_oihapicfg_started_openipmi
# Description: Update OpenIPMI-HAPI configuration on successful OpenIPMI start
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_oihapicfg_started_openipmi()
{
	## check file security before making changes
	instsvcdrv_oihapicfg_validate_addheader
	[ $? -ne ${STATUS_NO_ERROR} ] &&
		return ${STATUS_GENERIC_ERROR}

	## indicate started
	echo -e $"${OIHAPICFG_KEY_DRIVERSTARTED}=yes" >> ${OIHAPICFG_PATHFILENAME}

	## add support
	echo -e $"${OIHAPICFG_KEY_ISSUPPORTEDVERSION}=yes" >> ${OIHAPICFG_PATHFILENAME}

	## add poweroff
	modinfo ipmi_poweroff >/dev/null 2>&1
	if [ $? -eq 0 ]; then
		echo -e $"${OIHAPICFG_KEY_ISPOWEROFFCAPABLE}=yes" >> ${OIHAPICFG_PATHFILENAME}
	else
		echo -e $"${OIHAPICFG_KEY_ISPOWEROFFCAPABLE}=no" >> ${OIHAPICFG_PATHFILENAME}
	fi

	## add powercycle
	modinfo ipmi_poweroff 2>/dev/null | grep poweroff_control >/dev/null 2>&1 && \
		echo -e $"${OIHAPICFG_KEY_POWERCYCLECOMMAND}=poweroff_control=2" >> ${OIHAPICFG_PATHFILENAME}

	modinfo ipmi_poweroff 2>/dev/null | grep poweroff_powercycle >/dev/null 2>&1 && \
		echo -e $"${OIHAPICFG_KEY_POWERCYCLECOMMAND}=poweroff_powercycle=1" >> ${OIHAPICFG_PATHFILENAME}

	## add other constants
	echo -e $"${OIHAPICFG_KEY_POWEROFFMODULE}=ipmi_poweroff" >> ${OIHAPICFG_PATHFILENAME}
	echo -e $"${OIHAPICFG_KEY_POWERCYCLEMODULE}=ipmi_poweroff" >> ${OIHAPICFG_PATHFILENAME}
	echo -e $"${OIHAPICFG_KEY_BASEDRIVERPREFIX}=ipmi_si" >> ${OIHAPICFG_PATHFILENAME}
	echo -e $"${OIHAPICFG_KEY_DRIVERPATTERN}=ipmi_" >> ${OIHAPICFG_PATHFILENAME}

	## turn off usermode
	echo -e $"${OIHAPICFG_KEY_ALLOWUSERMODE}=no" >> ${OIHAPICFG_PATHFILENAME}

	echo -e "" >> ${OIHAPICFG_PATHFILENAME}
	return ${STATUS_NO_ERROR}
} # instsvcdrv_oihapicfg_started_openipmi


###############################################################################
# Function:    instsvcdrv_oihapicfg_usermode
# Description: Update OpenIPMI-HAPI configuration for user-mode
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_oihapicfg_usermode()
{
	## check file security before making changes
	instsvcdrv_oihapicfg_validate_addheader
	[ $? -ne ${STATUS_NO_ERROR} ] &&
		return ${STATUS_GENERIC_ERROR}

	## indicate started
	echo -e $"${OIHAPICFG_KEY_DRIVERSTARTED}=yes" >> ${OIHAPICFG_PATHFILENAME}

	## turn on usermode
	echo -e $"${OIHAPICFG_KEY_ALLOWUSERMODE}=yes" >> ${OIHAPICFG_PATHFILENAME}

	echo -e "" >> ${OIHAPICFG_PATHFILENAME}
	return ${STATUS_NO_ERROR}
} # instsvcdrv_oihapicfg_usermode


###############################################################################
# Function:    instsvcdrv_oihapicfg_stopped
# Description: Update OpenIPMI-HAPI configuration on driver stop
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_oihapicfg_stopped()
{
	## check file security before making changes
	instsvcdrv_oihapicfg_validate_addheader
	[ $? -ne ${STATUS_NO_ERROR} ] &&
		return ${STATUS_GENERIC_ERROR}

	## indicate started
	echo -e $"${OIHAPICFG_KEY_DRIVERSTARTED}=no" >> ${OIHAPICFG_PATHFILENAME}

	echo -e "" >> ${OIHAPICFG_PATHFILENAME}
	return ${STATUS_NO_ERROR}
} # instsvcdrv_oihapicfg_stopped


###############################################################################
# Function:    instsvcdrv_start_openipmi
# Description: Start OpenIPMI driver through its init script
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_start_openipmi()
{
	local l_status=${STATUS_GENERIC_ERROR}
	local l_val

	## check if system is IPMI
	instsvcdrv_get_sys_type
	if [ ${ISVCDD_SYS_TYPE} -ne ${SYS_TYPE_IPMI} ];
	then
		return ${STATUS_NO_ERROR}
	fi

	## start override from configuration file?
	l_val=$(grep -E "^${HAPICFG_HAPI_OI_LOAD}=" ${HAPICFG_PATHFILENAME} \
		2>/dev/null | cut -d= -f2 | sed 's/[\t ]*//g')
	if [ `echo ${l_val} | grep -Ec "(0|no|NO|No|false|False|FALSE)"` -ne 0 ];
	then
		return ${STATUS_NO_ERROR}
	fi

	## display what is to be done
	echo -n "Starting ${OPENIPMI_DISPLAY_NAME}: "

	## make sure the init script exist
	if [ -f "${OPENIPMI_SCRIPT}" ]; 
	then
		## is it running ?
		/sbin/lsmod | grep ipmi_devintf >/dev/null 2>&1
		if [ $? -ne 0 -o ! -c "/dev/ipmi0" ];
		then
			## validate OpenIPMI version
			openipmi_check_version
			if [ $? -eq ${STATUS_NO_ERROR} ]; 
			then
				## start it
				${OPENIPMI_SCRIPT} start >/dev/null 2>&1
				l_status=$?
			fi
			if [ ${l_status} -eq ${STATUS_NO_ERROR} ];
			then
				instsvcdrv_oihapicfg_started_openipmi
				instsvcdrv_supt_showsuccess ""
			else
				## check configuration file for override
				instsvcdrv_initfailok_openipmi
				if [ $? -ne ${STATUS_NO_ERROR} ];
				then
					instsvcdrv_oihapicfg_usermode
					instsvcdrv_supt_showwarning "failed ${OPENIPMI_INITFAIL_OK_MSG}"
					## good at this point
					l_status=${STATUS_NO_ERROR}
				else
					instsvcdrv_supt_showfailure ""
				fi
			fi
		else
			instsvcdrv_oihapicfg_started_openipmi
			instsvcdrv_supt_showsuccess "Already started"
			## good at this point
			l_status=${STATUS_NO_ERROR}
		fi
	else
		## init file not found, check if any is loaded
		/sbin/lsmod | grep ipmi_ >/dev/null 2>&1
		if [ $? -ne 0 ];
		then
			## no driver is loaded, check if usermode override
			instsvcdrv_initfailok_openipmi
			if [ $? -ne ${STATUS_NO_ERROR} ];
			then
				instsvcdrv_oihapicfg_usermode
				instsvcdrv_supt_showwarning "ipmi init not found ${OPENIPMI_INITFAIL_OK_MSG}"
				l_status=${STATUS_NO_ERROR}
			else
				instsvcdrv_supt_showfailure "ipmi init not found"
			fi
		else
			instsvcdrv_supt_showfailure "ipmi init not found"
		fi
	fi

	return ${l_status}
} # instsvcdrv_start_openipmi


###############################################################################
# Function:    instsvcdrv_status_openipmi
# Description: Status OpenIPMI driver through its init script
# Parameter1:  "quiet" will suppress messages to standard out
# Returns:     LSB status codes
#              STATUS_NO_ERROR on success
#              STATUS_GENERIC_ERROR on failure
###############################################################################
instsvcdrv_status_openipmi()
{
	local l_status=${STATUS_NO_ERROR}
	local l_arg1=$1

	## check if system is IPMI
	instsvcdrv_get_sys_type
	if [ ${ISVCDD_SYS_TYPE} -ne ${SYS_TYPE_IPMI} ];
	then
		return ${STATUS_NO_ERROR}
	fi

	## start override from configuration file?
	l_val=$(grep "^${HAPICFG_HAPI_OI_LOAD}=" ${HAPICFG_PATHFILENAME} \
		2>/dev/null | cut -d= -f2 | sed 's/[\t ]*//g')
	if [ `echo ${l_val} | grep -Ec "(0|no|NO|No|false|False|FALSE)"` -ne 0 ];
	then
		return ${STATUS_NO_ERROR}
	fi

	## display what is to be done
	[ "${l_arg1}" != "quiet" ] && 
		echo -n "${OPENIPMI_DISPLAY_NAME} is "

	## is it alive?
	if  [ ! -c "/dev/ipmi0" -o ! "`lsmod | grep ipmi_devintf`" ]; 
	then
		## update OpenIPMI-HAPI configuration file
		instsvcdrv_oihapicfg_stopped

		## check configuration file for override
		instsvcdrv_initfailok_openipmi
		if [ $? -eq ${STATUS_NO_ERROR} ];
		then
			[ "${l_arg1}" != "quiet" ] && 
				echo "stopped"
			## not running so error
			return ${STATUS_GENERIC_ERROR}
		else
			## not running but ignore
			[ "${l_arg1}" != "quiet" ] && 
				echo "stopped ${OPENIPMI_INITFAIL_OK_MSG}"
		fi
	else
		[ "${l_arg1}" != "quiet" ] && 
			echo "running"
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_status_openipmi


###############################################################################
# Function:    instsvcdrv_stop_users_before_start_openipmi
# Description: Stop users when it is currently running and openipmi is not
# Returns:     none
###############################################################################
instsvcdrv_stop_users_before_start_openipmi()
{

	instsvcdrv_status_openipmi quiet
	if [ $? -ne ${STATUS_NO_ERROR} ];
	then
		## ipmi driver is not running and we are about to start it
		## make sure that users are stopped since if they are currently
		## running it must be in user-mode
		instsvcdrv_stop_users
	fi

	return
} # instsvcdrv_stop_users_before_start_openipmi


###############################################################################
# Function:    instsvcdrv_start
# Description: Start device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_start()
{
	local driver_name driver_status status ipmistatus

	echo "Starting ${ISVCDD_PROD_NAME}:"

	status=${STATUS_NO_ERROR}

	instsvcdrv_get_driver_list
	if [ ! -z "${ISVCDD_LIST}" ];
	then
		for driver_name in ${ISVCDD_LIST};
		do
			instsvcdrv_start_driver ${driver_name}
			driver_status=$?
			if [ ${driver_status} != ${STATUS_NO_ERROR} ];
			then
				status=${driver_status}
			fi
		done
	fi

	instsvcdrv_start_openipmi
	ipmistatus=$?
	status=$((status | ipmistatus))

	return ${status}
} # instsvcdrv_start


###############################################################################
# Function:    instsvcdrv_start_driver <driver>
# Description: Start specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_start_driver()
{
	local driver_name status

	driver_name="$1"
	status=${STATUS_NO_ERROR}

	instsvcdrv_check_driver_name ${driver_name}
	if [ $? != ${STATUS_NO_ERROR} ];
	then
		return ${STATUS_INVALID_ARG}
	fi

	instsvcdrv_status_driver_quiet ${driver_name}
	case $? in
		${STATUS_NOT_RUNNING})
			instsvcdrv_load_driver ${driver_name}
			status=$?
			;;

		${STATUS_RUNNING})
			echo -n "Starting ${driver_name}: "
			echo -n "Already started"
			instsvcdrv_supt_showsuccess ""
			;;

		${STATUS_BUILTIN_KERNEL})
			echo "${driver_name} is built into the kernel"
			;;
	esac

	return ${status}
} # instsvcdrv_start_driver


###############################################################################
# Function:    instsvcdrv_stop
# Description: Stop device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_stop()
{
	local driver_name driver_status status

	echo "Stopping ${ISVCDD_PROD_NAME}:"

	status=${STATUS_NO_ERROR}

	instsvcdrv_get_driver_list
	if [ ! -z "${ISVCDD_LIST}" ];
	then
		for driver_name in ${ISVCDD_LIST};
		do
			instsvcdrv_stop_driver ${driver_name}
			driver_status=$?
			if [ ${driver_status} != ${STATUS_NO_ERROR} ];
			then
				status=${driver_status}
			fi
		done
	fi

	return ${status}
} # instsvcdrv_stop


###############################################################################
# Function:    instsvcdrv_stop_driver <driver>
# Description: Stop specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_stop_driver()
{
	local driver_name status

	driver_name="$1"
	status=${STATUS_NO_ERROR}

	instsvcdrv_check_driver_name ${driver_name}
	if [ $? != ${STATUS_NO_ERROR} ];
	then
		return ${STATUS_INVALID_ARG}
	fi

	instsvcdrv_status_driver_quiet ${driver_name}
	case $? in
		${STATUS_RUNNING})
			instsvcdrv_unload_driver ${driver_name}
			status=$?
			;;

		${STATUS_BUILTIN_KERNEL})
			echo "${driver_name} is built into the kernel"
			;;

		${STATUS_NOT_RUNNING})
			echo -n "Stopping ${driver_name}: "
			echo -n "Not started"
			instsvcdrv_supt_showsuccess ""
			;;
	esac

	return ${status}
} # instsvcdrv_stop_driver


###############################################################################
# Function:    instsvcdrv_status
# Description: Print and return status of device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_status()
{
	local driver_name status ipmistatus

	status=${STATUS_RUNNING}

	instsvcdrv_get_driver_list
	if [ ! -z "${ISVCDD_LIST}" ];
	then
		for driver_name in ${ISVCDD_LIST};
		do
			instsvcdrv_status_driver ${driver_name}
			case $? in
				${STATUS_NOT_RUNNING})
					status=${STATUS_NOT_RUNNING}
					;;
			esac
		done
	fi

	instsvcdrv_status_openipmi
	ipmistatus=$?
	status=$((status | ipmistatus))

	return ${status}
} # instsvcdrv_status


###############################################################################
# Function:    instsvcdrv_status_driver <driver module name>
# Description: Print and return status of specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_status_driver()
{
	local driver_name status

	driver_name="$1"

	instsvcdrv_check_driver_name ${driver_name}
	if [ $? != ${STATUS_NO_ERROR} ];
	then
		return ${STATUS_INVALID_STATUS_ARG}
	fi

	instsvcdrv_status_driver_quiet ${driver_name}
	status=$?

	case ${status} in
		${STATUS_RUNNING})
			echo "${driver_name} (module) is running"
			;;

		${STATUS_BUILTIN_KERNEL})
			echo "${driver_name} is built into the kernel"
			;;

		${STATUS_NOT_RUNNING})
			echo "${driver_name} (module) is stopped"
			;;
	esac

	return ${status}
} # instsvcdrv_status_driver


###############################################################################
# Function:    instsvcdrv_status_quiet
# Description: Return status of device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_status_quiet()
{
	local driver_name status ipmistatus

	status=${STATUS_RUNNING}

	instsvcdrv_get_driver_list
	if [ ! -z "${ISVCDD_LIST}" ];
	then
		for driver_name in ${ISVCDD_LIST};
		do
			instsvcdrv_status_driver_quiet ${driver_name}
			case $? in
				${STATUS_NOT_RUNNING})
					status=${STATUS_NOT_RUNNING}
					;;
			esac
		done
	fi

	instsvcdrv_status_openipmi quiet
	ipmistatus=$?
	status=$((status | ipmistatus))

	return ${status}
} # instsvcdrv_status_quiet


###############################################################################
# Function:    instsvcdrv_status_driver_quiet <driver module name>
# Description: Return status of specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_status_driver_quiet()
{
	local status

	instsvcdrv_set_driver_vars $1
	status=$?
	if [ ${status} != ${STATUS_NO_ERROR} ];
	then
		return ${status}
	fi

	lsmod | grep -iq ${ISVCDD_MODULE_NAME}
	if [ $? = 0 ];
	then
		return ${STATUS_RUNNING}
	elif [ ${ISVCDD_BUILTIN_KERNEL} = 1 ];
	then
		return ${STATUS_BUILTIN_KERNEL}
	else
		return ${STATUS_NOT_RUNNING}
	fi
} # instsvcdrv_status_driver_quiet


###############################################################################
# Function:    instsvcdrv_start_users
# Description: Start users of device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_start_users()
{
	# See if Data Engine needs to be restarted
	if [ ${FORCE_START_USERS} != 0 ] || [ ${DENG_WAS_RUNNING} != 0 ];
	then
		if [ -x ${DENG_SCRIPT} ];
		then
			${DENG_SCRIPT} start
		fi
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_start_users


###############################################################################
# Function:    instsvcdrv_stop_users
# Description: Stop users of device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_stop_users()
{
	# See if Data Engine is installed
	if [ -x ${DENG_SCRIPT} ];
	then
		#
		# See if Data Engine is running
		#

		# First check if the return codes from the installed dataeng script
		# follow LSB standards (0=running, 1=stopped).
		# Prior to Data Engine version 5.1.1, the return codes from the
		# dataeng script did not follow LSB standards. Instead, it returned
		# 0=stopped and non-zero=running.
		${DENG_SCRIPT} statusreturnlsb >/dev/null 2>&1
		if [ $? = 0 ];
		then
			#
			# Return codes follow LSB standards
			#

			# See if Data Engine is running
			${DENG_SCRIPT} status-quiet
			if [ $? = ${STATUS_RUNNING} ];
			then
				DENG_WAS_RUNNING=1

				# Stop Data Engine
				${DENG_SCRIPT} stop

				# Cleanup being done; wait a second
				sleep 1s

				# See if Data Engine stopped
				${DENG_SCRIPT} status-quiet
				if [ $? = ${STATUS_RUNNING} ];
				then
					echo "${DENG_PROD_NAME} failed to stop"
					echo "${ISVCDD_PROD_NAME} not stopped"
					return ${STATUS_GENERIC_ERROR}
				fi
			fi
		else
			#
			# Return codes do not follow LSB stndards
			#

			# See if Data Engine is running
			${DENG_SCRIPT} status-quiet
			if [ $? != 0 ];
			then
				DENG_WAS_RUNNING=1

				# Stop Data Engine
				${DENG_SCRIPT} stop

				# Cleanup being done; wait a second
				sleep 1s

				# See if Data Engine stopped
				${DENG_SCRIPT} status-quiet
				if [ $? != 0 ];
				then
					echo "${DENG_PROD_NAME} failed to stop"
					echo "${ISVCDD_PROD_NAME} not stopped"
					return ${STATUS_GENERIC_ERROR}
				fi
			fi
		fi
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_stop_users


###############################################################################
# Function:    instsvcdrv_build
# Description: Build device drivers
# Returns:     LSB status codes
###############################################################################
instsvcdrv_build()
{
	local driver_name

	# Check for build arguments to override defaults
	while [ ! -z "$1" ];
	do
		case "$1" in
			--kernel)
				TARGET_KERNEL=$2
				;;
			--kernelsrcdir)
				KERNEL_SOURCE_DIR=$2
				;;
			--installdir)
				ISVCDD_INSTALLPATH=$2
				ISVCDD_BIN_DIR="${ISVCDD_INSTALLPATH}/bin"
				ISVCDD_DRIVERS_DIR="${ISVCDD_INSTALLPATH}/drivers/${ISVCDD_PROC_ARCH}"
				;;
			--vardatadir)
				ISVCDD_VARDATAPATH=$2
				;;
			--outputdir)
				OUTPUT_DIR=$2
				;;
			*)
				echo "Invalid argument: $1"
				return ${STATUS_INVALID_ARG}
				;;
		esac

		if [ -z "$2" ];
		then
			echo "No value for argument: $1"
			return ${STATUS_INVALID_ARG}
		fi

		shift; shift
	done

	# Set defaults if not specified by user
	if [ -z "${TARGET_KERNEL}" ];
	then
		TARGET_KERNEL=${RUNNING_KERNEL}
	fi
	if [ -z "${KERNEL_SOURCE_DIR}" ];
	then
		KERNEL_SOURCE_DIR="${OS_MODULES_DIR}/${TARGET_KERNEL}/build"
	fi
	if [ -z "${OUTPUT_DIR}" ];
	then
		OUTPUT_DIR="${ISVCDD_VARDATAPATH}/drivers/${ISVCDD_PROC_ARCH}/${TARGET_KERNEL}"
	fi

	echo ""
	echo "Target kernel:    ${TARGET_KERNEL}"
	echo "Kernel source:    ${KERNEL_SOURCE_DIR}"
	echo "Output directory: ${OUTPUT_DIR}"
	echo ""

	# Set up output directory for device drivers
	if [ ! -d ${OUTPUT_DIR} ];
	then
		mkdir -p ${OUTPUT_DIR}
	fi

	# Build device drivers in list
	for driver_name in ${ISVCDD_DRIVER_LIST_ALL};
	do
		echo -n "Building ${driver_name}: "
		instsvcdrv_set_driver_vars ${driver_name}
		instsvcdrv_build_driver
		BUILD_STATUS=$?
		if [ ${BUILD_STATUS} = ${STATUS_NO_ERROR} ];
		then
			echo "OK"
			cp -f ${ISVCDD} ${OUTPUT_DIR}
		else
			echo "FAILED"
			case ${BUILD_STATUS} in
				${STATUS_DKS_FILES_NOT_FOUND} )
					echo "DKS files not found."
					;;
				${STATUS_NO_KERNEL_SOURCE} )
					echo "Kernel source not found."
					;;
				${STATUS_GCC_NOT_FOUND} )
					echo "gcc not found."
					;;
				* )
					echo "Check ${DKS_MODULE_BUILD_LOGFILE} for build error."
					;;
			esac
			echo ""
			return ${BUILD_STATUS}
		fi
	done
	echo ""

	return ${STATUS_NO_ERROR}
} # instsvcdrv_build


###############################################################################
# Function:    instsvcdrv_preupgrade
# Description: Prepare for upgrade
# Returns:     LSB status codes
###############################################################################
instsvcdrv_preupgrade()
{
	# upgrade needs same cleanup as uninstall
	instsvcdrv_preuninstall
	return $?
} # instsvcdrv_preupgrade


###############################################################################
# Function:    instsvcdrv_preuninstall
# Description: Prepare for uninstall
# Returns:     LSB status codes
###############################################################################
instsvcdrv_preuninstall()
{
	local driver_name

	# stop drivers if running
	instsvcdrv_status_quiet
	if [ $? = ${STATUS_RUNNING} ];
	then
		instsvcdrv_stop_users
		instsvcdrv_stop
	fi

	# get list of kernel names in drivers status directory
	SUBDIR_LIST=$(ls ${ISVCDD_STATUS_DIR})

	# remove device drivers from kernel module directory
	for driver_name in ${ISVCDD_DRIVER_LIST_ALL};
	do
		instsvcdrv_set_driver_vars ${driver_name}

		for SUBDIR in ${SUBDIR_LIST};
		do
			TMP=${ISVCDD_STATUS_DIR}/${SUBDIR}/${ISVCDD_MODULE_NAME}.installed
			if [ -f ${TMP} ];
			then
				rm -f ${OS_MODULES_DIR}/${SUBDIR}/${ISVCDD_KERNEL_MODULE_SUBDIR}/${ISVCDD_MODULE_NAME}.o
				rm -f ${OS_MODULES_DIR}/${SUBDIR}/${ISVCDD_KERNEL_MODULE_SUBDIR}/${ISVCDD_MODULE_NAME}.ko
				rm -f ${TMP}
			fi
		done
	done
	depmod -a >/dev/null 2>&1

	instsvcdrv_dks_cleanup

	if [ -d ${ISVCDD_STATUS_DIR} ];
	then
		rm -rf ${ISVCDD_STATUS_DIR}
	fi

	rm -f ${ISVCDD_SCRIPT_LOCKFILE}

	return ${STATUS_NO_ERROR}
} # instsvcdrv_preuninstall


###############################################################################
# Function:    instsvcdrv_restart_forcekernelmatch
# Description: Restart drivers with "kernel match" load option enabled
# Returns:     LSB status codes
###############################################################################
instsvcdrv_restart_forcekernelmatch()
{
	local driver status

	# stop drivers
	instsvcdrv_stop_users
	instsvcdrv_stop
	status=$?
	if [ ${status} != ${STATUS_NO_ERROR} ];
	then
		return ${status}
	fi

	# uninstall drivers that were installed by this script
	# for running kernel
	# (ISVCDD_LIST set up by instsvcdrv_stop)
	if [ ! -z "${ISVCDD_LIST}" ];
	then
		for driver in ${ISVCDD_LIST};
		do
			instsvcdrv_set_driver_vars ${driver}
			if [ -f ${ISVCDD_STATUSFILE_INSTALLED} ];
			then
				rm -f ${ISVCDD_KERNEL_MODULE_DIR}/${ISVCDD_BINARY_FILENAME}
				rm -f ${ISVCDD_STATUSFILE_INSTALLED}
			fi
		done
		depmod -a >/dev/null 2>&1
	fi

	# force DKS to be used if precompiled driver not found
	# in directory with name that matches running kernel
	ISVCDD_FORCE_KERNEL_MATCH=1

	# start drivers
	instsvcdrv_start
	status=$?
	# note: ignore exit code from instsvcdrv_start_users
	instsvcdrv_start_users

	return ${status}
} # instsvcdrv_restart_forcekernelmatch


###############################################################################
# Function:    instsvcdrv_get_sys_type
# Description: Get system type
# Returns:     system type via ISVCDD_SYS_TYPE
###############################################################################
instsvcdrv_get_sys_type()
{
	ISVCDD_SYS_TYPE=${SYS_TYPE_NONE}

	if [ -x ${ISVCDD_BIN_DIR}/${ISVCDD_DCHCFG_EXE} ];
	then
		${ISVCDD_BIN_DIR}/${ISVCDD_DCHCFG_EXE} command=getsystype >/dev/null 2>&1
		ISVCDD_SYS_TYPE=$?
	fi
} # instsvcdrv_get_sys_type


###############################################################################
# Function:    instsvcdrv_get_forcekernelmatch
# Description: Get "kernel match" option value for driver load
# Returns:     value via ISVCDD_FORCE_KERNEL_MATCH
###############################################################################
instsvcdrv_get_forcekernelmatch()
{
	local val

	# check if option already specified
	if [ -z "${ISVCDD_FORCE_KERNEL_MATCH}" ];
	then
		# option not enabled by default for Red Hat
		if [ -f /etc/redhat-release ];
		then
			ISVCDD_FORCE_KERNEL_MATCH=0
		else
			ISVCDD_FORCE_KERNEL_MATCH=1
		fi

		# check config file for option
		if [ -f ${HAPICFG_PATHFILENAME} ];
		then
			val=$(
				grep "^${HAPICFG_HAPI_FORCEKERMATCH_KEY}=" ${HAPICFG_PATHFILENAME} |
				sed "s/^${HAPICFG_HAPI_FORCEKERMATCH_KEY}=//")
			case "${val}" in
				true|TRUE|1)
					ISVCDD_FORCE_KERNEL_MATCH=1
					;;
				false|FALSE|0)
					ISVCDD_FORCE_KERNEL_MATCH=0
					;;
			esac
		fi
	fi
} # instsvcdrv_get_forcekernelmatch


###############################################################################
# Function:    instsvcdrv_check_driver_name <driver>
# Description: Check specified device driver name
# Returns:     LSB status codes
###############################################################################
instsvcdrv_check_driver_name()
{
	local driver isvcdd_driver

	driver="$1"

	if [ -z ${driver} ];
	then
		echo "${ISVCDD_SCRIPT_NAME}: driver not specified"
		return ${STATUS_INVALID_ARG}
	fi

	for isvcdd_driver in ${ISVCDD_DRIVER_LIST_ALL};
	do
		if [ "${driver}" = "${isvcdd_driver}" ];
		then
			return ${STATUS_NO_ERROR}
		fi
	done

	echo "${ISVCDD_SCRIPT_NAME}: driver name not valid"

	return ${STATUS_INVALID_ARG}
} # instsvcdrv_check_driver_name


###############################################################################
# Function:    instsvcdrv_get_driver_list
# Description: Get list of drivers configured for loading
# Returns:     LSB status codes
#              Driver list returned via ISVCDD_LIST
###############################################################################
instsvcdrv_get_driver_list()
{
	ISVCDD_LIST=""
	LOADDRIVERS="${HAPICFG_HAPI_LOADDRIVERS_ACTIVE}"

	if [ -f ${HAPICFG_PATHFILENAME} ];
	then
		HAPICFG_LOADDRIVERS=$(
			grep "^${HAPICFG_HAPI_LOADDRIVERS_KEY}=" ${HAPICFG_PATHFILENAME} |
			sed "s/^${HAPICFG_HAPI_LOADDRIVERS_KEY}=//")
		if [ ! -z "${HAPICFG_LOADDRIVERS}" ];
		then
			# validate value
			case "${HAPICFG_LOADDRIVERS}" in
				${HAPICFG_HAPI_LOADDRIVERS_ACTIVE} | \
				${HAPICFG_HAPI_LOADDRIVERS_ALL} | \
				${HAPICFG_HAPI_LOADDRIVERS_BASEONLY} | \
				${HAPICFG_HAPI_LOADDRIVERS_SELECTED} | \
				${HAPICFG_HAPI_LOADDRIVERS_NONE})
					LOADDRIVERS="${HAPICFG_LOADDRIVERS}"
					;;

				*)
					echo "Ignoring invalid ${HAPICFG_HAPI_LOADDRIVERS_KEY} value in ${HAPICFG_PATHFILENAME}"
					;;
			esac
		fi
	fi

	case "${LOADDRIVERS}" in
		${HAPICFG_HAPI_LOADDRIVERS_ACTIVE})
			instsvcdrv_get_sys_type
			if [ ${ISVCDD_SYS_TYPE} != ${SYS_TYPE_IPMI} ];
			then
				ISVCDD_LIST="${ISVCDD_LIST} ${ISVCDD_DRIVER_NAME_BASE}"
			fi
			ISVCDD_LIST="${ISVCDD_LIST} ${ISVCDD_DRIVER_NAME_RBU}"
			;;

		${HAPICFG_HAPI_LOADDRIVERS_ALL})
			ISVCDD_LIST="${ISVCDD_DRIVER_NAME_BASE} ${ISVCDD_DRIVER_NAME_RBU}"
			;;

		${HAPICFG_HAPI_LOADDRIVERS_BASEONLY})
			ISVCDD_LIST="${ISVCDD_DRIVER_NAME_BASE}"
			;;

		${HAPICFG_HAPI_LOADDRIVERS_SELECTED})
			LOADDBAS=$(grep "^${HAPICFG_HAPI_LOADDBAS_KEY}=" ${HAPICFG_PATHFILENAME} |
				sed "s/^${HAPICFG_HAPI_LOADDBAS_KEY}=//")
			if [ "${LOADDBAS}" = "yes" ];
			then
				ISVCDD_LIST="${ISVCDD_LIST} ${ISVCDD_DRIVER_NAME_BASE}"
			fi
			LOADDRBU=$(grep "^${HAPICFG_HAPI_LOADDRBU_KEY}=" ${HAPICFG_PATHFILENAME} |
				sed "s/^${HAPICFG_HAPI_LOADDRBU_KEY}=//")
			if [ "${LOADDRBU}" = "yes" ];
			then
				ISVCDD_LIST="${ISVCDD_LIST} ${ISVCDD_DRIVER_NAME_RBU}"
			fi
			;;

		${HAPICFG_HAPI_LOADDRIVERS_NONE})
			;;
	esac

	if [ -z "${ISVCDD_LIST}" ];
	then
		echo "No drivers are selected for use in ${HAPICFG_PATHFILENAME}"
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_get_driver_list


###############################################################################
# Function:    instsvcdrv_set_driver_vars <driver module name>
# Description: Set variables for specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_set_driver_vars()
{
	ISVCDD_MODULE_NAME=$1
	ISVCDD_LOG_PFNAME="${OS_VARLOG_DIR}/${ISVCDD_MODULE_NAME}.log"
	ISVCDD_STATUSFILE_INSTALLED="${ISVCDD_STATUS_KERNEL_DIR}/${ISVCDD_MODULE_NAME}.installed"
	ISVCDD_BUILTIN_KERNEL=0

	case ${ISVCDD_MODULE_NAME} in
		${ISVCDD_DRIVER_NAME_BASE})
			ISVCDD_KERNEL_MODULE_SUBDIR="kernel/drivers/firmware"
			ISVCDD_KERNEL_MODULE_DIR="${OS_MODULES_DIR}/${RUNNING_KERNEL}/${ISVCDD_KERNEL_MODULE_SUBDIR}"
			ISVCDD_DEVICE_NAME="EsmUMBASDev"
			ISVCDD_LOADED_DIR_NAME="/sys/devices/platform/dcdbas"
			ISVCDD_LOADING_PFNAME=""
			;;

		${ISVCDD_DRIVER_NAME_RBU})
			ISVCDD_KERNEL_MODULE_SUBDIR="kernel/drivers/firmware"
			ISVCDD_KERNEL_MODULE_DIR="${OS_MODULES_DIR}/${RUNNING_KERNEL}/${ISVCDD_KERNEL_MODULE_SUBDIR}"
			ISVCDD_DEVICE_NAME=""
			ISVCDD_LOADED_DIR_NAME="/sys/devices/platform/dell_rbu"
			ISVCDD_LOADING_PFNAME="/sys/class/firmware/dell_rbu/loading"
			;;

		*)
			echo "instsvcdrv_set_driver_vars: invalid module name: ${ISVCDD_MODULE_NAME}"
			return ${STATUS_GENERIC_ERROR}
			;;
	esac

	if [ ! -z "${ISVCDD_DEVICE_NAME}" ];
	then
		ISVCDD_DEVICE_PFNAME_1="${OS_DEVICE_DIR}/${ISVCDD_DEVICE_NAME}"
		ISVCDD_DEVICE_PFNAME_2="${OS_DEVICE_DIR}/${ISVCDD_DEVICE_NAME}0"
	fi

	# check if driver is built into kernel
	if [ ! -z "${ISVCDD_LOADED_DIR_NAME}" ] &&
	   [   -d "${ISVCDD_LOADED_DIR_NAME}" ];
	then
		lsmod | grep -iq ${ISVCDD_MODULE_NAME}
		if [ $? != 0 ];
		then
			ISVCDD_BUILTIN_KERNEL=1
		fi
	fi

	if [ -z "${TARGET_KERNEL}" ];
	then
		TARGET_KERNEL=${RUNNING_KERNEL}
	fi

	LOC_VERSION=$(echo ${TARGET_KERNEL} | sed "s/\..*//")
	LOC_PATCHLEVEL=$(echo ${TARGET_KERNEL} | sed "s/.\.//" | sed "s/\..*//")

	if [ ${LOC_VERSION} -gt 2 ] ||
	   [ ${LOC_VERSION} -eq 2 -a ${LOC_PATCHLEVEL} -gt 4 ];
	then
		LOC_EXT="ko"
	else
		LOC_EXT="o"
	fi

	ISVCDD_BINARY_FILENAME="${ISVCDD_MODULE_NAME}.${LOC_EXT}"

	return ${STATUS_NO_ERROR}
} # instsvcdrv_set_driver_vars


###############################################################################
# Function:    instsvcdrv_install_driver <driver binary pathfilename>
# Description: Install device driver into kernel module directory
# Returns:     LSB status codes
###############################################################################
instsvcdrv_install_driver()
{
	local srcfile destfile

	srcfile=$1
	destfile=${ISVCDD_KERNEL_MODULE_DIR}/${ISVCDD_BINARY_FILENAME}

	if [ ! -f ${srcfile} ];
	then
		return ${STATUS_INVALID_ARG}
	fi

	if [ ! -d ${ISVCDD_KERNEL_MODULE_DIR} ];
	then
		mkdir -p ${ISVCDD_KERNEL_MODULE_DIR}
	fi

	cp -f ${srcfile} ${destfile}
	chgrp root ${destfile}
	chmod 744  ${destfile}
	depmod >/dev/null 2>&1

	modprobe ${ISVCDD_MODULE_NAME} >>${ISVCDD_LOG_PFNAME} 2>&1
	if [ $? != 0 ];
	then
		return ${STATUS_INSMOD_ERROR}
	fi

	# indicate this script installed driver
	touch ${ISVCDD_STATUSFILE_INSTALLED}

	return ${STATUS_NO_ERROR}
} # instsvcdrv_install_driver


###############################################################################
# Function:    instsvcdrv_load_driver <driver module name>
# Description: Load specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_load_driver()
{
	local status

	instsvcdrv_set_driver_vars $1
	status=$?
	if [ ${status} != ${STATUS_NO_ERROR} ];
	then
		return ${status}
	fi

	# Make sure device driver support files are cleaned up
	instsvcdrv_clean_driver

	# Create device driver load log file
	touch ${ISVCDD_LOG_PFNAME}
	chmod 600 ${ISVCDD_LOG_PFNAME}

	# Find device driver that works with running kernel
	ISVCDD_FOUND=0
	ISVCDD_DKS_COPY=0
	ISVCDD_INSTALLED=0

	# try loading any already-installed driver
	modprobe ${ISVCDD_MODULE_NAME} >>${ISVCDD_LOG_PFNAME} 2>&1
	if [ $? = 0 ];
	then
		ISVCDD_FOUND=1
	fi

	if [ ${ISVCDD_FOUND} = 0 ];
	then
		# check for match on kernel name in HAPI precompiled driver directory
		PFNAME="${ISVCDD_DRIVERS_DIR}/${RUNNING_KERNEL}/${ISVCDD_BINARY_FILENAME}"
		instsvcdrv_install_driver "${PFNAME}"
		if [ $? = ${STATUS_NO_ERROR} ];
		then
			ISVCDD_FOUND=1
		fi
	fi

	if [ ${ISVCDD_FOUND} = 0 ]
	then
		# get "kernel match" option value
		instsvcdrv_get_forcekernelmatch

		# check if exact kernel match needed
		if [ ${ISVCDD_FORCE_KERNEL_MATCH} = 0 ];
		then
			# get running kernel version without extraversion
			RUNNING_KVER=$(echo ${RUNNING_KERNEL} | sed "s/-.*//")

			# get running kernel config
			RUNNING_KCFG=""
			KCFG_LIST="EL ELsmp ELhugemem ELBOOT"
			for KCFG in ${KCFG_LIST};
			do
				echo ${RUNNING_KERNEL} | grep "${KCFG}$" >/dev/null
				if [ $? = 0 ];
				then
					RUNNING_KCFG=${KCFG}
					break
				fi
			done

			# check each subdirectory for precompiled device driver
			# that works with running kernel
			SUBDIR_LIST=$(ls ${ISVCDD_DRIVERS_DIR})
			for SUBDIR in ${SUBDIR_LIST};
			do
				# get subdir kernel version without extraversion
				SUBDIR_KVER=$(echo ${SUBDIR} | sed "s/-.*//")

				# skip subdirectory if kernel version doesn't match
				if [ ${SUBDIR_KVER} != ${RUNNING_KVER} ];
				then
					continue
				fi

				# skip subdirectory if kernel config doesn't match
				if [ ! -z "${RUNNING_KCFG}" ];
				then
					echo ${SUBDIR} | grep "${RUNNING_KCFG}$" >/dev/null
					if [ $? != 0 ];
					then
						continue
					fi
				fi

				# try to load precompiled device driver
				PFNAME="${ISVCDD_DRIVERS_DIR}/${SUBDIR}/${ISVCDD_BINARY_FILENAME}"
				instsvcdrv_install_driver "${PFNAME}"
				if [ $? = ${STATUS_NO_ERROR} ];
				then
					ISVCDD_FOUND=1
					break
				fi
			done
		fi
	fi

	if [ ${ISVCDD_FOUND} = 0 ];
	then
		# look for device driver copied by user to DKS copy directory

		# The procedure for using this directory is documented in the
		# Server Administrator User's Guide.  See section "Copying a
		# Dynamically Built Device Driver to Systems Running the Same Kernel".
		ISVCDD_DKS_USER_COPY_DIR="/var/omsa/dks/${RUNNING_KERNEL}"

		# try to load DKS copy device driver
		PFNAME="${ISVCDD_DKS_USER_COPY_DIR}/${ISVCDD_BINARY_FILENAME}"
		instsvcdrv_install_driver "${PFNAME}"
		if [ $? = ${STATUS_NO_ERROR} ];
		then
			ISVCDD_FOUND=1
			ISVCDD_DKS_COPY=1
		fi
	fi

	if [ ${ISVCDD_FOUND} = 0 ];
	then
		# build device driver using DKS
		echo -n "Building ${ISVCDD_MODULE_NAME} using DKS:"
		instsvcdrv_build_driver
		BUILD_STATUS=$?
		if [ ${BUILD_STATUS} = ${STATUS_NO_ERROR} ];
		then
			# device driver built OK
			instsvcdrv_supt_showsuccess ""
			MSG_BLD_OK="${ISVCDD_MODULE_NAME} device driver built for kernel ${RUNNING_KERNEL}"
			instsvcdrv_supt_logmessage "${MSG_BLD_OK}"

			# ISVCDD is set by instsvcdrv_build_driver on success
			instsvcdrv_install_driver "${ISVCDD}"
			if [ $? = ${STATUS_NO_ERROR} ];
			then
				ISVCDD_FOUND=1
			fi
		else
			# device driver build failed
			instsvcdrv_supt_showfailure ""

			MSG_BLD_FAIL="${ISVCDD_MODULE_NAME} device driver build failed for kernel ${RUNNING_KERNEL}."

			if [ ${BUILD_STATUS} = ${STATUS_NO_KERNEL_SOURCE} ];
			then
				# Kernel source not found
				MSG_FAILSRC="DKS failed to find kernel source at ${KERNEL_SOURCE_DIR}."
				MSG_NEEDSRC="DKS requires kernel source to build device drivers."

				# Display message
				echo ${MSG_FAILSRC}
				echo ${MSG_NEEDSRC}

				# Log message
				instsvcdrv_supt_logmessage "${MSG_BLD_FAIL} ${MSG_FAILSRC} ${MSG_NEEDSRC}"
			elif [ ${BUILD_STATUS} = ${STATUS_GCC_NOT_FOUND} ];
			then
				# gcc not found
				MSG_FAILGCC="DKS failed to find gcc."
				MSG_NEEDGCC="DKS requires gcc to build device drivers."

				# Display message
				echo ${MSG_FAILGCC}
				echo ${MSG_NEEDGCC}

				# Log message
				instsvcdrv_supt_logmessage "${MSG_BLD_FAIL} ${MSG_FAILGCC} ${MSG_NEEDGCC}"
			else
				# Build error
				MSG_CHKLOG="Check ${DKS_MODULE_BUILD_LOGFILE} for build error."

				# Display message
				echo ${MSG_CHKLOG}

				# Log message
				instsvcdrv_supt_logmessage "${MSG_BLD_FAIL} ${MSG_CHKLOG}"
			fi

			# DKS build failed
			return ${BUILD_STATUS}
		fi
	fi

	echo -n "Starting ${ISVCDD_MODULE_NAME}:"
	if [ ${ISVCDD_DKS_COPY} = 1 ];
	then
		echo -n " DKS User Copy"
	fi

	# Check if device driver loaded
	if [ ${ISVCDD_FOUND} = 0 ];
	then
		if [ -f ${ISVCDD_STATUSFILE_INSTALLED} ];
		then
			PFNAME=${ISVCDD_KERNEL_MODULE_DIR}/${ISVCDD_BINARY_FILENAME}
			rm -f ${PFNAME}
			rm -f ${ISVCDD_STATUSFILE_INSTALLED}
		fi

		# Device driver failed to load
		instsvcdrv_supt_showfailure ""

		MSG_DD_LOAD_FAILED="${ISVCDD_MODULE_NAME} device driver load failed for kernel ${RUNNING_KERNEL}."
		MSG_DD_SEE_ERRFILE="See ${ISVCDD_LOG_PFNAME} for output from modprobe."

		# Display messages
		echo ${MSG_DD_LOAD_FAILED}
		echo ${MSG_DD_SEE_ERRFILE}

		# Log messages
		LOGMSG="${MSG_DD_LOAD_FAILED} ${MSG_DD_SEE_ERRFILE}"
		instsvcdrv_supt_logmessage "${LOGMSG}"

		return ${STATUS_INSMOD_ERROR}
	fi

	# Make character special file for device driver if needed
	if [ ! -z "${ISVCDD_DEVICE_NAME}" ] &&
	   [ -z "${ISVCDD_LOADED_DIR_NAME}"  -o  ! -d "${ISVCDD_LOADED_DIR_NAME}" ];
	then
		TYPE="c"
		MAJOR=$(grep ${ISVCDD_MODULE_NAME} /proc/devices | awk "{print \$1}")
		MINOR="0"
		mknod ${ISVCDD_DEVICE_PFNAME_2} ${TYPE} ${MAJOR} ${MINOR} >>${ISVCDD_LOG_PFNAME} 2>&1
		if [ $? != 0 ];
		then
			# mknod failed
			instsvcdrv_supt_showfailure ""

			# Add mknod parameters to error file
			echo "" >>${ISVCDD_LOG_PFNAME} 2>&1
			echo "mknod parameters:" >>${ISVCDD_LOG_PFNAME} 2>&1
			echo "NAME:  ${ISVCDD_DEVICE_PFNAME_2}" >>${ISVCDD_LOG_PFNAME} 2>&1
			echo "TYPE:  ${TYPE}" >>${ISVCDD_LOG_PFNAME} 2>&1
			echo "MAJOR: ${MAJOR}" >>${ISVCDD_LOG_PFNAME} 2>&1
			echo "MINOR: ${MINOR}" >>${ISVCDD_LOG_PFNAME} 2>&1

			MSG_MKNOD_FAILED="mknod failed for ${ISVCDD_MODULE_NAME} device driver."
			MSG_DD_SEE_ERRFILE="See ${ISVCDD_LOG_PFNAME} for output from mknod."

			# Display messages
			echo ${MSG_MKNOD_FAILED}
			echo ${MSG_DD_SEE_ERRFILE}

			# Log messages
			LOGMSG="${MSG_MKNOD_FAILED} ${MSG_DD_SEE_ERRFILE}"
			instsvcdrv_supt_logmessage "${LOGMSG}"

			# Unload device driver
			modprobe -r ${ISVCDD_MODULE_NAME}

			return ${STATUS_GENERIC_ERROR}
		fi
		chgrp root ${ISVCDD_DEVICE_PFNAME_2}
		chmod 660  ${ISVCDD_DEVICE_PFNAME_2}
		ln -sf ${ISVCDD_DEVICE_PFNAME_2} ${ISVCDD_DEVICE_PFNAME_1}
	fi

	# Device driver loaded OK
	instsvcdrv_supt_showsuccess ""
	LOGMSG="${ISVCDD_MODULE_NAME} device driver loaded"
	instsvcdrv_supt_logmessage "${LOGMSG}"

	# Remove load log file on successful load
	rm -f ${ISVCDD_LOG_PFNAME}

	# Initialization being done; wait a second
	sleep 1s

	return ${STATUS_NO_ERROR}
} # instsvcdrv_load_driver


###############################################################################
# Function:    instsvcdrv_unload_driver <driver module name>
# Description: Unload specified device driver
# Returns:     LSB status codes
###############################################################################
instsvcdrv_unload_driver()
{
	local status

	instsvcdrv_set_driver_vars $1
	status=$?
	if [ ${status} != ${STATUS_NO_ERROR} ];
	then
		return ${status}
	fi

	echo -n "Stopping ${ISVCDD_MODULE_NAME}:"

	# check if driver has loading file
	if [ ! -z "${ISVCDD_LOADING_PFNAME}" ] &&
	   [   -f "${ISVCDD_LOADING_PFNAME}" ];
	then
		# tell driver it's being unloaded
		echo -1 >${ISVCDD_LOADING_PFNAME}
	fi

	# unload device driver
	modprobe -r ${ISVCDD_MODULE_NAME}
	if [ $? = 0 ];
	then
		instsvcdrv_supt_showsuccess ""
		LOGMSG="${ISVCDD_MODULE_NAME} device driver unloaded"
		instsvcdrv_supt_logmessage "${LOGMSG}"
	else
		instsvcdrv_supt_showfailure ""
		LOGMSG="${ISVCDD_MODULE_NAME} device driver unload failed for kernel ${RUNNING_KERNEL}"
		instsvcdrv_supt_logmessage "${LOGMSG}"
		return ${STATUS_RMMOD_ERROR}
	fi

	# clean up device driver support files
	instsvcdrv_clean_driver

	return ${STATUS_NO_ERROR}
} # instsvcdrv_unload_driver


###############################################################################
# Function:    instsvcdrv_clean_driver
# Description: Clean up device driver support files
# Returns:     LSB status codes
###############################################################################
instsvcdrv_clean_driver()
{
	if [ ! -z "${ISVCDD_DEVICE_NAME}" ];
	then
		rm -f ${ISVCDD_DEVICE_PFNAME_1}
		rm -f ${ISVCDD_DEVICE_PFNAME_2}
	fi

	rm -f ${ISVCDD_LOG_PFNAME}
} # instsvcdrv_clean_driver


###############################################################################
# Function:    instsvcdrv_build_driver
# Description: Use DKS to build specified device driver
# Returns:     LSB status codes
# NOTE:        Device driver to build is specified using environment variables.
###############################################################################
instsvcdrv_build_driver()
{
	# Set these variables if needed
	if [ -z "${TARGET_KERNEL}" ];
	then
		TARGET_KERNEL=${RUNNING_KERNEL}
	fi
	if [ -z "${KERNEL_SOURCE_DIR}" ];
	then
		KERNEL_SOURCE_DIR="${OS_MODULES_DIR}/${TARGET_KERNEL}/build"
	fi

	export TARGET_KERNEL
	KERNEL_GENERIC_VER=$(echo ${TARGET_KERNEL} | sed "s/-.*//")

	# Determine if target kernel is greater than 2.4 kernel
	KERNEL_VERSION=$(echo ${TARGET_KERNEL} | sed "s/\..*//")
	KERNEL_PATCHLEVEL=$(echo ${TARGET_KERNEL} | sed "s/.\.//" | sed "s/\..*//")
	if [ ${KERNEL_VERSION} -gt 2 ];
	then
		LOC_KERNEL_IS_GT_2_4=1
	elif [ ${KERNEL_VERSION} -eq 2 ] && [ ${KERNEL_PATCHLEVEL} -gt 4 ];
	then
		LOC_KERNEL_IS_GT_2_4=1
	else
		LOC_KERNEL_IS_GT_2_4=0
	fi

	# Set up DKS path variables
	DKS_INSTALL_BASE_DIR="${ISVCDD_DRIVERS_DIR}/dks"
	DKS_INSTALL_COMMON_DIR="${DKS_INSTALL_BASE_DIR}/common"
	DKS_INSTALL_MODULE_DIR="${DKS_INSTALL_BASE_DIR}/${ISVCDD_MODULE_NAME}"
	DKS_VARDATA_BASE_DIR="${ISVCDD_VARDATAPATH}/drivers/${ISVCDD_PROC_ARCH}/dks"
	DKS_VARDATA_BUILD_DIR="${DKS_VARDATA_BASE_DIR}/build"
	DKS_VARDATA_MODULE_DIR="${DKS_VARDATA_BUILD_DIR}/esm"
	DKS_VARDATA_CURRENT_VER_DIR="${DKS_VARDATA_BUILD_DIR}/${TARGET_KERNEL}"
	DKS_VARDATA_GENERIC_VER_DIR="${DKS_VARDATA_BUILD_DIR}/${KERNEL_GENERIC_VER}-generic"
	DKS_MODULE_BUILD_LOGFILE="${OS_VARLOG_DIR}/${ISVCDD_MODULE_NAME}.dks.log"

	# Check for gcc
	GCC_VER=$(gcc -dumpversion 2>/dev/null)
	if [ $? != 0 ];
	then
		return ${STATUS_GCC_NOT_FOUND}
	fi

	# Set pathfilename for device driver to be built by DKS
	ISVCDD="${DKS_VARDATA_MODULE_DIR}/${ISVCDD_BINARY_FILENAME}"

	# Make sure DKS build log file is cleaned up
	rm -f ${DKS_MODULE_BUILD_LOGFILE}
	touch ${DKS_MODULE_BUILD_LOGFILE}
	chmod 600 ${DKS_MODULE_BUILD_LOGFILE}

	echo "Building ${ISVCDD_MODULE_NAME}..." >>${DKS_MODULE_BUILD_LOGFILE}

	# Check for DKS files
    if [ ! -e "${DKS_INSTALL_BASE_DIR}" ];
	then
		echo "Following DKS source directory not found: ${DKS_INSTALL_BASE_DIR}" >>${DKS_MODULE_BUILD_LOGFILE}
		return ${STATUS_DKS_FILES_NOT_FOUND}
	fi

	# Check for kernel source
    if [ ! -e "${KERNEL_SOURCE_DIR}/include" ];
	then
		echo "Following kernal source directory not found: ${KERNEL_SOURCE_DIR}/include" >>${DKS_MODULE_BUILD_LOGFILE}
		return ${STATUS_NO_KERNEL_SOURCE}
	fi

	# Prepare DKS build directory
	if [ -d ${DKS_VARDATA_BUILD_DIR} ];
	then
		rm -rf ${DKS_VARDATA_BUILD_DIR}
	fi
	mkdir -p ${DKS_VARDATA_BUILD_DIR}
	mkdir -p ${DKS_VARDATA_MODULE_DIR}

	# Copy files to DKS build directory
	cp -fp ${DKS_INSTALL_MODULE_DIR}/*.c ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
	cp -fp ${DKS_INSTALL_MODULE_DIR}/*.h ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
	cp -fp ${DKS_INSTALL_MODULE_DIR}/*.mak ${DKS_VARDATA_MODULE_DIR}
	mv -f ${DKS_VARDATA_MODULE_DIR}/${ISVCDD_MODULE_NAME}.mak ${DKS_VARDATA_MODULE_DIR}/Makefile

	if [ ${LOC_KERNEL_IS_GT_2_4} = 0 ];
	then
		# Set up kernel current version directory in DKS variable data directory
		mkdir -p ${DKS_VARDATA_CURRENT_VER_DIR}
		ln -sf ${KERNEL_SOURCE_DIR}/include ${DKS_VARDATA_CURRENT_VER_DIR}

		# Set up kernel generic version directory in DKS variable data directory
		mkdir -p ${DKS_VARDATA_GENERIC_VER_DIR}
		ln -sf ${KERNEL_SOURCE_DIR}/arch ${DKS_VARDATA_GENERIC_VER_DIR}
		ln -sf ${KERNEL_SOURCE_DIR}/scripts ${DKS_VARDATA_GENERIC_VER_DIR}

		# Copy .config file or configs/* if necessary
		cd ${KERNEL_SOURCE_DIR}
		if [ -e .config ];
		then
			cp -f ${KERNEL_SOURCE_DIR}/.config ${DKS_VARDATA_CURRENT_VER_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
		else
			cp -rf configs/* ${DKS_VARDATA_CURRENT_VER_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
		fi
		if [ $? != 0 ];
		then
			echo "Kernel source not found" >>${DKS_MODULE_BUILD_LOGFILE}
			return ${STATUS_NO_KERNEL_SOURCE}
		fi

		# Copy DKS master makefile to DKS build directory
		cp -fp ${DKS_INSTALL_BASE_DIR}/Makefile ${DKS_VARDATA_BUILD_DIR}

		# Copy files to kernel generic version directory
		cp -fp ${DKS_INSTALL_COMMON_DIR}/Rules.make ${DKS_VARDATA_GENERIC_VER_DIR}
		cp -fp ${DKS_INSTALL_COMMON_DIR}/Makefile ${DKS_VARDATA_GENERIC_VER_DIR}

		# Copy kernel-specific source files to DKS build directory
		if [ -d ${DKS_INSTALL_MODULE_DIR}/kernel24 ];
		then
			cp -fp ${DKS_INSTALL_MODULE_DIR}/kernel24/*.c ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
			cp -fp ${DKS_INSTALL_MODULE_DIR}/kernel24/*.h ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
		fi

		# Change to directory with DKS master makefile
		cd ${DKS_VARDATA_BUILD_DIR}

		# Compile
		make KERNEL_IS_GT_2_4=${LOC_KERNEL_IS_GT_2_4} >>${DKS_MODULE_BUILD_LOGFILE} 2>&1
		MAKE_STATUS=$?
	else
		# Copy kernel-specific source files to DKS build directory
		if [ -d ${DKS_INSTALL_MODULE_DIR}/kernel26 ];
		then
			cp -fp ${DKS_INSTALL_MODULE_DIR}/kernel26/*.c ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
			cp -fp ${DKS_INSTALL_MODULE_DIR}/kernel26/*.h ${DKS_VARDATA_MODULE_DIR} 2>>${DKS_MODULE_BUILD_LOGFILE}
		fi

		# Change to DKS module build directory
		cd ${DKS_VARDATA_MODULE_DIR}

		# Compile
		make -C ${KERNEL_SOURCE_DIR} SUBDIRS=${PWD} KERNEL_IS_GT_2_4=${LOC_KERNEL_IS_GT_2_4} modules  >>${DKS_MODULE_BUILD_LOGFILE} 2>&1
		MAKE_STATUS=$?
	fi

	# Check compile status
	if [ ${MAKE_STATUS} != 0 ];
	then
		echo "${ISVCDD_MODULE_NAME} compile failed" >>${DKS_MODULE_BUILD_LOGFILE}
		return ${STATUS_DKS_COMPILE_ERROR}
	fi

	# Change to DKS module build directory
	cd ${DKS_VARDATA_MODULE_DIR}
	
	# Link
	make dkslink KERNEL_IS_GT_2_4=${LOC_KERNEL_IS_GT_2_4} >>${DKS_MODULE_BUILD_LOGFILE} 2>&1
	if [ $? != 0 ];
	then
		echo "${ISVCDD_MODULE_NAME} link failed" >>${DKS_MODULE_BUILD_LOGFILE}
		return ${STATUS_DKS_LINK_ERROR}
	fi
	if [ ! -f ${ISVCDD} ];
	then
		echo "${ISVCDD_MODULE_NAME} binary not found" >>${DKS_MODULE_BUILD_LOGFILE}
		return ${STATUS_DKS_LINK_ERROR}
	fi

	# Remove file on successful build
	rm -f ${DKS_MODULE_BUILD_LOGFILE}

	# Pathfilename to device driver built using DKS
	# returned via ISVCDD environment variable

	return ${STATUS_NO_ERROR}
} # instsvcdrv_build_driver


###############################################################################
# Function:    instsvcdrv_dks_cleanup
# Description: Perform DKS cleanup
# Returns:     LSB status codes
###############################################################################
instsvcdrv_dks_cleanup()
{
	DKS_VARDATA_BASE_DIR="${ISVCDD_VARDATAPATH}/drivers/${ISVCDD_PROC_ARCH}/dks"
	DKS_VARDATA_BUILD_DIR="${DKS_VARDATA_BASE_DIR}/build"

	# Remove DKS build directory
	if [ -d ${DKS_VARDATA_BUILD_DIR} ];
	then
		rm -rf ${DKS_VARDATA_BUILD_DIR}
	fi

	return ${STATUS_NO_ERROR}
} # instsvcdrv_dks_cleanup


###############################################################################
# Function:    instsvcdrv_supt_showsuccess <message>
# Description: Display service success message
# Returns:     none
###############################################################################
instsvcdrv_supt_showsuccess()
{
	local MSG="$1"

	if [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_LSB} ];
	then
		log_success_msg "${MSG}"
	elif [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_RH} ];
	then
		echo -n "${MSG}"
		echo_success
		echo
	else
		echo -n "${MSG}"
		echo -en \\033[45G
		echo "OK"
	fi
} # instsvcdrv_supt_showsuccess


###############################################################################
# Function:    instsvcdrv_supt_showfailure <message>
# Description: Display service failure message
# Returns:     none
###############################################################################
instsvcdrv_supt_showfailure()
{
	local MSG="$1"

	if [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_LSB} ];
	then
		log_failure_msg "${MSG}"
	elif [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_RH} ];
	then
		echo -n "${MSG}"
		echo_failure
		echo
	else
		echo -n "${MSG}"
		echo -en \\033[45G
		echo "FAILED"
	fi
} # instsvcdrv_supt_showfailure


###############################################################################
# Function:    instsvcdrv_supt_showwarning <message>
# Description: Display service warning message
# Returns:     none
###############################################################################
instsvcdrv_supt_showwarning()
{
	local MSG="$1"

	if [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_LSB} ];
	then
		log_warning_msg "${MSG}"
	elif [ ${OS_SCRIPT_FUNCTIONS} = ${OS_SCRIPT_FUNCTIONS_RH} ];
	then
		echo -n "${MSG}"
		echo_warning
		echo
	else
		echo -n "${MSG}"
		echo -en \\033[45G
		echo "WARNING"
	fi
} # instsvcdrv_supt_showwarning


###############################################################################
# Function:    instsvcdrv_supt_logmessage <message>
# Description: Log message to OS log
# Returns:     none
###############################################################################
instsvcdrv_supt_logmessage()
{
	logger -t "${ISVCDD_SCRIPT_NAME}" "$1"
} # instsvcdrv_supt_logmessage


###############################################################################
# Function:    instsvcdrv_supt_lock
# Description: Prevent execution of another command
# Returns:     none
###############################################################################
instsvcdrv_supt_lock()
{
	# If another command is executing, give it some time to finish
	SECS=0
	while [ -f ${ISVCDD_SCRIPT_LOCKFILE} ] && [ ${SECS} -lt 60 ];
	do
		sleep 1
		SECS=$((SECS + 1))
	done

	touch ${ISVCDD_SCRIPT_LOCKFILE}
} # instsvcdrv_supt_lock


###############################################################################
# Function:    instsvcdrv_supt_unlock
# Description: Allow execution of another command
# Returns:     none
###############################################################################
instsvcdrv_supt_unlock()
{
	rm -f ${ISVCDD_SCRIPT_LOCKFILE}
} # instsvcdrv_supt_unlock


###############################################################################
# Check command line parameter for action to perform
###############################################################################

case "$1" in
	start)
		# stop running users if openipmi is about to be started
		instsvcdrv_stop_users_before_start_openipmi
		# start service
		instsvcdrv_supt_lock
		instsvcdrv_start
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		# re-start previously running users
		if [ ${EXIT_STATUS} = ${STATUS_NO_ERROR} ];
		then
			# note: ignore exit code from instsvcdrv_start_users
			instsvcdrv_start_users
		fi
		;;

	stop)
		# stop service (and any users that are currently running)
		# note: ignore exit code from instsvcdrv_stop_users
		instsvcdrv_stop_users
		instsvcdrv_supt_lock
		instsvcdrv_stop
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		;;

	restart|force-reload)
		# restart service (and any users that are currently running)
		# note: ignore exit code from instsvcdrv_stop_users
		instsvcdrv_stop_users
		instsvcdrv_supt_lock
		instsvcdrv_stop
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		if [ ${EXIT_STATUS} = ${STATUS_NO_ERROR} ];
		then
			instsvcdrv_supt_lock
			instsvcdrv_start
			EXIT_STATUS=$?
			instsvcdrv_supt_unlock
			# note: ignore exit code from instsvcdrv_start_users
			instsvcdrv_start_users
		fi
		;;

	status)
		# print and return current status of service
		instsvcdrv_supt_lock
		instsvcdrv_status
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		;;

	status-quiet)
		# return current status of service
		instsvcdrv_supt_lock
		instsvcdrv_status_quiet
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		;;

	reload)
		# reload configuration
		echo "${ISVCDD_SCRIPT_NAME}: reload not supported"
		EXIT_STATUS=${STATUS_NOT_IMPLEMENTED}
		;;

	startusers)
		# start users of the service
		FORCE_START_USERS=1
		instsvcdrv_start_users
		EXIT_STATUS=$?
		;;

	stopusers)
		# stop users of the service
		instsvcdrv_stop_users
		EXIT_STATUS=$?
		;;

	restartall)
		# restart service and all users, regardless of whether users
		# are currently running or not
		# note: ignore exit code from instsvcdrv_stop_users
		instsvcdrv_stop_users
		instsvcdrv_supt_lock
		instsvcdrv_stop
		EXIT_STATUS=$?
		instsvcdrv_supt_unlock
		if [ ${EXIT_STATUS} = ${STATUS_NO_ERROR} ];
		then
			instsvcdrv_supt_lock
			instsvcdrv_start
			EXIT_STATUS=$?
			instsvcdrv_supt_unlock
			# force start of all users
			FORCE_START_USERS=1
			# note: ignore exit code from instsvcdrv_start_users
			instsvcdrv_start_users
		fi
		;;

	build)
		# build drivers
		shift
		instsvcdrv_build "$@"
		EXIT_STATUS=$?
		;;

	preupgrade)
		# prepare for upgrade
		instsvcdrv_preupgrade
		EXIT_STATUS=$?
		;;

	preuninstall)
		# prepare for uninstall
		instsvcdrv_preuninstall
		EXIT_STATUS=$?
		;;

	restart-forcekernelmatch)
		instsvcdrv_restart_forcekernelmatch
		EXIT_STATUS=$?
		;;

	*)
		echo "${ISVCDD_SCRIPT_NAME}: Invalid argument"
		echo "Usage: ${ISVCDD_SCRIPT_NAME} {start|stop|restart|force-reload|status|startusers|stopusers|restartall}"
		EXIT_STATUS=${STATUS_INVALID_ARG}
esac

exit ${EXIT_STATUS}


###############################################################################
# End Script
###############################################################################

