#!/bin/sh
#
### BEGIN INIT INFO
# Provides: /opt/quest/qmxcm/sbin/qmxcmd
# Required-Start: $network questowcimomd
# Required-Stop: $network questowcimomd
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: /opt/quest/qmxcm/sbin/qmxcmd
#       Start/Stop the QMX for ConfigMgr Daemon
### END INIT INFO
#
#
# chkconfig: 2345 36 64
# description: QMX for ConfigMgr Daemon
# processname: qmxcmd

# Set the environment to some known safe values.
UMI_PREFIX=/opt/quest/umi
QMX_DEFAULT_LIB_PATH=/opt/quest/qmxcm/lib:${UMI_PREFIX}/lib:/lib:/usr/lib
PATH="/bin:/usr/bin:/usr/sbin"
SHLIB_PATH=$QMX_DEFAULT_LIB_PATH
LIBPATH=$QMX_DEFAULT_LIB_PATH
DYLD_LIBRARY_PATH=$QMX_DEFAULT_LIB_PATH
DYLD_FALLBACK_LIBRARY_PATH=$QMX_DEFAULT_LIB_PATH
LD_LIBRARY_PATH=$QMX_DEFAULT_LIB_PATH
LD_FLAGS=
LD_CONFIG=
LD_PRELOAD=
LD_LIBRARY_PATH_32=$QMX_DEFAULT_LIB_PATH
LD_FLAGS_32=
LD_CONFIG_32=
LD_PRELOAD_32=
LD_FLAGS_64=
LD_CONFIG_64=
LD_PRELOAD_64=

export PATH
export SHLIB_PATH
export LIBPATH
export DYLD_LIBRARY_PATH
export DYLD_FALLBACK_LIBRARY_PATH
export LD_LIBRARY_PATH
export LD_FLAGS
export LD_CONFIG
export LD_PRELOAD
export LD_LIBRARY_PATH_32
export LD_FLAGS_32
export LD_CONFIG_32
export LD_PRELOAD_32
export LD_FLAGS_64
export LD_CONFIG_64
export LD_PRELOAD_64


NAME=qmxcmd
VMX_INIT_SCRIPT=${NAME}_init
SBINDIR=/opt/quest/qmxcm/sbin
DAEMON=$SBINDIR/$NAME
OPTIONS=
# This value must match that of the product_tool_commands.  For compatibility
# reasons, this name cannot be changed when doing an upgrade.
REGISTERED_PRODUCT_NAME="qmxsms"
DESCRIPTIVE="QMX for ConfigMgr Daemon"
PRODUCT_ABBREV=QMXCM
PIDFILE=/var/opt/quest/qmxcm/logs/$NAME.pid
OSNAME=`uname | tr '[:lower:]' '[:upper:]'`
FUNCTION_FILE=
FUNCTION_FILE_REQUIRED=0
# HPUX uses this to say if the client should start.
RUN_QMXCM=1
# MacOSX uses this to say if the client should start.
QMXCM=-YES-
# The parameter to 'echo' that suppresses the newline.
ECHO_NO_NEWLINE=-n
OW_STATUS_RUNNING=0
USER=INVALID_USER
QUIET_OPT=0
STARTUP_DIR=`pwd`
DAEMON_DISABLING_FILE=/etc/opt/quest/qmxcm/QMXCM.nostartup
CIMOM_INIT_SCRIPT=${UMI_PREFIX}/sbin/quest-owcimomd_init

CheckRootUser()
{
	if [ -n "$EUID" -a "$EUID" != "0" ] || [ -n "$UID" -a "$UID" != "0" ]; then
		if id | grep 'uid=0' >/dev/null 2>/dev/null; then
			USER=root
		fi
	else
		USER=root
	fi
}

PathToExecutable()
{
	if [ $# -eq 1 ]; then
		PATH_TO_EXECUTABLE=
		if [ -f "/$1" ]; then
			PATH_TO_EXECUTABLE="`dirname \"/$1\"`"
		elif [ -f "./$1" ]; then
			PATH_TO_EXECUTABLE="$STARTUP_DIR/`dirname \"$1\"`"
		elif [ -f "$STARTUP_DIR/`dirname \"$1\"`/`basename \"$1\"`" ]; then
			PATH_TO_EXECUTABLE="$STARTUP_DIR/`dirname \"$1\"`"
		elif [ -f "`dirname \"$1\"`/`basename \"$1\"`" ]; then
			PATH_TO_EXECUTABLE="`dirname \"$1\"`"
		elif which "$1" >/dev/null 2>/dev/null; then
			temp="`which \"$1\"`"
			# which malfunctions on OSX, returning 0 when something was not found.
			# Verify the results.
			if [ -f "$temp" ]; then
				PATH_TO_EXECUTABLE="`dirname \"$temp\"`"
			fi
			unset temp
		fi
		if [ -n "$PATH_TO_EXECUTABLE" ]; then
			FULL_PATH_TO_EXECUTABLE="$PATH_TO_EXECUTABLE/`basename \"$1\"`"
			unset PATH_TO_EXECUTABLE
			if [ -f "$FULL_PATH_TO_EXECUTABLE" ] ; then
				echo $FULL_PATH_TO_EXECUTABLE
				unset FULL_PATH_TO_EXECUTABLE
				return 0
			fi
			unset FULL_PATH_TO_EXECUTABLE
		else
			unset PATH_TO_EXECUTABLE
		fi
	fi
	return 1
}

OW_GetPlatformSettings()
{
	case $OSNAME in
		LINUX)
			FUNCTION_FILE=/etc/rc.d/init.d/functions
			;;
		HP-UX)
			FUNCTION_FILE=/etc/rc.config.d/$NAME
			# The echo command on HPUX doesn't support -n.
			ECHO_NO_NEWLINE=
			;;
		DARWIN)
			FUNCTION_FILE=/etc/rc.common
			FUNCTION_FILE_REQUIRED=1
			;;
		AIX)
			# The echo command on AIX doesn't support -n.
			ECHO_NO_NEWLINE=
			;;
		SUNOS)
			# The echo command on Solaris doesn't support -n.
			ECHO_NO_NEWLINE=
			;;
		*)
			;;
	esac
}

DisplayOutput()
{
	if [ "$USER" = "root" ] && [ "x$OSNAME" = "xDARWIN" ]; then
		if [ $# -gt 0 ] && [ "x$1" = "x$ECHO_NO_NEWLINE" ]; then
			shift
		fi
		if [ -f "`which ConsoleMessage 2>/dev/null`" ]; then
			 ConsoleMessage "$@"
			 return 0
		fi
	fi
	echo "$@"
}

OW_FatalError()
{
	DisplayOutput "$@" >&2
	exit 1
}

OW_IsNumeric()
{
	if [ $# -lt 1 ]; then
		return 1
	fi
	for parameter in "$@"; do
		if [ "x$parameter" != "x" ]; then
			local_extracted_number=`echo "$parameter" | sed 's/[^0-9]//g'`
			if [ "x$local_extracted_number" != "x$parameter" ]; then
				return 1
			fi
		else
			return 1
		fi
	done
	return 0
}

# This function exists because some Linux platforms have added broken
# shells which cannot properly handle SIGnnnn names for signals.  This
# will try various forms of the named signal, trying to make one work.
OW_SendSignal()
{
	if [ $# -ne 2 ]; then
		echo "Incorrect number of arguments ($#).  Need a signal name and a PID" >&2
		return 1
	fi

	signal=$1
	pid_to_signal=$2

	if OW_IsNumeric "$pid_to_signal" && [ $pid_to_signal -gt 0 ]; then
		:
	else
		echo "Not sending $signal: Invalid pid specified: \"$pid_to_signal\"" >&2
		return 1
	fi

	signal_replacement_list=""

	case $signal in
		SIGTERM | TERM)
			signal_replacement_list="SIGTERM TERM 15"
			;;
		SIGKILL | KILL)
			signal_replacement_list="SIGKILL KILL 9"
			;;
		SIGHUP  | HUP)
			signal_replacement_list="SUGHUP HUP 1"
			;;
		[0-9] | [0-9][0-9])
			signal_replacement_list="$signal"
			;;
		*)
			OW_FatalError "Invalid signal: $signal"
			;;
	esac
	for new_signal in $signal_replacement_list; do
		if kill -$new_signal $pid_to_signal >/dev/null 2>&1; then
			return 0
		elif kill -s $new_signal $pid_to_signal >/dev/null 2>&1; then
			return 0
		fi
	done
	echo "Failed to send signal $signal to PID $pid_to_signal."
	return 1
}

OW_TestRunning()
{
	if OW_IsNumeric $1 && [ $1 -gt 0 ]; then
		if kill -0 $1 >/dev/null 2>&1; then
			return 0
		fi
	fi
	return 1
}

OW_DaemonEnabled()
{
	# If a nostartup file exists, we're disabled.
	if [ -f ${DAEMON_DISABLING_FILE} ]; then
		return 1
	fi
	if [ $RUN_QMXCM -ne 0 ] && [ "${QMXCM:=-NO-}" = "-YES-" ]; then
		return 0
	else
		return 1
	fi
}

# Run 'ps' using the various commandlines needed (displays all process IDs for $NAME).
OW_ExecutePS()
{
	correct_daemon_pattern="`echo \"$DAEMON\" | sed 's?/?[/]?g'`"
	correct_daemon_pattern="$correct_daemon_pattern[^_]"
	# special case for solaris 10 which has zones and ps will print processes from all the zones.
	if [ "$OSNAME" = "SUNOS" ] && [ `uname -r` = "5.10" ]; then
		if local_pids=`ps -z \`zonename\` -o pid,args 2>/dev/null | grep $correct_daemon_pattern | grep -v grep | awk '{ print $1; }'` ; then
			if [ -n "$local_pids" ]; then
				echo $local_pids
				return 0
			fi
		fi
		return 1
	fi

	# This works on:
	# (args) AIX, Solaris (<10), HPUX, Linux
	# (-ax,command) Linux, MacOSX
	for all_process_flag in "" -ax ; do
		for command_type in args command; do
			if UNIX95=1 ps $all_process_flag -eo pid,$command_type >/dev/null 2>&1; then
				# This product has the daemon name as a substring of the init
				# script name.  To avoid incorrect matches, we'll need to grep them
				# out.
				if local_pids=`UNIX95=1 ps $all_process_flag -eo pid,$command_type 2>/dev/null | grep $correct_daemon_pattern | grep -v grep | grep -v ${VMX_INIT_SCRIPT} | awk '{ print $1; }'` ; then
					if [ -n "$local_pids" ]; then
						echo $local_pids
						return 0
					fi
				fi
			fi
		done
	done
	return 1
}

# Run ps to determine if we are running.
OW_GetStatusFromPS()
{
	if OW_DaemonEnabled ; then
		startup_type=""
		enabled_text="enabled"
	else
		startup_type=" (manual startup)"
		enabled_text="disabled"
	fi

	if local_pids=`OW_ExecutePS 2>/dev/null`; then
		echo "$DESCRIPTIVE [$NAME] ($local_pids) is running${startup_type}."
		return 0
	else
		echo "$DESCRIPTIVE [$NAME] is $enabled_text and not running."
		return 3
	fi
}

# Use the PID file to determine if we are running.
OW_GetStatus()
{
	if OW_DaemonEnabled ; then
		startup_type=""
		enabled_text="enabled"
	else
		startup_type=" (manual startup)"
		enabled_text="disabled"
	fi

	if [ -s $PIDFILE ]; then
		PID=`cat $PIDFILE 2>/dev/null`
		if OW_TestRunning $PID ; then
			echo "$DESCRIPTIVE [$NAME] ($PID) is running${startup_type}."
			return 0
		else
			echo "$DESCRIPTIVE [$NAME] ($PID) is dead${startup_type}, but $PIDFILE exists."
			return 1
		fi
	else
		echo "$DESCRIPTIVE [$NAME] is $enabled_text and not running."
		return 3
	fi
}

OW_Status()
{
	quiet_status_checking=0
	if [ $# -gt 0 ] && [ "x$1" = "x--quiet" ]; then
		quiet_status_checking=1
	fi
	normal_status_text=`OW_GetStatus`
	normal_status=$?
	if [ $normal_status -eq 0 ]; then
		[ $quiet_status_checking = 1 ] || DisplayOutput "$normal_status_text"
		return $normal_status
	fi
	ps_status_text=`OW_GetStatusFromPS`
	ps_status=$?
	if [ $ps_status -eq 0 ]; then
		[ $quiet_status_checking = 1 ] || DisplayOutput "$ps_status_text"
		return $ps_status
	fi
	[ $quiet_status_checking = 1 ] || DisplayOutput "$normal_status_text"
	return $normal_status
}

OW_Start()
{
	if OW_DaemonEnabled ; then
		:
	else
		DisplayOutput "$DESCRIPTIVE is disabled: Refusing to start."
		return 1
	fi

	status_text=`OW_Status`
	status_code=$?
	if [ $status_code -eq 0 ] ; then
		DisplayOutput "Cannot start: $status_text"
		return 0
	fi
	if [ -f $PIDFILE ] ; then
		DisplayOutput "Stale $NAME pid file ($PIDFILE) found. Removing."
		rm -f $PIDFILE
	fi

	if ${CIMOM_INIT_SCRIPT} status >/dev/null 2>&1; then
		:
	else
		DisplayOutput "No CIMOM running.  Running ${CIMOM_INIT_SCRIPT}"
		${CIMOM_INIT_SCRIPT} start
	fi

	DisplayOutput $ECHO_NO_NEWLINE "Starting the $DESCRIPTIVE"
	$DAEMON $OPTIONS
	echo "."
	OW_Status
	return $?
}

OW_StopPIDS()
{
	for PID in "$@"; do
		for death_signal in TERM KILL; do
			# Wait for up to 5 minutes for the cimom to shut down...
			max_delay=300
			DisplayOutput "Sending $NAME ($PID) a $death_signal signal"
			DisplayOutput "This may take up to $max_delay seconds."
			OW_SendSignal $death_signal $PID
			# expr returns 1 (error) when the arguments evaluate to 0
			while max_delay=`expr $max_delay - 1`; do
				sleep 1
				if OW_Status --quiet ; then
					# Still running...
					:
				else
					return 0
				fi
			done
			if OW_Status --quiet ; then
				DisplayOutput "Signal $death_signal had no effect."
			else
				return 0
			fi
		done
	done
	if OW_Status --quiet ; then
		return 1
	else
		return 0
	fi
}

OW_Stop()
{
	status_text=`OW_Status`
	status_code=$?
	if [ $status_code -ne 0 ] ; then
		DisplayOutput "Cannot stop: $status_text"
		return 0
	fi

	# Stop daemons.
	DisplayOutput "Shutting down $DESCRIPTIVE..."
	if OW_Status --quiet ; then
		DisplayOutput "Stopping $NAME"

		if OW_StopPIDS `cat $PIDFILE 2>/dev/null` `OW_ExecutePS`; then
			DisplayOutput "$NAME is no longer running."
		else
			DisplayOutput "Could not stop $NAME"
			return 1
		fi
	else
		# Repeat the status message.
		DisplayOutput "Cannot stop: `OW_Status`"
		return 0
	fi

	if ${CIMOM_INIT_SCRIPT} status >/dev/null 2>&1; then
		if HaveOtherRegisteredProducts; then
			DisplayOutput "Not stopping the CIMOM: Other products are registered."
		else
			DisplayOutput "No other registered products using the CIMOM were detected.  Stopping it."
			${CIMOM_INIT_SCRIPT} stop
		fi
	fi
}

OW_Reload()
{
	if [ -r $PIDFILE ]; then
		PID=`cat $PIDFILE 2>/dev/null`
		if OW_TestRunning $PID; then
			DisplayOutput $ECHO_NO_NEWLINE "Reloading $DESCRIPTIVE"
			if OW_SendSignal HUP $PID; then
				sleep 3
				echo "."
				OW_Status
				return $?
			else
				DisplayOutput "Failed to send $DESCRIPTIVE a HUP signal"
				return 1
			fi
		fi
	fi
	if OW_Status --quiet; then
		PIDS=`OW_ExecutePS`
		if [ $? -eq 0 ]; then
			DisplayOutput $ECHO_NO_NEWLINE "Reloading $DESCRIPTIVE"
			failed_pids=""
			for pid in $PIDS; do
				if OW_SendSignal HUP $pid; then
					echo $ECHO_NO_NEWLINE "($pid)."
				else
					echo $ECHO_NO_NEWLINE "($pid)!"
					failed_pids="$failed_pids $pid"
				fi
			done
			echo "."
			if [ -n "$failed_pids" ]; then
				DisplayOutput "Failed to send HUP to $DESCRIPTIVE: $failed_pids"
				DisplayOutput "These may be threads that were terminated before the HUP could be sent."
			fi
			sleep 3
			OW_Status
			return $?
		else
			DisplayOutput "Cannot reload $DESCRIPTIVE: Failed to determine required PIDs."
			return 2
		fi
	else
		DisplayOutput "Cannot reload $DESCRIPTIVE: Not running"
		OW_Status --quiet
		return $?
	fi
}

HaveOtherRegisteredProducts()
{
	if ${UMI_PREFIX}/bin/product_tool --list-registered-products >/dev/null 2>&1; then
		registered_products=`${UMI_PREFIX}/bin/product_tool --list-registered-products | grep -v '^umi$' | grep -v "^${REGISTERED_PRODUCT_NAME}\$"`
		if [ "x${registered_products}" != x ]; then
			return 0
		fi
	fi
	return 1
}

# OSX (Darwin) Specific functions:
StartService()
{
	OW_Start
	return $?
}
StopService()
{
	OW_Stop
	return $?
}
RestartService()
{
	OW_Stop
	OW_Start
	return $?
}

OW_UsageError()
{
	OW_FatalError "Usage: `basename $0` {[re]start|stop|reload|force-reload|status}"
}

OW_Main()
{
	if [ $# -ne 1 ]; then
		# Exit with an error about usage.
		OW_UsageError
	fi
	# Set the current working directory
	cd /
	CheckRootUser
	if [ "$USER" = "root" ]; then
		:
	else
		DisplayOutput "This script must be run as root."
		exit 1
	fi

	[ -x $DAEMON ] || OW_FatalError "Daemon file \"$DAEMON\" not found for $DESCRIPTIVE."

	# The functions start, stop, and restart are supposed to be executed through
	# "RunService" on Darwin.
	if [ "x$OSNAME" = "xDARWIN" ]; then
		case "$1" in
			start | stop | restart)
				RunService "$1"
				return $?
				;;
			*)
				;;
		esac
	fi

	# This should *hopefully* be sufficient on every other platform (and for the
	# options not handled in the specific cases listed above (eg. Darwin).
	case "$1" in
		start)
			OW_Start
			return $?
			;;
		stop)
			OW_Stop
			return $?
			;;
		restart|force-reload)
			OW_Stop
			OW_Start
			return $?
			;;
		try-restart)
			if OW_Status >/dev/null 2>&1; then
				OW_Stop
				OW_Start
				return $?
			else
				OW_Status

				# LSB says that try-restart should return success if it is not running.
				return 0
			fi
			;;
		reload)
			OW_Reload
			return $?
			;;
		status)
			OW_Status
			return $?
			;;
		# {start,stop}_msg came from the HPUX init script.
		start_msg)
			DisplayOutput "Starting $DESCRIPTIVE"
			;;
		stop_msg)
			DisplayOutput "Terminating $DESCRIPTIVE"
			;;
		*)
			# Exit with an error about usage.
			OW_UsageError
			;;
	esac
	return 0
}

###############################################################################
# Stuff that must be done outside of main (sourcing other files, etc.).
###############################################################################
OW_GetPlatformSettings

# Source function library.
if [ -n "$FUNCTION_FILE" ] && [ -f $FUNCTION_FILE ]; then
	. $FUNCTION_FILE
fi

OW_Main "$@"
exit $?
