#!/bin/ksh
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2017,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
#
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r714 src/43haes/usr/sbin/cluster/events/utils/cl_deactivate_nfs.sh 1.2.5.1 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1990,2013 
# 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 
# @(#)  7d4c34b 43haes/usr/sbin/cluster/events/utils/cl_deactivate_nfs.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#
#   COMPONENT_NAME: EVENTUTILS
#
#   FUNCTIONS: none
#
#   ORIGINS: 27
#
#
#   (C) COPYRIGHT International Business Machines Corp. 1990,1995
#   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.
#
###############################################################################
#
#  Name:  cl_deactivate_nfs
#
#  Given a list of nfs-mounted filesystems, we try and unmount -f any that are
#  currently mounted.
#
#  Arguments: list of filesystems.
#
###############################################################################
# Including Availability metrics library file
. /usr/es/lib/ksh93/availability/cl_amlib

get_list_head()
{    
    typeset PS4_FUNC="get_list_head"
    echo $* | cut -f 1 -d : | sed 's/,/ /g' |read LIST
    print $LIST
}

get_list_tail()
{
    typeset PS4_FUNC="get_list_tail"
    case $* in
      *:* )
        echo $* | cut -f 2- -d : |read LIST
        print $LIST
        return
      ;;
      * )
       echo ""
      ;;
     esac
}

PROGNAME=$(basename ${0})
[[ "$VERBOSE_LOGGING" == "high" ]] && set -x
[[ "$VERBOSE_LOGGING" == "high" ]] && version='1.2.5.1 $Source$'

STATUS=0
PIDLIST=""

set -u

function do_umount
{
    typeset PS4_FUNC="do_umount" PS4_TIMER="true"
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    typeset fs=$1

    # kill any processes accessing the FS to umount
    # NOTE: A new -t flag has been added to cl_nfskill to find and kill
    #       processes which are just opening an NFS filesystem.  When
    #       this flag is specified, it requires the use of the crash
    #       command to find all processes which have certain NFS module
    #       names within their stack traces.  Since it is not possible to
    #       tell which NFS filesystem the process is related to, this
    #       could result in killing processes which belong to NFS mounted
    #       filesystems other than those which are cross-mounted from
    #       another HACMP node and under HACMP control.  This could also
    #       mean that the processes found could be related to filesystems
    #       under HACMP control but not part of the current resources
    #       being taken.  This flag should therefore be used with caution
    #       and only if you know you have a specific problem with umounting
    #       the nfs filesystems.  We have provided below, both the normal
    #       call to cl_nfskill with the -k and -u flags and also a commented
    #       call using the -t flag as well.  If you choose to use the -t
    #       flag, you should uncomment those calls and comment the original
    #       calls.

    # NOTE: cl_nfskill is called twice in succession before the first umount
    #       attempt to try to catch any processes on the second call which
    #       may have been missed by the first call.  This helps to prevent
    #       a possible umount hang.

    cl_nfskill -k -u $fs
#    cl_nfskill -k -u -t $fs
    sleep 2
    cl_nfskill -k -u $fs
#    cl_nfskill -k -u -t $fs
    sleep 2

    # Format for consumption by cl_am utility
    amlog_trace $AM_NFS_DEACTIVATE_BEGIN "Deactivating NFS|$fs"
    typeset COUNT=20
    while true ; do
        : Attempt $(((20-COUNT+1))) of 20 to unmount at $(date "+%h %d %H:%M:%S.000")
        umount -f $fs
        if (( $? != 0 )) ; then
            if (( $COUNT > 0 ))
            then
                COUNT=$(( $COUNT - 1 ))
            else
                # update resource manager
                cl_RMupdate resource_error $fs $PROGNAME
                # Format for consumption by cl_am utility
                amlog_err $AM_NFS_DEACTIVATE_FAILURE "Deactivating NFS|$fs"
                return 0
            fi
        sleep 2
        cl_nfskill -k -u $fs
#       cl_nfskill -k -u -t $fs
        else
            # unmount succeeded
            # Format for consumption by cl_am utility
            amlog_trace $AM_NFS_DEACTIVATE_END "Deactivating NFS|$fs"
            break
        fi
    done
    return 0
}



# Main

PROC_RES=false

# if JOB_TYPE is set, and it doesn't equal to "GROUP", then
# we are processing for process_resources
if [[ ${JOB_TYPE:-0} != 0 && $JOB_TYPE != "GROUP" ]]; then
   PROC_RES=true
else
    # otherwise command-line arguments are required
    if (( $# == 0 )) ; then
        cl_echo 26 'usage: $PROGNAME filesystems_to_unmount\n' $PROGNAME
        exit 2
    fi

    # set the RESOURCE_GROUPS as GROUPNAME, so that we can use the
    # same for loop for one and multiple RGs
    export RESOURCE_GROUPS=$GROUPNAME
fi


for GROUPNAME in $RESOURCE_GROUPS ; do
    
    export GROUPNAME

    if [[ $PROC_RES == true ]]; then
        get_list_head $FILE_SYSTEMS | read UNSORTED_FILELIST
        get_list_tail $FILE_SYSTEMS | read FILE_SYSTEMS
    else
        UNSORTED_FILELIST=$*
    fi

    # Sorting allows us to handle nested NFS mounts
    FILELIST=$(for i in $UNSORTED_FILELIST; do /bin/echo $i; done | \
               /bin/sort -r)

    echo $FILELIST | grep -q "\;/"
    CROSSMOUNT=$(( ! $? ))

    if [[ $CROSSMOUNT != 0 ]]
    then
        MNT=$(for i in $FILELIST; do /bin/echo $i; done | \
              /bin/sort -k 1,1r -t\;)
    else
        MNT=$FILELIST
    fi

    # update resource manager
    ALLNFS="All_nfs_mounts"
    cl_RMupdate resource_releasing $ALLNFS $PROGNAME

    METHOD=$(odmget -q "name=RECOVERY_METHOD AND group=$GROUPNAME" HACMPresource | grep value | awk '{print $3}' | sed 's/"//g')

    for i in $MNT ; do
        typeset PS4_LOOP="$MNT"
        if (( $CROSSMOUNT != 0 ))
        then
            fs=$(echo $i | cut -f2 -d\;)
            mnt=$(echo $i | cut -f1 -d\;)
        else
            fs=$i
            mnt=$i
        fi

        # this awk command prints the name of the filesystem ONLY if it is
        # currently NFS mounted
        f=$(mount | awk -v MFS=$mnt \
                    'BEGIN {MFS=sprintf("^%s$", MFS)} \
                    match($4, "nfs") && match($3, MFS) {print $2}')
                    
        # if it is mounted, we do the right thing to unmount it
        if [[ "$f" == "$fs" ]] ; then
            # perform the umount in the background, so that
            # they are done in parallel

            pid=
            
            # If recovery_method=sequential perform umount in foreground
            if [[ $METHOD == "sequential" ]]
            then
		#
		# This script can be called from node down processing
		# in which case it is called by clcallev, or it can
		# be called directly from the reconfig resource scripts.
		# These variables will only be set when called by
		# node down
		#
                if [[ "${EVENT_NAME:-}" == "node_down" && 
			"${NODENAME:-}" != "${LOCALNODENAME:-}" && 
			"${PARAM:-}" == "graceful" ]]||
                   [[ "${EVENT_NAME:-}" == "rg_move" ]]
                then
                    # If current event is graceful down of NFS server
                    # and the local node is not the NFS server,
                    # perform umount in background even though there
                    # may be nested filesystems, because server is
                    # down so umounts will take a long time.  Some
                    # umounts may fail with nested filesystems in this
                    # case.
                    do_umount $mnt &
                    pid=$!
                else
                    do_umount $mnt
                fi
            else
                do_umount $mnt &
                pid=$!
            fi

            if [[ -n "$pid" ]]
            then
                # search for pid in PIDLIST
                echo $PIDLIST | grep -qw $pid

                #if pid is not in the pid list, then add it
                if (( $? != 0 )) ; then
                    PIDLIST="$PIDLIST $pid"
                fi
            fi
        fi
        
    done # endof $MNT
    unset PS4_LOOP
done

# Wait here for umount processes to complete and check status
for pid in $PIDLIST ; do
    wait $pid
    if (( $? != 0 )) ; then
        if [[ $PROC_RES == true ]]; then
            STATUS=11
        else
            STATUS=1
        fi
    fi
done

# update resource manager
for GROUPNAME in $RESOURCE_GROUPS ; do
    ALLNOERRNFS="All_nonerror_nfs_mounts"
    cl_RMupdate resource_down $ALLNOERRNFS $PROGNAME
done

exit $STATUS
