#!/bin/sh
#
###############################################################################
#
# Copyright (c) 2002-2023, Dell Inc. or its subsidiaries. All Rights Reserved.
#
# PowerPath startup script.
# 
# This file is a part of Dell PowerPath.
#
# Description: Script to load and configure Dell PowerPath drivers.
#
###############################################################################

unset LC_ALL

umask 077

# 
# Log start details if tracing is enabled.
#
trace_base=/etc/opt/emcpower
if [ -f $trace_base/PP_TRACE_START -a -z "$PP_RESTART" ]
then
    PP_RESTART=T;export PP_RESTART
    echo '===========' >> $trace_base/PPStartTrace
    /bin/date          >> $trace_base/PPStartTrace
    echo $0 $@         >> $trace_base/PPStartTrace
    echo '===========' >> $trace_base/PPStartTrace
    
    sh -x $0 $@  2>> $trace_base/PPStartTrace
    exit
fi

################################################################################
### Import common script routines here.
###############################################################################
# Start of common.sh - Common script shared by PowerPath.common and
#                      EMCpower.LINUX.spec. 
##############################################################################

# Stop stordaemons. They will get restarted automatically.
pp_stop_stordaemons()
{
    if [ -x /usr/storapi/storbin/stordaemon ]; then
        /usr/storapi/storbin/stordaemon shutdown all > /dev/null 2>&1
    elif [ -x /usr/storapi/bin/stordaemon ]; then
            /usr/storapi/bin/stordaemon shutdown all > /dev/null 2>&1
    fi
}

# Check if Naviagent/Hostagent is running.
# Returns 0 if Naviagent/Hostagent is not running
#         1 if Naviagent is running
#         2 if Hostagent is running
is_navi_running()
{
    ps -C naviagent >> /dev/null 2>&1
    if [ $? -eq 0 ]; then
        return 1
    else
        # Check for Hostagent which is Unisphere equivalent of Naviagent.
        ps -C hostagent >> /dev/null 2>&1
        if [ $? -eq 0 ]; then
           return 2
        fi
    fi
    return 0  # Naviagent/Hostagent is not running.
}

# Return script to start/stop Naviagent/Hostagent. Be sure to match $1 with
# the return values from is_navi_running from above.
get_navi_script_loc()
{
  if [ $1 -eq 1 ]; then
      echo "/etc/init.d/naviagent"
  elif [ $1 -eq 2 ]; then
      echo "/etc/init.d/hostagent"
  else
      echo "" # Return an empty string if Naviagent/Hostagent is not running.
  fi
}

#
# Stop Naviagent/Hostagent and wait for upto 60 seconds for it to stop completely
# Returns 0 if Naviagent/Hostagent has been stop successfully
#         1 if failed to stop Naviagent/Hostagent
#
stop_navi()
{
    $1 stop > /dev/null 2>&1
    for cnt in 1 2 3 4 5 6 7 8 9 10 11 12
    do
    is_navi_running
    if [ $? -ne 0 ]; then
        sleep 5
    else
        return 0
    fi
    done

    return 1
}

restart_navi()
{
    #
    ## Restart Naviagent/Hostagent if we stopped it earlier.
    ## $1 not equal to 0 means Naviagent/Hostagent was running earlier and we stopped it.
    #
    if [ $1 -ne 0 ]; then
        $2 start > /dev/null 2>&1
        is_navi_running
        if [ $? -eq 0 ]; then
            echo "`eval_gettext \"Unable to restart Naviagent/Hostagent.  Please restart it manually.\"`"
        fi
    fi
}

#-----------------------------------------------------------
# Deactivate LVM volume groups present on PowerPath devices.
#-----------------------------------------------------------
pp_stop_lvm()
{
    if [ -x /sbin/vgchange -a -x /sbin/vgscan ] ; then
        open_vol=""
        vgnames=`vgdisplay 2>/dev/null | grep "VG Name" \
                | sed -e 's/VG Name/ /g'`

        for i in $vgnames
        do
            #
            # Dont try to deactivate root VGs.  The dependency of root VG
            # will be changed from pseudo to native in pp_reset_dm_deps.sh
            # script.
            #
            ROOT_VG_LV=`mount 2>/dev/null | grep "on / " | grep mapper | sed -e 's/^\/dev\/mapper\/\(.*\) on.*/\1/'`

            ROOT_VG=`echo $ROOT_VG_LV | sed -e "s/\($i\).*/\1/"`
            if [ "$ROOT_VG" = "$i" ]; then
                continue
            fi

            pv_names=`vgdisplay -v $i 2>/dev/null \
                      | grep "PV Name" | awk '{ print $3 }'`

            #
            # Extract the device name of the first pv only
            # omitting any partition number.
            #
            first_pv=`echo $pv_names \
                      | sed -e 's/^\/dev\/\([a-zA-Z]*\)[0-9]*.*$/\1/'`

            #
            # Find the pseudo device.
            #
            pseudo=`powermt display dev=$first_pv 2>/dev/null \
                    | grep "Pseudo name" | sed -e 's/Pseudo name=//'`

            if [ "$pseudo" != "" ] ; then
                err_stop=`vgchange -a n $i 2>&1 | grep "open logical volume"`
                if [ "$err_stop" != "" ]; then
                    if [ "$open_vol" = "" ]; then
                        mesg="Following LVM volume groups are in use:"
                        echo "`eval_gettext \"$mesg\"`"
                        open_vol=$err_stop
                    fi
                    var1=$i
                    var2=`echo $pv_names`
                    mesg="      Volume Group:"
                    echo "`eval_gettext \"$mesg \\$var1 (\\$var2)\"`"
                fi
            fi
        done
    fi

    if [ "$open_vol" != "" ]; then
        echo
        mesg1="These open logical volume devices use LUNs"
        mesg2="from PowerPath managed devices,"
        echo "`eval_gettext \"$mesg1 $mesg2\"`"
        mesg1="Please reissue the command after"
        mesg2="closing these volumes."
        echo "`eval_gettext \"$mesg1 $mesg2\"`"
        echo
        return 1
    fi
    return 0
}

#-------------------------------------------------------
# PowerPath and DM-Multipath cannot co-exist on the host.
# For SLES, this function attempts to unconfig DM-Multipath.
# Do not allow PowerPath to install or start if 
# DM-Multipath is configured and managing devices.
# check_dm_multipath_config() returns 1 if multipath is
# active and PowerPath should not continue. Returns 0 if
# PowerPath installation or start can continue.
#-------------------------------------------------------
check_dm_multipath_config ()
{
    local MULTIPATH_CONF="/etc/multipath.conf"
    local MULTIPATH_CONF_ORG="/etc/multipath.conf.orig"
    local MULTIPATH_CONF_PP="/etc/multipath.conf.PP"
    local create=1

    if [ $1 -eq 1 ]
    then
        # This func called during install, remove old $MULTIPATH_CONF_PP file
        rm -f $MULTIPATH_CONF_PP
    fi
    # We are now supporting NDI, by detecting PP_NDI_ENABLE environment variables, if it is set 
    # we need to allow the PowerPath instalation while NMP is active. But in case of suse we do extra
    # steps to disable multipathd and block list the devices in the multipath.conf, which will give undesired 
    # results if the user forgets to set the environment variable by mistake. in such case later when he enables it
    # and install powerpath it might have disabled NMP devices and stopped multipathd which is wrong. And also it 
    # gives wrong results while booting with NMP migrations are active.
    if lsmod | grep -w '^dm_multipath' >/dev/null
    then
        num=`/sbin/multipath -ll -v1 | grep -c '.*'`
        if [ $num -gt 0 ]
        then
            return 1
        fi
    fi

    #
    # Native multipathing is not active.
    #
    return 0
}

#-------------------------------------------------------
# PowerPath and NVMe multipath cannot co-exist on the host.
# For SLES, OL it is enabled by default and for RHEL it is 
# disabled by default. Do not allow PowerPath to install or 
# start if NVMe maltipath is active. check_nvme_multipath_config() 
# returns 1 if NVME multipath is active and PowerPath should not 
# continue. Returns 0 if PowerPath installation or start can continue.
#-------------------------------------------------------
check_nvme_multipath_config()
{
    local NVME_MULTIPATH_CONF="/sys/module/nvme_core/parameters/multipath" 
    ls /sys/class/block/nvme*  > /dev/null 2>&1 
    if [ $? == 0 ] ; then
        # On RHEL 7.x systems, NVME_MULTIPATH_CONF file doesn't exist, and NVMe multipath is disabled by default, there is no way to enable. 
        if [ -f $NVME_MULTIPATH_CONF ] ; then
            grep "Y" $NVME_MULTIPATH_CONF > /dev/null 2>&1
            if [ $? == 0 ] ; then
                return 1
            fi
        fi
    fi

    #
    # NVMe native multipathing is not active
    #
    return 0
}

#---------------------------------------------------------------------
# Some times, HBA drivers will not set tgtid_bind_type properly.
# Ideally it should be set to wwpn so that when paths fail and
# come back, the fc_remote_port target data structures are retained
# and hence the Target number as in B-T-L will not change.  This is
# critical for PowerPath.
# In case of Cisco fnic HBAs, the tgtid_bind_type is set to 'none' as
# default.  Because of this the target number changes on failover.
# To avoid this, set the tgtid_bind_type for all fc_host entries to
# wwpn.
#---------------------------------------------------------------------
set_tgtid_bind_type()
{
    for fc_host in `ls /sys/class/fc_host/`
    do
        echo wwpn > /sys/class/fc_host/$fc_host/tgtid_bind_type
    done
}

#-----------------------------------------------------------
# For NVMe devices, the dev_loss_tmo and fast_io_fail_tmo
# values of the rport cannot be changed in the PP driver
# code like its done for SCSI devices.  Hence, this function
# is used to set them in various instances like PP start
# and stop as well as before and after NDU.
#
# Note:  This function works only for rports of NVMe
# connections coming through Emulex (lpfc) HBAs only. For
# Qlogic (qla) HBAs, rport entries are not created in sysfs.
#-----------------------------------------------------------
set_nvme_rport_tmos()
{
    fast_io_fail_tmo=$1
    dev_loss_tmo=$2

    for rport in `ls /sys/class/fc_remote_ports/`
    do
        scsi_target_id=`cat /sys/class/fc_remote_ports/$rport/scsi_target_id`
        port_state=`cat /sys/class/fc_remote_ports/$rport/port_state`

        #
        # For NVMe rports, scsi_target_id is -1.
        #
        if [[ "$scsi_target_id" = "-1" && "$port_state" = "Online" ]]
        then
            echo $fast_io_fail_tmo > /sys/class/fc_remote_ports/$rport/fast_io_fail_tmo
            echo $dev_loss_tmo > /sys/class/fc_remote_ports/$rport/dev_loss_tmo
        fi
    done
}

#
# Check 'emcpowerX' device entries in /etc/fstab
# Return 0 on success if there are no entires
# Return 1 on failure 
#
ok_fstab()
{
    cat /etc/fstab | grep "^/dev/emcpower*" > /dev/null 2>&1 
    if [ $? -eq 0 ]; then
        ilog "`eval_gettext \"Error: /etc/fstab has PowerPath pseudo(emcpowerX) device entry(s).\"`"
        cat /etc/fstab | grep "^/dev/emcpower*" | grep "/boot" > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            ilog "`eval_gettext \"Boot from SAN is configured for this host.\"`"
            if [ -f /etc/emc/.emcpbfs_linux_done ]; then
                ilog "`eval_gettext \"Please run '/etc/opt/emcpower/emcpbfs_linux remove' to unconfigure Boot from SAN and try again.\"`"
            else
                ilog "`eval_gettext \"Please restore boot entry from /dev/emcpowerX to its original device in /etc/fstab and try again.\"`"
            fi
            return 1;
        fi 
        return 1;
    fi

    return 0;
}

#--------------------------------------------------------------------
# Calculate CPU usage every second for the specified duration plus 1
# second.  And return the max CPU usage in any one second interval.
#--------------------------------------------------------------------
get_cpu_usage()
{
    DURATION=$1

    PREV_TOTAL=0
    PREV_IDLE=0
    MAX_CPU_USAGE=0
    LOOP_TIME=0
 
    while true; do
        # Get the total CPU statistics, discarding the 'cpu ' prefix.
        CPU=($(sed -n 's/^cpu\s//p' /proc/stat))
        IDLE=${CPU[3]} # Just the idle CPU time.
 
        # Calculate the total CPU time.
        TOTAL=0
        for VALUE in "${CPU[@]:0:8}"; do
            TOTAL=$((TOTAL+VALUE))
        done
 
        # Calculate the CPU usage since we last checked.
        DIFF_IDLE=$((IDLE-PREV_IDLE))
        DIFF_TOTAL=$((TOTAL-PREV_TOTAL))
        DIFF_USAGE=$(((1000*(DIFF_TOTAL-DIFF_IDLE)/DIFF_TOTAL+5)/10))

        # The CPU usage calculated in the first second is not really indicative
        # of the usage in that second.  Rather it is the average of the CPU usage
        # since the system start and hence ignore it.
        if [ $LOOP_TIME -gt 0 -a $DIFF_USAGE -gt $MAX_CPU_USAGE ]
        then
            MAX_CPU_USAGE=$DIFF_USAGE
        fi
 
        # Remember the total and idle CPU times for the next check.
        PREV_TOTAL="$TOTAL"
        PREV_IDLE="$IDLE"
 
        LOOP_TIME=$((LOOP_TIME+1)) 
         
        if [ $LOOP_TIME -gt $DURATION ]
        then
            break
        fi

        # Wait before checking again.
        sleep 1
    done

    return $MAX_CPU_USAGE
}

#-----------------------------------------------------------------
# Get the physical memory usage and return space separated values
# in this format.  Memory values are in MB.
#
# Total  Used   Free  Percentage  Percentage
#  Mem   Mem    Mem    in float   rounded up
#
# 257994 2437 255556 0.953607 1
#-----------------------------------------------------------------
get_memory_usage()
{
    free -t -m | grep "Mem" | awk '{printf "%d %d %d %.2f %.0f", $2, $3, $4, $3*100/$2,  $3*100/$2}'
}


#--------------------------------------------------------------
# For logging messages to system log using logger if available.
#--------------------------------------------------------------
pp_logger ()
{
    msg=$*
    type logger > /dev/null 2>&1

    if [ $? -ne 0 ]
    then
        echo "`eval_gettext \"${msg}\"`"
    else
        logger ${msg}
    fi
}

#-------------------------------------------------------------------------
# run_pre_ndu_checks - Check for a few things to make sure that conditions
# are suitable for performing a Non-Disruptive Upgrade (NDU) of PowerPath.
#-------------------------------------------------------------------------
run_pre_ndu_checks()
{
    PRE_NDU_CHECK_ERROR="N"

    filename=$(basename $0)
    
    script_flag=false
    if [[ $filename == "pre_ndu_health_check.sh" ]]; then
        script_flag=true
        echo
        printf "%3s %-50s%-16s\n" " " "Check" "Status"
        printf "%3s %-50s%-16s\n" " " "=====" "======"
    fi

    #
    # Check if a valid licence key is installed.
    #
    if [ -f /sbin/emcpreg ]; then
        /sbin/emcpreg -l 2>&1 | grep -i "no license keys" > /dev/null 2>&1 ||
        /sbin/emcpreg -l 2>&1 | grep -i "No valid license" > /dev/null 2>&1
        if [ $? -eq 0 ]; then
           PRE_NDU_CHECK_ERROR="Y"
           if [[ "$script_flag" = false ]]; then
               pre_error "Error: No valid PowerPath license found."
               pre_error "Please try non disruptive upgrade only when PowerPath is licensed."
           else
	       echo
    	       printf "%3s %-50s%-16s\n" " " "Valid license present" "No"
               echo
   	       printf "%3s %-50s\n" " " "Error: No valid PowerPath licence found."
	       printf "%3s %-50s\n" " " "Please try non disruptive upgrade only when PowerPath is licensed."
               echo
               exit 1
           fi
        else
            if [[ "$script_flag" = false ]]; then
                flog "`eval_gettext \"A valid PowerPath license is present.\"`"
            else
		echo
                printf "%3s %-50s%-16s\n" " " "Valid license present" "Yes"
                echo
            fi
        fi
    fi

    #
    # Check if PowerPath is running.
    #
    /sbin/lsmod | grep -w emcp > /dev/null 2>&1
    if [ $? -ne 0 ]; then
        PRE_NDU_CHECK_ERROR="Y"
        if [[ "$script_flag" = false ]]; then
            pre_error "Error: PowerPath is not active."
            pre_error "Please try non disruptive upgrade only when PowerPath is active."
        else
    	    printf "%3s %-50s%-16s\n" " " "PowerPath is active" "No"
            echo
            printf "%3s %-50s\n" " " "Error: PowerPath is not active."
            printf "%3s %-50s\n" " " "Please try non disruptive upgrade only when PowerPath is active."
            echo
            exit 1
        fi
    else
        if [[ "$script_flag" = false  ]]; then
            flog "`eval_gettext \"PowerPath is started and active.\"`"
        else
	    printf "%3s %-50s%-16s\n" " " "PowerPath is active" "Yes"
            echo
        fi
    fi
   
    #
    # Check CPU and memory usage.
    #
    get_cpu_usage 5
    CPU_USAGE=$?
    if [ $CPU_USAGE -gt $MAX_NDU_CPU_USAGE_THRESHOLD ]; then
        PRE_NDU_CHECK_ERROR="Y"
        if [[ "$script_flag" = false ]]; then
            pre_error "Error: CPU usage of $CPU_USAGE% is high at the moment."
            pre_error "Please try non disruptive upgrade when CPU usage is less than $MAX_NDU_CPU_USAGE_THRESHOLD%."
        else
            printf "%3s %-50s%-16s\n" " " "CPU usage < 75%" "$MAX_NDU_CPU_USAGE_THREESHOLD%"
	    echo
            printf "%3s %-50s\n" " " "Error: CPU usage of $CPU_USAGE% is high at the moment."
            printf "%3s %-50s\n" " " "Please try non disruptive upgrade when CPU usage is less than $MAX_NDU_CPU_USAGE_THRESHOLD%."
            echo
	    exit 1
        fi
    else
        if [[ "$script_flag" = false ]]; then
            flog "`eval_gettext \"Host CPU usage is $CPU_USAGE%.\"`"
        else
            printf "%3s %-50s%-16s\n" " " "CPU usage < 75%" "$CPU_USAGE%"
            echo
        fi
    fi
       
    MEM_USAGE_VALUES=`get_memory_usage`
    set $MEM_USAGE_VALUES
    if [ $5 -gt $MAX_NDU_MEM_USAGE_THRESHOLD ]; then
        PRE_NDU_CHECK_ERROR="Y"
        if [[ "$script_flag" = false ]]; then
            pre_error "Total physical memory: $1 MB, Used: $2 MB, Free: $3 MB, Percentage used: $4%."
            pre_error "Error: Physical memory usage of $5% is high at the moment."
            pre_error "Please try non disruptive upgrade when memory usage is less than $MAX_NDU_MEM_USAGE_THRESHOLD%."
        else
            printf "%3s %-50s%-16s\n" " " "Memory usage < 75%" "$5%"
            echo
	    printf "%3s %-50s\n" " " "Total physical memory: $1 MB, Used: $2 MB, Free: $3 MB, Percentage used: $4%."
	    printf "%3s %-50s\n" " " "Error: Physical memory usage of $5% is high at the moment."
	    printf "%3s %-50s\n" " " "Please try non disruptive upgrade when memory usage is less than $MAX_NDU_MEM_USAGE_THRESHOLDD%."
    	    echo
	    exit 1
        fi
    else
        if [[ "$script_flag" = false ]]; then
            flog "`eval_gettext \"Total physical memory: $1 MB, Used: $2 MB, Free: $3 MB, Percentage used: $4%.\"`"
        else
            printf "%3s %-50s%-16s\n" " " "Memory usage < 75%" "$5%"
            echo
        fi
    fi

    if [ -f /sbin/powermt ];then

        #
        # Check for flaky paths.
        #
        /sbin/powermt display dev=all 2>/dev/null | grep "asb:iopf" > /dev/null 2>&1
        if [ $? -eq 0 ] ; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: Flaky paths with asb:iopf mode found."
                pre_error "Please try non disruptive upgrade only when there are no flaky paths."
	    else
	        printf "%3s %-50s%-16s\n" " " "Flaky paths present" "Yes"
                echo
                printf "%3s %-50s\n" " " "Error: Flaky paths with asb:iopf mode found."
                printf "%3s %-50s\n" " " "Please try non disruptive upgrade only when there are no flaky paths."
                echo
		exit 1
	    fi
        else
            #
            # Check for flaky paths with asb:fpin mode.
            #
            /sbin/powermt display dev=all 2>/dev/null | grep "asb:fpin" > /dev/null 2>&1
            if [ $? -eq 0 ] ; then
                PRE_NDU_CHECK_ERROR="Y"
                if [[ "$script_flag" = false ]]; then
                    pre_error "Error: Flaky paths with asb:fpin mode found."
                    pre_error "Please try non disruptive upgrade only when there are no flaky paths."
                else
                    printf "%3s %-50s%-16s\n" " " "Flaky paths present" "Yes"
                    echo
                    printf "%3s %-50s\n" " " "Error: Flaky paths with asb:fpin mode found."
                    printf "%3s %-50s\n" " " "Please try non disruptive upgrade only when there are no flaky paths."
                    echo
                    exit 1
                fi
            else
                if [[ "$script_flag" = false ]]; then
                    flog "`eval_gettext \"No flaky paths are present.\"`"
                else
                    printf "%3s %-50s%-16s\n" " " "Flaky paths present" "No"
                    echo
                fi
            fi
        fi

        #
        # Check for dead paths.
        #
        /sbin/powermt display dev=all 2>/dev/null | grep -w "dead" > /dev/null 2>&1
        if [ $? -eq 0 ] ; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: Dead paths are present on the host."
                pre_error "Please try non disruptive upgrade only when there are no dead paths."
            else
                printf "%3s %-50s%-16s\n" " " "Dead paths check" "Yes"
                echo
	        printf "%3s %-50s\n" " " "Error: Dead paths are present on the host."
	        printf "%3s %-50s\n" " " "Please try non disruptive upgrade only when there are no dead paths."
                echo
		exit 1
            fi
        else
            if [[ "$script_flag" = false ]]; then
                flog "`eval_gettext \"No dead paths are present.\"`"
            else
	        printf "%3s %-50s%-16s\n" " " "Dead paths check" "No"
                echo
            fi
        fi

        #
        # Check for manually set standby paths.
        #
        /sbin/powermt display dev=all 2>/dev/null | grep -w "standby" > /dev/null 2>&1
        if [ $? -eq 0 ] ; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: User configured standby paths are detected on the host."
                pre_error "Please finish the activity that required the paths to be set to standby, set them to active again and try nondisruptive upgrade again."
            else
                printf "%3s %-50s%-16s\n" " " "Standby paths present" "Yes"
                echo
	        printf "%3s %-50s\n" " " "Error: User configured standby paths are detected on the host."
     		printf "%3s %-50s\n" " " "Please finish the activity that required the paths to be set to standby."
     		printf "%3s %-50s\n" " " "Set them to active again and try non disruptive upgrade again."
     		echo
		exit 1 
            fi
        else
            if [[ "$script_flag" = false ]]; then
                flog "`eval_gettext \"No standby paths are present.\"`"
            else
                printf "%3s %-50s%-16s\n" " " "Standby paths present" "No"
                echo
            fi
        fi

        #
        # Check - Make sure powermt is not running and no devices are in use.
        #
        ps -C powermt > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: powermt command is running."
                pre_error "Please stop all powermt commands and then try non disruptive upgrade again."
            else
		printf "%3s %-50s%-16s\n" " " "powermt command running" "Yes"
                echo
    		printf "%3s %-50s\n" " " "Error: powermt command is running."
    		printf "%3s %-50s\n" " " "Please stop all powermt commands and then try non disruptive upgrade again."
    		echo
                exit 1	        
            fi
        else
            if [[ "$script_flag" = true ]]; then       
                 printf "%3s %-50s%-16s\n" " " "powermt command running" "No"
                 echo
            fi
        fi

        #
        # Check - Make sure no migrations are present during an upgrade.
        #
        if [ $INCLUDE_PPME -eq 1 ]; then
            mig_info=`/sbin/powermig info -all`
            if [ $? -eq 0 ]; then
                echo "$mig_info" | grep 'No migrations found' > /dev/null
                if [ $? -ne 0 ] ; then
                    PRE_NDU_CHECK_ERROR="Y"
                    if [[ "$script_flag" = false ]]; then
                        pre_error "Error: PPME migrations are present."
                        pre_error "Please complete and cleanup all PPME migrations and then try non disruptive upgrade again."
                    else
                        printf "%3s %-50s%-16s\n" " " "PPME migrations present" "Yes"
                        echo
    			printf "%3s %-50s\n" " " "Error: PPME migrations are present."
    			printf "%3s %-50s\n" " " "Please complete and cleanup all PPME migrations and then try non disruptive upgrade again."
    			echo
			exit 1
                    fi
                else
                    if [[ "$script_flag" = false ]]; then
                        flog "`eval_gettext \"No migrations are configured.\"`"
                    else
                        printf "%3s %-50s%-16s\n" " " "PPME migrations present" "No"
                        echo
                    fi

                fi
            fi
        fi

        #
        # Check - Make sure emcpadm, emcplun_linux and emcpbfs_linux are not running.
        #

        #
        # emcpadm exists only in pre-8.0 versions.  From 8.0 onwards, it is powermap.
        #
        if [ -f /sbin/emcpadm ]; then
            ps -C emcpadm > /dev/null 2>&1
            if [ $? -eq 0 ]; then
                PRE_NDU_CHECK_ERROR="Y"
                if [[ "$script_flag" = false ]]; then
                    pre_error "Error: emcpadm command is running."
                    pre_error "Please stop all emcpadm commands and then try non disruptive upgrade again."
                else
                    printf "%3s %-50s%-16s\n" " " "emcpadm command running" "Yes"
                    echo
                    printf "%3s %-50s\n" " " "Error: emcpadm command is running."
                    printf "%3s %-50s\n" " " "Please stop all emcpadm commands and then try non disruptive upgrade again."
                    echo
                    exit 1
                fi
            else
                if [[ "$script_flag" = true ]]; then
                    printf "%3s %-50s%-16s\n" " " "emcpadm command running" "No"
                    echo
                fi
            fi
        else
            ps -C powermap > /dev/null 2>&1
            if [ $? -eq 0 ]; then
                PRE_NDU_CHECK_ERROR="Y"
                if [[ "$script_flag" = false ]]; then
                    pre_error "Error: powermap command is running."
                    pre_error "Please stop all powermap commands and then try non disruptive upgrade again."
                else
                    printf "%3s %-50s%-16s\n" " " "powermap command running" "Yes"
                    echo
                    printf "%3s %-50s\n" " " "Error: powermap command is running."
                    printf "%3s %-50s\n" " " "Please stop all powermap commands and then try non disruptive upgrade again."
                    echo
                    exit 1
                fi
            else
                if [[ "$script_flag" = true ]]; then
                    printf "%3s %-50s%-16s\n" " " "powermap command running" "No"
                    echo
                fi
            fi
        fi

        ps -C emcplun_linux > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: emcplun_linux script is running."
                pre_error "Please try non disruptive upgrade after emcplun_linux script completes."
            else
                printf "%3s %-50s%-16s\n" " " "emcplun_linux script running" "Yes"
		echo
    		printf "%3s %-50s\n" " " "Error: emcplun_linux script is running."
    		printf "%3s %-50s\n" " " "Please try non disruptive upgrade after emcplun_linux script completes."
    		echo
		exit 1
            fi
        else
            if [[ "$script_flag" = true ]]; then
                printf "%3s %-50s%-16s\n" " " "emcplun_linux script running" "No"
                echo
            fi
        fi

        ps -C emcpbfs_linux > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            PRE_NDU_CHECK_ERROR="Y"
            if [[ "$script_flag" = false ]]; then
                pre_error "Error: emcpbfs_linux script is running."
                pre_error "Please try non disruptive upgrade after emcpbfs_linux script completes."
            else
                printf "%3s %-50s%-16s\n" " " "emcpbfs_linux script running" "Yes"
		echo
    		printf "%3s %-50s\n" " " "Error: emcpbfs_linux script is running."
    		printf "%3s %-50s\n" " " "Please try non disruptive upgrade after emcpbfs_linux script completes."
    		echo
		exit 1
            fi
        else
            if [[ "$script_flag" = true ]]; then
                printf "%3s %-50s%-16s\n" " " "emcpbfs_linux script running" "No"
                echo
            fi
        fi

    else
        if [[ "$script_flag" = false ]]; then
            pre_error "Error: Please ensure PowerPath is installed properly."
        else
            exit 1
        fi
        PRE_NDU_CHECK_ERROR="Y"
    fi

    if [ "$PRE_NDU_CHECK_ERROR" == "Y" ]; then
        if [[ "$script_flag" = false ]]; then
            cleanup_error_exit
        fi
    else
	if [[ "$script_flag" = true ]]; then 
	    printf "%3s %-50s\n" " " "---------------------------------------------------------------------------"
	    printf "%3s %-50s\n" " " "All checks have been completed and non disruptive upgrade can be attempted."
	    printf "%3s %-50s\n" " " "---------------------------------------------------------------------------"
        fi
    fi
}


# Check if Naviagent/Hostagent is running. Variable g_naviloc
# returns the Naviagent or Hostagent script for stopping and
# restarting the agent. Agent will be stopped and restarted
# in upgrade, uninstall, and "PowerPath stop".
#
is_navi_running
g_navi_running=$?
g_naviloc=`get_navi_script_loc $g_navi_running`

NDU_LOCK_FILE="/etc/opt/emcpower/.ndu_lock"
UPGRADE_ABORT_FILE="/etc/opt/emcpower/.upgrade_abort"
PMAX_FILE_CONFIG="/etc/enaslogconf"
NDI_LOCK_FILE="/etc/opt/emcpower/.ndi_lock"

###############################################################################
# End of common.sh - Common script shared by PowerPath.common and
#                      EMCpower.LINUX.spec. 
##############################################################################
################################################################################

################################################################################
### Import globals spec here.
#####################################################################
### Start of globals.spec
#####################################################################

# Temp directory used by the %pre section.  (Before $PP_I_DIR exists.)
#
PRE_TMP=/etc/opt/emcpower/.tmp/
#
# Default installation directory for emcpower
#
PP_I_DIR=/etc/opt/emcpower
SYS_LOG_DIR=/var/log
#
# The file name of the device file used to control the power path drivers
#
# created by sysfs in 2.6.
#POWER_DEV=/dev/emcpower
#
# Installation log file.
#
POWER_LOG=$SYS_LOG_DIR/powerpath_install.log
#
# Installation temporary file directory.
#
POWER_TMP_DIR=$PP_I_DIR/.tmp
#
# Backup archives used in case an installation is aborted in mid-stream
#
POWER_BACKUP_ARCHIVE=$PP_I_DIR/.archive.tar
POWER_BACKUP_ARCHIVE_NEW=$PP_I_DIR/.archive_NEW.tar
archive_dir=/etc/emc/archive

USE_MODPROBE_DIR=no
if [ -f /etc/ovs-release ]
then
    host_os=`sed '/^[ \t]*#/d;s/^.*release \([0-9]\)[0-9.]*/\1/' \
                                          /etc/ovs-release`
    host_os_name=OVS${host_os}
    if [ -d /etc/modprobe.d ]; then
        USE_MODPROBE_DIR=yes
    fi
elif [ -f /etc/oracle-release ]
then
    if [ $(uname -r | grep -c uek) -ne 0 ]
    then
        host_os=`sed '/^[ \t]*#/d;s/^.*release \([0-9]\)[0-9.]*.*/\1/' \
                                           /etc/oracle-release`
        host_os_name=OL${host_os}
    else
        host_os=`sed '/^[ \t]*#/d;s/^.*release \([0-9]\)[0-9.]*.*/\1/' \
                                               /etc/redhat-release`
        host_os_name=RHEL${host_os}
    fi
elif [ -f /etc/SuSE-release ]
then
    host_os=`awk '/^VERSION/ {version=$3}
                  END { print version }' /etc/SuSE-release`
    host_os_name=SLES${host_os}
    host_os_patchlevel=`awk '/^PATCHLEVEL/ {patchlevel=$3}
                  END { print patchlevel }' /etc/SuSE-release`
elif [ -f /etc/redhat-release ]
then
    citrix_release=`sed -n '/^[ \t]*#/d;s/XenServer release/&/p' \
            /etc/redhat-release`
    if [ -n "$citrix_release" ]
    then
        host_os="6"
        host_os_name=CXS${host_os}
    else
        host_os=`sed '/^[ \t]*#/d;s/^.*release \([0-9]\)[0-9.]*.*/\1/' \
                                               /etc/redhat-release`
        host_os_name=RHEL${host_os}
    fi
elif [ -f /etc/asianux-release ]
then
    host_os=`sed 's/^Asianux [a-zA-Z]* \([0-9]\)[0-9.]* .*/\1/' \
                                           /etc/asianux-release`
    host_os_name=Asianux-${host_os}
elif [ -f /etc/os-release ]
then
    OS_NAME=`awk -F'=|"' '$1 == "NAME" {print $3}' /etc/os-release`
    OS_REV=`awk -F'=|"' '$1 == "VERSION" {print $3}' /etc/os-release | awk '{print $1}' |  sed 's/[^a-zA-Z0-9]//g'`

    host_os=$OS_REV
    host_os_name=SLES${host_os}
    USE_MODPROBE_DIR=yes
fi

INCLUDE_DRACUT_CONFIG=0
if [ -d ${PP_I_DIR}/EMCpower.LINUX-%version-%{__release}/99powerpath ]; then
    INCLUDE_DRACUT_CONFIG=1
fi

INCLUDE_EMCPBFS_LINUX=0
if [ -f ${PP_I_DIR}/EMCpower.LINUX-%version-%{__release}/emcpbfs_linux ]; then
    INCLUDE_EMCPBFS_LINUX=1
fi

INCLUDE_SELINUX_POLICY_PKG=0
if [ -f ${PP_I_DIR}/EMCpower.LINUX-%version-%{__release}/PowerPath.pp ]; then
    INCLUDE_SELINUX_POLICY_PKG=1
fi

INCLUDE_NVME_SUPPORT=0
if [ -f ${PP_I_DIR}/EMCpower.LINUX-%version-%{__release}/pp_nvme.sh ]; then
    INCLUDE_NVME_SUPPORT=1
fi

INCLUDE_PFLEX_SUPPORT=0
if [ -f ${PP_I_DIR}/EMCpower.LINUX-%version-%{__release}/pp_pflex.sh ]; then
    INCLUDE_PFLEX_SUPPORT=1
fi

#
# local modprobe file
modprobe_file=/etc/modprobe.d/powerpath.conf

# Check platform compatibility for installing PPME components
# Set INCLUDE_PPME to 0 only if the platform is not supported
#
INCLUDE_PPME=1

MAX_NDU_CPU_USAGE_THRESHOLD=75
MAX_NDU_MEM_USAGE_THRESHOLD=75

#####################################################################
### End of globals.spec
#####################################################################
################################################################################

#---------------------------------------
# Begin declaration of global variables.
#---------------------------------------
PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PP_I_DIR/bin; 
export PATH

PPBASE="/etc/opt/emcpower/EMCpower.LINUX-8.1.0.00.00-070"

PPME_SUPPORT=yes
init_flag=false

TMP_MODP=/etc/opt/emcpower/.tmp/powerpath.conf
PP_MODP=/etc/modprobe.d/powerpath.conf

if [ -f $PP_I_DIR/.pp_version ] ; then
       PP_VERSION=`cat $PP_I_DIR/.pp_version`
fi

if [ -f $PP_I_DIR/.new_pp_version ] ; then
       NEW_PP_VERSION=`cat $PP_I_DIR/.new_pp_version`
fi

if [ -f $PP_I_DIR/.os_version ] ; then
       OS_VERSION=`cat $PP_I_DIR/.os_version`
fi
# Citrix XenServer doesn't have seperate /etc/<ditro>-release file.
# Use redhat release file to identify Citrix distro.
if [ -f /etc/redhat-release ]; then
   citrix_release=`sed -n '/^[ \t]*#/d;s/XenServer release/&/p' \
            /etc/redhat-release`
fi

if [ -f /etc/SuSE-release ]; then
    VENDOR=suse
elif [ -f /etc/ovs-release ]; then
    ovs_version=`sed '/^[ \t]*#/d;s/^.*release \([0-9]\)[0-9.]*/\1/' \
                                        /etc/ovs-release`
    VENDOR=oracle
    if [ "${ovs_version}" == "3" ]; then
        PPME_SUPPORT=no
    fi
elif [ -f /etc/oracle-release ]; then
    if [ $(uname -r | grep -c uek) -ne 0 ]
    then
        VENDOR=oracle
    else
        VENDOR=redhat
    fi
elif [ -n "$citrix_release" ]; then
    VENDOR=citrix
    PPME_SUPPORT=no
elif [ -f /etc/redhat-release ]; then
    VENDOR=redhat
elif [ -f /etc/os-release ]; then
    OS_NAME=`awk -F'=|"' '$1 == "NAME" {print $3}' /etc/os-release`
    OS_REV=`awk -F'=|"' '$1 == "VERSION" {print $3}' /etc/os-release | awk '{print $1}' | sed 's/[^a-zA-Z0-9]//g'`

    if [ "$OS_NAME" == "SLES" -a "$OS_REV" == "15SP4" -o "$OS_REV" == "15SP5" ]; then
        VENDOR=suse
    fi
fi

################################################################################
### Import platform specific pre spec definitions here.
# OL8 UEK x86_64 specific:
#
# Install only if this is a Oracle Linux, x86_64 system
#

EXPECTED_VENDOR=oracle
VENDOR_NAME=Oracle
VENDOR_OS_NAME=OL8

EXPECTED_OS_UEK6="5.4.17-2011"
EXPECTED_OS_UEK7="5.15.0-0"

EXPECTED_OS_REVP2="el8"

EXPECTED_ISA=x86_64
MIN_UPGRADE_REV=7.0.0
MIN_NDU_UPGRADE_REV=7.4.0

check_vendor_rev()
{
     uname -r | grep $EXPECTED_OS_REVP2 > /dev/null
}

#-----------------------------------------------------------------------
# identify_platform -
# Determine the set of drivers files compatible with the /lib/modules
# subdirectory passed as an argument and echo the tag for that set of
# drivers to stdout.
#-----------------------------------------------------------------------
identify_platform()
{
    local platform=

    #
    # Recognize production or custom Oracle kernel.
    #
    case "$1" in
        $EXPECTED_OS_UEK6*)  platform=ol8_uek6_x8664;;
        $EXPECTED_OS_UEK7*)  platform=ol8_uek7_x8664;;
        *)

        echo $1 | grep "5.4.17" > /dev/null
        if [ $? -eq 0 ]; then
            ol_update=`echo $1 | sed -e 's/5.4.17-\([0-9]*\)\..*/\1/'`
            if [ "$ol_update" -ge "2011" ]; then
                platform="ol8_uek6_x8664"
            fi
        fi
        echo $1 | grep "5.15.0" > /dev/null
        if [ $? -eq 0 ]; then
            ol_update=`echo $1 | sed -e 's/5.15.0-\([0-9]*\)\..*/\1/'`
            if [ "$ol_update" -ge "0" ]; then
                platform="ol8_uek7_x8664"
            fi
        fi
      ;;
    esac

    if [ "$platform" ] ; then
         /bin/true
    else
         /bin/false
    fi
    if [ $? -ne 0 ]
    then
        if [ "$1" = `uname -r` ]; then
            pre_error "This PowerPath package does not support $1 kernel."
            cleanup_error_exit
        fi
    fi

    if [ "$platform" ] ; then
        echo "$platform"
    fi
}
#################################################################################

if [ -f $NDU_LOCK_FILE ]; then
   export PP_NDU_IN_PROGRESS=1
fi

NVME_RUNTIME_SUPPORT=0
if [ -f ${PPBASE}/pp_nvme.sh ]; then
    NVME_RUNTIME_SUPPORT=1
    if [ "$host_os_name" = "OL7" ]; then
       uname -r | grep "4.14.35" > /dev/null
       if [ $? -eq 0 ]; then
           ol_update=`uname -r | sed -e 's/4.14.35-\([0-9]*\)\..*/\1/'`
           if [ "$ol_update" -lt "1902" ]; then
               NVME_RUNTIME_SUPPORT=0
           fi
       fi
    fi
#NVMe support is enabled only for RHEL 7.8 onwards
    if [ "$host_os_name" = "RHEL7" ]; then
       uname -r | grep "3.10.0" > /dev/null
       if [ $? -eq 0 ]; then
           rhel_update=`uname -r | sed -e 's/3.10.0-\([0-9]*\)\..*/\1/'`
           if [ "$rhel_update" -lt "1127" ]; then
               NVME_RUNTIME_SUPPORT=0
           fi
       fi
    fi
fi

PFLEX_RUNTIME_SUPPORT=0
if [ -f ${PPBASE}/pp_pflex.sh ]; then
    PFLEX_RUNTIME_SUPPORT=1
fi
    
#-------------------------------------
# End declaration of global variables.
#-------------------------------------

#-------------------------------------------
# Begin internationalization specific lines.
#-------------------------------------------

init_I18N()
{
    type -P gettext.sh > /dev/null 2>&1 && \
        type -p gettext >/dev/null  2>&1

    if [ $? -ne 0 ]; then
        gettext()
        {
            echo "$*"
        }
        eval_gettext()
        {
            eval "echo \"$*\""
        }
    else
        . gettext.sh

        TEXTDOMAIN=PowerPath
        export TEXTDOMAIN
        TEXTDOMAINDIR=$PPBASE/i18n/catalog
        export TEXTDOMAINDIR
    fi
}

#-----------------------------------------
# End internationalization specific lines.
#-----------------------------------------

#
# Functions to preserve exceptional command status return values
#

#-----------------------------------------------------------------------
# To reset all previous saved return values.
#-----------------------------------------------------------------------
ret_reset()
{
    ret_cmd_stat=0
    ret_script_stat=0
}

#-----------------------------------------------------------------------
# This function does two things:
#
# - saves the return value of the last executed command or function
#   in ret_script_stat - the overall script return value.
# - returns the return value of the last command or function.
#
# Useful in scenarios where you want to update the overall script
# return value as well as find the return value of the last command
# or function.
#-----------------------------------------------------------------------
ret_check()
{
    ret_cmd_stat=$?
    if [ $ret_cmd_stat -ne 0 ] ; then
         ret_script_stat=$ret_cmd_stat
    fi
    return $ret_cmd_stat
}

#-----------------------------------------------------------------------
# This function does two things:
#
# - check the return value of the last executed command or function
#   and update the overall script return value by calling ret_check.
# - returns the overall script return value.
#-----------------------------------------------------------------------
ret_script_status()
{
    ret_check
    return $ret_script_stat
}

#-----------------------------------------------------------------------
# To exit the script and return the overall script return value.
#-----------------------------------------------------------------------
ret_exit()
{
    exit $ret_script_stat
}

#-----------------------------------------------------------------------
# This function is called either at the end of the script or on an
# error exit.  It will update the overall script return value with
# the return value of the last executed command or function.
#
# Then it will print success or failure message. It takes either
# "Starting" or "Stopping" as an input argument.
#-----------------------------------------------------------------------
return_status()
{
    ret_check

    case "$ret_script_stat" in
        0)
            echo "`eval_gettext \"$1 PowerPath: done\"`"
            ;;
        *)
            echo "`eval_gettext \"$1 PowerPath: failed\"`"
            ;;
    esac

    return $ret_script_stat
}

#
#-----------------------------------------------------------------------
# To translate an error message and print it on the console.
#-----------------------------------------------------------------------
#
report_error()
{
    (eval_gettext "$*"
     echo ) 1>&2
}

#
#-----------------------------------------------------------------------
# This function should be called only when an error is encountered
# during PowerPath start and the script needs to be aborted.  It will
# call return_status to print a failure message before exiting the
# script.
#-----------------------------------------------------------------------
#
start_error_exit()
{
    /bin/false
    return_status Starting
    ret_exit
}

#-----------------------------------------------------------------------
# Restore system to the state that existed before this script ran.
# First, execute the commands in the undo list in reverse order, then
# untar archived files.
#-----------------------------------------------------------------------
rollback()
{
    awk '{print NR,$0}' $POWER_TMP_DIR/undolist | \
        tac $POWER_TMP_DIR/undolist | \
        sed 's/[^ ][^ ]* //' > $POWER_TMP_DIR/undo.sh
    sh $POWER_TMP_DIR/undo.sh

    if [ -f $POWER_TMP_DIR/rollbackfiles.tar ]; then
        tar -x --absolute-names --file $POWER_TMP_DIR/rollbackfiles.tar
    fi
}

#-----------------------------------------------------------------------
# Delete the files containing rollback information
#-----------------------------------------------------------------------
rollback_reset()
{
    rm -f $POWER_TMP_DIR/rollbackfiles.tar
    rm -f $POWER_TMP_DIR/undolist
    rm -f $POWER_TMP_DIR/undo.sh
}

#-----------------------------------------------------------------------
# Save a directory and contained files in the rollback archive
#-----------------------------------------------------------------------
save_dirtree_for_rollback()
{
    local pathname
    case "$1" in
        /*) pathname=$1 ;;
         *) pathname=`pwd`/$1 
    esac
   tar --append --preserve-permissions --absolute-names \
       --file $POWER_TMP_DIR/rollbackfiles.tar $pathname
}

#-----------------------------------------------------------------------
# Save a file or directory in the rollback archive
#-----------------------------------------------------------------------
save_for_rollback()
{
    local pathname
    case "$1" in
        /*) pathname=$1 ;;
         *) pathname=`pwd`/$1 
    esac
    tar --append --preserve-permissions --absolute-names \
    --no-recursion --file $POWER_TMP_DIR/rollbackfiles.tar $pathname
}

#-----------------------------------------------------------------------
# Add a shell command, for execution during rollback, to the undo list
#-----------------------------------------------------------------------
add_to_undolist()
{
    echo "cd `pwd`; $*" >> $POWER_TMP_DIR/undolist
    chmod 600 $POWER_TMP_DIR/undolist
}

#-----------------------------------------------------------------------
# Move a file in such a way that the original source and destination
# files are restored by rollback.
#-----------------------------------------------------------------------
move_file()
{
    save_for_rollback $1
    local dest
    if [ -d "$2" ]; then
        dest=$2/`basename $1`
    else
        dest=$2
    fi
    if [ -f "$dest" ]; then
        save_for_rollback $dest
    else
        add_to_undolist rm -f "$dest"
    fi
    mv -f $1 $dest
}

#-----------------------------------------------------------------------
# Copy a new file over an old one,in such a way that the old file
# can be restored during rollback. 
#-----------------------------------------------------------------------
copy_file()
{
    local dest
    if [ -d "$2" ]; then
        dest=$2/`basename $1`
    else
        dest=$2
    fi
    if [ -f "$dest" ]; then
        save_for_rollback $dest
    else
        add_to_undolist rm -f "$dest"
    fi
    cp -pf $1 $2
}

#-----------------------------------------------------------------------
# Save a file in the rollback archive and then delete it.
#-----------------------------------------------------------------------
remove_file()
{
    if [ -f "$1" ]; then
        save_for_rollback $1
        rm -f $1
    fi
}

#-----------------------------------------------------------------------
# Save a directory and contained files in the rollback archive and then
# delete them.
#-----------------------------------------------------------------------
remove_dirtree()
{
    if [ -d "$1" ]; then
        save_dirtree_for_rollback $1
        rm -rf $1
    fi
}

#-----------------------------------------------------------------------
# Make a directory in such a way that it will be removed during rollback.
# All non-existent directories in the given path are created.  If the
# directory already exists, do nothing.
#-----------------------------------------------------------------------
make_dir()
{
    local path
    local newdir
    set -- `echo $1 | sed 's:/:/ :g'`
    for dir 
    do
        path="${path}${dir}"
        if [ ! -d $path ]
        then
           add_to_undolist rmdir $path
           mkdir $path
           newdir=T
        fi
    done
    [ "$newdir" ] && chmod 700 $path && chown root:root $path
}

#-----------------------------------------------------------------------
# Copy a kernel module and set file pwermissions, group and owner
#-----------------------------------------------------------------------
copy_mod()
{
    copy_file "$1" "$2" && chmod 600 "$2" && chown root:root "$2"
}

#-----------------------------------------------------------------------
# Compare the vermagic string of the pp base driver to the vermagic string
# of the scsi_mod driver.
# input: path to PowerPath base driver, in package area.
# return 0 for matching strings.
#-----------------------------------------------------------------------
verify_driver_vermagic()
{
    local pp_drv_path=$1
    local ref_driver
    local ref_mod_version
    local pp_mod_version

    /sbin/depmod -a > /dev/null 2>&1
    ref_driver=`lsmod | sed -n -e 's/ .*//' -e '$p'`
    ref_mod_version=`modinfo $ref_driver | \
        sed -n '/^vermagic:/s/^vermagic:  *//p'`
    pp_mod_version=`modinfo $pp_drv_path | \
        sed -n '/^vermagic:/s/^vermagic:  *//p'`
    ref_mod_version=`echo $ref_mod_version | sed -e 's/^[^ ]* //'`
    pp_mod_version=`echo $pp_mod_version | sed -e 's/^[^ ]* //'`
    if [ "$pp_mod_version" = "$ref_mod_version" ]
    then
        true
    else
        false
    fi
}

#-----------------------------------------------------------------------
# Run "preinstall" checks to make sure the running system is compatible
# with this package.
#-----------------------------------------------------------------------
validate_install_target()
{
## Check - Require effective UID of root

    if [ $EUID != 0 ]; then
        report_error "You must be root to install PowerPath."
        start_error_exit
    fi

## Check - Only install on supported kernels

    uname -r | grep '2\.6\|3\.0\|3\.8\|3\.10\|3\.12\|4\.1\|4\.4\|4\.12\|4\.14\|5\.3\|5\.4\|5\.14\|5\.15' > /dev/null
    if [ $? -ne 0 ]; then
        report_error "This PowerPath package does not support this kernel."
        start_error_exit
    fi

## Check vendor

    if [ "$EXPECTED_VENDOR" != "$VENDOR" ]; then
        report_error 'This package requires a $VENDOR_NAME Platform.'
        start_error_exit
    fi

## Check vendor rev.

    check_vendor_rev $EXPECTED_OS_REV
    if [ $? != 0 ]; then
        report_error 'This package requires $VENDOR_NAME $VENDOR_OS_NAME.'
        start_error_exit
    fi

## Check hardware platform

    if [ "`uname -m`" != "$EXPECTED_ISA" ]; then
        report_error 'This package requires the $VENDOR_NAME $EXPECTED_ISA kernel.'
        start_error_exit
    fi

## Do we have modules that work with this kernel?

    TAG=`identify_platform \`uname -r\``
    if [ -z "$TAG" ]; then
        report_error "This PowerPath package does not support this kernel."
        report_error '$PPBASE'
        start_error_exit
    fi

## Check driver vermagic

    verify_driver_vermagic $PPBASE/bin/driver/$TAG/emcp.ko
    if [ $? != 0 ]; then
        report_error 'PowerPath driver version magic mismatch.'
        start_error_exit
    fi
}

#-----------------------------------------------------------------------
# Copy files from the PowerPath archive directory to their normal
# installed locations.  In case there are any issues when PowerPath
# is started after an upgrade, the configuration files from the
# last good start of PowerPath will still be available in the archive
# directory.  Hence, in such scenarios, the newer version of PowerPath
# can be uninstalled and the older version re-installed again.  And when
# PowerPath is started after the reinstallation, it will use the archived
# config files.
#-----------------------------------------------------------------------
restore_configuration_files()
{
    for file in /etc/emc/mpaa.lams \
        /etc/emc/mpaa.excluded /etc/emc/mapping.xml
    do
      if [ -f $archive_dir/`basename $file`.saved ]; then
          copy_file $archive_dir/`basename $file`.saved $file
      fi
    done

    for file in /etc/opt/emcpower/emcp_mond.conf /etc/opt/emcpower/snmpd.conf \
                /etc/opt/emcpower/custom.pem
    do
      if [ -f $archive_dir/`basename $file`.saved ]; then
          copy_file $archive_dir/`basename $file`.saved $file
      fi
    done

    if [ -f $archive_dir/powermt_custom.xml.saved ] ; then
        copy_file $archive_dir/powermt_custom.xml.saved \
                /etc/emc/powermt_custom.xml
    fi

    for file in /etc/opt/emcpower/server.pem /etc/opt/emcpower/.tmp/server.csr \
                /etc/opt/emcpower/ppmacert.pem /etc/opt/emcpower/cacert.pem
    do
      if [ -f $archive_dir/`basename $file`.saved ]; then
          copy_file $archive_dir/`basename $file`.saved $file
      fi
    done

    #
    # Create a new mapping DB file from the archived mapping.xml file.
    #
    if [ -f /etc/emc/mapping.xml ]; then
        /sbin/powermap create_mappingdb -f /etc/emc/mapping.xml
        rm -f /etc/emc/mapping.xml
    fi
}

#-----------------------------------------------------------------------
# tps_managed_classes - Return a true status if third party software
# is installed to manage the array named in $1.  Otherwise return a
# false status.
#-----------------------------------------------------------------------
tps_managed()
{
case "$1" in
    hitachi)
        if [ -d /opt/DynamicLinkManager/bin ] ; then
        	/bin/true
        else
                /bin/false
        fi
        ;;
    hpxp)
        if [ -d /usr/src/Autopath ] ; then
        	/bin/true
        else
                /bin/false
        fi
        ;;
    ess)
        if [ -d /opt/IBMsdd/bin ] ; then
              /bin/true
        else
              /bin/false
        fi
        ;;
    *)
        /bin/false
        ;;
esac
}

#-----------------------------------------------------------------------
# prev_unmanaged - Return a true status if the array named in $2
# is marked "unmanaged" in the mpaa.lams file named in $1
#-----------------------------------------------------------------------
prev_unmanaged()
{
  grep -w $2 $1 2>/dev/null | grep -w unmanaged > /dev/null 2>&1
}

#-----------------------------------------------------------------------
# prev_managed - Return a true status if the array named in $2
# is marked "managed" in the mpaa.lams file named in $1
#-----------------------------------------------------------------------
prev_managed()
{
  grep -w $2 $1 2>/dev/null | grep -w managed > /dev/null 2>&1
}
#-----------------------------------------------------------------------
# prev_unmanage_incomplete - Return a true status if the array named in $2
# is marked "unmanage_incomplete" in the mpaa.lams file named in $1
#-----------------------------------------------------------------------

prev_unmanage_incomplete()
{
  grep -w $2 $1 2>/dev/null | grep -w unmanage_incomplete > /dev/null 2>&1
}


#-----------------------------------------------------------------------
# file_compare - Compare the contents of two files.  This function is used
# because /usr/bin/diff may be unavailable.
#
# $1, $2 - Files to compare
#
# Return status
#  0 ==> The file are the same.
#  1 ==> The file are different.
#-----------------------------------------------------------------------
file_compare()
{
    file1_lines=`grep -c '.*' $1`
    file2_lines=`grep -c '.*' $2`
    if [ $file1_lines -ne $file2_lines ]
    then
        return 1
    else
        unique_lines=`cat $1 $2 | awk '!_[$0]++' | grep -c '.*'`
        if [ $unique_lines -ne $file1_lines ]
        then
            return 1
        else
            return 0
        fi
    fi
}

#-----------------------------------------------------------------------
# If no mpaa.lams file exists, create one.  Otherwise create a temporary
# mpaa.lams file, compare it to the existing file and replace the
# existing file with the temporary one if the two files differ. Also,
# create an empty mpaa.excluded if one doesn't exist.
#
# If previously any of the lams could not be unmanaged and the classes
# were in unmanage:incomplete state, those classes would be updated as
# unmanaged in the mpaa.lams file.
#-----------------------------------------------------------------------
update_lams_files()
{
    local lams_file="/etc/emc/mpaa.lams"
    local lams_excluded_file="/etc/emc/mpaa.excluded"
    local lams_new

    if [ -f "$lams_file" ]; then
        lam_ref=$lams_file
        lams_new=${lams_file}.tmp
    else
        lam_ref=/dev/null
        lams_new=$lams_file
    fi

    echo  "global:version:$PP_VERSION" > $lams_new
    for array in symm clariion hpxp hitachi ess vplex vnx xtremio unity sc powerstore powermax powerflex powerstore_nvme powerflex_nvme
    do
        if tps_managed $array || prev_unmanaged $lam_ref $array || 
           prev_unmanage_incomplete $lam_ref $array
        then
            echo "unmanaged:$array" >> $lams_new
        else
            echo "managed:$array" >> $lams_new
        fi
    done

    if prev_managed $lam_ref hphsx
    then
        echo "managed:hphsx" >> $lams_new
    else
        echo "unmanaged:hphsx" >> $lams_new
    fi

    if [ "$lams_new" = "${lams_file}.tmp" ]; then
        if file_compare $lams_file $lams_new ; then
            rm -f $lams_new
        else
            mv -f $lams_new $lams_file
        fi
    else
        add_to_undolist rm -f $lams_file
    fi

    if [ ! -f "$lams_excluded_file" ]; then
        echo  "global:version:$PP_VERSION" > $lams_excluded_file
        add_to_undolist rm -f $lams_excluded_file
    fi
}

#-----------------------------------------------------------------------
# Add PowerPath parameters to modprobe conf file
#-----------------------------------------------------------------------
update_driver_parameters()
{
    local lams_file="/etc/emc/mpaa.lams"
    local lams_excluded_file="/etc/emc/mpaa.excluded"

    rm -f $modprobe_file
    touch $modprobe_file

    ## Update the managedclass parameter line
    
    mng_class=`awk -F: '(NR == 2) && /^managed/ {printf "%s", $2}
                        (NR > 2) && /^managed/ {printf ",%s", $2}' $lams_file`
    if [ "$mng_class" ] ; then
        if grep "options emcp managedclass" $modprobe_file > /dev/null 2>&1
        then
            sed -i "/managedclass/c\
                    options emcp managedclass=$mng_class" $modprobe_file
        else
            echo "options emcp managedclass=$mng_class" >> $modprobe_file
        fi
    fi

    ## Update the excludedvolumes parameter line.  Put

    if [ `grep -c '.*' $lams_excluded_file` -gt 1 ] ; then
        excluded=`awk -F: '(NR == 2) {printf "%s", $2}
                           (NR > 2) {printf ",%s", $2}' $lams_excluded_file`
        if [ "$excluded" ] ; then
            if grep "options emcp excludedvolumes" \
                     $modprobe_file > /dev/null 2>&1 ; then
                sed -i "/excludedvolumes/c\
                    options emcp excludedvolumes=$excluded" $modprobe_file
            else
                echo "options emcp excludedvolumes=$excluded" >> \
                    $modprobe_file
            fi
        fi

    fi
}

#-----------------------------------------------------------------------
# Log to terminal
#-----------------------------------------------------------------------
ilog()
{
    echo -e $1
}

#-----------------------------------------------------------------------
# Delete old modules in all /lib/modules subdirectories, then install
# the new modules.
#-----------------------------------------------------------------------
install_driver_modules()
{
   for os in /lib/modules/*
   do
      case $os in
          /lib/modules/`uname -r`)
              for modpath in $os/powerpath/*
              do
                remove_file $modpath
              done
              ;;
          *)
              remove_dirtree $os/powerpath
              ;;
     esac
     for modpath in $os/extra/emcp*
     do
        remove_file $modpath
     done
   done

    ## Install new modules.

    MODULE_BASE=/lib/modules/`uname -r`

    make_dir $MODULE_BASE/powerpath

    for mod in `ls $PPBASE/bin/driver/$TAG`
    do
      copy_mod $PPBASE/bin/driver/$TAG/$mod $MODULE_BASE/powerpath/$mod
    done

    depmod
}

#-----------------------------------------------------------------------------------
# Start initial PowerPath configuration for  a newly installed PowerPath package to
# run or enable an existing package to run after a kernel upgrade.
#-----------------------------------------------------------------------------------
start_init_pp()
{
    init_flag=true
   
    rollback_reset

    validate_install_target

    if [ ${INCLUDE_PPME} = 1 ]; then
      make_dir /etc/emc/ppme
    fi

    if [ "$NEW_PP_VERSION" ] ; then
           restore_configuration_files
    fi

    install_driver_modules
}

#----------------------------------------------------------------------------------
# Finish initial PowerPath configuration for  a newly installed PowerPath package to
# run or enable an existing package to run after a kernel upgrade.
#----------------------------------------------------------------------------------
finish_init_pp()
{
    if [ $? -ne 0 ]
    then
        rollback
        rollback_reset
        report_error "Error setting up PowerPath to start automatically on boot."
        start_error_exit
    fi

    ## Update state info in /etc/opt/emcpower
    rm -f $PP_I_DIR/.os_version
    uname -r > $PP_I_DIR/.os_version
    chmod 600 $PP_I_DIR/.os_version
    rm -f $PP_I_DIR/.prev_pp_version
    if [ -f $PP_I_DIR/.new_pp_version ]
    then
        if [ -f $PP_I_DIR/.pp_version ] ; then
             mv -f $PP_I_DIR/.pp_version $PP_I_DIR/.prev_pp_version
        fi
        mv $PP_I_DIR/.new_pp_version $PP_I_DIR/.pp_version
    fi
}

#-------------------------------------
# Wait for /dev/emcpower to appear.
# $1 is the number of seconds to wait.
#-------------------------------------
dev_emcpower_is_back()
{
    for ((cnt=$1/3; $cnt > 0; cnt--)); do
          if [ -c /dev/emcpower ] ; then 
                break; 
          fi 
          sleep 3; 
    done;
    if [ -c /dev/emcpower ] ; then
          /bin/true
    else
          /bin/false
    fi

}

#-------------------------------------------------------------------------
# Load saved driver state.  If powermt load fails because of dead paths or
# changed native devices, then dont fail PP start.
#-------------------------------------------------------------------------
load_saved_settings()
{
    pmtload=`/sbin/powermt load 2>&1`
    pmtload_ret=$?

    if [ $pmtload_ret -ne 0 ]; then
        echo $pmtload |  grep "Error occurred loading saved driver state" |
                         grep "Loading continues" > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            /bin/true
        else
            return $pmtload_ret
        fi
    fi
}

#--------------------------
# Configure PowerPath paths
#--------------------------
configure_pp()
{
    if [ -d $PMAX_FILE_CONFIG ]; then
        /sbin/powermt set device_add_notifications=off > /dev/null 2>&1
        /sbin/powermt set ndme_support=off > /dev/null 2>&1
    fi

    if [ -f /etc/emc/mappingDB ]; then
        /etc/opt/emcpower/emcpmgr map -p > /dev/null 2>&1
        ret_check
    fi

    #
    # If the system has no license, config error is ok.
    #
    if /sbin/emcpreg -l 2>&1 | grep '^Key' > /dev/null 2>&1; then
        /sbin/powermt config > /dev/null 2>&1
    else
        /sbin/powermt config > /dev/null 2>&1
        /bin/true
    fi
    ret_check

    #
    # Wait for udev events to settle.If the hald
    # daemon is running,then udev events may take
    # more time to settle especially if there are
    # a large number of devices present.
    #
    if [ ! -d $PMAX_FILE_CONFIG ]; then
       /sbin/udevadm settle --timeout=2700 > /dev/null 2>&1
    fi

    #
    # Several jobs to create pseudo devices would have been enqueued to
    # emcpmiscd daemon by 'emcpmgr map -p' and 'powermt config' by now.
    # However, not all of them might have completed.  Hence, wait for
    # the count of pseudo dev nodes in /dev folder (including partition
    # entries) to stabilize for upto 30 seconds.
    #
    prev_pd_count=`/bin/ls -l /dev/emcpower*  2> /dev/null | wc -l`
    sleep 1

    for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    do
        pd_count=`/bin/ls -l /dev/emcpower*  2> /dev/null | wc -l`
 
        if [ "$pd_count" == "$prev_pd_count" ]
        then
            break;
        fi

        prev_pd_count=$pd_count
        sleep 2
    done

    #
    # load the saved settings('powermt load') when
    # the PowerPath persistent device DB file exists.
    #  
    if [ -f /etc/emc/powermt_custom.xml ]; then
        load_saved_settings
        ret_check
    fi

    #
    # Map unmapped/new luns/namespaces now.
    #
    /etc/opt/emcpower/emcpmgr map > /dev/null 2>&1
    ret_check

    if [ ! -e /etc/emc/powermt_custom.xml ]; then 
        /sbin/powermt save > /dev/null 2>&1
        ret_check
    fi 

    if [ "$PPME_SUPPORT" == "yes" ]; then
        # Run powermig in case 1st open of umd fails from system crash.
        # This will cause next powermig to open umd, recover, and
        # continue successfully.
        /sbin/powermig info -all -count > /dev/null 2>&1

        if ! /sbin/powermig info -all -count | grep -q "No migrations found"
        then
            /sbin/powermig options -startupInProgress 1  > /dev/null 2>&1
        fi 

        #
        # This needs to be run in PowerPath start when it is manually started.
        # Otherwise if a PPME migration is started and synced, there will be IO
        # errors.  On host reboot, the powermig transition command will be run
        # from PowerPathPost start.
        #       
        if [ "$HOST_BOOTED_UP" == "yes" ]; then
            /sbin/powermig transition -startup -noprompt   > /dev/null 2>&1
        fi

        # Don't fail PowerPath start even if the above powermig command
        # returns an error.
        /bin/true
    fi

    #
    # Only on a normal start (and not a start after NDU is completed), try to
    # start LVM. Notice ! in the if condition.
    #
    if [ ! -f $NDU_LOCK_FILE ]
    then
        #
        # Device mapper devices may have been started with dependencies on
        # native devices.  Reset the dependencies to emcpower devices.
        #
        if [ ! -f $NDI_LOCK_FILE ]; then
            /etc/opt/emcpower/pp_reset_dm_deps.sh  pseudo
        fi

        set_nvme_rport_tmos 5 300
    fi

    set_tgtid_bind_type
}

#-----------------------------------------------------------
# Check for Naviagent/Hostagent and powermt before stopping PowerPath.
#-----------------------------------------------------------
ok_to_stop()
{
    ps -C powermt >> /dev/null 2>&1
    if [ $? -eq 0 ]; then
        pp_logger "The powermt command is running."
        pp_logger "Please stop powermt and then reissue $script_name stop."
        return 1
    fi

    if [ "$PPME_SUPPORT" == "yes" ]; then
        mig_info=`/sbin/powermig info -all`
        if [ $? -eq 0 ]; then
            echo "$mig_info" | grep 'No migrations found' > /dev/null
            if [ $? -ne 0 ] ; then 
                pp_logger "PowerPath migrations are present."
                pp_logger "Please cleanup the migrations and then reissue $script_name stop."
                return 1
            fi
        fi
    fi

    #
    ## Only on a normal stop or stop during a normal upgrade (not NDU), try 
    ## to stop naviagent, stordaemons or LVM. Notice ! in the if condition.
    #
    if [ ! -f $NDU_LOCK_FILE ]
    then
        ok_fstab
        if [ $? -ne 0 ]; then
            return 1
        fi
        if [ ! -d $PMAX_FILE_CONFIG ]; then
           #
           ## Stop Navigent/Hostagent if it is running before stopping PP 
           #
           if [ $g_navi_running -ne 0 ]; then
              stop_navi $g_naviloc
              if [ $? -ne 0 ]; then
                  pp_logger "Failed to stop Naviagent/Hostagent."
                  pp_logger "Please stop Naviagent/Hostagent and then reissue $script_name stop."
                  return 1
              fi
           fi
        
           pp_stop_stordaemons

           if pp_stop_lvm ; then
              return 0
           fi

           #
           ## Restart Naviagent/Hostagent if we stopped it earlier.  We do this
           ## because in a normal stop or normal upgrade (not NDU), pp_stop_lvm
           ## above has failed and we are aborting stop.
           #
           if [ $g_navi_running -ne 0 ]; then
              restart_navi $g_navi_running $g_naviloc
           fi

           #
           ## If we are reaching here on a normal stop or normal upgrade (not NDU),
           ## it means pp_stop_lvm has failed and stop is being aborted.
           #
           return 1
        else
           return 0
        fi
    else
        return 0
    fi

}

#----------------------------------------------------------
# Load the extensions.  Dependencies will load base driver.
# Supply necessary module parameters and kernel metadata.
#----------------------------------------------------------
load_drivers()
{
    update_lams_files

    update_driver_parameters

    #
    # Wait for all the udev events to settle
    #
    if [ "$HOST_BOOTED_UP" == "yes" ]; then
        /sbin/udevadm settle --timeout=900 > /dev/null 2>&1
    fi

    copy_udev_rules

    klh=`fgrep -w kallsyms_lookup_name /proc/kallsyms | grep 'T' | awk '{ print $1 }' | awk '!_[$0]++'`

    failfastflag="osfailfast=0x0"

    emcpo=`cat $PP_MODP  | grep -w "options emcp"`

    touch $TMP_MODP > /dev/null 2>&1
    if ! [ -w $TMP_MODP ] ; then
        modp_path=$(echo $TMP_MODP | sed 's#/[^/]*$##')
        pp_logger "$modp_path is not accessible for creating temporary files."
        pp_logger "Please make sure $modp_path is available for read write operations and try again."
        /bin/false
        return
    fi

    cat $PP_MODP | grep -v -w "options emcp" > $TMP_MODP

    if [ "$emcpo" == "" ]; then
        #
        # No entry yet in /etc/modprobe.d/powerpath.conf
        #
        echo "options emcp emcplu=0x$klh $failfastflag" >> $TMP_MODP
    else
        #
        # Some emcp options entry found
        #
        oline=`cat $PP_MODP | grep -w "options emcp"\
          | sed -s 's/emcplu=0x[a-f0-9]*//' \
          | sed -s 's/osfailfast=0x[0-9]*//'` 
        echo "$oline emcplu=0x${klh} $failfastflag" >> $TMP_MODP
    fi
    mv -f $TMP_MODP $PP_MODP

    #
    # Call depmod to generate modules.dep before drivers are loaded.
    #
    /sbin/depmod -a > /dev/null 2>&1

    for d in `cat $ext; cat $mgr`
    do
        /sbin/modprobe -q -s --first-time $d
        ret_check
        if [ $? -ne 0 ] ; then
            pp_logger "PowerPath could not load module $d"
            break
        fi
    done

    if dev_emcpower_is_back 60; then
        recreate_emcpower_device
        /etc/opt/emcpower/powercf -k > /dev/null 2>&1
        ret_check
    else
        ret_check
        unload_drivers
    fi

    if ret_script_status ; then
        /sbin/modprobe -q -s --first-time emcpioc
        ret_check
        if [ $? -eq 0 ] ; then
            /sbin/modprobe -r -q -s --first-time emcpioc
        fi
        #create the user daemon for NVMe config 
        if [ $NVME_RUNTIME_SUPPORT -eq 1 ]; then
               $PP_I_DIR/emcpnvmecfgd.sh start 64 8 
        fi
    fi
}

#-------------------------------
# Unload drivers and extensions.
#-------------------------------
unload_drivers()
{
    remove_udev_rules

    #
    # Call depmod to generate the module dependencies before the unload.
    #
    /sbin/depmod -a > /dev/null 2>&1

    do_unload=0
    retry=4
    powermt prep_drv_unload > /dev/null 2>&1

    #
    # At this point, we really want the driver unload to succeed.
    # Try hard to make it happen.
    #
    while [ $retry -gt 0 ]
    do
        powermt remove dev=all 2> /etc/opt/emcpower/.tmp/.pp_exit
        devr=$?
        cat /etc/opt/emcpower/.tmp/.pp_exit | grep "not found" > /dev/null 2>&1
        cdevs=$?
        zerolen=`grep -c '.*' /etc/opt/emcpower/.tmp/.pp_exit`
        rm /etc/opt/emcpower/.tmp/.pp_exit

        #
        # Reset rc status since we are not willing to
        # report an error just yet.
        #
        ret_reset
        if [ $devr -eq 0 ] ; then
            do_unload=1
            retry=0 #success
        else
            if [ "$cdevs" -eq 0 -o "$zerolen" -eq 0 ] ; then
                do_unload=1
                retry=0 #success
            else
                sleep 5
                retry=$((retry - 1))
            fi
        fi
    done
    
    if [ $do_unload -eq 1 ] ; then
        #stop the NVMe config deamon
        if [ $NVME_RUNTIME_SUPPORT -eq 1 ]; then
            $PP_I_DIR/emcpnvmecfgd.sh stop
        fi

        /sbin/modprobe -r -q -s  `cat $mgr; cat $ext; echo emcp`
        uerr=$?
        return $uerr
    else
        pp_logger "PowerPath devices are open."
        pp_logger "Please close these devices and then try again."
        /bin/false
        uerr=$?
        return $uerr
    fi
}

#-----------------------------------------------------
# Create /dev/emcpower based on CURRENT misc driver.
# These values can be different when PP loads from RD.
#-----------------------------------------------------
recreate_emcpower_device()
{
    rm -f /dev/emcpower
    mmaj=`cat /sys/class/misc/emcpower/dev | gawk -F : '{print $1}'`
    mmin=`cat /sys/class/misc/emcpower/dev | gawk -F : '{print $2}'`

    #
    # Sometimes, it could happen that /dev/emcpower control device might
    # be in use when a powermt command is executed (probably when a udev
    # rule is triggered) and may not get deleted by the rm command above.
    # In such cases, dont try to create the device.
    #
    if [ ! -c /dev/emcpower ]; then
        mknod /dev/emcpower -m 600 c $mmaj $mmin > /dev/null
    fi

    if [ $? -ne 0 ]; then
        pp_logger "failed to create emcpower device"
    fi

}

#----------------------------------
# Copy udev rules
#----------------------------------
copy_udev_rules()
{
    if [ $NVME_RUNTIME_SUPPORT -eq 1 ]; then
        cp /etc/opt/emcpower/04-nvme-pp.rules /etc/udev/rules.d/04-nvme-pp.rules > /dev/null 2>&1
    fi
    if [ $PFLEX_RUNTIME_SUPPORT -eq 1 ]; then
        cp /etc/opt/emcpower/04-pflex-pp.rules /etc/udev/rules.d/04-pflex-pp.rules > /dev/null 2>&1
    fi
    cp /etc/opt/emcpower/05-udev-pp.rules /etc/udev/rules.d/05-udev-pp.rules > /dev/null 2>&1
    cp /etc/opt/emcpower/80-udev-pp2.rules /etc/udev/rules.d/80-udev-pp2.rules > /dev/null 2>&1

    #
    # Even though udev subsystem detects the above copied udev rules immediately and uses them, on
    # some hosts it is observed that it is not quickly enough.  Hence, reload the rules to make sure
    # they are activated.
    #
    /sbin/udevadm control --reload > /dev/null 2>&1
}

#----------------------------------
# Remove udev rules
#----------------------------------
remove_udev_rules()
{
    if [ $NVME_RUNTIME_SUPPORT -eq 1 ]; then
        rm -f /etc/udev/rules.d/04-nvme-pp.rules
    fi
    if [ $PFLEX_RUNTIME_SUPPORT -eq 1 ]; then
        rm -f /etc/udev/rules.d/04-pflex-pp.rules
    fi
    #
    # When any file is removed from the udev rules folder, udev will 
    # immediately rescan all the files.  Hence, if the PP udev rules are 
    # removed in separate lines, it could happen that on the first file
    # removal, udev rescan will happen and by the time it gets to the
    # second PP udev rule, it may have been removed.  This will cause
    # udev to log a message saying that the second rule file is not found.
    # This issue has been seen only on RHEL6/OL6.  To avoid this, remove
    # both the files simultaneously in the same line.
    #
    rm -f /etc/udev/rules.d/05-udev-pp.rules /etc/udev/rules.d/80-udev-pp2.rules

    /sbin/udevadm control --reload > /dev/null 2>&1
}

#
# check for BFS configured host
#
check_bfs()
{
    BFS=no
    UEFI=no
    if [ -d /sys/firmware/efi ]; then
        UEFI=yes
    fi

    if [[ ${UEFI} == "yes" ]]; then
        boot_par=/boot/efi
        mount | grep ${boot_par} > /dev/null 2>&1
    else
        boot_par=/boot
        mount | grep ${boot_par} > /dev/null 2>&1
    fi

    if [ $? -eq 0 ]; then
        boot_lun=$(df -h ${boot_par} | grep ${boot_par} |  awk '{ print $1 }' |
                 awk -F "/" '{ print $NF }' |\
                 sed 's/[1-9]//g')  > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            powermt display dev=$boot_lun > /dev/null 2>&1
            if [ $? -eq 0 ]; then
                BFS=yes
            fi
        fi
    fi
}


#-----------------
# main starts here
#-----------------

init_I18N

ret_reset

#
# Check if the script has been called by ExecStartPost or ExecStopPost
# after a previous error exit.  No need to do anything in that case.
#
if [ -f /etc/opt/emcpower/.tmp/.pp_systemctl_check ]
then
    #
    # Check if the marker file created on a previous error exit is less
    # than 5 seconds old.   In corner cases where after the marker file is
    # created on an error exit, the host crashed or power recycled
    # immediately, the script should not exit here.
    #
    age=$(expr $(date +%s) -  $(date +%s -r "/etc/opt/emcpower/.tmp/.pp_systemctl_check"))
    if [ $age -ge 0 ] && [ $age -lt 5 ] 
    then

        if [ "$1" == "stop" ]
        then
            pp_logger "Restoring PowerPath.service status as a previous start operation failed."
        elif [ "$1" == "start" ]
        then
            pp_logger "Restoring PowerPath.service status as a previous stop operation failed."
        fi

        rm -f /etc/opt/emcpower/.tmp/.pp_systemctl_check
        /bin/true
        ret_exit
    else
        rm -f /etc/opt/emcpower/.tmp/.pp_systemctl_check
    fi
fi

#
# Check if host has booted up fully.
#
HOST_BOOTED_UP=no
target=`systemctl get-default`
sysinit_status=`systemctl status sysinit.target | grep Active | sed -e 's/[ ]*Active: \([a-z]*\).*/\1/'`
if [ "$target" != "rescue.target" -o "$target" != "runlevel1.target" ]; then
    if [ "$sysinit_status" == "active" ]; then
        HOST_BOOTED_UP=yes
    fi
fi

#
# Check root authorization only if the host has already booted up.
#
if [ "$HOST_BOOTED_UP" == "yes" ]; then
    ruid=`id -ru`
    euid=`id -u`
    if [ $ruid -ne 0 -o $euid -ne 0 ]; then
        echo
        echo "`eval_gettext \"Insufficient user privilege.\"`"
        echo
        /bin/false
        ret_exit
    fi
fi
ret_reset

script_name=PowerPath
ext=$PPBASE/bin/.drivers_ext
mgr=$PPBASE/bin/.drivers_mgr
pp_config_complete="/etc/emc/.pp_config_complete"

case "$1" in

    start)

        if [[ -f /etc/emc/.emcpbfs_linux_done && -f /etc/lvm/lvm.conf ]]; then
            /etc/opt/emcpower/emcpbfs_linux default_lvm_filter
            /etc/opt/emcpower/emcpbfs_linux powerpath_lvm_filter
        fi

        #
        # Only in UEFI BIOS, SecureBoot is supported.
        # On SecureBoot enabled hosts, abort PowerPath start if PowerPath modules are not signed.
        # Check whether PowerPath modules are signed or not using "mokutil --list-enrolled" utility.
        #
        # When user manually disable mokutil validation with mokutil command and then it takes user
        # to the UEFI shim management during next boot to disable secure boot in shim. In this case,
        # PowerPath should be able to install and start properly as expected on a secure boot enabled
        # host but with shim validation disabled using mokutil.
        #
        if [ -d /sys/firmware/efi ]; then
            mokutil --sb-state 2>/dev/null | grep -i "SecureBoot validation is disabled in shim"  > /dev/null 2>&1
            if [ $? -ne 0 ]; then
                mokutil --sb-state 2>/dev/null | grep -i "SecureBoot enabled" > /dev/null 2>&1
                if [ $? -eq 0 ]; then
                    TAG=`identify_platform \`uname -r\``
                    emcp=$PPBASE/bin/driver/$TAG/emcp.ko

                    # Fetch sig_key for PowerPath modules.
                    sig_key=`modinfo $emcp | awk '/sig_key/,/sig_hashalgo/' | sed '$d' |  sed 's/sig_key://g' | tr -d '[:space:]'`

                    # Check if sig_key is present in enrolled keys to verify PowerPath modules are signed for SecureBoot.
                    mokutil --list-enrolled | grep -i $sig_key > /dev/null 2>&1
                    if [ $? -ne 0 ]; then
                        pp_logger "Error: SecureBoot is enabled on the host, but PowerPath modules are not signed for SecureBoot. \
                                   Refer to Installation and Administration Guide for steps to sign PowerPath modules."
                        start_error_exit
                    fi
                fi
            fi
        fi

        #
        # If there is a crash or a power-cycle during a NDU operation, the NDU_LOCK_FILE
        # would not have been removed properly.  Since the state of the NDU operation is
        # indeterminate in such situations, it is better not to start PowerPath either
        # automatically on host boot up or manually.
        #
        # Proceed with the start only if there is a process running with DellPower.LINUX
        # in the process name.  This could happen when PP is started during NDU.  In other
        # scenarios, abort the start.  If the rpm is signed for SecureBoot, it could happen
        # that the new package gets created with EMCpower.LINUX.... name.  Hence check for
        # that rpm name also.
        #
        if [ -f $NDU_LOCK_FILE ]; then
            PS=`ps -ef`
            echo $PS | grep -e DellPower.LINUX -e EMCpower.LINUX > /dev/null 2>&1
            if [ $? -ne 0 ]; then
                pp_logger "Error: A previous non disruptive operation had not completed properly."
                pp_logger "Please uninstall PowerPath, install it again and then start."
                start_error_exit
            fi
        fi

        if [ -d $PMAX_FILE_CONFIG ] ; then
            PPME_SUPPORT=no
        fi

        #
        # If modules are loaded and if host has booted up fully, exit
        # after printing message when PowerPath start is called.
        #
        lsmod | grep -w '^emcp' > /dev/null
        if [ $? -eq 0 ] ; then
            pp_logger "PowerPath is already running."
            start_error_exit
        fi

        #
        # Check if the kernel is retpoline enabled before proceeding.
        #
        cat /proc/kallsyms | grep __x86_indirect_thunk_ > /dev/null 2>&1
        if [ $? -ne 0 ] ; then
            pp_logger "Error: This version of PowerPath will work only on retpoline enabled kernels."
            start_error_exit
        fi

        #
        # Remove the marker_file 'pp_config_complete' file if it exists. 
        # The marker file should be removed here inorder to handle host 
        # crash/ungraceful shutdown scenarios where 'PowerPathPost stop' 
        # does not get invoked.
        #
        if [ -f $pp_config_complete ]; then
             rm $pp_config_complete
        fi
        #if this is PMAX file configuration ignore this
        if [ ! -d $PMAX_FILE_CONFIG ] ; then  
            # NDU_LOCK_FILE doesn't exists means its a new installation
            if [ ! -f $NDU_LOCK_FILE ]; then
                if [ -f $NDI_LOCK_FILE ]; then
                    #
                    # Blacklist PowerPath devices to avoid Pseudo devices getting
                    # inserted by default in all the DM devices during PowerPath
                    # start. Only Pseudo devices involved in migration are added
                    # under blacklist_exceptions using /etc/opt/emcpower/pp_ndi.sh
                    # script
                    #
                    cat /etc/multipath.conf | grep -w 'devnode "^emcpower"' > /dev/null 2>&1 
                    if [ $? -eq 0 ]; then
                        sed -i "/devnode \"^emcpower\"/d" /etc/multipath.conf > /dev/null 2>&1 
                    fi
                    BL=`cat /etc/multipath.conf | grep -E "(^| )blacklist( |$)" | grep '^[[:blank:]]*[^[:blank:]#]'` 
                    if [[ $BL =~ "blacklist" ]]; then
                        sed -i "s/^$BL/blacklist {\n    devnode \"^emcpower\"/g" /etc/multipath.conf

                        if [ -f "/etc/opt/emcpower/pp_ndi.sh" ] && [ "$HOST_BOOTED_UP" == "no" ] ; then
                             # During the system boot, remove the all devnodes that are addedd to blocklist
                             # and blocklist_exceptions sections in the /etc/multiapth.conf file during the
                             # last migration states. As we are going to bring back all migration states to
                             # setup stage on the NMP devices. This is needed as NMP devices starts much early 
                             # in the boot process. 
                             /etc/opt/emcpower/pp_ndi.sh startup >  /dev/null 2>&1
                        fi   
                    else
                        cat /etc/multipath.conf | grep -E "(^| )blacklist{( |$)" | grep '^[[:blank:]]*[^[:blank:]#]' > /dev/null 2>&1
                        if [ $? -eq 0 ]; then
                            sed -i "s/^blacklist{.*/blacklist {\n    devnode \"^emcpower\"/g" /etc/multipath.conf
                        else
                            echo "blacklist {" >> /etc/multipath.conf
                            echo "    devnode \"^emcpower\"" >> /etc/multipath.conf
                            echo "}" >> /etc/multipath.conf
                        fi
                    fi

                    #
                    # Create a temporary PP bindings file. This bindings file will be used to alter source
                    # and target WWID incase of reboot scenarios post migration and during PowerPath Uninstallation.
                    #
                    UF_CHECK=`/bin/cat /etc/multipath.conf | grep "user_friendly_names" | grep '^[[:blank:]]*[^[:blank:]#]'`
                    if [[ $UF_CHECK =~ "yes" ]]; then
                        cp /etc/multipath/bindings /etc/multipath/bindings_pp > /dev/null 2>&1
                    fi

                    #
                    # There is a limit for multipathd service to be restarted only 5 times within 10 secs.
                    # If its more within 10 secs, then subsequent restart fails. Similar limits exists
                    # for any other systemd service. This change is required if we have multiple migrations
                    # setup using a file in one go. Or if we have multiple path failures/addition at one time.
                    #
                    cat /usr/lib/systemd/system/multipathd.service 2>&1 | grep -w -A1 "\[Service\]" | grep -w "StartLimitBurst" | grep '^[[:blank:]]*[^[:blank:]#]' > /dev/null 2>&1
                    if [ $? -ne 0 ]; then
                        /bin/sed -i "s/\[Service\]/\[Service\]\nStartLimitBurst=0/g" /usr/lib/systemd/system/multipathd.service > /dev/null 2>&1
                        /sbin/systemctl daemon-reload > /dev/null 2>&1
                    fi

                    #
                    # In case of SLES, change path_checker to directio
                    #
                    if [[ $OS_NAME == "SLES" ]] ; then
                        cat /etc/multipath.conf | grep -w "path_checker" |  grep '^[[:blank:]]*[^[:blank:]#]' > /dev/null 2>&1
                        if [ $? -eq 0 ]; then
                            sed -i "/path_checker/d" /etc/multipath.conf > /dev/null 2>&1 
                        fi
                        defaults=`cat /etc/multipath.conf | grep -E "(^| )defaults( |$)" |  grep '^[[:blank:]]*[^[:blank:]#]'`
                        if [[ $defaults =~ "defaults" ]]; then
                            sed -i "s/^$defaults/defaults {\n    path_checker \"directio\"/g" /etc/multipath.conf
                        else
                            cat /etc/multipath.conf | grep -E "(^| )defaults{( |$)" |  grep '^[[:blank:]]*[^[:blank:]#]' > /dev/null 2>&1
                            if [ $? -eq 0 ]; then
                                sed -i "s/^defaults{.*/defaults {\n    path_checker \"directio\"/g" /etc/multipath.conf 
                            else
                                echo "defaults {" >> /etc/multipath.conf
                                echo "    path_checker \"directio\"" >> /etc/multipath.conf
                                echo "}" >> /etc/multipath.conf
                            fi
                        fi
                    fi
                    systemctl enable multipathd  > /dev/null 2>&1
                    systemctl restart multipathd > /dev/null 2>&1 
                    multipath -ll > /dev/null 2>&1
                else
                    #
                    # Abort  if any native multipath devices are found.
                    #
                    check_dm_multipath_config 0
                    if [ $? -eq 1 ] ; then
                        pp_logger "Error: Aborting PowerPath start as native multipathing might be active."
                        pp_logger "Please refer to PowerPath for Linux Installation and Administration Guide for steps to disable native multipathing and then try again."
                        start_error_exit
                    fi
                fi
            fi

            check_nvme_multipath_config
            if [ $? -eq 1 ] ; then
                pp_logger "Error: Aborting PowerPath start as NVMe multipathing might be active."
                pp_logger "Please refer to PowerPath for Linux Installation and Administration Guide for steps to disable NVMe multipathing and then try again."
                start_error_exit
            fi
        fi

        if ret_script_status; then
            #
            # On SuSE, hostname is not available at this point during startup.
            # Also MpxReserveKey is dependent on Hostname.  During boot if
            # hostname is null then all the nodes in the cluster get the same
            # MpxReserveKey.  Hence set the hostname manually before starting 
            # the daemon.
            #
            if [ -f /etc/SuSE-release ] && [ "$HOST_BOOTED_UP" == "no" ]
            then
                cat /etc/HOSTNAME | sed -e 's/\..*//g' > /proc/sys/kernel/hostname
            fi

            #
            # If a new kernel or new PowerPath is installed, fix things up for the
            # new kernel or new PowerPath
            #
            if [ -f $PPBASE/../.new_pp_version ] || [ "`cat $PPBASE/../.os_version`" != `uname -r` ]
            then
                start_init_pp
                ret_check
            fi
        fi

        #
        # Load PP iff it is not already loaded.
        #
        if ret_script_status ; then
            lsmod | grep -w '^emcp' > /dev/null
            if [ $? -ne 0 ]; then
                load_drivers
                ret_check

                if [ $? -ne 0 ]; then
                    rollback
                    rollback_reset
                    depmod
                    report_error "Error loading PowerPath kernel modules."
                    start_error_exit
                fi
             else
                if dev_emcpower_is_back 60; then
                    recreate_emcpower_device
                    /etc/opt/emcpower/powercf -k > /dev/null 2>&1
                    ret_check
                fi
             fi
            
            if $init_flag; then   
                finish_init_pp
            fi

            #
            # Remove PIOC if it was loaded during RD boot.
            #
            lsmod | grep emcpioc > /dev/null
            if [ $? -eq 0 ]; then
                /sbin/rmmod emcpioc > /dev/null
            fi
         
            if ret_script_status ; then
                if dev_emcpower_is_back 60; then

                    #
                    # Don't start Management Daemon if the host is still
                    # booting up since the network and snmpd service will
                    # not have started. Instead the daemon will be started
                    # when the EmcpMond.service or emcp_mond.sh service
                    # starts and by then, network and the snmpd service, if
                    # configured, should also have started.
                    #
                    if [ "$HOST_BOOTED_UP" == "yes" ]; then
                        systemctl start EmcpMond.service
                    fi

                    #
                    # Configure PowerPath devices.
                    #
                    configure_pp
                    
                    #
                    # Stop and start naviagent/hostagent so that it can
                    # send registration commands through Powerpath.  If
                    # this is not done, then naviagent may still send
                    # registration commands through sg devices which cannot
                    # be intercepted in PowerPath and which will result in
                    # wiping out PowerPath registration information on the
                    # array.
                    #
                    if [ $g_navi_running -ne 0 ]; then
                        stop_navi $g_naviloc
                        if [ $? -eq 0 ]; then
                            restart_navi $g_navi_running $g_naviloc
                        fi
                    fi
                else
                    ret_check
                    unload_drivers
                fi
            else
                lsmod | grep -w '^emcp' > /dev/null
                if [ $? -ne 0 ]; then
                    pp_logger "PowerPath: unable to load PowerPath modules."
                    unload_drivers
                fi
            fi
        fi
        ret_check

        #     
        # Set the IO scheduler by calling pp_udev.sh script. If the host is booting,
        # scheduler is set by calling pp_udev.sh in PowerPathPost script.  If the 
        # host is already up and PowerPath is started manually, then the pp_udev.sh
        # script is called from PowerPath script. 
        # After the pp_udev_xio.sh executes, a marker file .pp_config_complete is
        # created. The code block is added to ensure that there are no udev storms
        # in case of max config setup.
        # Once host boots up, the udev rule 80-udev-pp2.rules will be triggered 
        # for new devices being added and for devices which transition from dead to
        # alive.
        # 
        if [ "$HOST_BOOTED_UP" == "yes" ]; then
            /usr/lib/udev/pp_udev.sh scheduler all > /dev/null 2>&1 &
            touch $pp_config_complete
            /etc/opt/emcpower/emcpmgr startup_cfg_done > /dev/null 2>&1
        fi

        if [ "$HOST_BOOTED_UP" == "yes" ] && [ -d $PMAX_FILE_CONFIG ]; then
            /sbin/powermt set device_add_notifications=on > /dev/null 2>&1
        fi

        return_status Starting
        ;;

    stop)
        #
        # Check for BFS configured host
        #
        check_bfs

        #
        # During shutdown/reboot, systemd will try to stop PowerPath which is not desired.
        # The way to identify if PowerPath stop is called during shutdown/reboot is to check
        # the basic.target unit which gets deactivated during shutdown/reboot..
        #
        sysinit_status=`systemctl status basic.target | grep Active | sed -e 's/[ ]*Active: \([a-z]*\).*/\1/'`
        if [ "$sysinit_status" != "active" ]; then

            #
            # This is reached when host is rebooted.  Normally we exit from here
            # without doing anything.  However, if NVMe config daemon is still running,
            # then the OS will wait for it terminate automatically for upto 90 seconds
            # before forcefully killing it and proceeding with the shutdown.  To avoid
            # the 90 seconds delay in the shutdown, stop the daemon.
            #
            if [ $NVME_RUNTIME_SUPPORT -eq 1 ]; then
                $PP_I_DIR/emcpnvmecfgd.sh stop
            fi

            return_status Stopping
            ret_exit
        fi

        lsmod | grep -w '^emcp' > /dev/null
        if [ $? -ne 0 ] ;
        then
            pp_logger "PowerPath is not running"
        else
            #
            # The marker file .pp_config_complete should be deleted when 
            # PowerPath stop is executed.
            #
            if [ -f $pp_config_complete ]; then
                rm -f $pp_config_complete 
            fi

            #
            # Delete the udev rule in the directory /etc/udev/rules.d/
            # to avoid triggering udev rules when PowerPath is not
            # active.
            #
            remove_udev_rules

            #
            # Trespass can happen if new devices are added or some devices 
            # are removed by "powermt remove" before "PowerPath stop". The 
            # reason is that vgscan used by us issues "read" to all block 
            # devices.  We configure all devices to avoid unnecessary
            # trespass.
            #
            /sbin/powermt config > /dev/null 2>&1
            
            #
            # Before proceeding with PowerPath stop , wait for any 'powermt config' process
            # running in the background to complete.  On an export of a vol in Mpx,
            # an event will get sent to emcp_mond to trigger a 'powermt config'.
            # Wait on loop to ensure such 'powermt config' process(es) are done, otherwise
            # 'ok_to_stop' function will fail as it checks if any powermt command is still
            # running.
            #
            for i in 0 1 2 3 4 5 6 7 8 9 10
            do
                out=`ps -ef |grep "powermt config" |grep -v grep`
                if [ -z "$out" ] ; then
                    break
                fi
                sleep 2                
            done

            if ok_to_stop; then
                systemctl stop EmcpMond.service

                mond_pid=`/bin/ps -eu root | awk '{for(;NF!=0;){if(getline<=0) break;
                         i=NF;a=split($i,b,"/");if(b[a]=="emcp_mond"){print $1;}}}'`

                if [ "${mond_pid}" != "" ]; then
                    pp_logger "PowerPath Management daemon could not be stopped. Please try again."

                    systemctl start EmcpMond.service
                    copy_udev_rules
                    touch $pp_config_complete
                    exit 1
                fi

                /sbin/powermt save > /dev/null 2>&1
                ret_check

                #
                # Disable autoconfig so that devices don't get autoconfigured
                # in the brief time window after the devices are removed but
                # before 'powermt prep_drv_unload' is called.  If devices are
                # in use and cannot be removed, then autoconfig will get
                # enabled when 'powermt config' is called.
                #
                /sbin/powermt disable_autoconfig > /dev/null 2>&1

                /etc/opt/emcpower/emcpmgr unmap > /dev/null 2>&1
                ret_check

                #
                # On hosts with large number of devices, sometimes the first
                # powermt remove dev=all command may not remove all the
                # devices properly, even when none of them are in use.
                # This is because of the powermt config done at the start
                # of PowerPath stop.  This config may have triggered 
                # haldaemon which maybe sending some IOs to the native
                # devices and hence all the devices may not be removed.
                # Hence try again for upto 30 seconds.
                #
                /sbin/udevadm settle --timeout=180 > /dev/null 2>&1

                if [ ! -f $NDU_LOCK_FILE ]
                then
                    #
                    # Device mapper devices may have dependencies on pseudo devices as 
                    # PP may be currently active.  Reset the dependencies to native.
                    #
                    if [ ! -f $NDI_LOCK_FILE ]; then 
                        /etc/opt/emcpower/pp_reset_dm_deps.sh  native
                    fi
                    set_nvme_rport_tmos off 60
                fi


                #
                # Remove all devices from PowerPath.
                #
                for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
                    /sbin/powermt remove dev=all 2> /etc/opt/emcpower/.tmp/.pp_exit
                    devr=$?
                    cat /etc/opt/emcpower/.tmp/.pp_exit | grep "not found" > /dev/null 2>&1
                    cdevs=$?
                    zerolen=`grep -c '.*' /etc/opt/emcpower/.tmp/.pp_exit`
                    rm /etc/opt/emcpower/.tmp/.pp_exit
                    if [ $devr -eq 0 -o $cdevs -eq 0 -o $zerolen -eq 0 ]
                    then
                        break
                    fi
                    sleep 2
                done
                #
                # Reset rc status since we are not willing to quit.
                #
                ret_reset

                #
                # Proceed if all devices have been removed from PowerPath.
                #
                if [ $devr -eq 0 -o $cdevs -eq 0 -o $zerolen -eq 0 ] ; then
 
                    unload_drivers
                    ret_check
                    if [ $? -eq 0 ] ; then
                        #
                        # Wait for udev events to settle. If the hald
                        # daemon is running,then udev events may take
                        # more time to settle especially if there are
                        # a large number of devices present.
                        #
                        if [ ! -d $PMAX_FILE_CONFIG ]; then
                            /sbin/udevadm settle --timeout=2700 > /dev/null 2>&1
                        fi
                    else
                        if [ ! -f $NDU_LOCK_FILE ]
                        then
                            #
                            # Since 'unload_drivers' failed, 
                            # reset the dependencies back to emcpower devices.
                            # 
                            # if NDI is active then dont change the DM deps 
                            if [ ! -f $NDI_LOCK_FILE ]; then
                                /etc/opt/emcpower/pp_reset_dm_deps.sh  pseudo
                            fi

                            set_nvme_rport_tmos 5 300
                        fi

                        copy_udev_rules
                        touch $pp_config_complete

                        pp_logger "PowerPath could not unload PowerPath modules."
                        pp_logger "Please reboot the host and try again."
                    fi
                else
                    /etc/opt/emcpower/emcpmgr map -p > /dev/null 2>&1

                    copy_udev_rules
                    touch $pp_config_complete

                    /sbin/powermt config > /dev/null 2>&1
                    /sbin/powermt load > /dev/null 2>&1

                    if [ ! -f $NDU_LOCK_FILE ]
                    then
                        #
                        # Since 'powermt remove dev=all' failed, 
                        # reset the dependencies back to emcpower devices.
                        # 
                        if [ ! -f $NDI_LOCK_FILE ]; then
                            /etc/opt/emcpower/pp_reset_dm_deps.sh  pseudo
                        fi

                        set_nvme_rport_tmos 5 300
                    fi

                    #
                    # Start the PowerPath Management daemon.
                    #
                    systemctl start EmcpMond.service

                    pp_logger "PowerPath devices are open."
                    pp_logger "Please close these devices and then reissue $script_name stop."

                    /bin/false
                    ret_check
                fi
                #
                ## Restart Naviagent/Hostagent if we stopped it earlier
                #
                if [ $g_navi_running -ne 0 ]; then
                    restart_navi $g_navi_running $g_naviloc
                fi
            else

                copy_udev_rules
                touch $pp_config_complete

                /bin/false  ## not ok_to_stop
                ret_check
            fi
        fi

        #
        # For some of the  BFS hosts duing PowerPath stop systemd is unmounting /boot and /boot/efi. So mounting them manually.
        #
        systemctl daemon-reload
        if [[ ${BFS} == "yes" ]]; then
            if [[ ${UEFI} == "yes" ]]; then
                mount | grep /boot/efi > /dev/null 2>&1
                if [ $? -ne 0 ]; then
                   mount /boot/efi > /dev/null 2>&1
                fi
            fi
            mount | grep /boot > /dev/null 2>&1
            if [ $? -ne 0 ]; then
                mount /boot  > /dev/null 2>&1
            fi
        fi
 
        ret_check
        return_status Stopping
        ;;
    check_service_start)
        #
        # Check if PowerPath has indeed started properly.  If it has not,
        # then call 'systemctl stop' so that the status of the service is set
        # to 'inactive'.  Otherwise, if a 'systemctl start' is done again, 
        # systemd will not call '/etc/init.d/PowerPath start' as the status
        # of the service is already 'active'.
        #
        lsmod | grep -w '^emcp' > /dev/null
        if [ $? -ne 0 ]; then
            #
            # Create marker file so that 'systemctl stop' will
            # exit immediately without doing anything.
            #
            touch /etc/opt/emcpower/.tmp/.pp_systemctl_check

            #
            # The purpose of this command is just to set the status of the
            # service to 'inactive'.
            #
            nohup systemctl stop PowerPath.service &
            sleep 1
        fi

        /bin/true
        ret_check
        ;;
    check_service_stop)
        #
        # Check if PowerPath has indeed stopped properly.  If it has not,
        # then call 'systemctl start' so that the status of the service is set
        # to 'active'.  Otherwise, if a 'systemctl stop' is done again, 
        # systemd will not call '/etc/init.d/PowerPath stop' as the status
        # of the service is already 'inactive'.
        #
        lsmod | grep -w '^emcp' > /dev/null
        if [ $? -eq 0 ]; then
            #
            # Create marker file so that 'systemctl start' will
            # exit immediately without doing anything.
            #
            touch /etc/opt/emcpower/.tmp/.pp_systemctl_check

            #
            # The purpose of this command is just to set the status of the
            # service to 'active'.
            #
            nohup systemctl start PowerPath.service &
            sleep 1
        fi

        /bin/true
        ret_check
        ;;
    *)
        var=$0
        pp_logger "Usage: $var {start|stop}"
        ;;
esac

ret_exit
