#! /bin/sh
#
# ident	"@(#)hasap_dbms.shi	1.5	99/10/18 SMI"
#
# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
# All rights reserved.
#

# Define msg. file name and location
TEXTDOMAIN=hasap_dbms;  export TEXTDOMAIN
TEXTDOMAINDIR=/opt/SUNWcluster/locale;  export TEXTDOMAINDIR

##############################################################################
# Initializations

#
# The DATA_SERVICE variable must be a non-empty string
# The DATA_SERVICE is the service for which the dependenies and timeouts will be modified
#
DATA_SERVICE="sap"


#
# The VALID_METHOD_NAMES are the names of the methods that are recognized by the clustering software.
#
VALID_METHOD_NAMES="START START_NET STOP STOP_NET FM_INIT FM_START FM_STOP FM_CHECK"
ALL_VALID_METHOD_NAMES="START START_NET STOP STOP_NET ABORT ABORT_NET FM_INIT FM_START FM_STOP FM_CHECK"


#
# MIN_METHOD_TIMEOUT is the minimum acceptable value for a method timeout in seconds
# MAX_METHOD_TIMEOUT is the maximum acceptable value for a method timeout in seconds
#
MIN_METHOD_TIMEOUT=30
MAX_METHOD_TIMEOUT=1800

#
# CCD Format strings for the methods/timeouts
#
DS_METHOD_PATH_fmt="ds_name:start_path:start_to:stop_path:stop_to:abort_path:abort_to"
DS_NM_PATH_fmt="ds_name:nm_start_path:nm_start_to:nm_stop_path:nm_stop_to:nm_abort_path:nm_abort_to"
DS_FM_PATH_fmt="ds_name:fm_init_path:fm_init_to:fm_start_path:fm_start_to:fm_stop_path:fm_stop_to:fm_check_path:fm_check_to"

#
# Info Strings -- printed with error messages
#
METH_TO_STRING="Method Timeout Information"
NETMETH_TO_STRING="Net Method Timeout Information"
FMMETH_TO_STRING="Fault Method Timeout Information"
DEP_STRING="Dependency List"


##############################################################################
# Utility Functions

#
# usage for the dependency and timeout setting tool
#
usage() {
	lmsg=`gettext "Usage: %s -d depends_on_svc[,depends_on_svc]..."`
	printf "${lmsg}\n" "$0"
	echo "       \c" 
	lmsg=`gettext "%s -r"`
	printf "${lmsg}\n" "$0"
	echo "       \c" 
	lmsg=`gettext "%s -t method=timeout[,method=timeout]..."`
	printf "${lmsg}\n" "$0"
	echo "       \c" 
	lmsg=`gettext "%s -f"`
	printf "${lmsg}\n" "$0"
	exit 2
}


#
# is_svc_registered <Data Service Name>
#
# Returns 0 if the service is registered
# Returns 1 if the service is not registered.
#
is_svc_registered() {
	if [ -z "${1}" ]; then
		return 1
	fi

	# haget may fail if some rows are missing from ccd
	# so this function was re-written to check the
	# DS_STATE field in the CCD to see if the 
	# service is registered.
	#
	# haget -f service_is_on -s "${1}" >/dev/null 2>&1
	# if [ $? -ne 0 ]; then
	#	return 1
	# fi

	check_row_in_ccd  "DS_STATE" "ds_name" "${1}"
	return $?
}

#
# is_svc_off <Data Service Name>
#
# Returns 0 if the service is off
# Returns 1 if the service is on
# Exits 2 if there was an error
#
is_svc_off() {
	if [ -z "${1}" ]; then
		return 2
	fi

	# haget may fail if some rows are missing from ccd
	# so this function was re-written to check the
	# DS_STATE field in the CCD to see if the 
	# service is registered.
	#
	# svc_off=`haget -f service_is_on -s "${1}" 2>/dev/null`
	# if [ $? -ne 0 ]; then
	# 	return 2
	# fi

	check_row_in_ccd  "DS_STATE" "ds_name:state" "${1}:0"
	if [ $? -eq 0 ]; then
		return 0
	fi

	check_row_in_ccd  "DS_STATE" "ds_name:state" "${1}:1"
	if [ $? -eq 0 ]; then
		return 1
	fi

	lmsg=`gettext "ERROR: Could not get on/off state of data service \"%s\". Make sure the data service is registered before running this command."`
	printf "${lmsg}\n" "$1"
	exit 2
}

#
# is_member <element> "<set>"
#
# The second argument should be quoted, as shown.
#
# Returns 0 if the element is in the set.
# Returns 1 if the element is not in the set.
#
is_member() {
	for set_elem in $2 ; do
		if [ "$1" = "$set_elem" ]; then
			return 0
		fi
	done
	return 1
}

#
# is_subset "<set1>" "<set2>"
#
# The arguments should be quoted, as shown.
# The arguments may be empty lists provided that they are quoted.
# Returns 0 for true, 1 for false, ala Unix programs.
#
is_subset() {
	for ISS_X in $1 ; do
		is_member $ISS_X "$2"
		if [ $? -ne 0 ]; then
			return 1
		fi
	done
	return 0
}

#
# get_loghosts_associated_with_ds <svc>
#
get_loghosts_associated_with_ds()
{
	if [ -z "${1}" ]; then
		lmsg=`gettext "Internal Error: get_loghosts_associated_with_ds requires non-null argument."`
		printf "${lmsg}\n"
		exit 1
	fi

	#
	# The following query had to be rewritten to circumvent hareg.
	# If rows are missing from the ccd, the query will fail.
	#
	#loghosts=`hareg -q ${1} -H 2>/dev/null`

	loghosts=`scccd -r 5 -w 1 ${CLUSTNAME} "LOGHOST_DS" query "dsname" "${1}" | cut -d: -f2`
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Could not get logical hosts for data service %s."`
		printf "${lmsg}\n" "$1"
		exit 1
	fi

	echo ${loghosts}
}

#
# get_dependencies_associated_with_ds <svc>
#
get_dependencies_associated_with_ds()
{
	if [ -z "${1}" ]; then
		lmsg=`gettext "Internal Error: get_dependencies_associated_with_ds requires non-null argument."`
		printf "${lmsg}\n"
		exit 1
	fi

	dsdeps=`scccd -r 5 -w 1 ${CLUSTNAME} "DS_DEPSVC_LIST" query "ds_name" "${1}" | cut -d: -f3 | tr ',' ' '`
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Could not get dependencies for data service %s."`
		printf "${lmsg}\n" "$1"
		exit 1
	fi

	echo ${dsdeps}
}

#
# will_create_circular_dependency <svc> <dependent_svcs> <level> <total_num_svcs>
#
# level is to prevent the recursion from going crazy
# total_num_svcs is the total number of registered svcs (passed as arg so we don't have to recompute it.)
#
# Returns 0 if making svc dependent on dependent_svcs will not create a circular dependency
# Returns 2 if usage/internal error
# Returns 3 if exceeded recursion level (already a circular dependency)
# Returns 4 if circular dependency would be created with new addition
#
will_create_circular_dependency()
{
	new_svc=$1
	dep_svcs=$2
	level=$3
	num_svcs=$4

	if [ -z "${new_svc}" ]; then
		return 2
	fi

	if [ -z "${level}" ]; then
		return 2
	fi

	if [ -z "${num_svcs}" ]; then
		return 2
	fi

	if [ "${level}" -gt "${num_svcs}" ]; then
		return 3
	fi

	next_level=`expr "${level}" + 1`

	# Base case -- Can't have circular dependency at leaf
	if [ -z "${dep_svcs}" ]; then
		return 0
	fi

	for dsvc in ${dep_svcs}
	do
		# Base case -- The new service would be circularly dependent on itself
		if [ "${dsvc}" = "${new_svc}" ]; then
			return 4
		fi

		# next_level_dep=`hareg -q "${dsvc}" -D 2>/dev/null`
		next_level_dep=`get_dependencies_associated_with_ds "${dsvc}" 2>/dev/null`
		if [ $? -ne 0 ]; then
			lmsg=`gettext "ERROR: Could not get dependent services for data service \"%s\""`
			printf "${lmsg}\n" "$dsvc"
			exit 2
		fi

		# Execute in subshell because of recursion
		( will_create_circular_dependency "${new_svc}" "${next_level_dep}" "${next_level}" "${num_svcs}" )

		res=$?		
		if [ $res -ne 0 ]; then
			return $res
		fi
	done

	# If we haven't found a circular dependency yet, then there isn't one
	return 0
}

#
# is_positive() -	is_positive string
#
#	Returns zero if the string is positive (0 returns true)
#
is_positive()
{
	echo $1 | egrep -e '^[0-9]+$' >/dev/null 2>&1
	return $?
}

#
# is_valid_timeout <number>
#
# This function will take a single parameter and check 
# to see:
#
# 1. its a numeric value
# 2. in the range of MIN_METHOD_TIMEOUT-MAX_METHOD_TIMEOUT
#
# Return 0 if valid
# Return 1 if not valid
#
is_valid_timeout()
{
        timeout_value_to_validate="${1}"

        if [ -z "${timeout_value_to_validate}" ]; then
		lmsg=`gettext "ERROR: The timeout value was omitted."`
		printf "${lmsg}\n"
		return 1
	fi

	is_positive ${timeout_value_to_validate}
        if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: %s is not a number."`
		printf "${lmsg}\n" "${timeout_value_to_validate}"
		return 1
	fi
	
        if [ ${timeout_value_to_validate} -lt $MIN_METHOD_TIMEOUT -o ${timeout_value_to_validate} -gt $MAX_METHOD_TIMEOUT ]; then
		#
		# value is out of range
		#
		lmsg=`gettext "ERROR: %s is not in the valid timeout range."`
		printf "${lmsg}\n" "${timeout_value_to_validate}"
		return 1
        fi

        return 0
}


#
# get_method_timeout_field <method name>
#
# The mehod name must be a member of VALID_METHOD_NAMES
#
get_method_timeout_field()
{
	case "$1" in
		START | START_NET | FM_INIT) echo "4" ;;
		STOP | STOP_NET | FM_START) echo "6" ;;
		FM_STOP | ABORT | ABORT_NET) echo "8" ;;
		FM_CHECK) echo "10" ;;
		*) return 1 ;;
	esac

	return 0
}

#
# get_method_header <method name>
#
# The mehod name must be a member of VALID_METHOD_NAMES
#
get_method_header()
{
	case "$1" in
		START | STOP | ABORT) echo "DS_METHOD_PATH" ;;
		START_NET | STOP_NET | ABORT_NET) echo "DS_NM_PATH" ;;
		FM_INIT | FM_START | FM_STOP | FM_CHECK) echo "DS_FM_PATH" ;;
		*) return 1 ;;
	esac

	return 0
}

#
# replace_field <string> <field> <new_value>
#
# Replaces the current value of the specified field with the
# specified new value.  The string must be colon delimited.
#
# A field number of 1 refers to the first field of the string.
#
replace_field()
{
	input_string=$1
	field_num=$2
	new_value=$3
	min_field=3  # We will never change the first or second field
  	field_num_minus_one=`expr ${field_num} - 1` 
  	field_num_plus_one=`expr ${field_num} + 1` 

	total_num_fields=`echo ${input_string} | nawk -F: '{ print NF }'`
	
	if [ "${field_num}" -gt "${total_num_fields}" ]; then
		output_string=""
	elif [ "${field_num}" -lt ${min_field} ]; then
		output_string=""
	elif [ "${field_num}" -eq "${total_num_fields}" ]; then
		output_string="`echo ${input_string}|cut -d: -f1-${field_num_minus_one}`:${new_value}"
	else 
		output_string="`echo ${input_string}|cut -d: -f1-${field_num_minus_one}`:${new_value}:`echo ${input_string}|cut -d: -f${field_num_plus_one}-${total_num_fields}`"
	fi

	echo ${output_string}
	return 0
}

#
# shift_by_one_field <string>
#
# Prints the string without the first field and delimiter
# The string must be colon delimited.
#
shift_by_one_field()
{
	input_string=$1
	total_num_fields=`echo ${input_string} | nawk -F: '{ print NF }'`

	if [ "${total_num_fields}" -le 1 ]; then
		output_string=""
	else
		output_string="`echo ${input_string}|cut -d: -f2-${total_num_fields}`"
	fi

	echo ${output_string}
	return 0
}

#
# form_default_method <ds>
#
form_default_method()
{
	ds=$1
	if [ -z "${ds}" ]; then
		lmsg=`gettext "Internal Error: Data service name must be non-null to form_default_method."`
		printf "${lmsg}\n"
		exit 1
	fi

	start_to=`get_sun_field 7`
	stop_to=`get_sun_field 8`
	abort_to=15
	methstring="DS_METHOD_PATH:${ds}:${DS_BASEDIR}${ds}_svc_start:${start_to}:${DS_BASEDIR}${ds}_svc_stop:${stop_to}:${DS_BASEDIR}${ds}_svc_abort:${abort_to}"

	echo ${methstring}
	return 0
}

#
# form_default_net_method <ds>
#
form_default_net_method()
{
	ds=$1
	if [ -z "${ds}" ]; then
		lmsg=`gettext "Internal Error: Data service name must be non-null to form_default_net_method."`
		printf "${lmsg}\n"
		exit 1
	fi

	startnet_to=`get_sun_field 10`
	stopnet_to=`get_sun_field 11`
	abortnet_to=15
	netmethstring="DS_NM_PATH:${ds}:${DS_BASEDIR}${ds}_svc_start_net:${startnet_to}:${DS_BASEDIR}${ds}_svc_stop_net:${stopnet_to}:${DS_BASEDIR}${ds}_svc_abort_net:${abortnet_to}"

	echo ${netmethstring}
	return 0
}

#
# form_default_fm_method <ds>
#
form_default_fm_method()
{
	ds=$1
	if [ -z "${ds}" ]; then
		lmsg=`gettext "Internal Error: Data service name must be non-null to form_default_fm_method."`
		printf "${lmsg}\n"
		exit 1
	fi

	fminit_to=`get_sun_field 13`
	fmstart_to=`get_sun_field 14`
	fmstop_to=`get_sun_field 15`
	fmcheck_to=`get_sun_field 16`
	fmmethstring="DS_FM_PATH:${ds}:${DS_BASEDIR}${ds}_fm_init:${fminit_to}:${DS_BASEDIR}${ds}_fm_start:${fmstart_to}:${DS_BASEDIR}${ds}_fm_stop:${fmstop_to}:${DS_BASEDIR}${ds}_fm_check:${fmcheck_to}"

	echo ${fmmethstring}
	return 0
}

#
# get_sun_field <field num>
#
get_sun_field()
{
	if [ -z "$1" ]; then
		return 2
	fi
	
	field=`echo ${DS_SUN_ROW} | cut -d: -f${1}`

	echo ${field}
	return 0
}

#
# get_sun_supplied_ds_row <ds>
#
# print DS_SUN row
#
get_sun_supplied_ds_row()
{
	if [ -z "$1" ]; then
		return 2
	fi

	query_row=`scccd ${CLUSTNAME} "DS_SUN" query "ds_name" "$1"`
	echo "${query_row}"

	return 0
}

#
# get_ds_basedir <ds>
#
# print base dir
#
get_ds_basedir()
{
	if [ -z "$1" ]; then
		return 2
	fi

	query_row=`scccd ${CLUSTNAME} "DS_INFO" query "ds_name" "$1" | cut -d: -f6`
	echo "${query_row}"

	return 0
}

#
# check_row_in_ccd
#
check_row_in_ccd()
{
	CCD_PRIMARY_KEY=$1
	CCD_COLUMN=$2
	CCD_VALUE=$3

	#
	# query for the row in the ccd
	# 
	query_row=`scccd -r 5 -w 1 ${CLUSTNAME} "$CCD_PRIMARY_KEY" query "$CCD_COLUMN" "$CCD_VALUE"`
	if [ -n "${query_row}" ]; then
		return 0
	else
		return 1
	fi
}

#
# add_ccd_row
#
add_ccd_row()
{
	CCD_PRIMARY_KEY=$1
	CCD_COLUMN=$2
	CCD_VALUE=$3
	USER_ROW_NAME=$4

	#
	# add the row from the ccd
	# 
	scccd -r 5 -w 1 ${CLUSTNAME} "$CCD_PRIMARY_KEY" add "$CCD_COLUMN" "$CCD_VALUE" >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Could not add the %s. Try running this command again later."`
		printf "${lmsg}\n" "${USER_ROW_NAME}"
		exit 1
	fi

	return 0
}

#
# remove_ccd_row
#
remove_ccd_row()
{
	CCD_PRIMARY_KEY=$1
	CCD_COLUMN=$2
	CCD_VALUE=$3
	USER_ROW_NAME=$4

	#
	# remove the row from the ccd
	# 
	scccd ${CLUSTNAME} "$CCD_PRIMARY_KEY" remove "$CCD_COLUMN" "$CCD_VALUE" >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Could not update the %s. Try running this command again later."`
		printf "${lmsg}\n" "${USER_ROW_NAME}"
		exit 1
	fi

	return 0
}

#
# verify_ccd_row_added
#
verify_ccd_row_added()
{
	CCD_PRIMARY_KEY=$1
	CCD_COLUMN=$2
	CCD_VALUE=$3
	USER_ROW_NAME=$4

	#
	# query for the row in the ccd
	# 
	check_row_in_ccd "$CCD_PRIMARY_KEY" "$CCD_COLUMN" "$CCD_VALUE" >/dev/null 2>&1
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Failed to add the %s. Try running this command again later."`
		printf "${lmsg}\n" "${USER_ROW_NAME}"
		exit 1
	fi

	return 0
}

#
# verify_ccd_row_removed
#
verify_ccd_row_removed()
{
	CCD_PRIMARY_KEY=$1
	CCD_COLUMN=$2
	CCD_VALUE=$3
	USER_ROW_NAME=$4

	#
	# query for the row in the ccd
	# 
	check_row_in_ccd "$CCD_PRIMARY_KEY" "$CCD_COLUMN" "$CCD_VALUE" >/dev/null 2>&1
	if [ $? -eq 0 ]; then
		lmsg=`gettext "ERROR: Failed to remove the %s. Try running this command again later."`
		printf "${lmsg}\n" "${USER_ROW_NAME}"
		exit 1
	fi

	return 0
}

##############################################################################
# Main Code Section


#
# initialization
#
rem_dep="n"
set_dep="n"
set_timeouts="n"
set_default_timeouts="n"
set_dsname="n"
dep_svc_list=
method_timeout_list=
method_modified=n
nm_modified=n
fm_modified=n

#
# trap signals
#
trap "" 1 2 3 15 24

#
# read command line arguments
#
while getopts rfd:t:s: flag
do
	case $flag in
		r) 
			rem_dep="y" 
			;;
		d) 
			if [ "${set_dep}" = "n" ]; then
				dep_svc_list=$OPTARG 
				set_dep="y"
			else
				lmsg=`gettext "%s: cannot specify the -%s option twice"`
				printf "${lmsg}\n" "$0" "${flag}"
				usage
			fi
			;;
		t) 
			if [ "${set_timeouts}" = "n" ]; then
				method_timeout_list=$OPTARG 
				set_timeouts="y"
			else
				lmsg=`gettext "%s: cannot specify the -%s option twice"`
				printf "${lmsg}\n" "$0" "${flag}"
				usage
			fi
			;;
		f)
			if [ "${set_default_timeouts}" = "n" ]; then
				set_default_timeouts="y"
			else
				lmsg=`gettext "%s: cannot specify the -%s option twice"`
				printf "${lmsg}\n" "$0" "${flag}"
				usage
			fi
			;;
		s)
			if [ "${set_dsname}" = "n" ]; then
				DATA_SERVICE=$OPTARG 
				set_dsname="y"
			else
				lmsg=`gettext "%s: cannot specify the -%s option twice"`
				printf "${lmsg}\n" "$0" "${flag}"
				usage
			fi	
			;;
		\?) 
			usage
			;;
	esac
done
shift `expr $OPTIND - 1`

#
# Check that no extra arguments were given
#
if [ $# -ne 0 ]; then
	lmsg=`gettext "%s: extra argument found"`
	printf "${lmsg}\n" "$0"
	usage
fi

#
# Check that either dependecies will be set or removed, or that we are changing timeouts.
#
if [ "${set_dep}" = "n" -a  "${set_timeouts}" = "n" -a  "${rem_dep}" = "n" -a "${set_default_timeouts}" = "n" ]; then
	lmsg=`gettext "%s: must specify the -t, -f, -d, or -r option"`
	printf "${lmsg}\n" "$0"
	usage
	
fi

##############################################################################
# Check Cluster State -- node must be in the cluster to run this command

#
# Get the Cluster name
#
CLUSTNAME=`head -1 /etc/opt/SUNWcluster/conf/default_clustername 2>/dev/null`
if [ -z "${CLUSTNAME}" ]; then
	lmsg=`gettext "ERROR: Unable to get cluster name from this node."`
	printf "${lmsg}\n"
	exit 1
fi

#
# Check that this node is in the cluster
#
CLUSTM=/opt/SUNWcluster/bin/clustm

THIS_NODE=`${CLUSTM} getlocalnodeid ${CLUSTNAME} 2>/dev/null` 
if [ $? -ne 0 ]; then
	lmsg=`gettext "ERROR: Could not get node id to check status."`
	printf "${lmsg}\n"
	lmsg=`gettext "       The node on which this command is run must be a member of the cluster."`
	printf "${lmsg}\n"
	exit 1
fi

NODE_ACTIVE=`${CLUSTM} ismember ${CLUSTNAME} ${THIS_NODE} 2>/dev/null`
if [ $? -ne 0 ]; then
	lmsg=`gettext "ERROR: Could not get node status for this node."`
	printf "${lmsg}\n"
	lmsg=`gettext "       The node on which this command is run must be a member of the cluster."`
	printf "${lmsg}\n"
	exit 1
fi

if [ "${NODE_ACTIVE}" -ne 1 ]; then
	# Node is not active
	lmsg=`gettext "ERROR: This node is not part of the cluster so cannot set dependencies and timeouts."`
	printf "${lmsg}\n"
	lmsg=`gettext "       Node must be in the cluster to run this command."`
	printf "${lmsg}\n"
	exit 1
fi

#
# Check that the cluster is not in the middle of a reconfiguration
#
CLUST_STATE=`${CLUSTM} getstate ${CLUSTNAME} 2>/dev/null`
if [ "${CLUST_STATE}" != "end" ]; then
	lmsg=`gettext "ERROR: This cluster is in the middle of a reconfiguration."`
	printf "${lmsg}\n"
	lmsg=`gettext "       Please run this command after the cluster has finished its reconfiguration."`
	printf "${lmsg}\n"
	exit 1
fi


##############################################################################
# Check the Data Service State -- Data Service must be registered but not on

#
# Make sure the DATA_SERVICE variable is set
#
if [ -z "${DATA_SERVICE}" ]; then
	lmsg=`gettext "ERROR: The DATA_SERVICE variable was not set correctly"`
	printf "${lmsg}\n"
	exit 1
fi

#
# Make sure the DATA_SERVICE is a Sun Supplied data service that is installed
#
DS_SUN_ROW=`get_sun_supplied_ds_row "${DATA_SERVICE}"`
if [ -z "${DS_SUN_ROW}" ]; then
	lmsg=`gettext "ERROR: This command can only be used for a Sun supplied data service. That service must be registered but not on."`
	printf "${lmsg}\n"
	exit 1
fi

# 
# Make sure the DATA_SERVICE is registered
#
is_svc_registered "${DATA_SERVICE}"
if [ $? -ne 0 ]; then
	lmsg=`gettext "ERROR: Please register the \"%s\" data service before running this command"`
	printf "${lmsg}\n" "${DATA_SERVICE}"
	exit 1
fi

# 
# Make sure the DATA_SERVICE is not on
#
is_svc_off "${DATA_SERVICE}"
if [ $? -ne 0 ]; then
	lmsg=`gettext "ERROR: Please turn off the \"%s\" data service before running this command"`
	printf "${lmsg}\n" "${DATA_SERVICE}"
	exit 1
fi

#
# Make sure the DATA_SERVICE has its base dir
#
DS_BASEDIR=`get_ds_basedir "${DATA_SERVICE}"`
if [ -z "${DS_BASEDIR}" ]; then
	lmsg=`gettext "ERROR: The data service \"%s\" does not have its base directory set correctly in the DS_INFO row in the CCD. Try unregistering and re-registering it before running this command again."`
	printf "${lmsg}\n" "${DATA_SERVICE}"
	exit 1
fi


##############################################################################
# Remove the dependency if the -r flag was given

if [ "${rem_dep}" = "y" ]; then
	if [ "${set_dep}" = "n" -a "${set_timeouts}" = "n" -a "${set_default_timeouts}" = "n" ]; then

		#
		# Update the CCD to remove the dependencies
		#
		remove_ccd_row "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"
		verify_ccd_row_removed "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"
		add_ccd_row "DS_DEPSVC_LIST" "ds_name:service_list" "${DATA_SERVICE}:" "${DEP_STRING}"
		verify_ccd_row_added "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"

		#
		# Successfully removed the dependency so exit
		#
		exit 0
	else
		lmsg=`gettext "%s: cannot specify the -r option with any other option"`
		printf "${lmsg}\n" "${0}"
		usage
	fi
fi

##############################################################################
# Restore default timeouts if the -f flag was given

if [ "${set_default_timeouts}" = "y" ]; then
	if [ "${set_dep}" = "n" -a "${set_timeouts}" = "n" -a "${rem_dep}" = "n" ]; then


		ccd_method_path_string=`form_default_method "${DATA_SERVICE}"`
		ccd_method_path_string=`shift_by_one_field "${ccd_method_path_string}"`
		remove_ccd_row "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"
		verify_ccd_row_removed "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"
		add_ccd_row "DS_METHOD_PATH" "${DS_METHOD_PATH_fmt}" "${ccd_method_path_string}" "${METH_TO_STRING}"
		verify_ccd_row_added "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"


		ccd_nm_path_string=`form_default_net_method "${DATA_SERVICE}"`
		ccd_nm_path_string=`shift_by_one_field "${ccd_nm_path_string}"`
		remove_ccd_row "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"
		verify_ccd_row_removed "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"
		add_ccd_row "DS_NM_PATH" "${DS_NM_PATH_fmt}" "${ccd_nm_path_string}" "${NETMETH_TO_STRING}"
		verify_ccd_row_added "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"


		ccd_fm_path_string=`form_default_fm_method "${DATA_SERVICE}"`
		ccd_fm_path_string=`shift_by_one_field "${ccd_fm_path_string}"`
		remove_ccd_row "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"
		verify_ccd_row_removed "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"
		add_ccd_row "DS_FM_PATH" "${DS_FM_PATH_fmt}" "${ccd_fm_path_string}" "${FMMETH_TO_STRING}"
		verify_ccd_row_added "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"

		#
		# Successfully restored the timeouts
		#
		exit 0
	else
		lmsg=`gettext "%s: cannot specify the -f option with any other option"`
		printf "${lmsg}\n" "${0}"
		usage
	fi
fi


##############################################################################
# Do error checking for the new dependencies if the -d flag was given

if [ "${set_dep}" = "y" ]; then

	#
	# Convert the comma-delimited list into a space-delimited list
	#
	dep_svc_space_list=`echo $dep_svc_list | tr ',' ' '`
	svcs_seen_so_far=

	loghosts_associated_with_ds=`get_loghosts_associated_with_ds ${DATA_SERVICE}`

	#
	# Check the dependent services specified
	#
	for dep_svc in  $dep_svc_space_list
	do
		#
		# Check that the service is registered
		#
		is_svc_registered "${dep_svc}"
		if [ $? -ne 0 ]; then
			lmsg=`gettext "ERROR: The \"%s\" data service is not registered."`
			printf "${lmsg}\n" "${dep_svc}"
			lmsg=`gettext "       The data service must be registered in order to set the dependency."`
			printf "${lmsg}\n"
			exit 1
		fi

		#
		# Check that the service isn't listed twice
		#
		is_member "${dep_svc}" "${svcs_seen_so_far}"
		if [ $? -eq 0 ]; then
			lmsg=`gettext "ERROR: Service \"%s\" was listed multiple times."`
			printf "${lmsg}\n" "${dep_svc}"
			exit 1
		fi
		svcs_seen_so_far="${dep_svc} ${svcs_seen_so_far}"

		#
		# Check that all the logical hosts that are associated with ${DATA_SERVICE}
		# are also assoctiated with the service that we are creating the dependency on.
		# This is a requirement for the clustering software to work correctly.
		#	
		dep_loghosts=`get_loghosts_associated_with_ds ${dep_svc}`
		is_subset "${loghosts_associated_with_ds}" "${dep_loghosts}"
		if [ $? -ne 0 ]; then
			lmsg=`gettext "ERROR: The logical hosts associated with %s are not a subset of those associated with %s."`
			printf "${lmsg}\n" "${DATA_SERVICE}" "${dep_svc}"
			lmsg=`gettext "       You cannot set a dependency of %s on %s if all the logical hosts associated with %s are not also associated with %s."`
			printf "${lmsg}\n" "${DATA_SERVICE}" "${dep_svc}" "${DATA_SERVICE}" "${dep_svc}"
			lmsg=`gettext "       Data Service %s is associated with the logical hosts: %s."`
			printf "${lmsg}\n" "${DATA_SERVICE}" "${loghosts_associated_with_ds}"
			lmsg=`gettext "       Data Service %s is associated with the logical hosts: %s."`
			printf "${lmsg}\n" "${dep_svc}" "${dep_loghosts}" 
			exit 1
		fi
		

	done

	#
	# Check for circular dependencies in the dependency graph
	#
	num_services=`hareg|wc -l 2>/dev/null`
	if [ $? -ne 0 ]; then
		lmsg=`gettext "ERROR: Could not get the number of registered services."`
		printf "${lmsg}\n"
		exit 1
	fi

	if [ -z "${num_services}" ]; then
		lmsg=`gettext "ERROR: Could not get the number of registered services."`
		printf "${lmsg}\n"
		exit 1
	fi

	#
	# Call function to check if making "${DATA_SERVICE}" dependent on "${dep_svc_space_list}"
	# will create a cycle in the dependency graph
	#
	( will_create_circular_dependency "${DATA_SERVICE}" "${dep_svc_space_list}" "0" "${num_services}" )
	dep_check_res=$?

	if [ "${dep_check_res}" -ne 0 ]; then

		if [ "${dep_check_res}" -eq 3 ]; then
			lmsg=`gettext "ERROR: A circular dependency exists among the registered services."`
			printf "${lmsg}\n"
			lmsg=`gettext "       You must remove this circular dependency before running this command."`
			printf "${lmsg}\n"
		elif [ "${dep_check_res}" -eq 4 ]; then
			lmsg=`gettext "ERROR: The dependency you want to add would create a circular dependency."`
			printf "${lmsg}\n"
			lmsg=`gettext "       The data services are not allowed to be circularly dependent on themselves."`
			printf "${lmsg}\n"
		else 
			lmsg=`gettext "Internal Error: Could not check for circular dependencies."`
			printf "${lmsg}\n"
		fi

		exit 1
	fi
	
fi

##############################################################################
#  Do error checking for the new timeouts if the -t flag was given

if [ "${set_timeouts}" = "y" ]; then

	#
	# Get the Current Method Path/Timeout information
	#
	ccd_method_path_string=`scccd ${CLUSTNAME} DS_METHOD_PATH query ds_name "${DATA_SERVICE}"`
	if [ $? -ne 0 -o -z "${ccd_method_path_string}" ]; then
		lmsg=`gettext "WARNING: Could not query CCD to get method information. Will reconstruct defaults."`
		printf "${lmsg}\n"
		ccd_method_path_string=`form_default_method "${DATA_SERVICE}"`
	fi

	ccd_nm_path_string=`scccd ${CLUSTNAME} DS_NM_PATH query ds_name "${DATA_SERVICE}"`
	if [ $? -ne 0 -o -z "${ccd_nm_path_string}" ]; then
		lmsg=`gettext "WARNING: Could not query CCD to get net method information. Will reconstruct defaults."`
		printf "${lmsg}\n"
		ccd_nm_path_string=`form_default_net_method "${DATA_SERVICE}"`
	fi

	ccd_fm_path_string=`scccd ${CLUSTNAME} DS_FM_PATH query ds_name "${DATA_SERVICE}"`
	if [ $? -ne 0 -o -z "${ccd_fm_path_string}" ]; then
		lmsg=`gettext "WARNING: Could not query CCD to get fault method information. Will reconstruct defaults."`
		printf "${lmsg}\n"
		ccd_fm_path_string=`form_default_fm_method "${DATA_SERVICE}"`
	fi

	#
	# Convert the comma-delimited list into a space-delimited list
	#
	method_timeout_space_list=`echo $method_timeout_list | tr ',' ' '`
	
	for method_timeout in $method_timeout_space_list
	do
		method_name=`echo $method_timeout|nawk -F= '{print $1}'`
		timeout_value=`echo $method_timeout|nawk -F= '{print $2}'`
	
		# check valid method
		is_member "${method_name}" "${VALID_METHOD_NAMES}"
		if [ $? -ne 0 ]; then
			lmsg=`gettext "ERROR: The method name \"%s\" is not valid."`
			printf "${lmsg}\n" "${method_name}"
			lmsg=`gettext "       The method name is case sensitive and must be one of the following:"`
			printf "${lmsg}\n"
			echo `        ${VALID_METHOD_NAMES}`
			exit 1
		fi
	
		# check valid timeout
		is_valid_timeout "${timeout_value}"
		if [ $? -ne 0 ]; then
			lmsg=`gettext "       The timeout must be a number between %s and %s."`
			printf "${lmsg}\n" "${MIN_METHOD_TIMEOUT}" "${MAX_METHOD_TIMEOUT}"
			exit 1
		fi

		method_header=`get_method_header ${method_name}`
		method_field=`get_method_timeout_field ${method_name}`
		
		if [ "${method_header}" = "DS_METHOD_PATH" ]; then
			ccd_method_path_string=`replace_field "${ccd_method_path_string}" "${method_field}" "${timeout_value}"`
			method_modified=y
		elif [ "${method_header}" = "DS_NM_PATH" ]; then
			ccd_nm_path_string=`replace_field "${ccd_nm_path_string}" "${method_field}" "${timeout_value}"`
			nm_modified=y
		elif [ "${method_header}" = "DS_FM_PATH" ]; then
			ccd_fm_path_string=`replace_field "${ccd_fm_path_string}" "${method_field}" "${timeout_value}"`
			fm_modified=y
		else
			lmsg=`gettext "Internal Error: CCD header not valid"`
			printf "${lmsg}\n"
			exit 1
		fi
	done	

	#
	# Double Check that none of the CCD strings are empty
	#
	if [ -z "${ccd_method_path_string}" -o -z "${ccd_nm_path_string}" -o -z "${ccd_fm_path_string}" ]; then
		lmsg=`gettext "Internal Error: Invalid method timeout string created"`
		printf "${lmsg}\n"
		exit 1
	fi
fi


#################################################################################
# Update the CCD with the new settings -- Only done if there were no errors above

if [ "${set_dep}" = "y" ]; then

	#
	# Update the CCD with the new dependencies
	#
	remove_ccd_row "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"
	verify_ccd_row_removed "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"
	add_ccd_row "DS_DEPSVC_LIST" "ds_name:service_list" "${DATA_SERVICE}:${dep_svc_list}" "${DEP_STRING}"
	verify_ccd_row_added "DS_DEPSVC_LIST" "ds_name" "${DATA_SERVICE}" "${DEP_STRING}"

fi

if [ "${set_timeouts}" = "y" ]; then

	#
	# Update the CCD with the new timeouts
	#

	if [ "${method_modified}" = "y" ]; then
		ccd_method_path_string=`shift_by_one_field "${ccd_method_path_string}"`

		remove_ccd_row "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"
		verify_ccd_row_removed "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"
		add_ccd_row "DS_METHOD_PATH" "${DS_METHOD_PATH_fmt}" "${ccd_method_path_string}" "${METH_TO_STRING}"
		verify_ccd_row_added "DS_METHOD_PATH" "ds_name" "${DATA_SERVICE}" "${METH_TO_STRING}"
	fi

	if [ "${nm_modified}" = "y" ]; then
		ccd_nm_path_string=`shift_by_one_field "${ccd_nm_path_string}"`

		remove_ccd_row "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"
		verify_ccd_row_removed "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"
		add_ccd_row "DS_NM_PATH" "${DS_NM_PATH_fmt}" "${ccd_nm_path_string}" "${NETMETH_TO_STRING}"
		verify_ccd_row_added "DS_NM_PATH" "ds_name" "${DATA_SERVICE}" "${NETMETH_TO_STRING}"
	fi

	if [ "${fm_modified}" = "y" ]; then
		ccd_fm_path_string=`shift_by_one_field "${ccd_fm_path_string}"`

		remove_ccd_row "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"
		verify_ccd_row_removed "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"
		add_ccd_row "DS_FM_PATH" "${DS_FM_PATH_fmt}" "${ccd_fm_path_string}" "${FMMETH_TO_STRING}"
		verify_ccd_row_added "DS_FM_PATH" "ds_name" "${DATA_SERVICE}" "${FMMETH_TO_STRING}"
	fi
fi

exit 0
