#!/bin/ksh -p
#
# ident "@(#)utreplica.ksh	1.55 05/05/10 SMI"
#
# Copyright 2000-2005 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

PATH="/usr/sbin:/usr/bin:/bin"
BASEDIR=/etc/opt/SUNWut/basedir
UTPRODDIR="$BASEDIR/lib"
UTSRDSDIR="$BASEDIR/srds"
umask=066
PROGRAM_ID=$(basename $0)
SIGNIFIGANT_DATASTORE=20    # a SunRay datastore with no data has only
			    # 14 entries.  We set it to 20 giving it
			    # some leeway.
TMPDIR="/var/opt/SUNWut/tmp"
TMP_FILE="${TMPDIR}/$PROGRAM_ID.$$.tmp"
ERR_FILE="${TMPDIR}/$PROGRAM_ID.$$.err"

TIMESTAMP=$(date '+%Y_%m_%d_%H:%M:%S')
BACKUP_EXT="_bu_${TIMESTAMP}"
export BACKUP_FILES=""

# operation mode
MODE=""
SUBMODE=""
RESTART_SRDS=false
RESTART_UTSVC=false
DEFAULT_SRDS_PORT=7012
OLD_DEFAULT_SUNDS_PORT=389

HOSTNAME="$(uname -n)"

# Replication State Id's
ERROR_ID=UT_Replica_Id_Err
PRIMARY_ID=UT_Replica_Id_Pri
SECONDARY_ID=UT_Replica_Id_Sec
NON_REPLICA_ID=UT_Replica_Id_Non
SERVICE_PORT=UT_Replica_Port_Num
 
# files touched
SRDS_LDAP_CURRENT="/etc/opt/SUNWut/srds/current"
SRDS_LDAP_VAR="/var/opt/SUNWut/srds"
SRDS_DSSERV_CONF=$SRDS_LDAP_CURRENT/utdsd.conf
SRDS_DSSERV_INI=$SRDS_LDAP_CURRENT/utdsd.ini
SRDS_DSSERV_ACL=$SRDS_LDAP_CURRENT/utdsd.acl.conf
UT_ADM_CONF=/etc/opt/SUNWut/utadmin.conf

#
# The original file permission and group ownership of the $UT_ADM_CONF,
# SRDS_DSSERV_INI, SRDS_DSSERV_ACL and SRDS_DSSERV_CONF files needs to be
# preserved so that unprivileged users on LDAP secondary hosts can still
# use admin clis' that query LDAP.
# Currently the changes are made to these files by cat'ing the new content
# into the old file. This will preserve the old permissions. Using a
# "mv" command may alter permissions and should not be used.
#

SetPlatformDependencies () {
  case "$OS" in
              	SunOS)  LCL_PACKAGE="SUNWlldap"
                        LDAPSEARCH="/usr/bin/ldapsearch -L "
			GREP=/usr/xpg4/bin/grep
                        ETCSERVICES=/etc/inet/services
			LOGFILE="/var/adm/log/$PROGRAM_ID.${TIMESTAMP}.log"
                        ;;
                Linux)  LCL_PACKAGE="$(rpm -qf /usr/bin/ldapadd 2>/dev/null)"
                        LDAPSEARCH="/usr/bin/ldapsearch -x -LLL "
			GREP=/bin/grep
                        ETCSERVICES=/etc/services
			if [[ -d /var/log/SUNWut ]] ; then
				LOGFILE="/var/log/SUNWut/$PROGRAM_ID.${TIMESTAMP}.log"
                        else
				LOGFILE="/var/log/$PROGRAM_ID.${TIMESTAMP}.log"
                        fi
                        ;;
                *)      error "unknown OS name $OS"
                        exit 2
  esac
}

sendPing (){
  case "$OS" in
                SunOS)  ping $1 $2
                        ;;
                Linux)  ping $1 -w $2
                        ;;
                *)      error "unknown OS name $OS"
                        exit 2
  esac

}


Generic_Err_Print(){
  print -u2 "${PROGRAM_ID}: ${state:-Error}, ${*}\n"
}

# Call this when script has been called incorrectly
Usage() {
  state=Usage
  Generic_Err_Print "\
	\n\t$PROGRAM_ID -l\
	\n\t$PROGRAM_ID -u\
	\n\t$PROGRAM_ID -p [-a|-d] <secondary> [<secondary> ...]\
	\n\t$PROGRAM_ID -s <primary>\
	\n\t$PROGRAM_ID -z [<port#>]\
	\n\nThe following option is RESERVED:\
	\n\t-i"

  exit 1
}

# Call this when configuration has been abandoned intentionally by user.
Abort() {
  state=Abort
  Generic_Err_Print $*
  exit 0
}

# Call this when potential issues are discovered. Does not force an exit.
Warning() {
  state=Warning
  Generic_Err_Print $*
  state=""
}

# Call this when configuration has been abandoned due to unrecoverable error.
Fatal() {
  # Only massage ERR_FILE if in a tee'd function
  if [[ -f $ERR_FILE ]]; then
    print "1" >> $ERR_FILE
  fi
  Generic_Err_Print $*
  exit 1
}


#
# set the traps.  This is needed for tee subshell to work properly.
#
setTraps() {
    trap "Restore_all_backup_files; exit 1" HUP INT QUIT TERM
    trap "Remove_all_backup_files; rm -rf $TMP_FILE" EXIT
}


# This is a tracking file used by the Fatal function to communicate the
# error status to the main script. It is needed because the exit status
# of each operation is piped to tee and unavailable to main.
# Prep_err_file and Remove_err_file must use Generic_Err_Print as Fatal
# may only be used once ERR_FILE is in place.
Prep_err_file() {
  # Ensure ERR_FILE does not pre-exist and can be created
  if [ -f $ERR_FILE ]; then
    if ! rm -f $ERR_FILE; then
      Generic_Err_Print "can not remove existing error file $ERR_FILE"
    fi
  fi
  touch $ERR_FILE
  if [ ! -f $ERR_FILE ]; then
    Generic_Err_Print "can not create temporary file $ERR_FILE"
  fi
}

Remove_err_file() {
  if [ -f $ERR_FILE ]; then
    if ! rm -f $ERR_FILE; then
      Generic_Err_Print "can not remove existing error file $ERR_FILE"
    fi
  else
      Generic_Err_Print "$ERR_FILE does not exist"
  fi
}

Prep_tmp_file() {
  if [[ -z "$TMP_FILE" ]]; then
    Fatal "TMP_FILE not defined"
  fi
  # Ensure TMP_FILE does not pre-exist and can be created
  if [ -f $TMP_FILE ]; then
    if ! rm -f $TMP_FILE; then
      Fatal "can not remove existing temporary file $TMP_FILE"
    fi
  fi
  touch $TMP_FILE
  if [ ! -f $TMP_FILE ]; then
    Fatal "can not create temporary file $TMP_FILE"
  fi
}

#
# prepare a backup file for the file specified in $1
# The backup file format is based on <filename>_bu_<date>
# For each backup file created, it will be appended to the $BACKUP_FILES.
# When aborting the program, need to restore the backup files.
Prep_backup_file() {
 
    if [[ -z "$1" ]]; then
	Fatal "file not specified for backup"
    fi
    BU_FILE="${1}${BACKUP_EXT}"
    if [[ ! -f ${BU_FILE} ]]; then
	# only backup if not already backed up
    	cp $1 ${BU_FILE}
    	BACKUP_FILES="${BU_FILE} ${BACKUP_FILES}"
    fi
}

#
# restores all the backed up files to the original files.
# It uses the filenames stored in the $BACKUP_FILES variable.
#
Restore_all_backup_files() {
 
    typeset file
    typeset dst
    for file in ${BACKUP_FILES}
    do
	dst=${file%${BACKUP_EXT}}
	mv $file $dst
    done
}

#
#  Removes all the backup files.
#  It uses the filenames stored in the $BACKUP_FILES.
#
Remove_all_backup_files() {
    rm -f ${BACKUP_FILES}
}


CheckUidIsZero() {
  case "$(id)" in
    'uid=0('*) return 0;;  # uid is zero
    *)         Fatal "must be run as UID 0 (root)";;
  esac
}

UTInstalled() {
  $UTPRODDIR/utprodinfo -t installed SUNWuta
  return $?
}

LdapClientInstalled() {
  $UTPRODDIR/utprodinfo -t installed $LCL_PACKAGE
  return $?
}

LdapClientInstallPartial() {
  $UTPRODDIR/utprodinfo -t partial $LCL_PACKAGE
  return $?  
}

SunDSInstalled() {
  $UTPRODDIR/utprodinfo -t installed $SRDS_PACKAGE
  return $?
}

SunDSInstallPartial() {
  $UTPRODDIR/utprodinfo -t partial $SRDS_PACKAGE
  return $?  
}

SunDSVersion() {
  INSTALLED_VERSION="$($UTPRODDIR/utprodinfo -p $SRDS_PACKAGE PRODVERS 2>/dev/null)"
  #
  # above var is global, used in calling func error msg

  case "$INSTALLED_VERSION" in
    $1) return 0;;
    *)  return 1;;
  esac
}

# Defaults to No
ReplyIsNo() {
  while true; do
    print -u2 -n "$1 (y/[n])? "
    read
    case "$REPLY" in
      "" | [nN] | [Nn][Oo]) return 0;;
      [yY] | [Yy][Ee][Ss])    return 1;;
    esac
  done
}

# Defaults to Yes
ReplyIsYes() {
  while true; do
    print -u2 -n "$1 ([y]/n)? "
    read
    case "$REPLY" in
      [nN] | [Nn][Oo]) return 1;;
      "" | [yY] | [Yy][Ee][Ss])    return 0;;
    esac
  done
}

RestartSunDS() {

  print "\nRestarting $SRDS_PROD_NAME ..."

  /etc/init.d/utds stop
  /etc/init.d/utds start
}

RestartUT() {

  print "\nRestarting $UT_PROD_NAME ..."

  /etc/init.d/utsvc stop
  /etc/init.d/utsvc start
}

RestartSunMcAgent() {

  pgrep -f "^esd - init agent " >/dev/null 
  if [[ $? != 0 ]]; then
	return
  fi
  print "\nRestarting Sun Management Center agent ..."
  SUNMC_BASE="$($UTPRODDIR/utprodinfo -r SUNWescom 2>/dev/null)"
  SUNMC_BASEDIR="${SUNMC_BASE:-/opt}"

  $SUNMC_BASEDIR/SUNWsymon/sbin/es-stop -a
  $SUNMC_BASEDIR/SUNWsymon/sbin/es-start -a

}


Set_datastore_begin_end_markers() {

  # These markers should guarantee a file section ending _only_ in UT config
  # block
  Begin_mark="^# SUNWut begin"
  End_mark="^directory[ 	][ 	]*\/var\/opt\/SUNWut\/srds\/dbm.ut"
}
  
#
# it first checks to see if the specified server is configured as primary for
# the local host.  If not, abort the program.  If true, retrieve the port number
# from the server specified.
#
# $1 the server name to get the port number from
#
# Returns:
#	0 if successful
#	1 if failed to contact remote host or utrcmd fails
#	2 if remote utreplica returned with error
#	3 if info returned from the remote server does not include the port number.
#	  (ie. non 2.0 extension to -i).
#
Get_remote_ds_info() {
    # Determines the port used by the remote SunDS LDAP server.
    # argument 1 is the server to contact.
    if [[ -z "$1" ]]; then
	Fatal "Remote server not specified to retrieve the port number."
	return 1
    fi
    typeset TMP_ERR=${TMPDIR}/$PROGRAM_ID.utrcmd.$$
    rm -f $TMP_ERR
    remote_rep=$(/opt/SUNWut/lib/utrcmd $1 /opt/SUNWut/sbin/utreplica -i 2>${TMP_ERR})
    typeset remote_st=${?}
    if [[ $remote_st -ge 1 ]]; then
	# failed to contact server
	Warning "Unable to determine the replication status of ${1}."
	if [[ -s ${TMP_ERR} ]]; then
	    print -u2 "Error message from ${1}:"
	    cat ${TMP_ERR}
	fi
	rm -f ${TMP_ERR}
	return 1
    elif [[ -s ${TMP_ERR} ]]; then
	Warning "Unable to retrieve the replication info from server ${1}"
	print -u2 "Error message from ${1}:"
	cat ${TMP_ERR}
	rm -f ${TMP_ERR}
	return 2
    elif ! print $remote_rep | $GREP -q $PRIMARY_ID; then
	if [[ -n ${Primary_host} ]]; then
		Fatal "${Primary_host} is not configured as a Primary server."
	else
		Fatal "There is no Primary server configured."
	fi
    elif ! print $remote_rep | $GREP -qi "\<${HOSTNAME}\>"; then
	Fatal "${Primary_host} is not configured as a Primary for ${HOSTNAME}."
    elif print $remote_rep | $GREP -q "${SERVICE_PORT}="; then
	REMOTE_LDAP_PORT=$(print $remote_rep | \
		sed -n -e "s/.*${SERVICE_PORT}= *\([0-9][0-9]*\).*/\1/p")
    else
	# running old Sunray releases which do not support the port number extension
	Warning "Unable to determine the LDAP port number - incompatible remote server ${1}"
	if [[ -s ${TMP_ERR} ]]; then
	    print -u2 "Error message from ${1}:"
	    cat ${TMP_ERR}
	fi
	rm -f ${TMP_ERR}
	return 3
    fi
    rm -f ${TMP_ERR}
    return 0
}


Get_local_ldap_port() {
  # Determines the port used by the local SunDS LDAP server.
  # Note that once replication is configured, the port should not be changed
  # without unconfiguring replication.
  # Ensure to call this before any routine that utilises ldap CLI's
  LDAP_PORT=$(awk -F= '/^LdapPort/ {val =  $2} END {print val}'\
    $SRDS_DSSERV_INI)

  if [[ -z $LDAP_PORT ]]; then
    Fatal "could not determine the local LDAP port"
  fi
}

Get_datastore_suffix() {

  Set_datastore_begin_end_markers

  if [[ -f $SRDS_DSSERV_CONF ]]; then
    # Last match will guarantee we get the UT value
    DS_SUFFIX=$(sed -n "/$Begin_mark/,/$End_mark/p" $SRDS_DSSERV_CONF |\
      awk '/^suffix/ {val =  $2} END {print val}' | sed 's/\"//g')
  else
    Fatal "could not open $SRDS_DSSERV_CONF"
  fi

  if [[ -z $DS_SUFFIX ]]; then
    Fatal "could not determine datastore suffix"
  fi
}

Get_rootdn() {

  Set_datastore_begin_end_markers

  if [[ -f $SRDS_DSSERV_CONF ]]; then 
    ROOTDN=$(sed -n "/$Begin_mark/,/$End_mark/p" $SRDS_DSSERV_CONF |\
      awk -F\" '/^rootdn/ {print $2 }')
  else
    Fatal "could not open $SRDS_DSSERV_CONF"
  fi
  
  if [[ -z $ROOTDN ]]; then
    Fatal "could not determine datastore root DN"
  fi
}

Get_crypt_rootpw() {

  Set_datastore_begin_end_markers

  if [[ -f $SRDS_DSSERV_CONF ]]; then 
    CRYPT_ROOTPW=$(sed -n "/$Begin_mark/,/$End_mark/p" $SRDS_DSSERV_CONF |\
      awk '/^rootpw/ {val =  $2} END {print val}')
  else
    Fatal "could not open $SRDS_DSSERV_CONF"
  fi
  
  if [[ -z $CRYPT_ROOTPW ]]; then
    Fatal "could not determine datastore root password"
  fi
}

# NOTE: Set ldap_host to be the correct host prior to calling
Get_datastore_admin_data() {

  if [[ -z $ldap_host ]]; then
    Fatal "LDAP Host not defined"
  fi

  Get_datastore_suffix

  # Get ut admin and subtree DN's directly from specified datastore
  # Search must be based on datastore suffix
  ADMIN_SUBTREE=$($LDAPSEARCH -h $ldap_host -p $LDAP_PORT\
    -b $DS_SUFFIX -s sub 'objectclass=utServer' dn 2> /dev/null | grep -i '^dn:' |\
    awk -F: '{print $2}' | sed 's/ //g')
  ADMIN_USER_DN=$($LDAPSEARCH -h $ldap_host -p $LDAP_PORT\
    -b $DS_SUFFIX -s sub 'objectclass=person' dn 2> /dev/null | grep -i '^dn:' |\
    awk -F: '{print $2}' | sed 's/ //g')

  if [[ -z $ADMIN_SUBTREE ]] || [[ -z $ADMIN_USER_DN ]]; then
    Fatal "could not determine Primary datastore UT Admin specifiers"
  fi
}


#
# returns the value for the specified key in the specified file.
#
# Parameters:
#	$1	key
#	$2	filename
#
Get_valueBykey() {
    if [[ $# -ne 2 ]]; then
	return
    fi
    typeset key=$1
    typeset filename=$2

    if [[ -f $filename ]]; then
	sed -n -e "s/^[ 	]*${key}[ 	]*=[ 	]*//p" $filename 2>/dev/null
    fi
}

Sync_LDAP_ACL_with_datastore_data() {

  # Get subtree and proxy agent from local datastore
  ldap_host=localhost
  Get_local_ldap_port

  #
  # Get the ADMIN_SUBTREE and ADMIN_USER_DN info from the utadmin.conf file.
  # we use the admin.subtree and admin.user.name information from the utadmin.conf
  # file.  The information from this file should be in sync with the LDAP database.
  #
  ADMIN_SUBTREE=$(Get_valueBykey admin.subtree $UT_ADM_CONF)
  ADMIN_USER_DN=$(Get_valueBykey admin.user.name $UT_ADM_CONF)

  if [[ -z "$ADMIN_SUBTREE" ]] || [[ -z "$ADMIN_USER_DN" ]]; then
     #
     # we are still unable to get these information.  Do we proceed?
     # Since we have already done all the work in utdsd.conf file, we
     # might as well proceed but warn the user of such failure.
     #
     Warning "could not determine the admin user and/or subtree.\n" \
     "You may want to unconfigure and reconfigure the server using utconfig.\n" \
     "If you choose to proceed with the current configuration, you may not be\n" \
     "able to make any modification in the datastore due to insufficient rights."
  else
     ACCESS_TO=$(print "access to dn=\".*,$ADMIN_SUBTREE\"")
     ACCESS_BY=$(print "     by dn=\"$ADMIN_USER_DN\" write")

     Prep_tmp_file
     Prep_backup_file $SRDS_DSSERV_ACL
     sed -e "/^# SUNWut begin/,/^# SUNWut end/s/^access to dn=\"[^\"][^\"]*\"/${ACCESS_TO}/" \
	-e "/^# SUNWut begin/,/^# SUNWut end/s/^[ 	]*by dn=\".*write.*$/${ACCESS_BY}/" \
	$SRDS_DSSERV_ACL >> $TMP_FILE

     # Note that this replaces existing file
     cat $TMP_FILE > $SRDS_DSSERV_ACL
     rm $TMP_FILE
  fi
}

#
# returns the list of the secondary servers from the utdsd.conf file.
#
get_secondaries() {
    awk '/^push_replica/ {print $2}' $SRDS_DSSERV_CONF | \
	sed -e "s/host=\([^:]*\):[0-9]*/\1/"
}


#
# returns the primary server name from the utdsd.conf file.
get_primary() {
    typeset -l primary_host
    primary_host=$(awk '/^pull_replica/ {print $2}' $SRDS_DSSERV_CONF |\
      awk -F= '{print $2}' | awk -F: '{print $1}')
    if [[ -z "$primary_host" ]]; then
    	# this server is a primary, return hostname
    	primary_host=$(hostname)
    fi
    print $primary_host
}

#
# returns true if the server is the primary else false.
# It's a primary if pull_replica string is found in the
# config file
is_Primary() {
    ! $GREP -s -q '^pull_replica' $SRDS_DSSERV_CONF
}


#
# validate the port number specified.  It checks for the followings:
#	- positive number > 0 and < 65535
#	- not currently defined in the services database
#
# $1 specified port number in string format
#
# Returns:
# 	0 if it's a valid port number
#	1 if it's an invalid port number (eg. contains non-numeric charcters
#	  or already defined in the services database)
#
isValidPort() {
    typeset -r MAXRANGE=65535

    if [[ $# -eq 0 ]]; then
	# no port specified
	return 0
    fi
    typeset -i VALID_PORT
    VALID_PORT=`printf "%d" $1 2>/dev/null`
    if [[ $? -ne 0 ]] || [[ "$VALID_PORT" != "$1" ]]; then
	Generic_Err_Print "Invalid port number specified: non-numeric character found."
	return 1
    fi
    if [[ $VALID_PORT -le 0 ]] || [[ $VALID_PORT -ge $MAXRANGE ]]; then
	Generic_Err_Print "Invalid port number specified: must be greater than 0 and lesser than $MAXRANGE."
	return 1
    fi
    typeset SERV_NAME
    SERV_NAME=`getent services $VALID_PORT | awk '{ print $1}'`
    if [[ -n "$SERV_NAME" ]] && [[ "$SERV_NAME" != "utdsd" ]]; then
	# port already used
	Generic_Err_Print \
	"Invalid port number specified: port already defined in services database."
	return 1
    fi
    return 0
}


#
# returns true if  the parameter passed in is an
#
# removes the replication block from the utdsd.conf file and stores the
# result in the $TMP_FILE.  The TMP_FILE should be defined before the call.
# (contents between SUNWutrep begin and end)
#
remove_rep_block() {
    Prep_tmp_file
    Prep_backup_file $SRDS_DSSERV_CONF
    sed  '/^# SUNWutrep begin/,/^# SUNWutrep end/d'\
	$SRDS_DSSERV_CONF >> $TMP_FILE
}


#
# update the utdsd.ini file with the new port number specified by $NEW_LDAP_PORT
#
#  Parameters:
#  $1 the new port number
#
Update_init_file() {
    if [[ -z "$1" ]]; then
	return
    fi

    print "### updating the Datastore init file" 
    Get_local_ldap_port
    if [[ $1 -eq $LDAP_PORT ]]; then
	# nothing to do
	print "\t...already configured with port ${1}"
	return
    fi

    # update the utdsd.ini file
    Prep_tmp_file
    sed "s/^LdapPort=[0-9][0-9]*$/LdapPort=${1}/" $SRDS_DSSERV_INI \
	>> $TMP_FILE
    Prep_backup_file $SRDS_DSSERV_INI
    cat $TMP_FILE > $SRDS_DSSERV_INI
    rm $TMP_FILE
    RESTART_SRDS=true
    print "\t...done"
}


#
# update the pull replication block and put the result in the TMP file.
# This TMP_FILE must be defined before making this call.
#	$1 the primary servername.  If not defined, it behaves like a delete.
#
# NOTE: this scripts depends on the following variables:
#	TMP_FILE temporary working file
#	ROOTDN		the root dn (set by get_rootdn)
#	CRYPT_ROOTPW	the root password for replication (set by Get_crypt_rootpw)
#	DS_SUFFIX	the Sunray suffix, o=utdata (set by Get_datastore_suffix)
#	SRDS_DSSERV_CONF	global SRDS utdsd.conf file
#	LDAP_PORT	global SRDS port (set by Get_local_ldap_port)
#	
#	
Update_pull_block() {

    typeset primary_srv
    if [[ $# -ne 1 ]]; then
	Fatal "Invalid argument to Update_pull_block() call: $*"
    fi

    primary_srv="$1"

    Get_rootdn
    Get_crypt_rootpw
    Get_datastore_suffix
    Get_local_ldap_port
    print "### updating the SRDS config file"

    #
    # clears the replication block from the list first
    #
    remove_rep_block

    if [[ -n "$primary_srv" ]]; then
	# Note: Maintain only a single TAB indent for the HERE statment blocks.
	# The remaining block spacing must comply with SunDS file format.
	cat <<- EOF >> $TMP_FILE
	# SUNWutrep begin

	slave
	  replicadn="${ROOTDN}"
	  referral="ldap://${primary_srv}:${LDAP_PORT}"
	  subtree="${DS_SUFFIX}"

	pull_replica host=${primary_srv}:${LDAP_PORT}
	  binddn="${ROOTDN}"
	  bindmethod=sasl(cram-md5)
	  ldapsecurity=insecure
	  credentials=${CRYPT_ROOTPW}
	  subtree="${DS_SUFFIX}"
	  timeout=3600
	# SUNWutrep end
	EOF
    fi

    if diff $TMP_FILE $SRDS_DSSERV_CONF 2>&1 >/dev/null; then
	# already has the correct port
	print "\t...already configured with port ${LDAP_PORT}"
    else
	# Note this replaces the existing file
	cat $TMP_FILE > $SRDS_DSSERV_CONF
	RESTART_SRDS=true
	print "\t...done"
    fi
    rm -f $TMP_FILE
}

#
# update the push replication block and put the result in the TMP file.
# This TMP_FILE must be defined before making this call.
#	$* the list of secondary servers (must be quoted)
#
# NOTE: this scripts depends on the following variables:
#	TMP_FILE temporary working file
#	ROOTDN		the root dn (set by get_rootdn)
#	CRYPT_ROOTPW	the root password for replication (set by Get_crypt_rootpw)
#	DS_SUFFIX	the Sunray suffix, o=utdata (set by Get_datastore_suffix)
#	SRDS_DSSERV_INI	global SRDS utdsd.ini file
#	SRDS_DSSERV_CONF	global SRDS utdsd.conf file
#	LDAP_PORT	global SRDS port (set by Get_local_ldap_port)
#	
#	
Update_push_block() {

    typeset srv_list
    if [[ $# -ne 1 ]]; then
	Fatal "Invalid argument to Update_push_block() call: $*"
    fi
    srv_list="$*"

    Get_rootdn
    Get_crypt_rootpw
    Get_datastore_suffix
    Get_local_ldap_port
    print "### updating the SRDS config file"

    #
    # clears the replication block from the list first
    #
    remove_rep_block

    if [[ -n "$srv_list" ]]; then
	# Note: Maintain only a single TAB indent for the HERE statment blocks.
	# The remaining block spacing must comply with SunDS file format.
	cat <<- EOF >> $TMP_FILE
	# SUNWutrep begin

	EOF

	for slave in $srv_list
	do

	    cat <<- EOF >> $TMP_FILE
	push_replica host=${slave}:${LDAP_PORT}
	  binddn="${ROOTDN}"
	  bindmethod=sasl(cram-md5)
	  ldapsecurity=insecure
	  credentials=${CRYPT_ROOTPW}
	  subtree="${DS_SUFFIX}"
	
	EOF
	done

	# Only one entry to denote master subtree
	cat <<- EOF >> $TMP_FILE
	master
	  subtree="${DS_SUFFIX}"
	EOF


	cat <<- EOF >> $TMP_FILE
	# SUNWutrep end
	EOF

	if diff $TMP_FILE $SRDS_DSSERV_CONF 2>&1 >/dev/null; then
	    # already has the correct port
	    print "\t...already configured with port ${LDAP_PORT}"
	else
	    # Note this replaces the existing file
	    cat $TMP_FILE > $SRDS_DSSERV_CONF
	    RESTART_SRDS=true
	    print "\t...done"
	fi
	rm -f $TMP_FILE

	# ini file
	if ! $GREP -s -q -e "^StartDspushd=true" $SRDS_DSSERV_INI; then
	    Prep_tmp_file
    	    Prep_backup_file $SRDS_DSSERV_INI
	    sed 's/StartDspushd=false/StartDspushd=true/' $SRDS_DSSERV_INI\
		>> $TMP_FILE
	    # Note that this replaces existing file
	    cat $TMP_FILE > $SRDS_DSSERV_INI
	    RESTART_SRDS=true
	    rm $TMP_FILE
	fi
    else
	# all the secondary servers have been removed from the configuration
	# update the pushd info

	# Note this replaces the existing file
	cat $TMP_FILE > $SRDS_DSSERV_CONF
	rm $TMP_FILE
	RESTART_SRDS=true
	print "\t...done"

	# ini file
	if ! $GREP -s -q -e "^StartDspushd=false" $SRDS_DSSERV_INI; then
	    Prep_tmp_file
    	    Prep_backup_file $SRDS_DSSERV_INI
	    sed 's/StartDspushd=true/StartDspushd=false/' $SRDS_DSSERV_INI\
		>> $TMP_FILE
	    # Note that this replaces existing file
	    cat $TMP_FILE > $SRDS_DSSERV_INI
	    rm $TMP_FILE
	fi
    
    fi
}


#
#  Update the utdsd port number in the /etc/inet/services file
#
#  Parameters:
#  $1 the new port number
#
Update_etc_services() {
    if [[ -z "$1" ]]; then
	return
    fi

    print "### updating the system services file" 
    $GREP -q "^utdsd[   ][      ]*${1}/" ${ETCSERVICES}
    if [[ $? -eq 0 ]]; then
	# already has the correct port
	print "\t...already configured with port ${1}"
	return
    fi
    Prep_tmp_file
    Prep_backup_file ${ETCSERVICES}

    $GREP -q -s "^utdsd[        ]" ${ETCSERVICES}
    if [[ $? -ne 0 ]]; then
	# utdsd entry is not even in the services file
	# so take it from the services.SUNWut.prototype file
	typeset fromfile="${UTO_BASEDIR}/lib/prototype/services.SUNWut.prototype"
	typeset utdsdentry=`grep "^utdsd[ 	]" ${fromfile} | \
            sed -e "s/^\(utdsd[	 ][	 ]*\)[0-9][0-9]*\(\/.*\)$/\1${1}\2/"`
	cat ${ETCSERVICES} > ${TMP_FILE}
	ed - ${TMP_FILE} <<-EOE 2>&1 >/dev/null
	/^# End SUNWut/
	i
	${utdsdentry}
	.
	w
	q
	EOE
    else
        sed -e "s/^\(utdsd[	 ][	 ]*\)[0-9][0-9]*\(\/.*\)$/\1${1}\2/" \
		${ETCSERVICES} >> $TMP_FILE
    fi

    if diff $TMP_FILE ${ETCSERVICES} 2>&1 >/dev/null; then
	# already has the correct port
	print "\t...already configured with port ${1}"
    else
	# replace the services file
	cat $TMP_FILE > $ETCSERVICES
	RESTART_SRDS=true
        print "\t...done"
    fi
    rm -f ${TMP_FILE}
}


#
#  Updates the utadmin.conf file with the new port number specified.
#
#  Parameters:
#  $1 the new port number
#
Update_utadmin_conf() {

    if [[ -z "${1}" ]]; then
	# no new port specified
	return 1
    fi
    print "### updating the SunRay admin config file" 
    $GREP -q "^admin.server.port[       ]*=[    ]*${1}[  ]*$" \
	${UT_ADM_CONF}
    if [[ $? -eq 0 ]]; then
	# already has the correct port
	print "\t...already configured with port ${1}"
	return
    fi

    # change configured port in utadmin.conf
    Prep_tmp_file
    Prep_backup_file ${UT_ADM_CONF}
    sed -e "s/^\(admin.server.port[ 	]*=[ 	]*\)[0-9].*$/\1${1}/" \
	${UT_ADM_CONF} >> $TMP_FILE

    # replace the utadmin.conf file
    cat $TMP_FILE > $UT_ADM_CONF
    rm -f ${TMP_FILE}
    RESTART_UTSVC=true
    print "\t...done"
}


Config_Pri() {

  setTraps
  typeset -l CURR_SERVER_LIST
  typeset -l NEW_SERVER_LIST
  typeset -l TOTAL_SERVER_LIST
  typeset -l server

  Get_local_ldap_port
  Get_datastore_suffix

  #
  # if no suboption -a or -d defined, we need to check if the server
  # is already configured either as a primary or secondary.  If yes,
  # then you must run -u before configure it as a primary (ie. -p
  # without suboptions).  This is preserve the existing -p behaviour.
  #
  if [[ -z "$SUBMODE" ]]; then
	if $GREP -s -q -e '^pu.._replica' $SRDS_DSSERV_CONF
	then
	    Fatal "Already configured as a replica server.\
	    \nYou must unconfigure with \"-u\" first or add the secondaries\
	    \nincrementally using the \"-a\" option."
	fi
  elif $GREP -s -q -e '^pull_replica' $SRDS_DSSERV_CONF
  then
	Fatal "This server is currently configured as a secondary server"
  fi

  #
  # get the current list of servers
  #
  CURR_SERVER_LIST=$(get_secondaries)
  #
  # manipulate the list according to the suboption.  If no suboption
  # specified, handle it as -a.  This allows us to check multiply defined
  # secondary servers in the input list.
  #
  if [[ "$SUBMODE" = "d" ]]; then
	#
	# delete from the CURR_SERVER_LIST.  If not in the list, just
	# give out warning and continue.
	#
	if [[ -z "$CURR_SERVER_LIST" ]]; then
		#
		# empty list, nothing to delete
		#
		Fatal "No secondary servers are currently defined"
	fi

	NEW_SERVER_LIST="$CURR_SERVER_LIST"
	for server in $SERVER_LIST
	do
	    print $CURR_SERVER_LIST | $GREP -s -q -e "\<${server}\>"
	    if [[ $? -ne 0 ]]; then
		Warning "skipping server ${server} -- not currently configured in the secondary list"
		continue
	    fi
	    NEW_SERVER_LIST=$(print $NEW_SERVER_LIST | sed -e "s/\<$server\>//")
	done
	if [[ "$NEW_SERVER_LIST" = "$CURR_SERVER_LIST" ]]; then
	    Fatal "no secondary servers to delete"
	fi
	print "Deleting secondary servers from the current secondary list"
  elif [[ "$SUBMODE" = "a" ]]; then
	#
	# append to the list if it's not already in the list.  If already
	# in the list, just give out warning and continue.
	#
	NEW_SERVER_LIST=""
	for server in $SERVER_LIST
	do
	    print $CURR_SERVER_LIST | $GREP -s -q -e "\<${server}\>"
	    if [[ $? -eq 0 ]]; then
		Warning "skipping server ${server} -- already configured as secondary"
		continue
	    fi
	    NEW_SERVER_LIST="$NEW_SERVER_LIST $server"
	done
	#
	# in the add case, check the servers in NEW_SERVER_LIST
	#
	if [[ -z "$NEW_SERVER_LIST" ]]; then
	    Fatal "no secondary servers added"
	fi
	print "Adding new secondary servers to the current secondary list"
  else
	NEW_SERVER_LIST="$SERVER_LIST"
	print "Converting Administration Standalone Server to Administration"\
	"Primary"
  fi

  #
  # at this point, we should have 2 lists:
  # NEW_SERVER_LIST and CURRENT_SERVER_LIST
  # In the "-d" case, NEW_SERVER_LIST contains the list of servers left after
  # deleting the specified ones.
  # In the "-a" and no suboption cases, NEW_SERVER_LIST are the list of servers
  # that need to be added in addition to the ones currently defined in the
  # CURR_SERVER_LIST.  CURR_SERVER_LIST should be empty when "-a" suboption
  # is not specified.
  # 

  if [[ "$SUBMODE" != "d" ]]; then
	# add case
	for server in $NEW_SERVER_LIST
	do
	    # Can not be Primary for itself.
	    if [[ $server == $HOSTNAME ]]; then
		Fatal "$HOSTNAME is not a valid Secondary."
	    fi

	    # check to see if the servername specified is defined in the hosts
	    # naming database.
	    getent hosts $server > /dev/null 2>&1
	    if [ $? -ne 0 ]; then
		Warning "$server is not defined in the hosts naming database"
	    elif ! sendPing $server 5 >/dev/null 2>&1 ; then
		# Note: Reachability is not actually required for the
		# configuration of a primary but it is preferable that all
		# group members are reachable and correctly configured at
		# this point. So post a warning for any of the indicated
		# discrepancies.
		Warning "$server is unreachable."
	    else
		if ! $LDAPSEARCH -h $server -p $LDAP_PORT\
			-b "" -s base 'objectclass=*' > /dev/null 2>&1; then
		    # utdsd is not rurnning on the specified secondary
		    Warning "could not contact LDAP server on $server on port "\
			"${LDAP_PORT}."
		elif ! $LDAPSEARCH -h $server -p $LDAP_PORT \
			-b $DS_SUFFIX -s sub 'objectclass=utServer' 2>&1 | \
			grep utServer > /dev/null 2>&1; then
		    # SunRay not configured on the secondary
		    Warning "$server is not an administered Sun Ray server."
		fi

		# Note: Allow stderr from utrcmd to be printed to provide
		# information to administrator on nature of any errors.
		remote_rep=$(/opt/SUNWut/lib/utrcmd $server \
		/opt/SUNWut/sbin/utreplica -i)
		result=$?
		if [[ $result != 0 ]]; then
		    Warning "Incompatible secondary server ${server}:\
		    \n\tUnable to determine the replication status of ${server}."
		elif print $remote_rep | egrep "($PRIMARY_ID|$SECONDARY_ID)"\
			>/dev/null 2>&1; then
		    Warning "$server is already configured as a replica server."
		fi
	    fi
	done
	TOTAL_SERVER_LIST="$CURR_SERVER_LIST $NEW_SERVER_LIST"
  else
	# delete case
	TOTAL_SERVER_LIST="$NEW_SERVER_LIST"
  fi

  Update_push_block "$TOTAL_SERVER_LIST"

  # In future consider tweaking sizelimit and main timeouts

  # HUP utdsd.  Need to cleanup the utdsd.replog if it contains no "replica:"
  # info.   Otherwise, leave the utdsd.replog file alone because it may actually
  # contain valid replication data that need to be pushed to existing secondaries
  # in the case of adding a new secondary to an existing group.
  DSSERV_REPLOG=${SRDS_LDAP_VAR}/log/utdsd.replog

  # stop the utds service
  typeset utds_pid=$(pgrep utdsd 2>/dev/null)
  if [[ -n "$utds_pid" ]]; then
  	/etc/init.d/utds stop
  fi

  if [ -f $DSSERV_REPLOG ]
  then
	# only check the first line of the file.  This avoids the problem of accidentally
	# picking up the "replica" attribute which will also have the same string match.
  	head -1 $DSSERV_REPLOG | grep '^replica: ' >/dev/null 2>&1
  	if [ $? -ne 0 ]
	then
		cat /dev/null > $DSSERV_REPLOG
	fi
  fi

  # start the utdsd
  /etc/init.d/utds start

  # HUP utsvc
  # Required as utauthd connection will have been broken by RestartSunDS
  # 
  RestartUT
  RestartSunMcAgent

  print "\nConfiguration of Failover Administration has completed."
  print "Please check the log file, $LOGFILE, for errors.\n"
}

Config_Sec() {

  setTraps
  Get_datastore_suffix
  Primary_host=${SERVER_LIST}

  if grep '^pu.._replica' $SRDS_DSSERV_CONF >/dev/null 2>&1
  then      
    Fatal "Already configured as a replica server"
  fi

  if [[ $Primary_host == $HOSTNAME ]]; then
    Fatal "$HOSTNAME is not a valid Primary"
  fi

  # As Secondary configuration involves a dspull, the Primary must be
  # at least reachable.
  sendPing $Primary_host 5 >/dev/null 2>&1
  if [[ $? != 0 ]]; then
    Fatal "$Primary_host is unreachable"
  fi

  # get the LDAP port from primary
  REMOTE_LDAP_PORT=""
  Get_remote_ds_info $Primary_host
  typeset remote_st=${?}
  case ${remote_st} in
  1 | 2)	# utrcmd failed or remote utreplica returned with error
	fmt <<-!

	Unable to retrieve the SRDS port from the primary.  Please make sure
	that the SunRay software is installed/configured on the primary server.
	
	You may continue with the setup by choosing the software release running
	on the primary.

	!

	if ! ReplyIsYes "\nContinue?"; then
	    Abort "Administration Failover Configuration Aborted"
	fi
    	if ReplyIsYes "Is the primary running SunRay 1.x software?"; then
	    REMOTE_LDAP_PORT=${OLD_DEFAULT_SUNDS_PORT}
	    print "...using the old SunDS default port $REMOTE_LDAP_PORT"
	else
	    REMOTE_LDAP_PORT=${DEFAULT_SRDS_PORT}
	    print "...using the new SRDS default port $REMOTE_LDAP_PORT"
	fi
	;;
  3)	# older SR software, so use port 389
	print "Old SunRay software is running on the primary.  The old SunDS port\
	\n${OLD_DEFAULT_SUNDS_PORT} will be used."
	REMOTE_LDAP_PORT=${OLD_DEFAULT_SUNDS_PORT}
	;;
  esac

  if ! $LDAPSEARCH -h $Primary_host -p $REMOTE_LDAP_PORT\
      -b "" -s base 'objectclass=*' >/dev/null 2>&1; then
    # The specified Primary must have a running utdsd listening
    # on $REMOTE_LDAP_PORT
    Fatal "could not contact LDAP server on $Primary_host on port "\
	  "${REMOTE_LDAP_PORT}."
  elif ! $LDAPSEARCH -h $Primary_host -p $REMOTE_LDAP_PORT\
      -b $DS_SUFFIX -s sub 'objectclass=utServer' 2>&1 | grep utServer\
      > /dev/null 2>&1; then
    # The specified Primary must be a UT configured server.
    Fatal "$Primary_host is not an administered Sun Ray server."
  fi

  Get_rootdn
  Get_crypt_rootpw
  # Get admin data from the primary
  ldap_host=$Primary_host
  LDAP_PORT=$REMOTE_LDAP_PORT
  Get_datastore_admin_data
  
  # Everything should check out by here so proceed with config
  # Note: pull attempt "timeout" of 1/2 hour
  # May need tweak if really large initial datastore expected
  # In future, use snmp data to gauge this
  print "Converting Administration Standalone Server to Administration"\
	"Secondary"

  # Check servers own datastore entry count to determine potential overwrite 
  # impact.
  num_existing_entries=$(${UTSRDSDIR}/lib/utdscmd -s dsaentries |\
    awk -F: '$1 ~ /Master entries/ { print $2 }')
  if (( num_existing_entries > SIGNIFIGANT_DATASTORE )); then
    print "Examination of the local datastore has detected existing" 
    print "administration data."
    print "Completion of this operation will overwrite that data."
    if ReplyIsNo "\nContinue"; then
      Abort "Administration Failover Configuration Aborted"
    fi
  fi

  # Clean out old database and log files
  /etc/init.d/utds stop
  /bin/rm -f ${SRDS_LDAP_VAR}/dbm.ut/* ${SRDS_LDAP_VAR}/log/* ${SRDS_LDAP_VAR}/replog/*

  NEW_LDAP_PORT=$REMOTE_LDAP_PORT
  Update_init_file $NEW_LDAP_PORT
  Update_pull_block "$Primary_host"
  Update_etc_services $NEW_LDAP_PORT
  Update_utadmin_conf $NEW_LDAP_PORT

  # HUP utdsd, must restart in order to utpull to work
  /etc/init.d/utds start

  if ${UTSRDSDIR}/sbin/utpulld -o 2>&1 | grep Error >/dev/null 2>&1
  then
    Fatal "Failed to syncronize $HOSTNAME datastore with $Primary_host.\n \
      Please run utreplica -u."
  fi

  # Sync up Secondary Ut Admin write access specifiers with the Primary
  # particulars for the proxy agent and subtree.
  cp -p "$UT_ADM_CONF" "$TMP_FILE"
  sed -e "s/^\(admin.user.name[ 	]*= \).*$/\1${ADMIN_USER_DN}/" \
      -e "s/^\(admin.subtree[	 ]*= \).*$/\1${ADMIN_SUBTREE}/" \
        "$TMP_FILE" > "$UT_ADM_CONF"
  rm $TMP_FILE
  
  # HUP utsvc
  # Required both to register above utadmin.conf changes and also because
  # utauthd connection will have been broken by RestartSunDS
  #
  RestartUT
  RestartSunMcAgent

  print "\nConfiguration of Failover Administration has completed."
  print "Please check the log file, $LOGFILE, for errors.\n"
}

List() {

  # Parse files
  # Determine replica type - make checks more rigorous
  # for partial config , etc...
  if [[ ! -f $SRDS_DSSERV_CONF ]]; then
    Fatal "could not read $SRDS_DSSERV_CONF"
  fi
  if grep '^push_replica' $SRDS_DSSERV_CONF >/dev/null 2>&1
  then

      server_list=$(awk '/^push_replica/ {print $2}' $SRDS_DSSERV_CONF |\
        awk -F= '{print $2}' | awk -F: '{print $1}')

      print "$HOSTNAME is a primary server for:\n$server_list\n"

  elif grep '^pull_replica' $SRDS_DSSERV_CONF >/dev/null 2>&1
  then
      primary_host=$(awk '/^pull_replica/ {print $2}' $SRDS_DSSERV_CONF |\
        awk -F= '{print $2}' | awk -F: '{print $1}')

      print "$HOSTNAME is a secondary server"
      print "The primary server is: $primary_host\n"

  else
      print "\nNo replica context for this server\n"
  fi
}


List_State_Id() {

  # Function similar to List except this emits an I18N neutral
  # configuration ID on success for use in remote enquiries.

  if [[ ! -f $SRDS_DSSERV_CONF ]]; then
    print "${ERROR_ID}\n"
    exit 1
  fi

  # print the ldap port
  Get_local_ldap_port
  if [[ -n "${LDAP_PORT}" ]]; then
    print "${SERVICE_PORT}"="${LDAP_PORT}"
  fi

  if grep '^push_replica' $SRDS_DSSERV_CONF >/dev/null 2>&1
  then

    server_list=$(awk '/^push_replica/ {print $2}' $SRDS_DSSERV_CONF |\
      awk -F= '{print $2}' | awk -F: '{print $1}')

    # Print the I18N neutral configuration code and secondary server
    # hostname(s).
    print "${PRIMARY_ID}\n$server_list\n"

  elif grep '^pull_replica' $SRDS_DSSERV_CONF >/dev/null 2>&1
  then
    primary_host=$(awk '/^pull_replica/ {print $2}' $SRDS_DSSERV_CONF |\
      awk -F= '{print $2}' | awk -F: '{print $1}')

    # Print the I18N neutral configuration code and Primary server
    # hostname.
    print "${SECONDARY_ID}\n$primary_host\n"

  else
    print "${NON_REPLICA_ID}\n"
  fi
}


#
# sanity check for the -z option
#
# $* arguments currently left in the command line
#
Check_z() {
    if is_Primary; then
	# on the primary, you can override the default port 7012 by specifying the
	# port number.
	typeset message
	if [[ $# -eq 0 ]]; then
	    NEW_LDAP_PORT=${DEFAULT_SRDS_PORT}
	    message="the default SRDS port ${NEW_LDAP_PORT}"
	else	# one argument passed
	    message=${NEW_LDAP_PORT}
	fi
	print "Updating the port number for the SRDS service to ${message}."
    else
	# on the secondary, sync up with the primary.
	typeset primary=$(get_primary)
	Get_remote_ds_info $primary
	typeset remote_st=${?}
	if [[ $# -eq 0 ]]; then
	    # sync up with the port number on the primary
	    case "$remote_st" in
	    0)	fmt <<-!

		Syncing up the port number with the primary server
		for the SRDS service.

		!
		NEW_LDAP_PORT=$REMOTE_LDAP_PORT
		;;
	    1 | 2)
		Fatal "Unable to retrieve the port number from the primary server.\
		\nPlease make sure that the primary server is configured properly."
		;;
	    3)
	    	Fatal "Unable to retrieve the port number from the primary server.\
		\nThe primary server may be running older SunRay releases."
		;;
	    esac
	else
	    # forcing a port change on the local server.  Check against the port on the
	    # primary and warn about mismatch if any.
	    case "$remote_st" in
	    0)	if [[ "$REMOTE_LDAP_PORT" -ne "$NEW_LDAP_PORT" ]]; then
		    fmt <<-!

			The specified port "${NEW_LDAP_PORT}" does not match the one
			on the primary.  If you proceed with this change, this server may
			not be able to share the SunRay data within the failover group.
			!
		    if ReplyIsNo "\nContinue"; then
		        Abort "Administration Failover Configuration Aborted"
		    fi
		else
	    	    print "Updating the port number for the SRDS service to ${NEW_LDAP_PORT}."
		fi
		;;
	    1 | 2| 3)
		fmt <<-!

		Unable to verify the specified port number with the primary server.
		The primary server is either down, running older SunRay releases,
		or encountered some error while looking up the information.
		Please make sure that the specified port number is the same as the one
		on the primary server.  Otherwise, this server may not be able to share
		the SunRay data within the failover group.

		!
		if ReplyIsNo "\nContinue"; then
		    Abort "Administration Failover Configuration Aborted"
		fi
		;;
	    esac
	fi
    fi
}


#
# UpdatePort - update the LDAP port to NEW_LDAP_PORT
# After changing the port number in utdsd.ini, it will update the replication
# blocks to use the new port number.
UpdatePort() {

    setTraps
    if [[ -z "$NEW_LDAP_PORT" ]]; then
	Fatal "new LDAP port not defined."
    fi

    print "### updating the port number for the Administration Service to $NEW_LDAP_PORT.\n"
    # update the utdsd.ini file
    Update_init_file $NEW_LDAP_PORT

    if is_Primary; then
	# on the primary
	typeset CURR_LIST=$(get_secondaries)
	if [[ -n "${CURR_LIST}" ]]; then
	    # update the push block
	    Update_push_block "$CURR_LIST"
	fi
    else
	# on the secondary
	typeset Primary=$(get_primary)
	if [[ -n "${Primary}" ]]; then
	    # update the pull block
	    Update_pull_block $Primary
	fi
    fi
    Update_etc_services $NEW_LDAP_PORT

    Update_utadmin_conf $NEW_LDAP_PORT

    if $RESTART_SRDS; then
	typeset utdsd_pid=$(pgrep utdsd)
	if [ -z "$utdsd_pid" ]; then
	    fmt -c <<-!


		*** WARNING:

	 	The SunRay datastore service was not started because it was not
	 	running when you first started this configuration script.  Your
		recent changes will not take effect until you restart the SunRay
		services.  Here is the procedure on how to restart the SunRay 
		service manually:
		!
	    print  "\n\t\t# /etc/init.d/utds start\
		    \n\t\t# /etc/init.d/utsvc restart\
		    \n\t\t# /opt/SUNWsymon/sbin/es-stop -a\
		    \n\t\t# /opt/SUNWsymon/sbin/es-start -a"

	    RESTART_UTSVC=false
	    RESTART_SRDS=false
	fi
    fi
	
    if $RESTART_SRDS; then
	# need to restart the SRDS services
	# HUP utdsd
	RestartSunDS
	# once SRDS is restarted, the Authd must be restarted too
	RESTART_UTSVC=true
    fi
    if $RESTART_UTSVC; then
	# need to restart the SunRay services
	# HUP utsvc
	RestartUT
	RestartSunMcAgent
    fi
}



Unconfig() {

  setTraps
  # Determine replica type - make checks more rigourous
  # for partial confi , etc...
  if [[ ! -f $SRDS_DSSERV_CONF ]]; then
    Fatal "could not read $SRDS_DSSERV_CONF"
  fi
  if grep '^push_replica'  $SRDS_DSSERV_CONF >/dev/null 2>&1
  then
    # A primary
    print "Converting Server from Administration Primary to"\
	  "Administration Standalone"
    Prep_tmp_file
    Prep_backup_file $SRDS_DSSERV_CONF
    sed  '/^# SUNWutrep begin/,/^# SUNWutrep end/d'\
        $SRDS_DSSERV_CONF >> $TMP_FILE
    cat $TMP_FILE > $SRDS_DSSERV_CONF
    rm $TMP_FILE

    Prep_tmp_file
    Prep_backup_file $SRDS_DSSERV_INI
    sed 's/StartDspushd=true/StartDspushd=false/' $SRDS_DSSERV_INI\
        >> $TMP_FILE
    cat $TMP_FILE > $SRDS_DSSERV_INI
    rm $TMP_FILE

    # HUP utdsd
    RestartSunDS

    # HUP utsvc
    # Required as utauthd connection will have been broken by RestartSunDS
    RestartUT
    RestartSunMcAgent

  elif grep '^pull_replica'  $SRDS_DSSERV_CONF >/dev/null 2>&1
  then
    # A secondary
    print "Converting Server from Administration Secondary to"\
	  "Administration Standalone"
    Prep_tmp_file
    Prep_backup_file $SRDS_DSSERV_CONF
    sed  '/^# SUNWutrep begin/,/^# SUNWutrep end/d'\
        $SRDS_DSSERV_CONF >> $TMP_FILE
    cat $TMP_FILE > $SRDS_DSSERV_CONF
    rm $TMP_FILE

    # Leave utadmin.conf based on the inherited datastore.
    # Only other alternative is to revert datastore naming to standalone
    # hostname based entries. This would require re-generation of most
    # of the datastore - not trivial in situation with large data
    # However, ensure that ACL is revised to reflect local access by a proxy
    # agent based on the inherited datastore particulars when returning to
    # Administration Standalone from Slave. This ACL was not required while
    # operating as Secondary.
    Sync_LDAP_ACL_with_datastore_data

    # HUP utdsd
    RestartSunDS

    # HUP utsvc
    # Required as utauthd connection will have been broken by RestartSunDS
    RestartUT
    RestartSunMcAgent
  else
    Fatal "No replica context for this server"
  fi

  print "\nUnconfiguration of Administration Failover has completed."
  print "\nPlease run /opt/SUNWut/sbin/utconfig -u to complete the"\
	"process of converting it to a standalone server."
  print "Please check the log file, $LOGFILE, for errors.\n"
}


#
# setMode - this routine is used to check if more than one option is
#	specified.  It will first check to see if the $1 variable is set.
#	If set, prints error message and exits.  Otherwise, it just echoes the
#	argument $1.
setMode() {
    if [[ -z "$2" ]] || [[ "$2" = "$1" ]]; then
	echo $1
	return 0
    else
	Generic_Err_Print "conflicting options -${2} and -${1}"
	Usage
    fi
}


#
# getServerList - this routine is used to parse the server list arguments.
#	It also checks to see if there is any additional option is specified
#	within the list.  If an option is found, prints error message and exits.
#	Otherwise, it assigns the list of servers to $SERVER_LIST.
getServerList() {
    typeset -l srv
    for srv in $*
    do
	case $srv in
	-*) Generic_Err_Print "illegal option $srv found in server list"
	    Usage;;
	*)  getent hosts $srv >/dev/null 2>&1
	    if [ $? -eq 0 ]; then
		if [ -z $SERVER_LIST ]; then
		    SERVER_LIST=$srv
		else
		    SERVER_LIST="$SERVER_LIST $srv"
		fi
	    else
		Generic_Err_Print "server \"$srv\" not found in the hosts naming\
		\ndatabase.  Please either correct the server name or add this new\
		\nserver into the hosts naming database."
		exit 1
	    fi
	    ;;
	esac
    done
}

#
# main {
#
OS=`uname -s`
CheckUidIsZero
SetPlatformDependencies

# Note: i option is undocumented.
OPTSTR=":lupsiadz"
# check params
if (( $# == 0 )); then
  Usage
fi

setTraps

while getopts $OPTSTR OPT; do
    case "$OPT" in
    z)	if ! MODE=$(setMode "z" "$MODE"); then exit 1; fi;;
    p)	if ! MODE=$(setMode "p" "$MODE"); then exit 1; fi;;
    s)	if ! MODE=$(setMode "s" "$MODE"); then exit 1; fi;;
    u)	if ! MODE=$(setMode "u" "$MODE"); then exit 1; fi;;
    l)	if ! MODE=$(setMode "l" "$MODE"); then exit 1; fi;;
    i)	if ! MODE=$(setMode "i" "$MODE"); then exit 1; fi;;
    a)	if ! SUBMODE=$(setMode "a" "$SUBMODE"); then exit 1; fi;;
    d)	if ! SUBMODE=$(setMode "d" "$SUBMODE"); then exit 1; fi;;
   \?)	Usage;;
    esac
done
shift $(($OPTIND - 1))

if [[ -n "$SUBMODE" ]] && [[ $MODE != "p" ]]; then
    Generic_Err_Print "invalid -${SUBMODE} option with -${MODE}"
    Usage
elif [[ $MODE = "z" ]]; then
    typeset message=""
    if [[ $# -gt 1 ]]; then
	Generic_Err_Print "-z option only accepts 0 or 1 argument"
	Usage
    fi
    if [[ $# -eq 1 ]]; then
	# check for the port number specified
	if isValidPort "$@"; then
	    NEW_LDAP_PORT=$1
	else
	    Usage
	fi
    fi
    Check_z $*
elif [[ $MODE = "u" ]] || [[ $MODE = "l" ]] || [[ $MODE = "c" ]]; then
    # options that take no arguments
    if [[ $# -ne 0 ]]; then
	Usage
    fi
elif [[ $MODE = "p" ]]; then
    if [[ $# -gt 0 ]]; then
	getServerList $*
    else
	Generic_Err_Print "-p option requires one or more secondary server names"
	Usage
    fi
elif [[ $MODE = "s" ]]; then
    if [[ $# -eq 1 ]]; then
	getServerList $*
    else
	if [[ $# -eq 0 ]]; then
	    Generic_Err_Print "-s option requires the primary server name"
	else
	    Generic_Err_Print "more than one primary server specified.  Only one\
	    \nprimary server name should be specified with the -s option."
	fi
	Usage
    fi
fi

if [[ $MODE = "s" ]]; then
  param_cnt=$(print $SERVER_LIST | wc -w)
  (( param_cnt == 1 )) || Usage
fi

# Check for SRS
UT_PROD_NAME="Sun Ray server"
UT_VERSION="3.1"
if ! UTInstalled; then
   Fatal "$UT_PROD_NAME is not installed on this host"
fi

# Check for SDS
UTA_BASEDIR="$($UTPRODDIR/utprodinfo -r SUNWuta)/SUNWut"
UTO_BASEDIR="$($UTPRODDIR/utprodinfo -r SUNWuto)/SUNWut"
ETC_OPT_UT="/etc/opt/SUNWut"
UT_TEMPLATE_LDAP="$UTA_BASEDIR/etc/template/ldap"
SRDS_PROD_NAME="Sun Ray Data Store"
SRDS_VERSION="2.1"
SRDS_PACKAGE="SUNWutdso"
if ! SunDSInstalled; then
  Fatal "$SRDS_PROD_NAME is not installed on this host"
elif ! SunDSVersion $SRDS_VERSION; then
  Fatal "version $SRDS_VERSION of $SRDS_PROD_NAME is not installed on this host"
elif SunDSInstallPartial; then
  Fatal "$SRDS_PROD_NAME version $SRDS_VERSION is only partially installed"
fi


# check for LDAP Client libs
LCL_PROD_NAME="LDAP Client Libraries"

if [ -z $LCL_PACKAGE ]; then
   Fatal "$LCL_PROD_NAME is not installed on this host"
elif ! LdapClientInstalled; then
   Fatal "$LCL_PROD_NAME is not installed on this host"
elif LdapClientInstallPartial; then
   Fatal "$LCL_PROD_NAME is only partially installed"
fi

# Ensure that utconfig has been utilised
if [[ ! -f $UT_ADM_CONF ]]; then
  Fatal "please run utconfig prior to using utreplica"
fi

print "\n$UT_PROD_NAME $UT_VERSION"
print "Administration Failover Configuration\n"

print "# Script: ${PROGRAM_ID}\tVersion: 3.1_32.18,REV=2005.08.24.08.55\n" > $LOGFILE

Prep_err_file
case "$MODE" in
  p)	Config_Pri 2>&1 | tee -a $LOGFILE;;
  s)	Config_Sec 2>&1 | tee -a $LOGFILE;;
  u)	Unconfig   2>&1 | tee -a $LOGFILE;;
  l)	List ; rm $LOGFILE;;
  i)	List_State_Id ; rm $LOGFILE;;
  z)	UpdatePort 2>&1 | tee -a $LOGFILE;;
esac

EXIT_STAT=$(< $ERR_FILE)
Remove_err_file
if [[ $EXIT_STAT -eq 1 ]]; then
  exit 1
else
  exit 0
fi

# }
