#!/bin/bash
################################################################################
# Filename: ./src/base/include/qrm-functions
# 
# The contents of this file are subject to the Qlusters Public License
# Version 1.1 (the License); you may not use this file except in compliance
# with the License.
# You may obtain a copy of the License at
# http://www.openqrm.org/content/view/33/69/.
# 
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
# the specific language governing rights and limitations under the License.
# 
# The Original Code is openQRM.
# 
# The Initial Developer of the Original Code is Qlusters Corporation. Portions
# created by Qlusters Corporation are Copyright (C) 2003-2005. All Rights
# Reserved.
# 
# Contributor(s):
# 
# Description:
# 
# Comments:
################################################################################
# Qrm common functions
# 

export QRM_SERVER_BASE_DIR=${QRM_SERVER_BASE_DIR:-`readlink /etc/init.d/qrm-server | sed -e "s#/qrm/etc/init.d/qrm-server##g"`}
export QRM_SERVER_LOG_DIR=${QRM_SERVER_LOG_DIR:-$QRM_SERVER_BASE_DIR/qrm/logs}
export QRM_NODES_BASE_DIR=${QRM_NODES_BASE_DIR:-$QRM_SERVER_BASE_DIR}
export QRM_NODES_LOG_DIR=${QRM_NODES_LOG_DIR:-syslog}
export QRM_TEMP=${QRM_TEMP:-"/tmp"}
export WGET=/usr/bin/wget
export QSENSEDPORT=11121
export STATEPORT=3003
export PORT=8080
export QRM_BOOT_IMAGE_DIR=$QRM_SERVER_BASE_DIR/qrm/tftpboot/boot
export QRM_SERVER_HOOKS="$QRM_SERVER_BASE_DIR/qrm/sbin/qrm-hooks"
export QRM_DATABASE_USER=${QRM_DATABASE_USER:-root}
# CONFIGSERVER is only used for a location of a common qrm-nodes.conf file.
export CONFIGSERVER="10.100.0.101"

######################### common functions #########################

function qrm_error() {
	echo "ERROR: $@" 1>&2
}

function qrm_true_false() {
        if [ -n "$1" ] && echo "$1" | grep -qie '\(true\|^1\)'; then
                echo "true"
        else
                echo "false"
        fi
}


function qrm_log_convert_string_to_level() {
	case $1 in
		DEBUG)
			echo 1;
			;;
		INFO)
			echo 2;
			;;
		WARNING)
			echo 3;
			;;
		ERROR)
			echo 4;
			;;
		*)
			echo 2;
			;;
	esac
}

# global log initialization
QRM_LOG_THRESHOLD=`qrm_log_convert_string_to_level ${q_loglevel:-INFO}`
if [ -f $QRM_SERVER_BASE_DIR/qrm/include/qrm-server-functions ]; then
	QRM_LOG_FILE=${QRM_LOG_FILE:-"$QRM_SERVER_LOG_DIR/`basename $0`.log"}
else
	QRM_LOG_FILE=${QRM_LOG_FILE:-"$QRM_NODES_LOG_DIR/`basename $0`.log"}
fi


# function qlog()
# parameter 1 : log-level (INFO/DEBUG/WARNING/ERROR)
# parameter 2 : message to log
# logic : puts text to log in common QRM-logfile
function qlog() {
	if (( $# < 2 )); then
		return 6
	fi
	if [ `qrm_log_convert_string_to_level $1` -ge $QRM_LOG_THRESHOLD ]; then
		LOGNOW=`date +%Y"-"%m"-"%d" "%H":"%M":"%S`

		if [ -f $QRM_SERVER_BASE_DIR/qrm/include/qrm-server-functions ]; then
			# logging for the server
			if [ "$QRM_SERVER_LOG_DIR" == "syslog" ]; then
				# log to syslog
				logger "$LOGNOW ($$) - $1 - $2"
			else	
				# log to file
				QRM_LOG_DIR=`dirname $QRM_LOG_FILE`
				if [ ! -d "$QRM_LOG_DIR" ]; then
					mkdir -p $QRM_LOG_DIR;
				fi
				echo "$LOGNOW ($$) - $1 - $2" >> $QRM_LOG_FILE
			fi
		else
			# logging for nodes
			if [ "$QRM_NODES_LOG_DIR" == "syslog" ]; then
				# log to syslog
				logger "$LOGNOW ($$) - $1 - $2"
			else	
				# log to file
				QRM_LOG_DIR=`dirname $QRM_LOG_FILE`
				if [ ! -d "$QRM_LOG_DIR" ]; then
					mkdir -p $QRM_LOG_DIR;
				fi
				echo "$LOGNOW ($$) - $1 - $2" >> $QRM_LOG_FILE
			fi
		fi
	fi
}

function qinfo() {
	qlog INFO "$@"
}
function qdebug() {
	qlog DEBUG "$@"
}
function qwarning() {
	qlog WARNING "$@"
}
function qerror() {
	qlog ERROR "$@"
}
function qnotice() {
	qlog DEBUG "$@"
	echo "$@"
}



# validates user input
function qrm_validate_input() {
	NAME="$1"
	MAXLENGTH=100
	if [ -z "$NAME" ]; then
		qrm_error "Got empty string $NAME in user input"
		return 1
	fi
	if echo $NAME | grep [[:space:]] 1>/dev/null; then
		qrm_error "Found space character in string from user input. Please remove spaces!"
		return 1
	fi
	LEN=`expr length $NAME`
	if (( $LEN > $MAXLENGTH )); then
		qrm_error "Got too long input string from user input (maxlength=$MAXLENGTH)"
		return 1
	fi
	NAME=`echo ${NAME:0:$MAXLENGTH}`
	for (( LOOP=0; LOOP<$LEN; LOOP++ )); do
		TESTCHAR=`echo ${NAME:$LOOP:1}`
		if [ -z "$TESTCHAR" ]; then
			qrm_error "Got empty string from user"
			return 1
		elif ! echo $TESTCHAR | grep "[0-9A-Za-z]" 1>/dev/null; then
			if [ "$TESTCHAR" != "_" ] && [ "$TESTCHAR" != "-" ] && [ "$TESTCHAR" != "." ]; then
				qrm_error "Got bad character '$TESTCHAR' in string from user input. Please remove bad char!"
				return 1
			fi
		fi
	done
	return 0
}


# validates an ip-address
function qrm_validate_ipaddress() {
	IP_ADDRESS=$1
	if ! echo $IP_ADDRESS | grep ^[0-9].*\.[0-9].*\.[0-9].*\.[0-9]$ 1>/dev/null 2>&1; then
		qrm_error "Bad format for ip-address $IP_ADDRESS"
		return 1
	fi
	if echo $IP_ADDRESS | grep [:alpha:] 1>/dev/null 2>&1; then
		qrm_error "Characters detected in ip-address $IP_ADDRESS"
		return 1
	fi
	I1=`echo $IP_ADDRESS | cut -d'.' -f 1`
	I2=`echo $IP_ADDRESS | cut -d'.' -f 2`
	I3=`echo $IP_ADDRESS | cut -d'.' -f 3`
	I4=`echo $IP_ADDRESS | cut -d'.' -f 4`
	if [ -z "$I1" ] || [ -z "$I2" ] ||[ -z "$I3" ] ||[ -z "$I4" ]; then
		qrm_error "Bad format for ip-address $IP_ADDRESS"
		return 1
	fi
	if (( $I1 > 255 )) || (( $I2 > 255 )) || (( $I3 > 255 )) || (( $I4 > 255 )); then
		qrm_error "Bad format for ip-address $IP_ADDRESS"
		return 1
	fi
	if (( $I1 < 0 )) || (( $I2 < 0 )) || (( $I3 < 0 )) || (( $I4 < 0 )); then
		qrm_error "Bad format for ip-address $IP_ADDRESS"
		return 1
	fi
	return 0
}


# function to urlencode a character
function urlencodechar() {
	# notice : "%", "*" and "\" are not supported
	UCHAR=$1
	UCHAR=${UCHAR/\~/%7E}
	UCHAR=${UCHAR/\!/%21}
	UCHAR=${UCHAR/\@/%40}
	UCHAR=${UCHAR/\\#/%23}
	UCHAR=${UCHAR/\\$/%24}
	#UCHAR=${UCHAR/\%/%25}
	UCHAR=${UCHAR/\^/%5E}
	UCHAR=${UCHAR/\&/%26}
	#UCHAR=${UCHAR/\\*/%2A}
	UCHAR=${UCHAR/\(/%28}
	UCHAR=${UCHAR/\)/%29}
	UCHAR=${UCHAR/\+/%2B}
	UCHAR=${UCHAR/\|/%7C}
	UCHAR=${UCHAR/\{/%7B}
	UCHAR=${UCHAR/\}/%7D}
	UCHAR=${UCHAR/\:/%3A}
	UCHAR=${UCHAR/\"/%22}
	UCHAR=${UCHAR/\</%3C}
	UCHAR=${UCHAR/\>/%3E}
	UCHAR=${UCHAR/\\?/%3F}
	UCHAR=${UCHAR/\`/%60}
	UCHAR=${UCHAR/\=/%3D}
	#UCHAR=${UCHAR/\\/%5C}
	UCHAR=${UCHAR/\[/%5B}
	UCHAR=${UCHAR/\]/%5D}
	UCHAR=${UCHAR/\;/%3B}
	UCHAR=${UCHAR/\'/%27}
	UCHAR=${UCHAR/\,/%2C}
	UCHAR=${UCHAR/\//%2F}
	# whitespace
	if [ -z $UCHAR ]; then
	        UCHAR=%20
	fi
	echo "$UCHAR"
}


# function to urlencode a character
function urlencodestring() {
	USERINPUT=$@
	LENGTH=${#USERINPUT}
	for (( LOOP=0; LOOP<$LENGTH; LOOP++ )); do
		TESTCHAR=`echo ${USERINPUT:$LOOP:1}`
		TESTCHAR=`urlencodechar $TESTCHAR`
		echo -n $TESTCHAR
	done
}



# A more portable "chkconfig". 
# Uses chkconfig or rc.d-update as found, if not then "manual".
function qrm_chkconfig() {
	action="$1"
	service="$2"

	if [ $action != "add" ] && [ $action != "del" ] ; then
		echo "qrm_chkconfig: action must be either \"add\" or \"del\""
		return 1
	fi
	if [ -z "$service" ] ; then
		echo "qrm_chkconfig: service must be valid service name"
		return 1
	fi

	# For Redhat/SuSe
	if [ -x /sbin/chkconfig ] ; then
		if [ $action == "add" ] ; then
			chkconfig --add $service
			chkconfig $service on
		elif [ $action == "del" ] ; then
			chkconfig --del $service
		fi
	# For Debian
	elif [ -x /usr/sbin/update-rc.d ] ; then
		if [ $action == "add" ] ; then
			update-rc.d $service defaults 91
		elif [ $action == "del" ] ; then
			update-rc.d -f $service remove 1>/dev/null 2>&1
		fi
	# "Manual".  Uses S91 by default
	else
		# Get default runlevel
		runlevel=$( grep default /etc/inittab | grep ^id: | cut -f 2 -d: )

		# Find directory for script links
		if [ -d /etc/rc.d/ ] ; then
		        rcdir=/etc/rc.d/rc${runlevel}.d
		else
		        rcdir=/etc/rc${runlevel}.d
		fi

		if [ $action == "add" ] ; then 
			if [ ! -f $rcdir/S??${service} ] && [ -f /etc/init.d/$service ] ; then
			       ln -s /etc/init.d/$service $rcdir/S91${service}
			fi
		elif [ $action == "del" ] ; then
			if [ -f $rcdir/S??${service} ] ; then
			       rm $rcdir/S??${service}
			fi
		fi
	fi
	return 0
}




# converts bytes to mega-bytes
function qrm_bytes_to_mega() {
	echo $1 | awk '{printf("%.0f",  $1 /  1024/ 1024)}'
}


# logic : converts an ip + subnet to a node-id
function qrm_ip_to_id() {
	IPADDRESS=$1
	SUBNET=$2
	if [ $# != 2 ]; then
		exit 6
	fi
	I1=`echo $IPADDRESS | cut -d'.' -f 1`
	I2=`echo $IPADDRESS | cut -d'.' -f 2`
	I3=`echo $IPADDRESS | cut -d'.' -f 3`
	I4=`echo $IPADDRESS | cut -d'.' -f 4`
	N1=`echo $SUBNET | cut -d'.' -f 1`
	N2=`echo $SUBNET | cut -d'.' -f 2`
	N3=`echo $SUBNET | cut -d'.' -f 3`
	N4=`echo $SUBNET | cut -d'.' -f 4`
	IP_ID=$[($I1 << 24) | ($I2 << 16) |  ($I3  << 8) | $I4]
NET_ID=$[($N1 << 24) | ($N2 << 16) |  ($N3  << 8) | $N4]
	NODEID=$[~${NET_ID} & ${IP_ID}]
	echo $NODEID
	}

# calculates the network address
function qrm_util_ip_get_network() {
	local network=$1
	local subnet=$2
	eval "local " `ipcalc -n $network/$subnet`
	echo $NETWORK
}


function qrm_edit_inplace() {
	# todo: optionally backup file
	local IFS=
	local filename=$1
	local filename_tmp=$QRM_TEMP/`basename $filename`.tmp
	local expression=$2

	if ! [ -f $filename ]; then
		qrm_error "Unable to find file $filename for modification"
		return 1
	fi
	cat $filename | sed -e $expression > $filename_tmp
	if [ -s $filename_tmp ]; then
		if [ -x $filename ]; then
			chmod a+x $filename_tmp
		fi
		mv -f $filename_tmp $filename
	else
		qrm_error "Unable to modify file $filename"
	fi

}


function qrm_export_functions() {
	if [ ! -f $1 ]; then
		return 1
	fi
	for f_name in `grep ^function $1 | sed -e "s/function //" | sed -e "s/(.*//" | cut -d':' -f 2`; do
        	export -f $f_name
	done
}






# function returning a uniq string per linux distribution
function get_linux_distribution() {
	# find out which distribution it is
	# find out which version it is
	# optional set QRM_FILESYSTEM_IMAGE_ROOT_FS to check a mounted system
	if [ -f $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/redhat-release ]; then
		RELEASE=`cat $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/redhat-release | head -1`
		case $RELEASE in
			*Stentz*)
				echo "fedora_core4"
				;;
			*Nahant*)
				echo "redhat_enterprise4"
				;;
			*Shrike*)
				echo "redhat_90"
				;;
			*Psyche*)
				echo "redhat_80"
				;;
			*Valhalla*)
				echo "redhat_73"
				;;
			*Taroon*)
				echo "redhat_el3"
				;;
			*)
				echo "redhat"
				;;
		esac
	elif [ -f $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/SuSE-release ]; then
		RELEASE=`cat $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/SuSE-release | head -1`
		case $RELEASE in
			*9*)
				echo "suse_90"
				;;
			*10*)
				echo "suse_10"
				;;
			*)
				echo "suse"
				;;
		esac
	elif [ -f $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/UnitedLinux-release ]; then
		RELEASE=`cat $QRM_FILESYSTEM_IMAGE_ROOT_FS/etc/UnitedLinux-release | head -1`
		case $RELEASE in
			*8*)
				echo "suse_80"
				;;
			*)
				echo "suse"
				;;
		esac
	else
		echo "generic"
	fi

}


# function to check optional parameters in scripts
function check_optional_parameters() {
	local PARAM=$1
	local CONTENT=$2
	if [ -z "$CONTENT" ]; then
		echo "ERROR: Optional parameter $PARAM is set but has no content."
		exit 1
	fi
}



