#!/bin/sh

# Commun function to all drbd script
# Copyright (C) 2000, Thomas Mangin <thomas.mangin@free.fr>
# This file is under the GPL licence
# Thank you to Dan Yocum, <yocum@linuxcare.com> for is help bug fixing

HOST=`hostname -s`
CONFIG="/etc/sysconfig/drbd"
STATE="/var/lib/drbd"

# Source function library.
# Some distributions don't have it, so test and act accordingly

if [ -f /etc/rc.d/init.d/functions ]; then
	result=`grep success /etc/rc.d/init.d/functions`
	if [ $? ]; then
		. /etc/rc.d/init.d/functions
		HAVE_SUCCESS=1
	fi
fi

# TODO/NOT TODO: A test for failure ??

if [ -z "$HAVE_SUCCESS" ]; then
	# Does not react exactly like the "functions" ones
	success() {
		echo -n [OK]\r
	}
	failure() {
		echo -n [FAILED]\r
	}
fi

failed()
{
	echo -n $*
	# This echo is here to allow the use of cut on the sentence with " "
	echo -n " "
	failure
	echo
}

succed()
{
	echo -n $*
	# This echo is here to allow the use of cut on the sentence with " "
	echo -n " "
	success
	echo
}

# action substitution
action()
{
	text=$1...
	#echo -n $1...
	# This echo is here to allow the use of cut on the sentence with " "
	#echo -n " "
	shift
	eval $*
	if [ $? -eq 0 ]; then
		succed $text
		return 0
	else
		failed $text
		return 1
	fi
}

# /proc analysis

# Check if the node is primary
# Param : The resource
# Return "1" or "0"
isPrimary()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep ":Primary/" | grep "^$NUMBER" | wc -l | cut -b7`
}

# Check if the other node is primary
# Param : The resource
# Return "1" or "0"
haveRemotePrimary()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep "/Primary" | grep "^$NUMBER" | wc -l | cut -b7`
}

# Check if the other node is slave
# Param : The resource
# Return "1" or "0"
haveRemoteSecondary()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep "/Secondary" | grep "^$NUMBER" | wc -l | cut -b7`
}

# Check if the node is in a connected state
# Param : The resource
# Return "1" or "0"
isConnected()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep "Connected" | grep "^$NUMBER" | wc -l | cut -b7`
}

# Check if the node is in the process of full syncing
# Param : The resource
# Return "1" or "0"
isSyncing()
{
        NUMBER=`echo $1 | cut -b5`
        return `cat /proc/drbd | grep "Syncing" | grep "^$NUMBER" | wc -l | cut -b7`
}


# Check if the node is a working slave
# Param : The resource
# Return "1" or "0"
isWorkingSecondary()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep "Connected" | grep "^$NUMBER" | grep "Secondary/" | wc -l | cut -b7`
}

# Check if the node is a working master
# Param : The resource
# Return "1" or "0"
isWorkingPrimary()
{
	NUMBER=`echo $1 | cut -b5`
	return `cat /proc/drbd | grep "Connected" | grep "^$NUMBER" | grep "Primary/" | wc -l | cut -b7`
}

# Boot state check/set

isMasterBoot()
{
	if [ $STATE/"$1"_master ]; then
		return 1
	else
		return 0
	fi
}

setMasterBoot()
{
	touch $STATE/"$1"_master
}

setSlaveBoot()
{
	rm -f $STATE/"$1"_master 2> /dev/null
}

# Usefull function ..

range()
{
	number=$1
	while [ "$number" -lt "$2" ]
	do
		echo -n "$number "
		number=`expr $number + 1`
	done
	echo
}

# Information grabbing

# set LOCAL_DEVICE : set environement value with the node configuration info
# $1 RESOURCE DIRECTORY
# $2 RESOURCE FILE
setLocal()
{
	# This setup the local configuration variable for the local computer

	. $1/$2

	LOCAL_DEVICE=""
	LOCAL_FSCK=""

	# This part of the code is N node safe

	HOST_NAMES=`grep _HOST $CONFIG/$2 | grep $HOST`
	LOCAL_NUMBER=`echo $HOST_NAMES | cut -f1 -d"_" | cut -f2 -d"E"`

	if [ "$LOCAL_NUMBER" = "" ]; then
		failed "The configuration file don't define this host"
		exit 1
	fi

	for LINE in `cat $1/$2 | sed -e"s/ /#/g" | grep -v "^#"`
	do
		# Look if a configuration line match our resource

		KEEP=`echo $LINE | grep -i ^node$LOCAL_NUMBER | wc -l`
		if [ "$KEEP" -eq 1 ]; then
		 	VALUE=`echo $LINE | sed -e"s/[nN][oO][dD][eE]$LOCAL_NUMBER/LOCAL/g" | sed -e"s/#/ /g"`
			eval $VALUE
		fi

		# Strip the GLOBAL_ part of the configuration variable name

		KEEP=`echo $LINE | grep -i global_ | wc -l`
		if [ "$KEEP" -eq 1 ]; then
			VALUE=`echo $LINE | sed -e"s/[gG][lL][oO][bB][aA][lL]_//g" | sed -e"s/#/ /g"`
			eval $VALUE
		fi
	done

	# TODO: In a configuration with more than two nodes, drdbsetup syntax
	# is not nice as you have several "REMOTE_IF" parameter to catch.

	# This part of the code is only working with TWO nodes

	for LINE in `cat $1/$2 | sed -e"s/ /#/g" | grep -v "^#"`
	do
		KEEP=`echo $LINE | grep "^[nN][oO][dD][eE]" | grep -v "^[nN][oO][dD][eE]$LOCAL_NUMBER" | grep "_IF" | wc -l`

		if [ "$KEEP" -eq 1 ]; then
			REMOTE_NUMBER=`echo $LINE | cut -f1 -d"_" | cut -f2 -d"E"`
			VALUE=`echo $LINE | sed -e"s/[nN][oO][dD][eE]$REMOTE_NUMBER/REMOTE/g" | sed -e"s/#/ /g"`
			eval $VALUE
		fi
	done
}

runForAll ()
{
	# Already Tested when $DEVICES set
	#if [ $NB_DEVICES -eq 0 ]; then
	#	failed "No configuration file present"
	#	exit 1
	#fi

	for DEVICE in $DEVICES; do
		for RUN in $*; do
			$0 $DEVICE $RUN
		done
	done
}

# Check if a environment value is set
# $1 Name
# $2 Value
have_env()
{
	if [ ! $2 ]; then
		echo "This script is not programmed to be used standalone"
		failed "$0 needs the environment value '$1'"
		exit 1
	fi
}


# Check the presence of a directory
# $* Directories to find
have_dir()
{
	for NAME in $*
	do
		if [ ! -d $NAME ]; then
			failed "$0 needs the configuration directory '$NAME'"
			exit 1
		fi
	done
}

# Check the presence of a file
# $* files check
have_file()
{
	for NAME in $*
	do
		if [ ! -f $NAME ]; then
			failed "$0 need the file '$NAME'"
			exit 1
		fi
	done
}

# Check the presence in the path of an application
# $* commands without path
have_command()
{
	for NAME in $*
	do
		if [ -z "`which $NAME 2>/dev/null`" ]; then
			failed "$0 needs the command '$NAME'"
			exit 1
		fi
	done
}

# Check the presence in the path of an application
# $* the device name
have_device()
{
	for NAME in $*
	do
		if [ ! -b $NAME ]; then
			failed "$0 needs the device '$NAME'"
			exit 1
		fi
	done
}

# Check for a file
# Installation integrity check

have_env HOST $HOST
have_env STATE $STATE
have_env CONFIG $CONFIG
have_env INSTALL $INSTALL

have_dir $CONFIG
have_dir $STATE
have_file $INSTALL/drbd_common
have_command drbdsetup fuser lsmod modprobe

# RETVAL will work as a "stuck bit" for any error. The construct
# RV=$?
# [ $RETVAL -eq 0 ] && RETVAL=$RV
# allows us to have it stuck at 1 when some error occur, even if
# subsequent operations don't fail. Using $RV prevents us from getting
# the exit value of [ ... ]. That was a dumb one... :)

RETVAL=0        # this means there were errors
RV=0            # this means there were errors in the current device

if [ "$2" != "" ]; then
	OPTION=$2
	RESOURCE=$1
else
	OPTION=$1
	RESOURCE=""
fi

pushd . > /dev/null
	cd $CONFIG
	DEVICES=`for I in \`seq 0 255\`; do if [ -e drbd$I ]; then ls drbd$I | sort 2>/dev/null; fi; done`
	#DEVICES=`ls drbd[0-9]* | sort 2>/dev/null`
popd > /dev/null


NB_DEVICES=`echo "$DEVICES" | wc -w`

if [ $NB_DEVICES -eq 0 ]; then
	failed "No configuration file present"
	exit 1
fi

