#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2017,2018,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
#
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r720 src/43haes/usr/sbin/cluster/events/utils/cl_unexport_fs.sh 1.6.1.1 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2007,2015 
# 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_unexport_fs.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM

#
#   COMPONENT_NAME: EVENTUTILS
#
#   FUNCTIONS: none
#
#   ORIGINS: 27
#
###############################################################################
#
#  Name:  primary
#
#  Return the first entry in a list.
#
#  Returns:
#    0 - Success
#
#  Arguments:  list of strings
#
#  Environment: None
#
###############################################################################
primary( )
{
    echo ${1:-}
}

###############################################################################
#
#  Name:  secondary
#
#  Returns all entries in a list except for the first.
#
#  Returns:
#    0 - Success
#
#  Arguments:  list of strings
#
#  Environment: None
#
###############################################################################
secondary( )
{
    [[ -n "${1:-}" ]] && shift
    echo "${@:-}"
}


###############################################################################
#
#  Name:  cl_unexport_fs
#
#  Given a list of NFS exported filesystems, unexport them or reexport them
#  with a different protocol.
#
#  In the case that the resource group has stable storage configured, then
#  we may also need to unregister the NFS node.  There are a few issues that
#  need to be kept in mind w.r.t. unregistering NFSv4 nodes and unexporting
#  NFSv4 exports.
#
#  1. If an NFSv4 node is unregistered, then all of the exports associated with
#     it will be automatically unexported and the stable storage for those
#     exports will be left intact for fallover.
#  2. If an NFSv4 export is unexported while its NFSv4 node is registered, then
#     NFS will delete the stable storage associated with that export.
#  3. If, after we are done, there are no more NFSv4 exports for the resource
#     group, then we should unregister its NFS node.
#
#  As part of the processing, this command must determine whether or not the
#  stable storage should be kept or deleted.  Here is what it will do:
#
#  A. If this is a reconfig event (i.e., DARE operation), and one or more
#     (possibly all) NFSv4 exports are being removed, then these exports are
#     going away for good.  We want to manually unexport these filesystems so
#     that their stable storage gets removed.  Once we are done, if the
#     resource does not have any NFSv4 exports then we need to unregister the
#     NFS node.
#  B. This script is called by the event release_vg_fs (which appears to be
#     unnecessary) after it has already been called by
#     reconfig_resource_release.  We treat this event as if it was
#     reconfig_resource_release.
#  C. In all other cases, we are bringing the resource group offline.  The
#     intent is that we will want to fallover sometime in the future.  We want
#     to unregister the NFS node up front so that the stable storage is left
#     intact.
#
#  To accomodate these two flavors of operation, the code is structured as
#  follows:
#
#    If this is not a reconfig_resource_release event and
#       this is not a release_vg_fs event, then
#      unregister the NFS node
#    Unexport all remaining exports that we were asked to unexport
#    If there are no more NFSv4 exports then
#      unregister the NFS node
#
#  Returns:
#    0 - Success
#    1 - Any runtime errors (unable to export, startsrc failures)
#    2 - Incorrect number of arguments was passed.
#
#  Arguments:  list of filesystems to unexport via nfsv3,
#              list of filesystems to unexport via nfsv4
#
#  Environment: PATH, VERBOSE_LOGGING
#
###############################################################################

typeset PROGNAME=${0##*/}
export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"
if [[ $VERBOSE_LOGGING == "high" ]]; then
    set -x
    version='%I%'
fi

. /usr/es/sbin/cluster/events/utils/cl_nfs_utils

UNEXPORT_V3="$1"
UNEXPORT_V4="$2"

STATUS=0

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
fi

set -u

if (( $# != 2 ))
then
    cl_echo 45 "usage: $PROGNAME 'v3 exports' 'v4 exports'\n" $PROGNAME
    exit 2
fi

if [[ "$PLATFORM" == "__AIX__" ]]
then
    if (( $(oslevel -r | cut -c1-2) > 52 ))
    then
        FORCE="-F"
    else
        FORCE=
    fi
fi


# The following code handles migration.  In 5.4.0 and earlier the nfs export
# version was specified in the HACMP exports file.  Starting in 5.4.1 it
# became a property of the resource group.  In order to make these two
# methods coexist in a backwards compatible manner, if the resource group has
# no NFSv4 exports configured, then get the version information from the
# HACMP exports file.

EXPFILE="/usr/es/sbin/cluster/etc/exports"
DARE_EVENT=reconfig_resource_release

# Check memory to see if NFSv4 exports have been configured.
unexport_v4=${UNEXPORT_V4:-${EXPORT_FILESYSTEM_V4:-}}
if [[ -z "$unexport_v4" && ${EVENT_NAME:-$DARE_EVENT} == $DARE_EVENT ]]
then
    # During DARE operations, these variables only represent the exports
    # that are changing.  So look it up from the ODM to make sure.
    query="name=EXPORT_FILESYSTEM_V4 AND group=$GROUPNAME"
    unexport_v4=$(odmget -q "$query" HACMPresource |
                  sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')
fi

# If we don't have NFSv4 exports configured then determine the protocol
# version(s) from the HACMP exports file.
if [[ -z "$unexport_v4" && -r $EXPFILE ]]
then
    unexport_v3=

    for fs in $UNEXPORT_V3
    do
        # Get the export file for the filesystem from the exports file.
        # Only look at the part of the line preceding comments.
        getline_exports $fs
        export_line=$cl_exports_data


        # The line is of the format:  filesystem -option1,option2,...
        # This will give "option1 option2 ..."
        options=$(echo $export_line | awk '{ for (i=2; i<=NF; i++) printf $i " "; print "" }' |
                  cut -d- -f2- | tr ',' ' ')

        # Each option can be of the format name=value, or just name.
        # We only care about the vers option.

        # Have we seen the vers option?
        vers_missing=1

        # Loop through all of the export options for this export.
        for option in $options
        do
            case $option in
              vers=*)
                vers_missing=0

                # Merge in the vers option.
                case $option in
                  *2*)    unexport_v3="$unexport_v3 $fs"  ;;
                  *3*)    unexport_v3="$unexport_v3 $fs"  ;;
                esac

                case $option in
                  *4*)    unexport_v4="$unexport_v4 $fs"  ;;
                esac
                ;;
            esac
        done

        # If we didn't find the vers option, then NFSv3 is the default.
        (( vers_missing )) && unexport_v3="$unexport_v3 $fs"
    done 

    UNEXPORT_V3=$unexport_v3
    UNEXPORT_V4=$unexport_v4
fi

hasrv=
    
if [[ -z "${STABLE_STORAGE_PATH:-}" ]]
then
    query="name=STABLE_STORAGE_PATH AND group=$GROUPNAME"
    STABLE_STORAGE_PATH=$(odmget -q "$query" HACMPresource |       \
                          sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')
fi

if [[ -z "$STABLE_STORAGE_PATH" ]]
then
  STABLE_STORAGE_PATH=/var/adm/nfsv4.hacmp/$GROUPNAME
fi

if [[ -z "${SERVICE_LABEL:-}" ]]
then
    query="name=SERVICE_LABEL AND group=$GROUPNAME"
    SERVICE_LABEL=$(odmget -q "$query" HACMPresource |       \
                    sed -n 's/^[ 	]*value = "\(.*\)"/\1/p')
fi

if ps -eo 'args' | grep -w nfsd | grep -qw -- '-gp on'
then
    gp=on
else
    gp=off
fi

KERNEL_BITS=$(/usr/sbin/bootinfo -K)

if [[ $gp == "on" && $KERNEL_BITS == 64 && -x /usr/sbin/nfs4smctl ]]
then
    hasrv=$(primary $SERVICE_LABEL)
    NFSv4_REGISTERED=1
else
    NFSv4_REGISTERED=0
fi


V3=":2:3"
V4=":4"

if [[ "${EVENT_NAME}" != "reconfig_resource_release" ]] &&
   [[ "${EVENT_NAME}" != "release_vg_fs" ]]
then

    # If we are unexporting NFSv4 exports AND this is not a reconfiguration
    # event (i.e., not a DARE operation), then we will be unexporting ALL
    # NFSv4 exports.  The proper way to do this is to unregister the NFSv4
    # node first (which should implicitly unexport these exports).

    if [[ -n "$UNEXPORT_V4" && -n $hasrv ]]
    then
        cl_RMupdate resource_releasing NFSv4_Node $PROGNAME

        if ! cl_nfs4smctl -U -N $GROUPNAME
        then
            cl_log 10200 "$PROGNAME : Unable to unregister NFSv4 node instance $GROUPNAME.\n" $PROGNAME $GROUPNAME
            cl_RMupdate resource_error NFSv4_Node $PROGNAME

            STATUS=1
            hasrv=
        else
            cl_RMupdate resource_down NFSv4_Node $PROGNAME
        fi

        NFSv4_REGISTERED=0
    fi

    # If this is not a reconfiguration event, then that means we are trying
    # to release all resources and should therefore unexport all versions
    # of the filesystem so that it may be unmounted.  Clearing V3 and V4
    # here will allow us to gracefully handle the case where the user
    # re-exported a filesystem with a different version.
    V3=
    V4=
fi


ALLEXPORTS="All_exports"
# update resource manager with this action
cl_RMupdate resource_releasing $ALLEXPORTS $PROGNAME

FILESYSTEM_LIST=$(echo $UNEXPORT_V3 $UNEXPORT_V4 | tr " " "\n" | sort)

for fs in $FILESYSTEM_LIST
do
    v3=
    v4=
    root=
    old_options=
    new_options=

    export_line=$(exportfs | grep "^[[:space:]]*${fs}[[:space:]]")

    [[ -z "$export_line" ]] && continue

    old_options=$(echo $export_line | cut -d' ' -f2- | cut -d- -f2- | tr ',' ' ')

    for option in $old_options
    do
        case $option in
          hasrv=*)
            # Squash the hasrv option.  We will provide our own.
            ;;
          vers=*)
            # Merge in the vers option.
            case $option in
              *2*)    v3="$V3"  ;;
              *3*)    v3="$V3"  ;;
            esac

            case $option in
              *4*)    v4="$V4"  ;;
            esac
            ;;
          *)
            # Merge in all remaining options.
            new_options="$new_options,$option"
            ;;
        esac
    done

    # If no export version option was given, then use the default
    [[ -z "$v3$v4" ]] && v3=$V3

    # We have established the current export protocol versions.  Now clear
    # them if we are unexporting the filesystem.
    # If no more versions are left, then unexport the filesystem.  Otherwise
    # re-export the filesystem using the remaining protocol versions.
	NFS_VER3=""
    for fs3 in $UNEXPORT_V3
    do
        [[ "$fs" == "$fs3" ]] && v3="" && NFS_VER3="3" && break
    done
	NFS_VER4=""
    for fs4 in $UNEXPORT_V4
    do
        [[ "$fs" == "$fs4" ]] && v4=""&& NFS_VER4="4" && break
    done
	if [[ $NFS_VER4 == "4" && $NFS_VER3 == "3" ]]
	then
		NFS_VER4=""
		NFS_VER3=""
		EXP_VER=$(/usr/sbin/exportfs|grep "^[[:space:]]*${fs}[[:space:]]"|cut -f1 -d","|cut -f2 -d "="|sed s/://)
		if [[ $EXP_VER == "4" ]]
		then
			NFS_VER4="4"
		fi
	fi
				

    # Strip off the leading colon
    vers=$(echo "$v3$v4" | cut -d: -f2-)

    if [[ -z "$vers" ]]
    then
		if [[ $NFS_VER4 == "4" ]]
		then
			exportfs -i -u $FORCE -V 4 $fs
		else
			exportfs -i -u $FORCE $fs
		fi
		if (( $? != 0 ))
		then
			cl_echo 97 "$PROGNAME : Failed to unexport the file system $fs\n" $PROGNAME $fs
			STATUS=1
			# update resource manager with results
			cl_RMupdate resource_error $fs $PROGNAME
		fi
		continue
    fi

    # Versions 2 and 3 are the default versions.  Some versions of AIX do
    # not support the vers export option, so only use the option if we are
    # exporting a non-default value (i.e., 4)
    if [[ -n "$v4" ]] ; then
        new_options="$new_options,vers=$vers"

        # If grace periods are enabled, then use the hasrv option.
        [[ -n "$hasrv" ]] && new_options="$new_options,hasrv=$hasrv"
    fi


    # Strip off the leading comma
    new_options=$(echo "$new_options" | cut -d, -f2-)

    exportfs -i -o $new_options $fs

    if (( $? != 0 ))
    then
        cl_log 43 "$PROGNAME: Unable to export $fs.\n" $PROGNAME $fs

        if [[ $PROC_RES == true ]]; then
            STATUS=11
        else
            STATUS=1    # note error and keep going
        fi
        
        # update resource manager with results
        cl_RMupdate resource_error $fs $PROGNAME
    fi
done


if [[ -n "$UNEXPORT_V4" && -n $hasrv ]]
then
    if (( NFSv4_REGISTERED ))
    then
        (( count = 0 ))

        for service_label in $SERVICE_LABEL
        do
            (( count += $(exportfs | grep -cw "hasrv=$service_label") ))
        done

        if (( $count == 0 )) 
        then
            cl_RMupdate resource_releasing NFSv4_Node $PROGNAME

            if ! cl_nfs4smctl -U -N $GROUPNAME
            then
                cl_log 10200 "$PROGNAME : Unable to unregister NFSv4 node instance $GROUPNAME.\n" $PROGNAME $GROUPNAME
                cl_RMupdate resource_error NFSv4_Node $PROGNAME

                STATUS=1
            else
                cl_RMupdate resource_down NFSv4_Node $PROGNAME
            fi
        fi
    fi
fi

ALLNOERREXPORT="All_nonerror_exports"
# update resource manager with results
cl_RMupdate resource_down $ALLNOERREXPORT $PROGNAME

exit $STATUS
