#!/bin/sh
#
### BEGIN INIT INFO
# Provides: opensafd
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Should-Start: 
# Should-Stop: 
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: Start and stop the OpenSAF node
# Description: Start and stop the OpenSAF node
### END INIT INFO

osafdirfile=/etc/opensaf/osafdir.conf
osafprog="opensafd"
osafprog_inprogress="opensafd_inprogress"

# Source LSB functions library
. /lib/lsb/init-functions

if [ ! -r $osafdirfile ]; then
	logger -t $osafprog "can't read $osafdirfile, exiting."
	exit 6
else
	. $osafdirfile
	. $pkgsysconfdir/nid.conf
fi

binary=$pkglibdir/$osafprog
lockfile=$lockdir/$osafprog
lockfile_inprogress=$lockdir/$osafprog_inprogress
amfnd_bin=$pkglibdir/osafamfnd
amfnd_pid=$pkgpiddir/osafamfnd.pid

MANAGE_TIPC=${OPENSAF_MANAGE_TIPC:-"yes"}
RETVAL=0
TERMTIMEOUT=${OPENSAF_TERMTIMEOUT:-60}

nodetype=$(cat $pkgsysconfdir/node_type)
nodeinitdotconf=$pkgsysconfdir/nodeinit.conf.$nodetype

osafversion=1
if [ $osafversion = "1" ] ; then
       osafversion=5.22.01
fi

osafcshash=@OSAF_LONG_GIT_REV@

unload_tipc() {

  	# Unload TIPC if already loaded
	if [ "$MANAGE_TIPC" = "yes" ] && grep tipc /proc/modules >/dev/null 2>&1; then
		modprobe -r tipc >/dev/null 2>&1
		if [ $? -eq 1 ]; then
			logger -t $osafprog "warning: TIPC module unloading failed"
		fi
	fi
}

check_tipc() {

	if [ "$MANAGE_TIPC" != "yes" ]; then
		return 0
	fi

	tipc=$(which tipc 2> /dev/null)
	tipc_config=$(which tipc-config 2> /dev/null)

	if ! [ -x "${tipc}" ] && ! [ -x "${tipc_config}" ]; then
		logger -s -t $osafprog "error: neither tipc nor tipc-config is available"
		exit 1
	fi

	unload_tipc
}

setup_env() {
	# The following lines if --enable-gcov is configured
	# If running in UML uncomment the next line
	# echo 100 >  /proc/sys/net/ipv4/igmp_max_memberships
	# gcov collecton is using multicast, to change default multicast group and multicast group:
	# IPv4:
	# export OPENSAF_GCOV_MULTICAST_GROUP="224.0.0.1"
	# IPv6:
	# export OPENSAF_GCOV_MULTICAST_GROUP="ff02::1"
	# export OPENSAF_GCOV_MULTICAST_PORT="4711"

	# Make sure this kernel has POSIX shared memory configured
	if [ ! -d /dev/shm ]; then
		logger -s -t $osafprog "POSIX shared memory (/dev/shm) not enabled, exiting."
		exit 6
	fi

	# /var/lock & /var/run could be tmpfs mounts and needs to be
	# recreated at each boot
	directories="$lockdir $pkgpiddir"
	for directory in $directories; do
		mkdir -p $directory
		if [ -n "$OPENSAF_GROUP" ]; then
			getent group $OPENSAF_GROUP > /dev/null && chgrp $OPENSAF_GROUP $directory
		fi
		if [ -n "$OPENSAF_USER" ]; then
			getent passwd $OPENSAF_USER > /dev/null && chown $OPENSAF_USER $directory
		fi
	done
}

clean_shm() {
	# Remove shared memory files created by OpenSAF
	find /dev/shm/. -maxdepth 1 -name 'opensaf_*' -exec rm -f {} \;
}

enable_coredump() {
	core_size="unlimited"
	core_pattern="/var/crash/opensaf/core_%t.%e.%p"

	if [ ! -d /var/crash/opensaf ]; then
		mkdir -p /var/crash/opensaf
	fi

	if [ `ulimit -c` = 0 ]; then
		ulimit -c $core_size
	fi
	echo $core_pattern > /proc/sys/kernel/core_pattern
}

final_clean() {
	# Loop throught all the OpenSAF LSB CLC-CLI scripts to clean staling pid/lock
	for cmd in `ls $pkgclcclidir/osaf-*`; do
		# skip dtm here to allow shutdown of other services (e.g. amfd)
		if [ "$cmd" != "$pkgclcclidir/osaf-dtm" ]; then
			$cmd stop >/dev/null 2>&1
		fi
	done

	if [ "$MDS_TRANSPORT" = "TIPC" ]; then
		unload_tipc
	else
		# stop dtm, now all dependent services should be stopped
		$pkgclcclidir/osaf-dtm stop >/dev/null 2>&1
		rm -f $pkglocalstatedir/osaf_dtm_intra_server
	fi

	clean_shm

	rm -f "$lockfile" "$NIDFIFO" "$pkglocalstatedir/node_id"
}

generate_nodeid() {
	CHASSIS_ID_FILE=$pkgsysconfdir/chassis_id
	SLOT_ID_FILE=$pkgsysconfdir/slot_id
	SUBSLOT_ID_FILE=$pkgsysconfdir/subslot_id
	CHASSIS_ID=2
	SUBSLOT_ID=15
	if test -f "$CHASSIS_ID_FILE"; then
		CHASSIS_ID=$(cat "$CHASSIS_ID_FILE")
		if [ "$CHASSIS_ID" -gt "16" ] || [ "$CHASSIS_ID" -lt "1" ]
		then
			echo "CHASSIS ID Should be in the range of 1 to 16"
			echo "Quitting......"
			exit 1
		fi
	fi
	if test -f "$SUBSLOT_ID_FILE"; then
		SUBSLOT_ID=$(cat "$SUBSLOT_ID_FILE")
		if [ "$SUBSLOT_ID" -gt "15" ] || [ "$SUBSLOT_ID" -lt "0" ]; then
			echo "SUBSLOT ID Should be in the range of 0 to 15"
			echo "Quitting......"
			exit 1
		fi
	fi
	if ! test -f "$SLOT_ID_FILE"; then
		return 0
	fi
	SLOT_ID=$(cat "$SLOT_ID_FILE")
	if [ "$SLOT_ID" -eq "0" ]; then
		return 0
	fi
	if [ "$SLOT_ID" -gt "4095" ] || [ "$SLOT_ID" -lt "1" ]
	then
		echo "SLOT ID Should be in the range of 1 to 4095"
		echo "Quitting......"
		exit 1
	fi
	printf "00%02x%02x%02x\n" $CHASSIS_ID $((SLOT_ID & 255)) $((SUBSLOT_ID ^ ((SLOT_ID >> 8) & 15) )) > $pkglocalstatedir/node_id
	chmod 744 $pkglocalstatedir/node_id
}

check_transport() {
	rm -f $pkglocalstatedir/osaf_dtm_intra_server
	if [ $MDS_TRANSPORT != "TCP" ] && [ $MDS_TRANSPORT != "TIPC" ]
	then
		export MDS_TRANSPORT=TCP
	fi

	if [ "$MDS_TRANSPORT" = "TIPC" ]; then
		# Transport TIPC
		check_tipc
	else
		# Transport TCP
		generate_nodeid
	fi
}

# Create a mutex for start/stop on the filesystem. Will use trap if available.
mutex_create() {
	timeout=10
	interval=2
	while [ $timeout -gt 0 ]; do
		if mkdir "$lockfile_inprogress"; then
			trap 'rmdir "$lockfile_inprogress"; exit $?' INT TERM EXIT 2> /dev/null
			return 0
		else
			# lockfile exist, try again until timeout
			if [ $timeout -eq 10 ]; then  # log only one time
				log_warning_msg "opensafd start/stop in progress. Waiting for lockfile to be removed"
				logger -t $osafprog "opensafd start/stop in progress. Waiting for lockfile to be removed"
			fi
			sleep $interval
			timeout=$((timeout-interval))
		fi
	done

	log_warning_msg "opensafd start/stop already in progress. Unable to continue"
	logger -t $osafprog "opensafd start/stop already in progress. Unable to continue"
	log_warning_msg "To forcefully start/stop OpenSAF remove $lockfile_inprogress"
	logger -t $osafprog "To forcefully start/stop OpenSAF remove $lockfile_inprogress"
	return 1
}

mutex_remove() {
	rmdir "$lockfile_inprogress" 2> /dev/null
	trap - INT TERM EXIT 2> /dev/null
}

start() {
	setup_env

	if ! mutex_create; then
		return 1
	fi

	export LD_LIBRARY_PATH=$pkglibdir:$LD_LIBRARY_PATH
        pidofproc -p $amfnd_pid $amfnd_bin > /dev/null 2>&1
	lsb_status=$?
	if [ $lsb_status -eq 0 ]; then
		RETVAL=0
		log_success_msg
		mutex_remove
		return $RETVAL
	fi

	rm -f $pkgpiddir/*
	rm -f $pkglogdir/nid.log

	[ -x $daemon ] || exit 5

	check_transport

	logger -t $osafprog "Starting OpenSAF Services($osafversion - $osafcshash) (Using $MDS_TRANSPORT)"

	# Comment/Uncomment if you want cores disabled/enabled
	#enable_coredump

	echo -n "Starting OpenSAF Services (Using $MDS_TRANSPORT):"
	start_daemon $binary $args
	RETVAL=$?
	if [ $RETVAL -eq 0 ]; then
		logger -t $osafprog "OpenSAF($osafversion - $osafcshash) services successfully started"
		touch $lockfile
		log_success_msg
	else
		final_clean
		log_failure_msg
		if [ $REBOOT_ON_FAIL_TIMEOUT -ne 0 ]; then
			logger -t $osafprog "Starting OpenSAF failed, rebooting..."
			sleep $REBOOT_ON_FAIL_TIMEOUT
			mutex_remove
			/sbin/reboot &
		else
			logger -t $osafprog "Starting OpenSAF failed"
		fi
	fi
	mutex_remove
	return $RETVAL
}

stop() {
	# flush all internal opensaf log messages into disk before stopping
	$bindir/osaflog --flush

	if ! mutex_create; then
		return 1
	fi

	logger -t $osafprog "Stopping OpenSAF Services"
	amfpid=`pidofproc -p $amfnd_pid $amfnd_bin`
	echo -n "Stopping OpenSAF Services: "
	if [ -n "$amfpid" ]; then
		kill $amfpid
		timeout=$TERMTIMEOUT
		while [ $timeout -gt 0 ]; do
			sleep 1
			[ -d /proc/$amfpid ] || break
			timeout=$((timeout-1))
		done
		[ -d /proc/$amfpid ] && RETVAL=1
		if [ $RETVAL -eq 1 ]; then
			logger -t $osafprog "amfnd has not yet exited, killing it forcibly."
			kill -9 $amfpid
		fi
	else
		pkill -9 osaf* >/dev/null 2>&1
	fi

	final_clean
	mutex_remove

	if [ $RETVAL -eq 0 ]; then
		logger -t $osafprog "OpenSAF services successfully stopped"
		log_success_msg
	else
		log_failure_msg
		# If AMF fails to terminate its components,
		# this system is out of control, reboot it now!
		if [ $REBOOT_ON_FAIL_TIMEOUT -ne 0 ]; then
			logger -t $osafprog "Stopping OpenSAF failed, rebooting..."
			sleep $REBOOT_ON_FAIL_TIMEOUT
			/sbin/shutdown -r now "OpenSAF termination failed (timeout)"
		else
			logger -t $osafprog "Stoping OpenSAF failed"
		fi
	fi
	return $RETVAL
}

restart() {
	stop
	start
}

tryrestart() {
	[ -e $lockfile ] && restart
	return 0
}

reload() {
	echo -n "Reloading $osafprog: "
	log_warning_msg
	logger -t $osafprog "reloading configuration is currently an unimplemented LSB feature"
	return 3
}

forcereload() {
	reload
	restart
	return 0
}

status() {
	amfpid=`pidofproc -p $amfnd_pid $amfnd_bin`
	if [ -n "$amfpid" ]; then
		amf-state siass ha
		RETVAL=$?
	else
		echo "The OpenSAF HA Framework is not running"
		RETVAL=3
	fi

	return $RETVAL
}

case "$1" in
  start)
	start
	RETVAL=$?
	;;
  stop)
	stop
	RETVAL=$?
	;;
  restart)
	restart
	RETVAL=$?
	;;
  try-restart|condrestart)
	tryrestart
	RETVAL=$?
	;;
  reload)
	reload
	RETVAL=$?
	;;
  force-reload)
	forcereload
	RETVAL=$?
	;;
  status)
	status
	RETVAL=$?
	;;
  *)
	echo "Usage: $0 {start|stop|restart|try-restart|reload|force-reload|status}"
	RETVAL=2
esac

exit $RETVAL
