#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72F src/bos/usr/lib/nim/methods/c_switch_master.sh 1.8.1.6 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2001,2017 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)71    1.8.1.6  src/bos/usr/lib/nim/methods/c_switch_master.sh, cmdnim, bos72F, f2017_09A7  2/24/17  13:51:40 
#
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_switch_master.sh
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1993
#   All Rights Reserved
#   Licensed Materials - Property of IBM
#   US Government Users Restricted Rights - Use, duplication or
#   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
#

# include common NIM shell defines/functions
NIMPATH=/usr/lpp/bos.sysmgt/nim
NIM_METHODS="${NIMPATH}/methods"
. ${NIM_METHODS}/c_sh_lib

IFCONFIG="/etc/ifconfig"
NETSTAT="/usr/bin/netstat"
NIMINIT="/usr/sbin/niminit"

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS="originator new_master"
OPTIONAL_ATTRS="connect async show_progress"
platform=""
pif_name=""
ring_speed=""
cable_type=""
TYPE=""
force=""
mv_niminfo=""
rc=0
OK_TO_UPDATE=""

# ---------------------------- switch_master
#
# NAME: switch_master
#
# FUNCTION:	 Changes the defined master for a NIM client
#
# RETURNS: (int)
#	0	= SUCCESS
#	1	= FAILURE
#
# --------------------------------------------------------------------------- #
# 
function switch_master {

if [[ -s ${NIMINFO} ]]; then
	. ${NIMINFO} 
fi

# if new_master = nim_master_hostname, then return
if [[ ${new_master} = ${NIM_MASTER_HOSTNAME} ]]
then
	return 0
fi

# if originator != nim_master_hostname, then check nim_master_hostname_list
if [[ ${NIM_MASTER_HOSTNAME} != ${originator} ]] \
&& [[ `${ECHO} ${NIM_MASTER_HOSTNAME} | ${CUT} -f1 -d.` != ${originator} ]] \
&& [[ ${force:=no} != yes ]]
then
	for mstr in ${NIM_MASTER_HOSTNAME_LIST}
	do
		if [[ ${mstr} = ${originator} ]] \
		   || [[ `${ECHO} ${mstr} | ${CUT} -f1 -d.` = ${originator} ]]
	    then
			OK_TO_UPDATE="yes"
			break
		fi
	done

	if [[ -z $OK_TO_UPDATE ]]; then
		##### send this to originator instead of current_master
		[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R failure
		error ${ERR_INVALID_MASTER}
	fi
fi

if [[ -z "${NIM_MASTER_HOSTNAME}" ]] \
|| [[ ${NIM_MASTER_HOSTNAME} = ${originator} ]] \
|| [[ `${ECHO} ${NIM_MASTER_HOSTNAME} | ${CUT} -f1 -d.` = ${originator} ]] \
|| [[ ${force:=no} = yes ]] \
|| [[ ${OK_TO_UPDATE} = yes ]]
then
	# construct niminit call -
	hostname=${NIM_HOSTNAME%%.*}
	platform=`${BOOTINFO} -p`

	if [[ -n $NIM_IPV6_HOSTS ]]
	then
		for i in $NIM_IPV6_HOSTS
		do
			# separate IP address from hostname
			IFS='|' set -- $i
			addr=$1
			hname=$2
			# select that address if hname match NIM_HOSTNAME
			if [[ $hname == $NIM_HOSTNAME ]]
			then
				IP_HOSTNAME=$addr
			fi
		done
	fi

	if [[ -n $NIM_HOSTS ]]
	then
		for i in ${NIM_HOSTS}
		do
			# separate IP address from hostname
			addr=${i%%:*}
			hname=${i##*:}
			# select that address if hname match NIM_HOSTNAME
			if [[ $hname == $NIM_HOSTNAME ]]
			then
				IP_HOSTNAME=$addr
			fi
		done
	fi

	pif_name=`${NETSTAT} -n -if inet | \
		${AWK} -v cmp=${IP_HOSTNAME} '{if ($4 == cmp) print $1 }'`

	if [[ ${pif_name} = tr* ]]; then
		ring_speed=`${MKTCPIP} -S ${pif_name} 2>&1 | \
		  ${AWK} 'BEGIN { RS="\n"; FS=":" } \
		  { for (i=1;i<=NF;i++) \
		  { if ( match($i,/speed/) ) (j=i) } \
		  if (NR==2) {print $j} }'`
		  TYPE="-a ring_speed1=${ring_speed}";
	else
	  if [[ ${pif_name} = e[nt]* ]]; then
		cable_type=`${MKTCPIP} -S ${pif_name} 2>&1 | \
		  ${AWK} 'BEGIN { RS="\n"; FS=":" } \
		  { for (i=1;i<=NF;i++) \
		  { if ( match($i,/type/) ) (j=i) } \
		  if (NR==2) {print $j} }'`
		  TYPE="-a cable_type1=${cable_type}";
	  fi
	fi

	# temporarily remove /etc/niminfo
	${MV} /etc/niminfo /etc/niminfo.cnm >/dev/null 2>&1
	mv_niminfo="yes"

	connect=${connect:-$NIM_SHELL}
	# now lets run niminit
	${NIMINIT} ${show_progress:+-v} -a name=${NIM_NAME} \
	  -a master=${new_master} \
	  -a pif_name=${pif_name} ${TYPE} \
	  -a platform=${platform} \
	  -a restart_nimsh=no \
	  ${connect:+-a connect=$connect} 2>${ERR}

	if [[ $? != 0 ]]; then
		#### replace /etc/niminfo in case the the master removed it
		${MV} /etc/niminfo.cnm /etc/niminfo

		##### send this to originator instead of current_master
		[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R failure
		err_from_cmd ${NIMINIT}
	fi
	return 0
else
	##### send this to originator instead of current_master
	# return the appropriate error code to the calling method;
	# print the formatted msg from calling method
	[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R failure
	error ${ERR_INVALID_MASTER}
fi
} # end of switch_master

function direct_switch_master
{
	TEMP=/tmp/$$

	# backup existing copies of .rhosts and niminfo
	if [[ ! -s $NIMINFO || ! -s $RHOSTS ]]
	then 
		exit 444
	else
		$CP $NIMINFO ${NIMINFO}.previous
		$CP $RHOSTS ${RHOSTS}.previous
	fi

	#change the .rhosts file
	$SED "s/${originator}/${new_master}/" $RHOSTS > $TEMP 2>/dev/null
	$CP $TEMP $RHOSTS 2>&1 >/dev/null

	#change the niminfo file
	$SED "s/${originator}/${new_master}/" $NIMINFO > $TEMP	2>/dev/null
	$CP $TEMP $NIMINFO 2>&1 >/dev/null

	#clean up
	$RM $TEMP 2>&1 > /dev/null
}

#---------------------------- c_switch_master
#
# NAME: c_switch_master
#
# FUNCTION:
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#		calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#		parameters:
#		global:
#
# RETURNS: (int)
#		0	= success
#		1	= failure
#
#-------------------------------------------------------------------------------

# signal processing
trap cleanup 0
trap err_signal 1 2 11 15

# normally, we perform NIM initialization
# but its not needed since we're recreating
# the niminfo file

# initialize local variables
typeset c=""

# set parameters from command line
while getopts :a:qvfn c
do
	case ${c} in

		a)		# validate the attr ass
				parse_attr_ass "${OPTARG}"

				# include the assignment for use in this environment
				eval ${variable}=\"${value}\"
				;;

		q)		# show attr info
				cmd_what
				exit 0
				;;

		v)		# verbose mode (for debugging)
				set -x
				for i in $(typeset +f)
				do
					typeset -ft $i
				done
				;;

		f)		# force option
				force=yes
				;;

		n)		#if changing the master's if1 only, then edit the files directly
				#the force flag must be set in order to use this
				direct=yes
				;;

		\?)		# unknown option
				error ${ERR_BAD_OPT} ${OPTARG}
				;;
	esac
done

[[ ${async} = yes ]] && NIM_ASYNC=yes

# check for missing attrs
ck_attrs

#
mk_tmp_dir

# doing asynchronous processing?  (ie. master not waiting for script to finish)
if [[  ${NIM_ASYNC} = yes ]] 
then
	
	# update the state of the client object
	# Only do so if not called from nim_script.  The state is updated
	# there instead.
	##### send this to originator instead of current_master
	#####[[ ${NIM_SCRIPT} != yes ]] && ${NIMCLIENT} -R success
	:

	# set the following variable so that errors are appended to err_info
	# attribute on the client object.  When c_installp is called from
	# the nim_script, the async flag is not passed to this script so
	# this variable is exported there.
	##### send this to originator instead of current_master
	####UPDT_CL_ERR_INFO=yes
fi

# if the files are being edited directly, then do it and exit
if [[ $direct = "yes" && $force = "yes" ]]
then
	direct_switch_master
	if [[ $rc -ne 0 ]]
	then
		##### send this to originator instead of current_master
		# update state on master if it isn't waiting for us to finish
		[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R failure
	else
		# update state on master if it isn't waiting for us to finish
		[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R success
	fi

	# this takes us from takeover_success to ready
	# update state on master if it isn't waiting for us to finish
	[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R success

	exit 0
fi

# change 
if switch_master
then
	# remove original niminfo file
	${RM} /etc/niminfo.cnm >/dev/null 2>&1

	# update state on master if it isn't waiting for us to finish
	[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R success
else
	# keep original niminfo file, but only if created during
	# the current method call -  could be an old one
	[[ -n ${mv_niminfo} ]] && \
	${MV} /etc/niminfo.cnm /etc/niminfo >/dev/null 2>&1

	##### send this to originator instead of current_master
	# update state on master if it isn't waiting for us to finish
	[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R failure
fi

# this takes us from takeover_success to ready
# update state on master if it isn't waiting for us to finish
[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R success

# until a master can be specified to nimclient - send one more result to
# acount for the transition from takeover_setup to takeover
[[ ${NIM_ASYNC} = yes ]] && ${NIMCLIENT} -R success

# all done
exit $rc
