#!/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