#!/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_r720 src/43haes/usr/sbin/cluster/cspoc/utilities/cl_vglvfs_info.sh 1.10 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2013,2015 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)  7d4c34b 43haes/usr/sbin/cluster/cspoc/utilities/cl_vglvfs_info.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
###############################################################################
#
# Name: cl_vglvfs_info
#
# Description:
#   Use the lsvg, lslv, lsfs and lsjfs[2] commands to capture output about a
#   given volume group and its logical volumes and filesystems, and write that
#   information to stdout in the form
#   ATTRIBUTE=value:ATTRIBUTE=value: ...
#
# Arguments:
#
#   Volume group name, assumed vary'd on
#
# Output:
#   As provided by the various ls commands
#
# Return Values:
#   As set by lsvg
#
################################################################################


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

###############################################################################
#
#   Name:       ls_parser
#
#   Function:   The lsvg and lslv commands put out a two column list of
#               attributes and values.  A colon indicates the end of an
#               attribute, but both the attributes and values may have
#               embedded blanks.
#
#               Turn this into a serial list of the form:
#
#                   ATTRIBUTE_NAME="value"
#
#   Input:      Output from lsvg/lslv passed via STDIN.
#
#   Output:     ATTRIBUTE="value" format written to STDOUT,
#               one per line
#
###############################################################################
function ls_parser {
    typeset DATA="$1"

    typeset -u VARNAME=""
    typeset    VALUE="" LINE=""

    #=========================================================================
    # This task is much easier to accomplish in PERL, using regular
    # expressions. The alogrithm is as follows:
    #
    # 1. The first PERL regular expression removes the whitespace between
    #    each attribute and its value. So this:
    #       FREE PPs:       2533 (20264 megabytes)"
    #    becomes this:
    #       FREE PPs:2533 (20264 megabytes)
    #
    # 2. The next expression replaces all value spaces with an underscore.
    #    So this:
    #       FREE PPs:2533 (20264 megabytes)
    #    becomes this:
    #       FREE PPs:2533_(20264_megabytes)
    #
    # 3. The next expression makes sure that each ATTRIBUTE:VALUE pair is
    #    on its own line, one pair per line. So this:
    #       MAX LVs:256                      FREE PPs:2533_(20264_megabytes)
    #    becomes this:
    #       MAX LVs:256
    #       FREE PPs:2533_(20264_megabytes)
    #
    # 4. The last expression removes the temporary underscores that the
    #    second expression established. So this:
    #       FREE PPs:2533_(20264_megabytes)
    #    becomes this again:
    #       FREE PPs:2533 (20264 megabytes)
    #
    # The remaining code places undescores in the attribute, if needed,
    # replaces the colon with and equals, and quotes the value. This simple
    # work does not need the power of PERL, so it's done in ksh93 code.
    #=========================================================================
    print -- "$DATA" |\
    perl -p -e 's/(\S+:)\s+(\S+)/$1$2/g;' \
         -e 's/(\d+)[ \t]([\(a-z])/$1___$2/g;' \
         -e 's/(\S+:\S+)\s+/$1\n/g;' \
         -e 's/(\d+)___/$1 /g;' |\
    while read LINE; do
        print -- "$LINE" | IFS=: read VARNAME VALUE
        print "${VARNAME// /_}=\"$VALUE\""
    done
} # End of "ls_parser()"


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

# single input is a vg name
vg_name=$1			#   Assumed vary'd on

export LC_ALL=C			#   Parsing code assumes English characters
integer last_rc=0

#
:   Get node name, or host name if node name not available, e.g. when 
:   the cluster is first being configured
#
node_name=$(get_local_nodename)
if [[ -z $node_name ]]
then
    node_name=$(hostname)
fi
node_name=${node_name%%,*}

#
:   Information on volume group $vg_name
#
lsvg_output=$(LC_ALL=C lsvg -L $vg_name 2>/var/hacmp/log/${PROGNAME}.lsvg.err)
lsvg_rc=$?

# stderr was captured to file so we can display it after an error - discard 
# the file if empty 
[[ -e /var/hacmp/log/${PROGNAME}.lsvg.err && 
 ! -s /var/hacmp/log/${PROGNAME}.lsvg.err ]] && 
    rm /var/hacmp/log/${PROGNAME}.lsvg.err

if (( $lsvg_rc == 0 ))
then
    #
    :	Get major number
    #
    ls -l /dev/${vg_name} | read skip skip skip skip major rest
    major_num=${major%%,*}
    major_num="MAJOR_NUMBER=\"${major_num}\""

    #
    :	Get time stamp
    #
    timestamp=$(clodmget -q "name = ${vg_name} and attribute = timestamp" -f value -n CuAt)
    timestamp="TIMESTAMP=\"${timestamp}\""

    #
    :	Get the physical volumes
    #
    pv_list=""
    lspv -L 2>/var/hacmp/log/${PROGNAME}.lspv.err |\
    while read hdisk pvid vg rest; do
        if [[ $vg == $vg_name ]]
        then
            pv_list=${pv_list:+$pv_list","}${hdisk}@${node_name}@${pvid}
        fi
    done
    [[ -e /var/hacmp/log/${PROGNAME}.lspv.err && 
     ! -s /var/hacmp/log/${PROGNAME}.lspv.err ]] && 
        rm /var/hacmp/log/${PROGNAME}.lspv.err
    pv_list="PHYSICAL_VOLUME=\"${pv_list}\""

    #
    :	Get the logical volumes
    #
    lv_list=$(lsvg -l ${vg_name} 2>/var/hacmp/log/${PROGNAME}.lsvg_l.err | 
        tail +3 | cut -f1 -d' ' | paste -s -d',' -)
    [[ -e /var/hacmp/log/${PROGNAME}.lsvg_l.err && 
     ! -s /var/hacmp/log/${PROGNAME}.lsvg_l.err ]] && 
        rm /var/hacmp/log/${PROGNAME}.lsvg_l.err
    lv_list="LOGICAL_VOLUMES=\"${lv_list}\""

    #
    :	Get volume group type
    #
    vg_type_num=$(lqueryvg -j -g $(getlvodm -v $vg_name))
    case $vg_type_num in
        2 ) vg_type="SCALABLE" ;;
        0 ) vg_type="ORIGINAL"
            #
            :	To determine legacy volume groups we need to peek at the vgda
            #
            first_hdisk=${pv_list%%@*}
            first_hdisk=${first_hdisk##*\"}
            LC_ALL=C readvgda $first_hdisk | grep '^version:' | read skip version
            if (( $version == 12 ))
            then
                vg_type="LEGACY"
            fi
        ;;
        1 ) vg_type="BIG" ;;
        * ) vg_type="UNKNOWN" ;;
    esac

    #
    :	Get the mirror pools
    #
    mp_list=""
    mp_ss="no"
    if [[ $vg_type == 'SCALABLE' ]]
    then
        #
        #   Only scalable volume groups support mirror pools.
        #   For others, lsmp gives an error so we avoid with this check.
        #
        lsmp -L ${vg_name} 2>/var/hacmp/log/${PROGNAME}.lsmp_L.err |\
        while read f1 f2 mp_name rest; do
            [[ "$f1 $f2" == "MIRROR POOL:" ]] && mp_list=${mp_list:+$mp_list","}${mp_name}
        done
        [[ -e /var/hacmp/log/${PROGNAME}.lsmp_L.err && 
         ! -s /var/hacmp/log/${PROGNAME}.lsmp_L.err ]] && 
            rm /var/hacmp/log/${PROGNAME}.lsmp_L.err
    fi
    mp_list="MIRROR_POOLS=\"${mp_list}\""

    #
    :	Get the volume group attributes from the lsvg command,
    :	and turn them into a colon delimited string
    #
    vg_attrs=$(ls_parser "$lsvg_output" | paste -s -d: -)

    #
    :	Ouput the colon delimited info for this vg
    #
    print -- "VG:${vg_name}:TYPE=\"${vg_type}\":${lv_list}:${pv_list}:${mp_list}:${vg_attrs}:${major_num}:${timestamp}"

    #
    :	Now, show info for the individual logical volumes
    #
    eval $lv_list
    if [[ -n $LOGICAL_VOLUMES ]]
    then
        for lv_name in ${LOGICAL_VOLUMES//,/ }; do
            #
            :	Get the logical volume attributes
            #
            lslv_output=$(lslv -L $lv_name 2>/var/hacmp/log/${PROGNAME}.lslv_L.err)
            lslv_rc=$?
            [[ -e /var/hacmp/log/${PROGNAME}.lslv_L.err && 
             ! -s /var/hacmp/log/${PROGNAME}.lslv_L.err ]] && 
                rm /var/hacmp/log/${PROGNAME}.lslv_L.err
            if (( $lslv_rc == 0 ))
            then
                lv_attrs=$(ls_parser "$lslv_output" | paste -s -d: -)
                lv_disk=$(lslv -l $lv_name | tail -n +3 | cut -f1 -d' ')
                pv_list=""
                echo "$lv_disk" | while read hdisk; do
                    lspv | grep -w $hdisk | while read disk pvid rest; do
                        pv_list=${pv_list:+$pv_list","}${hdisk}@${node_name}@${pvid}
                    done
                done 
                #
                :	Print the info for this lv
                #
                print -- "LV:${lv_name}:${lv_attrs}:PHYSICAL_VOLUMES=\"$pv_list\""

                #
                :	If there is a file system on this logical volume,
                :	get its mount point
                #
                fs_name=${lv_attrs##*:MOUNT_POINT=}
                fs_name=${fs_name%%:*}
                fs_name=${fs_name%\"}
                fs_name=${fs_name#\"}

                if [[ -z $fs_name || $fs_name == 'N/A' ]]
                then
                    continue	#   On to next logical volume since no file system
                fi

                #
                :   Pick up the file system type - JFS or JFS2
                :	that may exist on this logical volume
                #
                lsfs_output=$(lsfs -c $fs_name 2>/var/hacmp/log/${PROGNAME}.lsfs.err)
                lsfs_rc=$?
                [[ -e /var/hacmp/log/${PROGNAME}.lsfs.err && 
                 ! -s /var/hacmp/log/${PROGNAME}.lsfs.err ]] && 
                    rm /var/hacmp/log/${PROGNAME}.lsfs.err
                if (( $lsfs_rc == 0 ))
                then
                    # type will be blank for jfs or "2" for jfs2
                    VFS_type=$(print -- "$lsfs_output" | tail +2 | cut -f3 -d':')

                    #
                    :   Get log information from the file systems
                    :	entry in /etc/filesystems
                    #
                    loglv=$(grep -wp "^${fs_name}:" /etc/filesystems | 
                        sed -n '/log.*=/s/^.*= \([^ ]*\).*/\1/p')
                    if [[ -n $loglv ]]
                    then
                        loglv=$(basename $loglv)
                    fi

                    #
                    #   Run the appropriate list command, appending log lv to
                    #   the end.
                    #   The lsjfs and lsjfs2 commands put out two lines, a colon
                    #   delimited header followed by a colon delimited set of
                    #   values.
                    #
                    header=""
                    lsjfs_output=$(ls${VFS_type} $fs_name 2>/var/hacmp/log/${PROGNAME}.lsfs.err)
                    lsjfs_rc=$?
                    [[ -e /var/hacmp/log/${PROGNAME}.lsfs.err && 
                     ! -s /var/hacmp/log/${PROGNAME}.lsfs.err ]] && 
                        rm /var/hacmp/log/${PROGNAME}.lsfs.err
                    if (( $lsjfs_rc == 0 ))
                    then
                        # parse out a header and data line for each
                        print -- "$lsjfs_output" |\
                        while read line
                        do
                            if [[ -z $header ]]
                            then
                                header="${line%:}:loglv:"
                            else
                                data="${line}${loglv}:"
                            fi
                        done

                        header=${header#'#'}
                        header=${header/:OtherOptions:/:MountOptions:}
                        header=${header/:Options:/:Permissions:}

                        #
                        :	Collect the file system attributes
                        #
                        fs_attrs=""
                        fs_type=""
                        typeset -u attribute
                        while [[ -n $header ]]
                        do
                            #
                            :   Pick up the individual header values, and
                            :   the corresponding value, and turn them into
                            :   'ATTRIBUTE="value"' pairs
                            #
                            attribute=${header%%:*}
                            value=${data%%:*}

                            #
                            :   File system type, in terms used during creation
                            #
                            if [[ $attribute == 'VFS' && $value == 'jfs' ]]
                            then
                                fs_type='STANDARD'
                            elif [[ $attribute == 'VFS' && $value == 'jfs2' ]]
                            then
                                fs_type='ENHANCED'
                            elif [[ $attribute == 'COMPRESS' && $value == @(yes|true|LZ) ]]
                            then
                                fs_type='COMPRESSED'
                            elif [[ $attribute == 'BF' && $value == 'true' ]]
                            then
                                fs_type='LARGE'
                            fi

                            if [[ $attribute != 'TYPE' ]]
                            then
                                fs_attrs="${fs_attrs:+$fs_attrs":"}${attribute}=\"${value}\""
                            fi

                            header=${header#*:}
                            data=${data#*:}
                        done

                        #
                        :   Print the data for this fs
                        #
                        print -- "FS:${fs_name}:${fs_attrs}:TYPE=\"$fs_type\""
                    else
                        #
                        :   lsjfs for file system $fs_name failed
                        #
                        last_rc=$lsfs_rc
                        print -u2 "${PROGNAME}: Could not display information for file system $fs_name"
                        # print what we have
                        if [[ -n $lslv_output ]]
                        then
                            print -u2 -- "$lsjfs_output"
                        fi
                        # along with any stderr from the command
                        if [[ -s /var/hacmp/log/${PROGNAME}.lsjfs.err ]]
                        then
                            cat /var/hacmp/log/${PROGNAME}.lsjfs.err 1>&2
                        fi

                        #
                        :   Flag error in normal output
                        #
                        print -- "ERROR: lsjfs $fs_name"
                    fi
                else
                    #
                    :   lsfs for file system $fs_name failed
                    #
                    last_rc=$lsfs_rc
                    print -u2 "${PROGNAME}: Could not display information for file system $fs_name"
                    # print any data we do have
                    if [[ -n $lslv_output ]]
                    then
                        print -u2 -- "$lsjfs_output"
                    fi
                    # along with any stderr from the command
                    if [[ -s /var/hacmp/log/${PROGNAME}.lsfs.err ]]
                    then
                        cat /var/hacmp/log/${PROGNAME}.lsfs.err 1>&2
                    fi

                    #
                    :   Flag error in normal output
                    #
                    print -- "ERROR: lsfs $fs_name"
                fi
            else
                #
                :   lslv for logical volume $lv_name failed
                #
                last_rc=$lslv_rc
                print -u2 "${PROGNAME}: Could not display information for logical volume $lv_name"
                # not likely, but print anything we have
                if [[ -n $lslv_output ]]
                then
                    print -u2 -- "$lsvg_output"
                fi
                # along with any stderr
                if [[ -s /var/hacmp/log/${PROGNAME}.lslv_L.err ]]
                then
                    cat /var/hacmp/log/${PROGNAME}.lslv_L.err 1>&2
                fi

                #
                :   Flag error in normal output
                #
                print -- "ERROR: lslv $lv_name"
            fi
        done
    fi
else
    #
    :	lsvg for volume group $vg_name failed
    #
    last_rc=$lsvg_rc
    print -u2 "${PROGNAME}: Could not display information for volume group $vg_name"
    # show any stderr from the command - there is no other info gathered if
    # lsvg fails
    if [[ -s /var/hacmp/log/${PROGNAME}.lsvg.err ]]
    then
        cat /var/hacmp/log/${PROGNAME}.lsvg.err 1>&2
    fi

    #
    :   Flag error in normal output
    #
    print -- "ERROR: lsvg $vg_name"
fi

return $last_rc