#!/bin/sh
#++
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      lockfile - OCM lockfile implementation
#
#    DESCRIPTION
#      when a system-wide lockfile utility is not available, we use this script
#
#    EXIT CODES
#      0 - Success
#      1 - Failure
#      2 - Missing argument(s)
#      3 - other...
#--

# Define the paths for /usr/bin. These are used in subsequent path
# specifications for native commands.
_binDir=/bin
_usrBinDir=/usr/bin

# Set the variables that map to explicit paths to prevent from trojan
# horse type attacks and allow for more consistent installation experience
# by eliminating the use of aliases.
AWK=${_binDir}/awk
BASENAME=${_binDir}/basename
CAT=${_binDir}/cat
CHMOD=${_binDir}/chmod
DATE=${_binDir}/date
DIRNAME=${_usrBinDir}/dirname
ECHO=${_binDir}/echo
GREP=${_binDir}/grep
LN=${_binDir}/ln
LNS="$LN -s"
LS=${_binDir}/ls
LSL="$LS -l"
PWDD=${_binDir}/pwd
RM=${_binDir}/rm
RMF="$RM -f"
SED=${_binDir}/sed
TOUCH=${_binDir}/touch
TR=${_usrBinDir}/tr

if [ -f ${_binDir}/cut ]
then
  CUT=${_binDir}/cut
elif [ -f ${_usrBinDir}/cut ]
then
  CUT=${_usrBinDir}/cut
fi

if [ -z "${CUT}" ] 
then
  exit 2
fi

if [ -f ${_binDir}/uname ]
then
    UNAME=${_binDir}/uname
elif [ -f ${_usrBinDir}/uname ]
then
    UNAME=${_usrBinDir}/uname
fi
if [ -z "${UNAME}" ] 
then
  exit 2
fi

PLATFORM=`$UNAME | $CUT -f1`

if [ $PLATFORM = "OSF1" ]
then
  if [ -z "${BIN_SH}" ]
  then
    BIN_SH=xpg4
    export BIN_SH
    $0 "$@"
    exit $?
  fi
fi

if [ -z "${CCR_TEMP}" ]
then
    CCR_TEMP=/tmp
fi

# Extract the binary directory specification where this script resides.
# The enclosed code will come up with an absolute path.
_OCMBinDir=`$DIRNAME $0 | $TR -s '/'`
_OCMBinDir=`$ECHO $_OCMBinDir | $SED -e 's/^\(\.\/\)*//g' -e 's/\/\(\.\/\)*/\//g' -e 's/\/\.$//g'`
_OCMBinDir=`$ECHO $_OCMBinDir | $AWK -f ${_OCMBinDir}/strip_path.awk PWD=$PWD`

# Construct the CCR installation directory root based upon the bin
# directory being a child.
CCR_HOME=`$DIRNAME ${_OCMBinDir}`
export CCR_HOME

debug=0
if [ ! -z "${CCR_INSTALL_DEBUG}" -o ! -z "${CCR_DEBUG}" ]; then
   debug=1
fi

sleepTime=`$ECHO $1 | $CUT -f2 -d'-'`
retryFlag=$2
retryNum=$3
timeOutFlag=$4
timeOut=$5
lockFile=$6

#Create lockfile.debug.log
if [ ! -z "${LOCKFILE_LOG}" ]; then
   LOCKFILE_LG=$LOCKFILE_LOG
   LOCKFILE_LG=`$ECHO $LOCKFILE_LG | $AWK -f $CCR_HOME/bin/strip_path.awk PWD=$PWD`
fi
RET=1

#function to print messages to a file if the debug vaiable are set otherwise it will print on the screen
printDebug()
{
  text=$1
  if [ $debug -eq 1 ]; then
    if [ ! -z "$LOCKFILE_LG" ]; then
       $ECHO ${text} >>$LOCKFILE_LG
    else
       $ECHO ${text}
    fi
  fi
}

checkTimeOut()
{
  lkYear=`$CAT $lockFile | $AWK '{print $1}'`
  lkMonth=`$CAT $lockFile | $AWK '{print $2}'`
  lkDay=`$CAT $lockFile | $AWK '{print $3}'`
  lkHour=`$CAT $lockFile | $AWK '{print $4}'`
  lkMin=`$CAT $lockFile | $AWK '{print $5}'`
  lkSec=`$CAT $lockFile | $AWK '{print $6}'`
  
  cuDate=`$DATE +'%Y %m %d %H %M %S'`
  cuYear=`$ECHO $cuDate | $AWK '{print $1}'`
  cuMonth=`$ECHO $cuDate | $AWK '{print $2}'`
  cuDay=`$ECHO $cuDate | $AWK '{print $3}'`
  cuHour=`$ECHO $cuDate | $AWK '{print $4}'`
  cuMin=`$ECHO $cuDate | $AWK '{print $5}'`
  cuSec=`$ECHO $cuDate | $AWK '{print $6}'`

  lkTotalSec=`expr $lkYear \* 365 \* 30 \* 24 \* 60 \* 60 + $lkMonth \* 30 \* 24 \* 60 \* 60 + $lkDay \* 24 \* 60 \* 60 + $lkHour \* 60 \* 60 + $lkMin \* 60 + $lkSec`
  cuTotalSec=`expr $cuYear \* 365 \* 30 \* 24 \* 60 \* 60 + $cuMonth \* 30 \* 24 \* 60 \* 60 + $cuDay \* 24 \* 60 \* 60 + $cuHour \* 60 \* 60 + $cuMin \* 60 + $cuSec`

  diffSec=`expr $cuTotalSec - $lkTotalSec`
  if [ $diffSec -gt $timeOut ]; then
    printDebug "Removing lockfile by Force : $lockFile"
    $RMF ${lockFile}
    #Remove the old target files 
    files=`$LS ${lockFile}* | $GREP "$lockFile\.[0-9]*\.[0-9]*"`
    $RMF $files
  fi
}

lockfile()
{
  printDebug "Trying to lock : $lockFile"
  timeStamp=`$DATE +'%Y %m %d %H %M %S'`

  #converting the lockfile path into absolute path
  lockFile=`$ECHO $lockFile | $AWK -f $CCR_HOME/bin/strip_path.awk PWD=$PWD`
  lockfile_target=${lockFile}.$$.`$ECHO "$timeStamp" | $SED 's/ //g'`

  #dump the time stamp into the lockfile
  $ECHO $timeStamp > ${lockfile_target}

  if [ -f  ${lockfile_target} ]; then
     #create the link after creating the source file
     #Display the error messages on stdout in case of failure
     #and LOCKFILE_LOG is not defined
     timeStamp1=`$DATE +'%Y %m %d %H %M %S'`
     lf_log=$CCR_TEMP/lklog.$$.`$ECHO "$timeStamp1" | $SED 's/ //g'`
    
     $LNS $lockfile_target $lockFile 2>>$lf_log
     ret_code=$?
     if [ ! -z "$LOCKFILE_LG" ]; then
         $CAT $lf_log>>$LOCKFILE_LG
     else 
         $CAT $lf_log
     fi
     $RMF $lf_log
     if [ $ret_code -eq 0 ]; then
       printDebug "GOT The LOCK...!!!"
       RET=0
     else
       printDebug "Could not create link" 
       if [ -h ${lockFile} -a ! -r ${lockFile} ]; then
          $ECHO "Fatal Error: ${lockFile} is a dangling symlink, exiting" 1>&2
          $RMF $lockfile_target
          exit 1
       fi
       $RMF $lockfile_target
       checkTimeOut
     fi
  else
     printDebug "Couldn't create file ${lockfile_target}"
  fi
}

printDebug "INFO : sleepTime:$sleepTime, retryNum:$retryNum, timeOut:$timeOut lockFile:$lockFile"

#Set umask for file permissions
umask 266

if [ -z "${sleepTime}" -o -z "${retryFlag}" -o -z "${retryNum}" -o -z "${timeOutFlag}" -o -z "${timeOut}" -o -z "${lockFile}" ]; then
  exit 2
fi

lockfile

if [ $RET -eq 1 ]; then
  count=1
  while [ $count -le $retryNum ]
  do
    printDebug "Sleeping : $sleepTime seconds, TRY No. : $count"
    sleep $sleepTime
    lockfile
    if [ $RET -eq 0 ]; then
      break;
    fi
    count=`expr $count + 1`
  done
 #Check if the no of retries expired before getting the lock  
  if [ $count -eq `expr $retryNum + 1` ]; then
    if [ $RET -eq 1 ]; then
       printDebug "Could not acquire the lock"
       printDebug "No of retries expired before aging of the existing lock"
    fi
  fi
fi
exit $RET 
