#!/bin/sh
#
#    Copyright (c) 2005-2006 Brocade Communications Systems, Inc.
#    All rights reserved.
#
#    File name:   date
#    Module name: fabos/src/utils/sys
#
#    This script is wrapper to the traditional /bin/date command
#    to be able to save the changed date into flash. It also
#    propagates date to the counterpart CP.
#
export PATH=/fabos/sbin:/fabos/bin:/bin:/usr/bin:/sbin

SWBD_SKYBOLT=SWBD148
SWBD_AMP=SWBD171
SWBD_AWING=SWBD178

# [ Applicable for both Amp, Skyb
SKYB_AMP_DP0_IP=127.2.10.20
SKYB_AMP_DP1_IP=127.2.10.21
# ]

#To fetch system HW time
DATE_VAL=0
#Allowed range in number of seconds for the date change operation
MAX_LIMIT=0

date_usage() {
	
		echo "Usage:"
		echo "To show usage:"
		echo "	date -h"
		echo "	date --help"
		echo "To display date:"
		echo "	date [-u|--utc|--universal]"
		echo "To change date:"
		echo "	date MMDDhhmm[YY]"
		echo "	date [-u|--utc|--universal] MMDDhhmm[YY]"
}

#
# check_time_lic_present
#
# Checks whether the temporary licenses are 
# installed on the switch
#
# Return value:
#	0 if temporary licenses are installed
#	0 if TruFOS Certicate is not installed
#	0 if TruFOS Certicate is Expired
#	1 if temporary licenses are not installed
#
check_time_lic_present()
{
	/fabos/libexec/lutil -t 2>&1 
	ret_val=$?
	# echo "check_time_lic_present:ret_val: $ret_val"
	if [ $ret_val -eq 1 ];
	then
		# Temporary licenses are installed
		# Exit without changing the date
		echo "Cannot change the date since temporary licenses are installed on the switch"
		return 0
	elif [ $ret_val -eq 2 ];
	then
		echo "Cannot change the date since TruFOS certificate is not installed on the switch"
		return 0
	elif [ $ret_val -eq 3 ];
	then 
		echo "Cannot change the date since TruFOS certificate is expired"
		return 0
	else
		return 1
	fi
}


# get_hw_date
#
# Get the hardware date value from the system
#
# Return value:
# -1: Error
# <value>: Correct system date value
#
get_hw_date()
{
	DATE_VAL=`/fabos/libexec/lutil -c 2>&1`
	if [ $? -eq -1 ]
	then
		return 1
	else
		return 0
	fi
}


# get_date_change_max_limit_str
#
# Get the max limit value allowed for the date change operation
#
# Return value:
# -1: Error
# <value> : Correct allowed max limit value for date change
#
get_date_change_max_limit_str()
{
	MAX_LIMIT=`/fabos/libexec/lutil -g 2>&1`
	if [ $? -eq -1 ]
	then
		return 1
	else
		return 0
	fi
}

#
# swbd
#
# Retrieve the current system platform name, of the form "SWBDn", where n
# is cardinal number, assuming a sin input stream.
#
swbd()
{
    sed -n -e 's/^.\+\(SWBD[[:digit:]]\{1,\}\).\+$/\1/gp'
}

#
# set_dp_time
# 
# If Skybolt or AMP platform, sync the CP time to each DP.
# As date command on DP is trimmed down binary with less
# switches, get the CP time/date and frame a custom date
# command runnable at each DP.
#
set_dp_time() 
{
	SWBD=`/sbin/sin | swbd 2> /dev/null`

	if [ $SWBD = $SWBD_SKYBOLT ] || \
	   [ $SWBD = $SWBD_AWING ] || \
	   [ $SWBD = $SWBD_AMP ]; then
		# DP0
		ping -c 1 $SKYB_AMP_DP0_IP >/dev/null
		if [ $? -eq 0 ]; then
			# pingable, attempt DP0 time sync
			local_cp_date_time=`/bin/date '+%Y.%m.%d-%H:%M:%S'`
			rsh -n $SKYB_AMP_DP0_IP date -s $local_cp_date_time >/dev/null
			if [ $? -ne 0 ]; then
				echo "date: DP0 date/time sync failed with $?"
			fi
		else
			echo "date: $SWBD: DP0 Unreachable, skipped timesync"
		fi

		# DP1

		if [ $SWBD != $SWBD_AWING ]; then
			ping -c 1 $SKYB_AMP_DP1_IP >/dev/null
			if [ $? -eq 0 ]; then
				# pingable, attempt DP1 time sync
				local_cp_date_time=`/bin/date '+%Y.%m.%d-%H:%M:%S'`
				rsh -n $SKYB_AMP_DP1_IP date -s $local_cp_date_time >/dev/null
				if [ $? -ne 0 ]; then
					echo "date: DP1 date/time sync failed with $?"
				fi
			else
				echo "date: $SWBD: DP1 Unreachable, skipped timesync"
			fi
		fi
	fi
}

check_context_switch_required() {
	if [ "$VF_ENABLED" == "1" ] && [ "$FABOS_SWITCHNO" != "0" ]; then
		return 1
		return 0
	fi
}

# This function checks if 64 seconds has lapsed since the last date change operation.
# Is yes, then return 1, else 0.
check_last_date_change_time_lapsed() {
	current_vf=$CURRENT_VF
	check_context_switch_required
	switch_context=$?
	if [ $switch_context -eq 1 ]; then
		eval $(/fabos/cliexec/lscfg_util --chassis)
	fi
	last_dateset_timestamp=`/fabos/cliexec/config get date.timestamp 2`
	if [ $switch_context -eq 1 ]; then
		eval $(/fabos/cliexec/lscfg_util --switch $current_vf)
        fi

	if [ -z "$last_dateset_timestamp" ]; then
		return 1
	fi
	current_timestamp=`/bin/date +%s`
	if [ $current_timestamp -gt $last_dateset_timestamp ]; then
		time_lapse=`expr $current_timestamp - $last_dateset_timestamp`
	else
		time_lapse=`expr $last_dateset_timestamp - $current_timestamp`
	fi
	if [ $time_lapse -gt 64 ]; then
		return 1
	else
		return 0
	fi
}

# Skip checking Director Clock Alert Mode of FICON-CUP if first param is -nDCAM
# This parameter is used when setting date through MS-API.
chk_DCAM=1
if [ "$1" = "-nDCAM" ]; then
   chk_DCAM=0
   shift
fi

if [ $? -ne 0 ]; then
	exit 127
fi

if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
	if [ $# -gt 1 ]; then
		echo "Failed: Invalid argument passed"
	fi
	date_usage
	exit
elif [ "$1" = "-u" ] || [ "$1" = "--utc" ] || [ "$1" = "--universal" ]; then
	if [ $# -gt 2 ]; then
		date_usage
		exit
	fi
else
	if [ $# -gt 1 ]; then
		date_usage
		exit
	fi
fi


setOp=0
if [ $# -gt 1 ]; then
	args=$(echo $* | tr ' ' '\n')
	for arg in $args
	do
		if [ `echo $arg |cut -c -2` = "-s" -o `echo $arg |cut -c -3` = "--s" ]; then
			setOp=1
		fi
	done
fi

if [ $# -eq 0 ]; then
   /bin/date
elif [ $# -eq 1 ] || \
     [ "$1" = "-u" ] || \
     [ "$1" = "--utc" ] || \
     [ "$1" = "--universal" ] || \
     [ $setOp -eq 1 ] || \
     [ `echo $1|cut -d' ' -f1|  wc --bytes 2> /dev/null` -gt 2  -a \
       `echo $1 |cut -c -2 2> /dev/null` = "-s"	] || \
     [ `echo $1|cut -d' ' -f1|  wc --bytes 2> /dev/null` -gt 2  -a \
       `echo $1 |cut -c -3 2> /dev/null` = "--s" ]; then

        #user=`/usr/bin/whoami`
	user=`echo $SWLOGNAME`
#Find whether it is read or write command.


        if [ `echo $1|cut -d' ' -f1|  wc --bytes 2> /dev/null` -gt 2 ] && [ `echo $1 |cut -c -2` = "-s" \
              -o `echo $1 |cut -c -3` = "--s" ]; then
               setOp=2
        elif [ $# -eq 1 ]; then
	       arg=`echo $1 |cut -c -1`
               if [ "$arg" != "-" \
                    -a "$arg" != "+" ]; then
	            setOp=2
	       fi
	elif [ $# -gt 1 ]; then
               if [ "$1" = "-u" \
         	    -o "$1" = "--utc" \
                    -o "$1" = "--universal" ]; then
		  setOp=3
               fi
	fi

	#Check for Time based licenses.
	if [ $setOp -eq 1 -o $setOp -eq 2 -o $setOp -eq 3 ]; then
		# Check if 64 seconds has lapsed since previous date set operation
      check_last_date_change_time_lapsed
       if [ $? -eq 0 ]; then
              echo "Date change within 64 seconds from previous change is not allowed"
              exit
        fi

		# Check whether the temporary licenses are 
		# installed on the switch
		check_time_lic_present
		ret_val=$?
		if [ $ret_val -eq 0 ]; then
			exit
		fi

    		# Check whether hardware date value can be fetched
		# from the switch.
		get_hw_date
		ret_val=$?
		if [ $ret_val -eq 1 ]; then
			# Error
			# Exit without changing the date
			echo "Cannot change the date. Hardware date value error reported."
			exit
		fi

		# Check whether max limit allowed range for date change operation
		# can be fetched.
		get_date_change_max_limit_str
		ret_val=$?
		if [ $ret_val -eq 1 ]; then
			# Error
			# Exit without changing the date
			echo "Cannot change the date. Allowed limit range error reported."
			exit
		fi

		/fabos/sbin/eos_check
		if [ $? -eq 1 ];then
			# EOS time reached
			# Exit without changing the date
			exit
		fi
	fi

#Check for active CP or non Ulys switch. 
	chassis_info=`getchassisconfig`
	ischassis=`echo $chassis_info | \
		sed -n -e 's/.*Chassis based system: //gp' | \
		sed -n -e 's/ .*//gp'`
	num_switches=`echo $chassis_info | \
		sed -n -e 's/Number of switches: //gp' | \
		sed -n -e 's/ .*//gp'`
	if [ "$ischassis" = "Yes" ]; then
		cp=`/fabos/cliexec/hashow | /bin/grep Local | \
	    /bin/sed -e "s/[ ]*//g" | /usr/bin/cut -d: -f2 | \
	    /usr/bin/cut -d, -f1 2> /dev/null`
	fi

	if [ $setOp -eq 0 ]; then
	            /bin/date $* 2> /dev/null
         	    if [ $? -eq 1 ]; then
			echo "Failed: Invalid argument passed"
			date_usage
			exit 1
		    fi
#It is a write command so check if it is Active CP.
        elif [ "$cp" = "Active" -o "$ischassis" != "Yes" ]; then

#Check with Time Service if date can be changed
             /fabos/cliexec/tsIsUpdatable

# ERROR is non-zero; OK is zero
             ts_ret=$?

             if [ $ts_ret -ne 0 ]; then
                 exit
             fi

#
# Warn the user if the Director Clock Alert Mode of FICON-CUP is ON.
# This check is not performed for Access Gateway
#
	     AG_FILENAME=/etc/fabos/ag_platform.$FABOS_SWITCHNO
	     if [ -f $AG_FILENAME ]; then
	             SWITCH_AGMODE=1
	     else
	             SWITCH_AGMODE=0
	     fi
	     if [ $SWITCH_AGMODE -eq 0 -a $chk_DCAM -eq 1 ]; then
                 ficoncupshow modereg DCAM |grep 1  > /dev/null 2>&1
                 if [ $? -eq 0 ]; then
                    echo "date: Warning! Director time stamp is about to be modified."
                    echo "      Do you want to continue? [y/n] :"
                    read response
                    if [ "$response" != "y" -a "$response" != "Y" ]; then
                        echo "date: Aborting date modification..."
                        exit
                    fi
                 fi
             fi
		# setOp as 1 and 2 are same except for arguments passed to /bin/date,
		#option +%T won't work with "".
		if [ $setOp -eq 1 ]; then
			olddate=$(/bin/date +"%D-%T");
			#Validating user provided input date is as per date man page
			if [[ $1 =~ [^0-9] ]]; then
				echo "Failed: Invalid argument passed"
				date_usage
				exit 1
			else
				# Parse the date in date "MMDDhhmmYY (or) MMDDhhmm" format
				# and convert it into MM/DD/YY hh:mm (or) MM/DD hh:mm
				# which will be the applicable format to convert it in EPOCH
				# seconds.
				wc_argc=`echo -n $1 | wc -c`
				# Allowed arguments are "MMDDhhmmYY (or) MMDDhhmm", so input
				# date value should be greater than or equal to 8.
				if [ "$wc_argc" -lt "8" ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				if [ "$wc_argc" -gt "8" ]; then
					newdate="${1:0:2}/${1:2:2}/${1:8:2} ${1:4:2}:${1:6:2}"
				else
					newdate="${1:0:2}/${1:2:2} ${1:4:2}:${1:6:2}"
				fi
			
				#Convert the newdate value in EPOC seconds for RTA validation
				newdateS=$(/bin/date -d "$newdate" +%s);
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				#Validate date change is within range for RTA validation
				if [ "$newdateS" -gt "$DATE_VAL" ]; then
					time_diff=`expr $newdateS - $DATE_VAL`
				else
					time_diff=`expr $DATE_VAL - $newdateS`
				fi
				if [ "$time_diff" -gt "$MAX_LIMIT" ]; then
					echo "Error: Date change not within allowed range of +-7 days"
					exit
				fi
				# Set the new date as it passed RTA validation
				/bin/date $* 2> /dev/null
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1 
				fi	
				newdate=$(/bin/date +"%D-%T");
			fi
				
		   # date change notify to raslogd quiet time 
		   /fabos/cliexec/quietdatechange

		elif [ $setOp -eq 2 ]; then
			olddate=$(/bin/date +"%D-%T");
			#date "MMDDhhmmYY" format, which will have setOp 2 been set
			# Parse the date in date "MMDDhhmmYY (or) MMDDhhmm"
			# format and convert it into MM/DD/YY hh:mm (or)  MM/DD hh:mm
			# which will be the applicable format to convert it in EPOCH
			# seconds.
			wc_argc=`echo -n "$1" |wc -c`
			#Validating user provided input date is as per date's man page
			if [[ $1 =~ [^0-9] ]]; then
				echo "Failed: Invalid argument passed"
				date_usage
				exit 1
			else
				# Allowed arguments are "MMDDhhmmYY (or) MMDDhhmm", so input
				# date value should be greater than or equal to 8.
				if [ "$wc_argc" -lt "8" ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				if [ "$wc_argc" -gt "8" ]; then
					newdate="${1:0:2}/${1:2:2}/${1:8:2} ${1:4:2}:${1:6:2}"
				else
					newdate="${1:0:2}/${1:2:2} ${1:4:2}:${1:6:2}"
				fi
				#Convert the newdate value in EPOC seconds for RTA validation
				newdateS=$(/bin/date -d "$newdate" +%s);
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				#Validate date change is within range for RTA validation
				if [ "$newdateS" -gt "$DATE_VAL" ]; then
					time_diff=`expr $newdateS - $DATE_VAL`
				else
					time_diff=`expr $DATE_VAL - $newdateS`
				fi
				if [ "$time_diff" -gt "$MAX_LIMIT" ]; then
					echo "Error: Date change not within allowed range of +-7 days"
					exit
				fi
				# Set the new date as it passed RTA validation
				/bin/date "$*" 2> /dev/null
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1 
				fi	
				newdate=$(/bin/date +"%D-%T");
			fi
			# date change notify to raslogd quiet time
			/fabos/cliexec/quietdatechange

		elif [ $setOp -eq 3 ]; then
			olddate=$(/bin/date +"%D-%T");
			#Validating user provided input date is as per date's man page
			if [[ $2 =~ [^0-9] ]]; then
				echo "Failed: Invalid argument passed"
				date_usage
				exit 1
			else
				# Parse the date in date -u "MMDDhhmmYY (or) MMDDhhmm"
				# format and convert it into MM/DD/YY hh:mm (or) MM/DD hh:mm
				# which will be applicable format to convert it in EPOCH
				# seconds.
				wc_argc=`echo -n $2 | wc -c`
				# Allowed arguments are "MMDDhhmmYY (or) MMDDhhmm", so input
				# date value should be greater than or equal to 8.
				if [ "$wc_argc" -lt "8" ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				if [ "$wc_argc" -gt "8" ]; then
					newdate="${2:0:2}/${2:2:2}/${2:8:2} ${2:4:2}:${2:6:2}"
				else
					newdate="${2:0:2}/${2:2:2} ${2:4:2}:${2:6:2}"
				fi
				#Convert the newdate value in EPOC seconds for RTA validation
				newdateS=$(/bin/date -d "$newdate" +%s);
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1
				fi
				#Validate date change is within range for RTA validation
				if [ "$newdateS" -gt "$DATE_VAL" ]; then
					time_diff=`expr $newdateS - $DATE_VAL`
				else
					time_diff=`expr $DATE_VAL - $newdateS`
				fi
				if [ "$time_diff" -gt "$MAX_LIMIT" ]; then
					echo "Error: Date change not within allowed range of +-7 days"
					exit
				fi
				# Set the new date as it passed RTA validation
				/bin/date $* 2> /dev/null
				if [ $? -eq 1 ]; then
					echo "Failed: Invalid argument passed"
					date_usage
					exit 1 
				fi	
				newdate=$(/bin/date +"%D-%T");
			fi
			# date change notify to raslogd quiet time
			/fabos/cliexec/quietdatechange

		else
		  date_usage
		  exit 1
		fi

                if [ $? -eq 0 ]; then

                   /sbin/hwclock -w --utc
				   set_dp_time
#Find if counterpart CP exists and then proceed.
                   output=`/sbin/sin|grep "Processor No"  2> /dev/null`
	           if [ $? -eq 0 ]; then	
                      IDX=`sin |grep "Processor No"| cut -d: -f2 2> /dev/null`
                      if [ $IDX -eq 0 ]; then
                         RIDX=6
                      else
                         RIDX=5
                      fi
		   fi

	           output=`/fabos/bin/hashow 2>/dev/null`	
                   if [ $? -eq 0 -a "$cp" = "Active" ]; then
                      redundant=`/fabos/bin/hashow |grep "Remote" |cut -d' ' -f6 2> /dev/null`
		      if [ "$redundant" = "Standby" -a $setOp -eq 1 ] || \
			 [ "$redundant" = "Standby" -a $setOp -eq 2 ]; then
                         /usr/bin/rsh 10.0.0.$RIDX rdate -s 10.0.0.`expr $IDX + 5`
	              elif [ "$redundant" = "Standby" -a $setOp -eq 3 ]; then
                         /usr/bin/rsh 10.0.0.$RIDX /bin/date $*
	              fi		
		
                      if [ "$redundant" = "Standby" -a $? -eq 0 ]; then
                         /usr/bin/rsh 10.0.0.$RIDX /sbin/hwclock -w --utc
                      fi
                   fi
                fi
# Propagate date change to fabric
                /fabos/rbin/tsDateChange $olddate $newdate
		current_vf=$CURRENT_VF
		check_context_switch_required
		switch_context=$?
		if [ $switch_context -eq 1 ]; then
			eval $(/fabos/cliexec/lscfg_util --chassis)
		fi
		datechange_timestamp=`/bin/date +%s`
                /fabos/cliexec/config set date.timestamp 2 $datechange_timestamp
		/fabos/cliexec/config update
		if [ $switch_context -eq 1 ]; then
			eval $(/fabos/cliexec/lscfg_util --switch $current_vf)
		fi
        else # if [ $? -eq 0 ] date write command successful
           echo "date: cannot set date: operation not permitted"
        fi
else
        if [ $setOp -eq 1 ];then
                check_last_date_change_time_lapsed
                if [ $? -eq 0 ]; then
                        echo "Date change within 64 seconds from previous change is not allowed"
                        exit
                fi
        fi

	check_time_lic_present
	ret_val=$?
	if [ $ret_val -eq 0 ]; then
		exit
	fi

	
    	# Check whether hardware date value can be fetched
	# from the switch.
	get_hw_date
	ret_val=$?
	if [ $ret_val -eq 1 ]; then
		# Error
		# Exit without changing the date
		echo "Cannot change the date. Hardware date value error reported."
		exit
	fi

	# Check whether max limit allowed range for date change operation
	# can be fetched.
	get_date_change_max_limit_str
	ret_val=$?
	if [ $ret_val -eq 1 ]; then
		# Error
		# Exit without changing the date
		echo "Cannot change the date. Allowed limit range error reported."
		exit
	fi

	/fabos/sbin/eos_check
	if [ $? -eq 1 ];then
		# EOS time reached
		# Exit without changing the date
		exit
	fi

	/bin/date $* 2> /dev/null 

	if [ $setOp -eq 1 ]; then
                current_vf=$CURRENT_VF
                check_context_switch_required
                switch_context=$?
                if [ $switch_context -eq 1 ]; then
			eval $(/fabos/cliexec/lscfg_util --chassis)
                fi
                datechange_timestamp=`/bin/date +%s`
                /fabos/cliexec/config set date.timestamp 2 $datechange_timestamp
                /fabos/cliexec/config update
                if [ $switch_context -eq 1 ]; then
			eval $(/fabos/cliexec/lscfg_util --switch $current_vf)
                fi
	fi
fi

