#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2018,2019,2020,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/usr/sbin/cluster/cspoc/utilities/clgetpvid.sh 1.28 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1999,2016 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
#                                                                              
# @(#)  7d4c34b 43haes/usr/sbin/cluster/cspoc/utilities/clgetpvid.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

#
#   Component:	hacmp.cspoc
#
#   Function:	returns a list of the known disks not currently in a volume
#		group, along with an indication of whether they can support a
#		concurrent mode volume group
#
#		returns the size of the disk
#
#		'-r' gives a range of disk sizes, in megabytes, of the form 'N:M'
#		     if either is left off, there is no limit on that end of the
#		     range.  E.g., "-r 1000:64000" says the disk must be between
#		     1 and 64 GB, as returned by "bootinfo -s", while "-r 1000:"
#		     would mean all disks larger than 1GB, and "-r :64000" would
#		     mean all disks less than 64 GB.
#
#		'-A' returns information on all disks, including those in a
#		     volume group
#
#		'-u' adds the disk UUID to the output
#
#		'-R' checking associated with potential repository disks
#
#		returns a list of the free major numbers for logical volumes
#
#		If a free disk does not have a PVID associated with it, and it is
#		not in use as a raw disk, a PVID is assigned.
#
#		Output is of the form:
#
#		    hdisk4:00c48bb0d1f9c3d5:C:Y:5120
#		    hdisk6:00c48bb052afaeae:C:Y:140013
# 		    hdisk11:00c48bb04bd88346:C:Y:10240
#		    FREEMAJORS:53...
#
#   Origins:	27
#
#   Arguments:	None
#
#   Environment:None
#
#############################################################################

#
: Load the "CL_PVID_ASSIGNMENT" from the environment file, if
: present, allowing for any unexpected leading whitespace.
#
typeset TAB=$'\t'
typeset INDENT="$TAB "
eval $(grep -w '^[$INDENT]*CL_PVID_ASSIGNMENT' /etc/environment)

PROGNAME=${0##*/}
PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)"

if [[ $VERBOSE_LOGGING == "high" ]]
then
    set -x
    version='1.28'
fi

integer DISK_SIZE=0
integer MIN_SIZE=0
integer MAX_SIZE=0
integer NO_ORACLE=0
integer ALL_DISKS=0
integer ADD_UUID=0
integer REPOSITORY=0
typeset ineligible_disk_criteria=""

#
:   Directory to hold work files
#
if [[ -d /var/hacmp/log/ksh93_tmp ]]
then
    TMPDIR='/var/hacmp/log/ksh93_tmp'
else
    TMPDIR='/var/hacmp/log'
fi

#
:   Common classification of disk types
#
if [[ -x /usr/sbin/gsclvmd ]]; then
    #
    :   If the group services CLVM daemon is present,
    :   pretty much anything can be used in a concurrent
    :   volume group
    #
    CONCURRENT="C"
    ENHANCE_CONCURRENT_ONLY="Y"

else
    #
    :   Anything else cannot be used in a concurrent volume group
    #
    CONCURRENT="N"
    ENHANCE_CONCURRENT_ONLY="N"
fi

#
: This script uses the following temporary work files
#
rm -f ${TMPDIR}/clgetpvid_[1-7].$$		
#   1 - all hdisks and their UUIDs, sorted by UUID
#   2 - all UUIDs for defined RAW_DISKs, sorted by UUID
#   3 - hdisks and UUIDs for RAW_DISKs, sorted by hdisk name
#   4 - lspv output, sorted by hdisk name
#   5 - returned disk information
#   6 - all hdisks and their UUIDs, sorted by hdisk name
#   7 - all hdisks minus any raw disks

#
:   Check for a specified size range
#
while getopts ':Ar:OuR' option
do
    case $option in
        r ) print $OPTARG | IFS=: read MIN_SIZE MAX_SIZE
            #
            :   Disks must be between $MIN_SIZE and $MAX_SIZE
            #
        ;;

        O ) : Do not list any Oracle raw disks
            NO_ORACLE=1
        ;;

        A ) :	Look at all known disks
            ALL_DISKS=1
        ;;

        u ) :	Append disk UUID to returned information
            ADD_UUID=1
            LC_ALL=C /usr/es/sbin/cluster/utilities/cl_get_rdisks | sort -b -k2,2 > ${TMPDIR}/clgetpvid_1.$$
        ;;

	R ) :	Repository disk checks
	    NO_ORACLE=1
	    REPOSITORY=1
	;;

        * ) :	Invalid operand
            return 1
        ;;
    esac
done

#
#   Disks that are not to be managed by AIX LVM/associated with different
#   storage management can, in some cases, be identified based on criteria
#   given in the cl_disk_tags.lst file.
#
if [[ -s /usr/es/sbin/cluster/etc/cl_disk_tags.lst ]]
then
    #
    :   Disks that match the criteria mentioned in the file should not be considered
    :   for adding PVID automatically.
    #
    ineligible_disk_criteria=${TMPDIR}/clgetpvid_idc.$$
    grep -v '^#' /usr/es/sbin/cluster/etc/cl_disk_tags.lst | sort -b -k1,1 | cut -f1,2 -d' ' > $ineligible_disk_criteria
fi

#
:   Check if vpath is installed and get list of vpath disks
#
if [[ -x /usr/sbin/lsvpcfg ]]
then
    lsvpcfg > ${TMPDIR}/lsvpcfg.out.$$ 2>> ${TMPDIR}/lsvpcfg.err
fi

#
:   If there are defined raw disks - which are known only by their UUID - they are
:   not available as free disks, and should not have a PVID assigned.
#
if (( ! ALL_DISKS ))             #   if we don't want everything
then
    #
    :	First, get a list of all hdisks and their UUIDs, sorted by UUID
    #
    if (( ! ADD_UUID ))              #   Not already collected above
    then
        LC_ALL=C /usr/es/sbin/cluster/utilities/cl_get_rdisks | sort -b -k2,2 > ${TMPDIR}/clgetpvid_1.$$
    fi

    #
    :	Get a list of all the UUIDs for defined RAW_DISKs known to PowerHA
    :	sorted by UUID
    #
    /usr/es/sbin/cluster/utilities/clodmget -q "name = RAW_DISK" -f value -n HACMPresource | sort -b > ${TMPDIR}/clgetpvid_2.$$

    if [[ -s ${TMPDIR}/clgetpvid_1.$$ && -s ${TMPDIR}/clgetpvid_2.$$ ]]
    then
        #
        :   If the above two operations found anything, get a list of
        :   hdisks and their corresponding UUIDs, sorted by hdisk name
        :   for all defined RAW_DISKs
        #
        join -1 2 ${TMPDIR}/clgetpvid_1.$$ ${TMPDIR}/clgetpvid_2.$$ | cut -f2 -d' ' | sort -b -k1,1 > ${TMPDIR}/clgetpvid_3.$$
    fi
fi

if [[ -s ${TMPDIR}/clgetpvid_3.$$ ]]		#   If there are RAW_DISKs known on this node
then
    #
    :	Get a list of physical volumes known on this node, sorted by hdisk name
    #
    lspv -L | sort -b -k1,1 > ${TMPDIR}/clgetpvid_4.$$

    #
    :	Finally, use the join command to remove from the list generated by lspv
    :	all those disks which are RAW_DISKs
    #
    join -v 2 -1 1 -2 1 ${TMPDIR}/clgetpvid_3.$$ ${TMPDIR}/clgetpvid_4.$$ >${TMPDIR}/clgetpvid_7.$$
else
    #
    :	No defined RAW_DISKs present, or want them all, so just use lspv output
    #
    lspv -L >${TMPDIR}/clgetpvid_7.$$
fi

typeset -i caa_4KDisk_available=0
if (( $REPOSITORY ))
then
    #==================================================
    : Check 4KDisk Capability Availability
    #==================================================
    if LC_ALL=C cl_get_capabilities -q -i 4KDISK
    then
        caa_4KDisk_available=1
    fi
fi

sort -r ${TMPDIR}/clgetpvid_7.$$ | while read DISK PVID VG rest
do
    valid_flag="TRUE"

    if [[ "None" != $VG ]] && (( ! ALL_DISKS ))
    then
        #
        :   Skip disks that are already in a volume group
        #
        continue

    elif [[ "none" == $PVID ]] && (( ! ALL_DISKS ))
    then
        #
        :   If the device does not have a PVID assigned, see if one
        :   can be assigned.  This is only done in the case where the
        :   actual PVID on the platter is not already present in CuAt,
        :   which would be the case for a disk that is part of a
        :   multipath object.
        #

        #
        : Recognized values for CL_PVID_ASSIGNMENT are "false", "no",
        : "disable", or zero. Any other value preserved the default
        : behavior, allowing PVIDs to be automatically assigned, as
        : needed.
        #
        if [[ -n $CL_PVID_ASSIGNMENT &&
            $CL_PVID_ASSIGNMENT == @(f|F|n|N|d|D|0)* ]]
        then
            : The customer has explicitly disabled automatic PVID assignment
            continue
        fi

        if ! On_disk_PVID=$(VERBOSE_LOGGING="" /usr/es/sbin/cluster/events/utils/cl_querypv $DISK 2>>${TMPDIR}/clgetpvid.err)
        then
            continue                    #   Cannot read disk, assign PVID won't work

        elif [[ -z $On_disk_PVID ]]
        then
            continue                    #   Cannot read disk, assign PVID won't work

        else
            if [[ -z $(odmget -q "attribute = pvid and value = $On_disk_PVID" CuAt) ]]
            then
                #
                :   There is something on the disk - might just be zeros
                :   See if the disk is ineligible for PVID assignment
                :   before doing so.
                #
                if [[ -n $ineligible_disk_criteria ]]
                then
                    #
                    :	Check to see if this disk has a flag on it that makes
                    :	it ineligible for PVID assignment.
                    #
                    lquerypv -h /dev/${DISK} | join -1 1 -2 1 -o 2.1,1.2,2.6 $ineligible_disk_criteria - |\
                    while read field_offset field_content xlate ; do
                        xlate=${xlate##\|}
                        if [[ $xlate == ${field_content}* ]]
                        then
                            #
                            :   Disk ${DISK} is ineligible for PVID assignment
                            :   because the field at offset 0x${field_offset}
                            :   has value $xlate which matches the criteria
                            :   $field_content from cl_disk_tags.lst
                            #
                            valid_flag="FALSE"
                            break
                        fi
                    done
                    #
                    #	The careful reader will note that the above algorithm
                    #	assumes that the field to be searched for starts on a
                    #	16 byte boundary, and is no more than 16 bytes long,
                    #	and is a character - as opposed to hex - string.  This
                    #	works, as of this writing, for disks used by Oracle ASM (R)
                    #
                fi

                if [[ $valid_flag == "TRUE" ]]
                then
                    #
                    :	This is an eligible disk, try assigning a PVID
                    #
                    chdev -l $DISK -a pv=yes >/dev/null 2>>${TMPDIR}/clgetpvid.err
                    PVID=$(/usr/es/sbin/cluster/utilities/clodmget -q "name = $DISK and attribute = pvid" -f value -n CuAt)
                    PVID=${PVID:-none}
                    PVID=${PVID%0000000000000000}
                    #
                    :   Now, try that test again
                    #
                    if [[ "none" == $PVID ]]; then
                        #
                        :   Skip disks that do not have a PVID assigned
                        #
                        continue
                    else
                       #
                       :  Record newly assigned pvid disks list 
                       #
                       PVID_ASSIGNED_DISKS=${PVID_ASSIGNED_DISKS:+$PVID_ASSIGNED_DISKS, }$DISK
                    fi
                else
                    #
                    :	This is an ineligible disk and should not be assigned a PVID
                    #
                    continue
                fi
            else
                #
                : Skip disks if "On_disk_PVID" is already assigned to
                : another device, i.e. part of a multipath object
                #
                continue
            fi
        fi
    fi

    if [[ -s ${TMPDIR}/lsvpcfg.out.$$ &&	#   We have vpath configuration information, and
        $DISK != @(vpath*) &&	#   this disk is not a vpath, and
        $(grep -w "$DISK" ${TMPDIR}/lsvpcfg.out.$$ | cut -d'(' -f 2 | cut -d')' -f 1 | grep -w "pv") ]]	#   the corresponding vpath is a physical volume
    then
        #
        :   Skip disks that have PVID on a vpath and hdisk
        #
        continue
    fi

    #
    :	Pick up the size of the disk while we are at it
    :	Skip any disk that does not meet the size requirements
    #
    /usr/sbin/bootinfo -s $DISK 2>/dev/null | read DISK_SIZE
    DISK_SIZE=${DISK_SIZE:-0}
    if (( $MIN_SIZE != 0 && $DISK_SIZE < $MIN_SIZE ))
    then
        continue
    elif (( $MAX_SIZE != 0 && $DISK_SIZE > $MAX_SIZE ))
    then
        continue
    fi

    #
    :	Checks for potential repository disks.
    :   Skip any disks with block size other than 512 bytes.
    #
    if (( $REPOSITORY ))
    then
        VERBOSE_LOGGING=""
        blk_size=$(cl_querypv -b $DISK 2>>${TMPDIR}/clgetpvid.err)
        #  Skip any disks with block size other than 512 bytes and 4K as CAA only supports disk with 512 and 4K block size.
        if (( caa_4KDisk_available != 1 && $blk_size != 512 ))
        then
            continue
        elif (( caa_4KDisk_available == 1 && $blk_size != 512 && $blk_size != 4096 ))
        then
            continue
        fi
    fi

    #
    : If requested, do not list any Oracle ASM disks
    #
    if (( NO_ORACLE )); then
        if [[ -n $ineligible_disk_criteria ]]
        then
            #
            :   Check to see if this disk has a flag on it that makes
            :   it ineligible for PVID assignment.
            #
            typeset -i ORACLE=0
            lquerypv -h /dev/${DISK} | join -1 1 -2 1 -o 2.1,1.2,2.6 $ineligible_disk_criteria - |\
                    while read field_offset field_content xlate ; do
                        xlate=${xlate##\|}
                        if [[ $xlate == ${field_content}* ]]
                        then
                            ORACLE=1
                            break
                        fi
                    done
            (( ORACLE )) && continue
        fi
    fi

    #
    :	Pass back the collected data
    #
    if (( ! ADD_UUID ))
    then
        print "${DISK}:${PVID}:${CONCURRENT}:${ENHANCE_CONCURRENT_ONLY}:${DISK_SIZE}"
    else
        print "${DISK}:${PVID}:${CONCURRENT}:${ENHANCE_CONCURRENT_ONLY}:${DISK_SIZE}" >> ${TMPDIR}/clgetpvid_5.$$
    fi
done

if [[ -n $PVID_ASSIGNED_DISKS ]] 
then
    #
    :	Logging pvid assignment details to cspoc.log
    #
    MSG="One or more disks were assigned PVID. They are $PVID_ASSIGNED_DISKS"
    CSPOC_DIR=$(clodmget -q "name = cspoc.log" -f value -n HACMPlogs)
    typeset DATE=$(LC_ALL=C date +'%D %T')
    typeset LHOST=$(get_local_nodename)
    print -- "$DATE $LHOST: $MSG" >> $CSPOC_DIR/cspoc.log
    logger -p user.info "$DATE $LHOST: $MSG"
fi

if (( ADD_UUID ))
then
    #
    :	As requested, add the UUID, if present, for each disk to the output
    #
    sort -b -k1,1 ${TMPDIR}/clgetpvid_1.$$ | sed 's/  */:/' > ${TMPDIR}/clgetpvid_6.$$
    if [[ -s ${TMPDIR}/clgetpvid_5.$$ ]]
    then
        sort -t: -b -k1,1 ${TMPDIR}/clgetpvid_5.$$ | join -t: -1 1 -2 1 -a 1 - ${TMPDIR}/clgetpvid_6.$$
    fi
fi

#
:   Clean up work files, if not saved for debugging
#
if [[ $VERBOSE_LOGGING != 'high' ]]
then
    rm -f ${TMPDIR}/lquerypv.out
    rm -f $ineligible_disk_criteria
    rm -f ${TMPDIR}/lsvpcfg.out.$$
    rm -f ${TMPDIR}/clgetpvid_[1-7].$$
fi

#
:   And also pass back the free major numbers
#
print -- "FREEMAJORS:$(lvlstmajor)"
