#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72Q src/bos/usr/lib/nim/methods/c_viosbr.sh 1.7 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2018 
# 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 
#
# @(#)17 1.7 src/bos/usr/lib/nim/methods/c_viosbr.sh, cmdnim, bos72Q, q2018_48A1 10/18/18 13:09:06 
#
#   COMPONENT_NAME: CMDNIM
#
#   FUNCTIONS: ./usr/lib/nim/methods/c_viosbr.sh
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 2018
#   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=${0%/*}
NIMPATH=${NIMPATH%/*}
[[ ${NIMPATH} = ${0} ]] && NIMPATH=/usr/lpp/bos.sysmgt/nim
NIM_METHODS="${NIMPATH}/methods"
. ${NIM_METHODS}/c_sh_lib

#---------------------------- local defines     --------------------------------
VIOSBR="/usr/ios/cli/ioscli viosbr"
CLSTARTSTOP="/usr/ios/utils/clstartstop"
viosbr_mnt_dir=""

#---------------------------- module globals    --------------------------------
REQUIRED_ATTRS="location viosbr_action" 
OPTIONAL_ATTRS="viosbr_flags force_push server force clustername skipcluster currentdb mount_opts obj_name"
location=""
viosbr_action=""
viosbr_flags=""
force_push=""
server=""
force=""
clustername=""
skipcluster=""
currentdb=""
mount_opts=""
obj_name=""
set_reboot=""
rm_itab=""

#------------------------------- check_space -----------------------------------
#
# NAME: check_space
#
# FUNCTION:  Calculate the maximum amount of space required for 
#            the viosbr image along with the free space available
#            in the target location.  If the maximum required is 
#            greater than the space available, give an error and 
#            exit.  Otherwise, show the user the space 
#            requirements and continue.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#       calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#       parameters:
#       global:  location_access
#
# RETURNS: (int)
#       0                   = success
#
# OUTPUT:
#-------------------------------------------------------------------------------
function check_space {

	typeset FREE_SPACE=0

	# get the free space in the target filesystem 
	# (in 1024-byte blocks)
	FREE_SPACE=`${DF} -k \`${DIRNAME} ${location_access}\` | ${AWK} 'NR==2{print $3}'`
	[[ -z "${FREE_SPACE}" ]] && err_from_cmd ${DF}

	(( REQ_MEG = 1024 * 5 ))

	# is there enough space for the viosbr image? 
	if (( REQ_MEG > FREE_SPACE )); then
		# if force ignore space requirements 
		if [[ "${force}" != "yes" ]]; then
			# 0042-210 <method>: The maximum space required for the backup is greater
			# 	than the amount of free space in the target filesystem.  To ignore
			# 	space requirements use the "-F" flag when defining the mksysb
			# 	resource.
			error ${ERR_SPACE_MKSYSB}
		fi
	fi 

} # end check_space

#---------------------------- c_viosbr_cleanup ----------------------------
#
# NAME: c_viosbr_cleanup 
#
# FUNCTION:  Call the generic cleanup function to make sure
#            everything gets unmounted.
#
# EXECUTION ENVIRONMENT:
#
# NOTES:
#       calls error on failure
#
# RECOVERY OPERATION:
#
# DATA STRUCTURES:
#       parameters:
#       global:
#
# RETURNS: 
#
# OUTPUT:
#-------------------------------------------------------------------------------
function c_viosbr_cleanup {

	# clean up the mount point if we mounted the image write directory over.
	# we need to do this here since if the unmount fails the entire directory 
	# might get erased.  
	if [[ -n "${viosbr_mnt_dir}" ]]; then
		nim_unmount ${viosbr_mnt_dir} 2>/dev/null

		# Check to see if the unmount failed.  If it failed then
		# leave the temporary directory there.  We don't want to 
		# inadvertently erase extra files.
		${MOUNT} | ${EGREP} -q ${viosbr_mnt_dir}
		if [[ $? -ne 0 ]]; then
			${RM} -r ${viosbr_mnt_dir}
		fi
	fi

	cleanup
	unmount_meth_dir >/dev/null 2>&1

} # end c_viosbr_cleanup


function unmount_meth_dir {

	typeset filename="/tmp/__NIMCLIENT_viosbr.mnt"

	# Check if methods dir has been mounted
	if [[ "$force_push" = "yes" ]]; then
		# lets verify that the cron daemon is running
		cron_up=`${PS} -u root | ${GREP} -q cron; echo $?`
		if [ -z "$cron_up" ] || [ "$cron_up" != "0" ]
		then
		  /usr/sbin/cron >/dev/null 2>&1 &
		fi
		# unmount methods dir (nfs filesystem mount)
		echo "cd / ; ${SLEEP} 1 ; ${UMOUNT} ${NIM_METHODS}" > $filename

		${CHMOD} 755 $filename
		${AT} now < $filename > /dev/null 2>&1
		${RM} $filename
	fi
}

function send_Cresult {

	typeset status=${1:-success}
	typeset filename="/tmp/__NIMCLIENT_viosbr.rc"

	# create a cron job to update the database object?
	if [[ "$viosbr_action" = "restore" ]]; then

		# lets verify that the cron daemon is running
		cron_up=`${PS} -u root | ${GREP} -q cron; echo $?`
		if [ -z "$cron_up" ] || [ "$cron_up" != "0" ]
		then
			/usr/sbin/cron >/dev/null 2>&1 &
		fi

		# send client status of cmd execution
		echo "cd / ; ${SLEEP} 3 ; ${NIMCLIENT} -R $status" > $filename

		# remove inittab entry?
		if [[ -n $rm_itab ]]; then
			echo "${RMITAB} c_viosbr 2>/dev/null" >> $filename
		fi

		# reboot required?
		if [[ -n $set_reboot ]]; then
		       	echo "${SHUTDOWN} -Fr" >> $filename
			${NIMCLIENT} -o change -a force=yes \
			  -a ignore_lock=yes -a info="Rebooting.. additional devices will be restored upon restart"
		else
			${NIMCLIENT} -o change -a force=yes -a ignore_lock=yes -a info=""
		fi

		${CHMOD} 755 $filename
		${AT} now < $filename > /dev/null 2>&1
		${RM} $filename
	else
		${NIMCLIENT} -R $status
	fi
}


#-------------------------------  MAIN  ---------------------------------------

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

# NIM initialization
nim_init
RC=0

undo_on_interrupt=c_viosbr_cleanup

# set parameters from command line
while getopts :a:qv 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
			;;

		\?)	# unknown option
			# 0042-016 <method>: "-<OPTARG>" is not a valid option for this
			# operation
			# 	<>
			error ${ERR_BAD_OPT} ${OPTARG}
			;;
	esac
done

# check for missing attrs
ck_attrs

# mount the remote location 

# going to create a tmp directory at "/tmp/$$.mnt"
# look for lowest, unused seqno
typeset -i idx=0
while (( ${idx} < ${MAX_MNT} )); do
	viosbr_mnt_dir="/tmp/$$.mnt${idx}"
	[[ ! -d ${viosbr_mnt_dir} ]] && break
	let idx=idx+1
done
(( ${idx} >= ${MAX_MNT} )) && error ${ERR_GEN_SEQNO} /tmp/$$.mnt

${MKDIR} ${viosbr_mnt_dir} 2>${ERR} || err_from_cmd ${MKDIR}

if [[ "$viosbr_action" = "backup" ]]; then
	nim_mount ${server}:`${DIRNAME} ${location}` ${viosbr_mnt_dir}
	location_access=${access_pnt}/`${BASENAME} ${location}`
else
	nim_mount ${location} ${viosbr_mnt_dir}/`${BASENAME} ${location}`
	location_access=${access_pnt}
fi

# do space checking for ios_backup image
check_space

# Execute the ioscli viosbr program, log output to the nim.script log
${C_TIME_STAMP} >> ${SCRIPT_LOG}

rcfile="${TMPDIR}/_viosbr$$.rc"

# call viosbr (using appropriate command action)
case $viosbr_action in
	backup)	  # create the backup image
		(
		  eval ${VIOSBR} -backup -file "${location_access}" ${clustername:+-clustername "$clustername"}
		  echo $? > $rcfile
		  ) 2>&1 | ${TEE} -a ${SCRIPT_LOG}
		  ;;

	view)	  # view contents of the backup image
		(
		  eval ${VIOSBR} -view -file "${location_access}" ${clustername:+-clustername "$clustername"} "${viosbr_flags}"
		  echo $? > $rcfile
		  ) 2>&1 | ${TEE} -a ${SCRIPT_LOG}
		  ;;

	recoverdb) # recover from a corrupted SSP database
		(
		  eval ${VIOSBR} -recoverdb ${clustername:+-clustername "$clustername"} -file "${location_access}"
		  echo $? > $rcfile
		  ) 2>&1 | ${TEE} -a ${SCRIPT_LOG}
		  ;;

	restore)  # restore the backup image

		  # First, verify the interface defines..remove any in 'Stopped' state
		  for interface in `LANG=C ${LSDEV} -Cc if | ${AWK} '/Stopped /{print $1}'`
		  do
			  ${RMDEV} -l ${interface} >/dev/null 2>&1
		  done

		  # Notify master of viosbr restore
		  ${NIMCLIENT} -o change -a force=yes -a ignore_lock=yes -a info="Restoring viosbr backup.."
		(
		  eval ${VIOSBR} -restore ${clustername:+-clustername "$clustername"} -file "${location_access}" "${viosbr_flags}" ${skipcluster:+-skipcluster} ${currentdb:+-currentdb}
		  echo $? > $rcfile
		  ) 2>&1 | ${TEE} -a ${SCRIPT_LOG}

		  [[ -s $rcfile ]] && RC=`${CAT} $rcfile`

		  # assume we're called from init
		  # (if presence of /etc/inittab entry)
		  /usr/sbin/lsitab c_viosbr >/dev/null 2>&1
		  if [[ $? -eq 0 ]]; then
			 # remove force_push attr - no methods dir to unmount
			 unset force_push
			 # remove old inittab entries
			 rm_itab="yes"
			 # dealloc of ios_backup required
			 ${NIMCLIENT} -o deallocate -aios_backup=${obj_name} 2>&1 | ${TEE} -a ${SCRIPT_LOG}
		  fi

		  # for cluster restores, we must restart the cluster
		  if [[ $RC -eq 0 ]] && [[ -n $clustername ]]; then
			 # Notify master of cluster start
			 ${NIMCLIENT} -o change -a force=yes -a ignore_lock=yes -a info="Attempting to start cluster.."
			(
			eval ${CLSTARTSTOP} -start -n ${clustername} -m `$HOSTNAME`
			echo $? > $rcfile
			) 2>&1 | ${TEE} -a ${SCRIPT_LOG}
		  elif [[ $RC -eq 98 ]]; then
			# special handling for reboot attempt
			typeset varargs="$@"
			echo "${NIMCLIENT} -o allocate -aios_backup=${obj_name} 2>/dev/null" >> /etc/firstboot

			# If called from lsitab, then no need for mkitab entry
			# Else, clear out original rm_itab setting
			if [[ -z $rm_itab ]]; then
				${MKITAB} -i ctrmc "c_viosbr:2:once:${NIM_METHODS}/c_viosbr $varargs > /dev/console 2>/dev/null #re-attempt the viosbr restore" \
					2>&1 | ${TEE} -a ${SCRIPT_LOG}
			else
				rm_itab=""
			fi
			# reboot required
			set_reboot="yes"
			${RM} $rcfile && RC=0
		  fi
		  ;;

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

${C_TIME_STAMP} -e >> ${SCRIPT_LOG}

# exit with return code from viosbr
if [[ -s $rcfile ]]; then
	RC=`${CAT} $rcfile`
	${RM} $rcfile
fi

# inform the master of the result
[[ $RC -eq 0 ]] && send_Cresult "success" || send_Cresult "failure"

# all done
exit $RC
