#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2000,2006 # 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 # @(#)16 1.43.1.1 src/avs/fs/mmfs/ts/admin/mmlsnsd.sh, mmfs, avs_rgpfs24, rgpfs24s008a 11/22/06 15:43:42 ############################################################################# # # List information for the disks that belong to a GPFS cluster. # # Usage: # # mmlsnsd [ -a | -F | -f Device | -d "DiskName[;DiskName]" ] # [ -L | -m | -M | -X ] [-v] # # where # # -a list all disks. This is the default. # # -F list all disks that do not belong to any file system. # # -f Device list all disks that belong to file system Device. # # -d "DiskName[;DiskName]" list the disks in the specified list # of ";"-separated disk names. # # -L display longer disk information. # # -m display the disk device name on the local node, # or, if applicable, the disk device names on the # primary and backup server nodes. # # -M display the disk device names on all nodes to which # the disk is attached. Caution: This is a slow operation! # # -v display additional error information where available. # # -X display eXtended disk information. # ############################################################################# # Include global declarations and service routines. . /usr/lpp/mmfs/bin/mmglobfuncs . /usr/lpp/mmfs/bin/mmsdrfsdef . /usr/lpp/mmfs/bin/mmfsfuncs sourceFile="mmlsnsd.sh" [[ -n $DEBUG || -n $DEBUGmmlsnsd ]] && set -x $mmTRACE_ENTER "$*" # Local work files. Names should be of the form: # fn=${tmpDir}fn.${mmcmd}.$$ disksToShow=${tmpDir}disksToShow.${mmcmd}.$$ collectedDiskData=${tmpDir}collectedDiskData.${mmcmd}.$$ LOCAL_FILES=" $disksToShow $collectedDiskData " # Local variables usageMsg=428 headerPrinted=no underline="----------------------------------------------------------" underline="${underline}----------------------------------------------" underline="${underline}----------------------------------------------" # Local functions ########################################################################## # # Display local nsd data for the desired disks. # This function prints the local device name on all nodes # for all disks that were specified by the user. # # Input: $1 - file containing disk data collected from the nodes # $2 - file containing disk data from the mmsdrfs file # $3 - file containing a list of nodes to check # ########################################################################## function showLocalDeviceInfo # { typeset sourceFile="mmlsnsd.sh" [[ -n $DEBUG || -n $DEBUGshowLocalDeviceInfo ]] && set -x $mmTRACE_ENTER "$*" typeset diskDataFile=$1 typeset sdrfsDiskData=$2 typeset nodeFile=$3 typeset diskLine diskFoundOnNode diskFoundOnPrimary diskFoundOnBackup typeset nodeName globalName pvid localDiskName diskdataLine typeset primaryServer backupServer nsdSubtype remarks xRemarks # If this is a single node cluster, prepend the node name # to the front of each record in the diskDataFile, since # mmcommon onall does not use mmdsh for single node clusters. if [[ $MMMODE = single ]] then $sed "s/^/$ourNodeName: /" $diskDataFile > $tmpfile2 $mv $tmpfile2 $diskDataFile checkForErrors "mv $tmpfile2 $diskDataFile" $? fi # end of if [[ $MMMODE = single ]] # Separate the valid nsd data into one file, and any error messages # into another. The error messages (if any) will be displayed later. $grep getLocalNsdData $diskDataFile > $tmpfile $grep -v getLocalNsdData $diskDataFile > $errMsg # Sort the collected nsd data by the NSD id (pvid). $sort -t : -k 3,3 $tmpfile -o $tmpfile2 checkForErrors "$mmcmd: sort of tmpfile" $? # Sort the disk data from the mmsdrfs file based on the NSD id (pvid). $sort -t : -k 2,2 $sdrfsDiskData -o $sdrfsDiskData checkForErrors "$mmcmd: sort of sdrfsDiskData" $? # Join the file containing the nsd data collected from the nodes # with the file containing the mmsdrfs data for the desired nsds; # the join is performed based on the NSD id (pvid) value. # The lines in the resulting file have the following fields: # nodeName:diskName:pvid:localDiskName:primaryServer:backupServer:localNsdSubtype:nsdSubtype $join -1 2 -2 3 -t: -o 2.1,1.1,1.2,2.4,1.3,1.4,2.5,2.6 $sdrfsDiskData $tmpfile2 > $tmpfile checkForErrors "$mmcmd: join" $? $touch $tmpfile # Make sure the file exists, even if it is empty. # Sort the disk data file by disk name and the node file # by node name to ensure the output of the nested loops # below is in the order most easily read by the user. $sort -t : -k 1,1 $sdrfsDiskData -o $sdrfsDiskData checkForErrors "$mmcmd: second sort of sdrfsDiskData" $? $sort -t : -k 1,1 $nodefile -o $nodefile checkForErrors "$mmcmd: sort of nodefile" $? # Loop through the disks from the mmsdrfs file to print their data. IFS=":" # Change the field separator to ':'. exec 3<&- exec 3< $sdrfsDiskData while read -u3 diskLine do # Parse the line. set -f ; set -- $diskLine ; set +f globalName=$1 pvid=$2 primaryServer=$3 backupServer=$4 nsdSubtype=$5 IFS="$IFS_sv" # Restore the default IFS settings. diskFoundOnPrimary=false diskFoundOnBackup=false # Get the lines from the joined file that match this disk. # The awk script takes into account that tspreparedisk treats # hdisk and generic as equivalent, and either nsd subtype could # be present if the cluster has both AIX and Linux nodes or the # filesystem was imported from one OS environment to the other. $rm -f $tmpfile2 $awk -F: ' \ $3=="'$pvid'" && \ ( $7=="'$nsdSubtype'" || \ ($7=="hdisk" && "'$nsdSubtype'"=="generic") || \ ($7=="generic" && "'$nsdSubtype'"=="hdisk") ) \ {print $1":"$4":"$7":"$8 >> "'$tmpfile2'"} \ ' $tmpfile checkForErrors awk $? # Process the lines that were found. if [[ -s $tmpfile2 ]] then # Print a line of output for each line extracted from the joined file. # For -M we report all nodes, while for -m and -X, we only report # the node running the command and any server nodes. IFS=":" # Change the field separator to ':'. exec 4<&- exec 4< $tmpfile2 while read -u4 diskdataLine do # Parse the line. set -f ; set -- $diskdataLine ; set +f nodeName=$1 localDiskName=$2 devType=$3 extendedRemarks=$4 IFS="$IFS_sv" # Restore the default IFS settings. if [[ -n $Mflag || ( (-n $mflag || -n $Xflag) && ($nodeName = $ourNodeName || $nodeName = $primaryServer || $nodeName = $backupServer ) ) ]] then # Set the remarks field appropriately. if [[ $nodeName = $primaryServer ]] then diskFoundOnPrimary=true remarks="primary node" elif [[ $nodeName = $backupServer ]] then diskFoundOnBackup=true remarks="backup node" else remarks="directly attached" fi # end of if [[ $nodeName = $primaryServer ]] # Append extended remarks if there are any. [[ -n $extendedRemarks ]] && remarks="$remarks,$extendedRemarks" # Print the line of output. if [[ -n $Xflag ]] then printf " %-12s %-18s %-14s %-8s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$devType" "$nodeName" "$remarks" else printf " %-12s %-18s %-14s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$nodeName" "$remarks" fi fi # end of if [[ -n $Mflag || ... IFS=":" # Change the separator back to ":" for the next iteration. done # end of while read -u4 diskdataLine fi # end of if [[ -s $tmpfile2 ]] # Check whether the disk is missing anywhere and report it if it is. if [[ -z $primaryServer ]] then # Report this directly-attached disk as missing on nodes on which # it was not found. For -M we report all nodes, while for -m and -X, # we only report the node running the command. exec 4<&- exec 4< $nodefile while read -u4 nodeName do if [[ -n $Mflag || ( (-n $mflag || -n $Xflag) && $nodeName = $ourNodeName ) ]] then # Check whether the disk was found on this node. # The awk script takes into account that tspreparedisk treats # hdisk and generic as equivalent, and either nsd subtype could # be present if the cluster has both AIX and Linux nodes or the # filesystem was imported from one OS environment to the other. diskFoundOnNode=$($awk -F: ' \ BEGIN { foundFlag = "false" } \ $1 == "'$nodeName'" && $3 == "'$pvid'" && \ ( $7=="'$nsdSubtype'" || \ ($7=="hdisk" && "'$nsdSubtype'"=="generic") || \ ($7=="generic" && "'$nsdSubtype'"=="hdisk") ) { \ { foundFlag = "true" } \ { exit } \ } \ END { print foundFlag } \ ' $tmpfile) checkForErrors "awk $tmpfile" $? if [[ $diskFoundOnNode = false ]] then localDiskName=$UNRESOLVED remarks="(not found) directly attached" if [[ -n $Xflag ]] then devType=$UNRESOLVED printf " %-12s %-18s %-14s %-8s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$devType" "$nodeName" "$remarks" else printf " %-12s %-18s %-14s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$nodeName" "$remarks" fi fi # end of if [[ $diskFoundOnNode = false ]] fi # end of if [[ -n $Mflag || ( (-n $mflag || -n $Xflag) && ... done # end of while read -u4 nodeName else # Output a line for the primary or backup server # if either was specified but was not found. if [[ -n $primaryServer && $diskFoundOnPrimary = false ]] then localDiskName=$UNRESOLVED nodeName=$primaryServer remarks="(not found) primary node" if [[ -n $Xflag ]] then devType=$UNRESOLVED printf " %-12s %-18s %-14s %-8s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$devType" "$nodeName" "$remarks" else printf " %-12s %-18s %-14s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$nodeName" "$remarks" fi fi # end of if [[ -n $primaryServer && $diskFoundOnPrimary = false ]] if [[ -n $backupServer && $diskFoundOnBackup = false ]] then localDiskName=$UNRESOLVED nodeName=$backupServer remarks="(not found) backup node" if [[ -n $Xflag ]] then devType=$UNRESOLVED printf " %-12s %-18s %-14s %-8s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$devType" "$nodeName" "$remarks" else printf " %-12s %-18s %-14s %-24s %s\n" "$globalName" \ "$pvid" "$localDiskName" "$nodeName" "$remarks" fi fi # end of if [[ -n $backupServer && $diskFoundOnBackup = false ]] fi # end of if [[ -z $primaryServer ]] IFS=":" # Change the separator back to ":" for the next iteration. done # end of while read -u3 diskLine do # If -v was specified, display any error messages # that were produced on the remote nodes. [[ -n $verboseOutput ]] && $cat $errMsg $rm -f $errMsg return 0 } #----- end of function showLocalDeviceInfo ------------------ ####################### # Mainline processing ####################### ################################# # Process the command arguments. ################################# [[ $arg1 = '-?' || $arg1 = '-h' || $arg1 = '--help' || $arg1 = '--' ]] && \ syntaxError "help" $usageMsg while getopts :ad:Ff:LMmvX OPT do case $OPT in a) [[ -n $aflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" aflag="-$OPT" [[ -n $dflag || -n $Fflag || -n $fflag ]] && \ syntaxError "invalidCombination" $usageMsg $aflag $dflag $Fflag $fflag ;; d) [[ -n $dflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" dflag="-$OPT" [[ -n $aflag || -n $Fflag || -n $fflag ]] && \ syntaxError "invalidCombination" $usageMsg $dflag $aflag $Fflag $fflag darg="$OPTARG" [[ "$OPTARG" = *+([-:,${BLANKchar}${TABchar}])* ]] && \ syntaxError "badSeparator_notSemicolon" $noUsageMsg disksToDisplay=$(print -- "$OPTARG" | $sed 's/;/ /g') ;; F) [[ -n $Fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Fflag="-$OPT" [[ -n $aflag || -n $dflag || -n $fflag ]] && \ syntaxError "invalidCombination" $usageMsg $Fflag $aflag $dflag $fflag ;; f) [[ -n $fflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" fflag="-$OPT" [[ -n $aflag || -n $dflag || -n $Fflag ]] && \ syntaxError "invalidCombination" $usageMsg $fflag $aflag $dflag $Fflag farg="$OPTARG" ;; L) [[ -n $Lflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Lflag="-$OPT" [[ -n $Mflag || -n $mflag || -n $Xflag ]] && \ syntaxError "invalidCombination" $usageMsg $Lflag $Mflag $mflag $Xflag ;; M) [[ -n $Mflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Mflag="-$OPT" [[ -n $Lflag || -n $mflag || -n $Xflag ]] && \ syntaxError "invalidCombination" $usageMsg $Mflag $Lflag $mflag $Xflag ;; m) [[ -n $mflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" mflag="-$OPT" [[ -n $Lflag || -n $Mflag || -n $Xflag ]] && \ syntaxError "invalidCombination" $usageMsg $mflag $Lflag $Mflag $Xflag ;; v) [[ -n $vflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" vflag="-$OPT" verboseOutput=yes ;; X) [[ -n $Xflag ]] && syntaxError "multiple" $noUsageMsg "-$OPT" Xflag="-$OPT" [[ -n $Lflag || -n $Mflag || -n $mflag ]] && \ syntaxError "invalidCombination" $usageMsg $Xflag $Lflag $Mflag $mflag ;; :) syntaxError "missingValue" $usageMsg $OPTARG ;; +[adFfLMmvX]) syntaxError "invalidOption" $usageMsg "$OPT" ;; *) syntaxError "invalidOption" $usageMsg $OPTARG ;; esac done # end of while getopts :ad:Ff:LMmv OPT shift OPTIND-1 [[ $# != 0 ]] && syntaxError "extraArg" $usageMsg $1 # If no disk selection option was specified, default to -a. [[ -z $aflag && -z $dflag && -z $Fflag && -z $fflag ]] && \ aflag="-a" ###################################################################### # Set up trap exception handling and call the gpfsInit function. # It will ensure that the local copy of the mmsdrfs and the rest # of the GPFS system files are up-to-date. No need to lock the sdr. ###################################################################### trap pretrap2 HUP INT QUIT KILL gpfsInitOutput=$(gpfsInit nolock) setGlobalVar $? $gpfsInitOutput # In single mode environment -M does not make much sense. if [[ -n $Mflag && $MMMODE = single ]] then Mflag="" mflag="-m" fi ################################################################# # If a particular file system is requested, make sure it exists. ################################################################# if [[ -n $farg ]] then findFSoutput=$(findFS "$farg" $mmsdrfsFile) [[ -z $findFSoutput ]] && cleanupAndExit # Parse the output from the findFS function. set -f ; set -- $findFSoutput ; set +f # fqfsDeviceName=$1 fsDeviceName=$2 fsHomeCluster=$3 # Exit with a message if the command was invoked for a remote file system. if [[ $fsHomeCluster != $HOME_CLUSTER ]] then # Command is not allowed for remote file systems. printErrorMsg 106 $mmcmd $farg $fsHomeCluster cleanupAndExit 1 fi fi # end of if [[ -n $farg ]] ############################### # Select the disks to display. ############################### $rm -f $disksToShow $nodefile $diskNamesFile IFS=":" # Change the field separator to ':'. exec 3<&- exec 3< $mmsdrfsFile while read -u3 sdrfsLine do # Parse the line. set -f ; set -A v -- - $sdrfsLine ; set +f IFS="$IFS_sv" printLine=false # assume line is not needed if [[ ${v[$LINE_TYPE_Field]} = $SG_DISKS ]] then # This line describes a disk. If it matches our selection # criteria, add the line to disksToShow. Otherwise, skip the line. if [[ -n $aflag ]] then printLine=true elif [[ -n $Fflag && ${v[$NODESETID_Field]} = $FREE_DISK ]] then printLine=true elif [[ -n $fflag && ${v[$DEV_NAME_Field]} = $fsDeviceName ]] then printLine=true elif [[ -n $dflag ]] then # See if this disk is one of the disks to be displayed. tempList="" displayThisDisk=no for diskName in $disksToDisplay do if [[ ${v[$DISK_NAME_Field]} = $diskName ]] then # The disk represented by the current SG_DISKS line # is one of the disks that we want to display. if [[ $displayThisDisk = no ]] then # We are seeing this disk for the first time. printLine=true displayThisDisk=yes else # We have already seen this name during the current iteration. # It must be a duplicate entry in the command line list. : # ignore the duplicate - do not fail the command. fi else # diskName does not match the name of the disk in the current # SG_DISKS line. Add diskName to the temporary list. tempList="$tempList $diskName" fi # end of if [[ ${v[$DISK_NAME_Field]} = $diskName ]] done # for diskName in $disksToDisplay # If this disk will be displayed, its name does not appear in tempList. # In other words, tempList contains only the names of the disks that # are to be displayed but for which the corresponding SG_LINES have not # been encountered yet. # Initialize the disksToDisplay list for the next iteration. disksToDisplay=$tempList else # This is an SG_DISKS line that does not match our selection criteria. : # skip this line fi # end of if [[ -n $aflag ]] if [[ $printLine = true ]] then print_newLine >> $disksToShow checkForErrors "writing to file $disksToShow" $? # If -m or -X was specified and the disk has primary or backup servers, # add the servers to the list of nodes to collect data from. if [[ -n $mflag || -n $Xflag ]] then [[ -n ${v[$NSD_PRIMARY_NODE_Field]} ]] && \ print ${v[$NSD_PRIMARY_NODE_Field]} >> $nodefile [[ -n ${v[$NSD_BACKUP_NODE_Field]} ]] && \ print ${v[$NSD_BACKUP_NODE_Field]} >> $nodefile fi # If -m, -M, or -X was specified, add data for the disk # to a file that will be used later. [[ -n $mflag || -n $Mflag || -n $Xflag ]] && \ print ${v[$DISK_NAME_Field]}:${v[$PVID_Field]}:${v[$NSD_PRIMARY_NODE_Field]}:${v[$NSD_BACKUP_NODE_Field]}:${v[$NSD_SUBTYPE_Field]} >> $diskNamesFile fi # end of if [[ $printLine = true ]] elif [[ ${v[$LINE_TYPE_Field]} = $MEMBER_NODE && -n $Mflag ]] then # Generate a list of all nodes in the cluster. print ${v[$REL_HOSTNAME_Field]} >> $nodefile else # This is not a line that we care about. : # Skip this line. fi # end of if [[ ${v[$LINE_TYPE_Field]} = $SG_DISKS ]] IFS=":" # Change the separator back to ":" for the next iteration. done # end while read -u3 sdrfsLine IFS="$IFS_sv" # Restore the default IFS settings. # If there are no disks matching the selection criteria, # put out a message and give up. if [[ ! -s $disksToShow ]] then # No disks were found. printErrorMsg 418 $mmcmd cleanupAndExit 0 fi # If -d option was used and there are still entries in the # disksToDisplay list, tell the user that not all disks were found. if [[ -n $disksToDisplay ]] then # Some disks were not found. for diskName in $disksToDisplay do printErrorMsg 524 $mmcmd $diskName done fi # Finish creating the node file if -m or -X was specified. if [[ -n $mflag || -n $Xflag ]] then # Add the node running the command to the list of nodes to check. print $ourNodeName >> $nodefile # Sort the file for uniqueness so that we do not have any # nodes listed more than once. $sort -u $nodefile -o $nodefile fi # Print the appropriate header line. # This depends on the specified formatting option. if [[ -n $Lflag ]] then # header "File system Disk name NSD volumeID Primary node Backup node" header=$(printInfoMsg 501) printf "\n%s\n%.${#header}s\n" "$header" "$underline" elif [[ -n $Mflag || -n $mflag || -n $Xflag ]] then if [[ -n $Xflag ]] then # header "Disk name NSD volumeID Device Devtype Node name Remarks" header=$(printInfoMsg 512) else # header "Disk name NSD volumeID Device Node name Remarks" header=$(printInfoMsg 502) fi printf "\n%s\n%.${#header}s\n" "$header" "$underline" # Obtain the local nsd data from the nodes. $mmcommon onall $nodefile $unreachedNodes getLocalNsdData $Xflag >$collectedDiskData 2>&1 else # header "File system Disk name Primary node Backup node" header=$(printInfoMsg 503) printf "\n%s\n%.${#header}s\n" "$header" "$underline" fi # end of if [[ -n $Lflag ]] # If -m, -M, or -X was specified, sort the disk data file and call routine # to print the output for the desired disks on all of the pertinent nodes. if [[ -n $mflag || -n $Mflag || -n $Xflag ]] then # Invoke routine to display the disk data from the nodes. showLocalDeviceInfo $collectedDiskData $diskNamesFile $nodefile else # For options other than -m, -M, or -X, loop through the selected # disks one by one and print the desired information. IFS=":" exec 3<&- exec 3< $disksToShow while read -u3 diskLine do # Parse the line. set -f ; set -A v -- - $diskLine ; set +f IFS="$IFS_sv" # Check whether this is a free disk. [[ ${v[$NODESETID_Field]} = $FREE_DISK ]] && \ v[$DEV_NAME_Field]="(free disk)" if [[ -n $Lflag ]] then # Extended disk information requested. # If no primary node, indicate the disk is directly-attached. [[ -z ${v[$NSD_PRIMARY_NODE_Field]} ]] && \ v[$NSD_PRIMARY_NODE_Field]="(directly attached)" # Print the line of output for the disk. printf " %-13s %-12s %-18s %-24s %s\n" \ "${v[$DEV_NAME_Field]}" "${v[$DISK_NAME_Field]}" "${v[$PVID_Field]}" \ "${v[$NSD_PRIMARY_NODE_Field]}" "${v[$NSD_BACKUP_NODE_Field]}" else # Default disk information requested. # If no primary node, indicate the disk is directly-attached. [[ -z ${v[$NSD_PRIMARY_NODE_Field]} ]] && \ v[$NSD_PRIMARY_NODE_Field]="(directly attached)" # Print the line of output for the disk. printf " %-13s %-12s %-24s %s\n" \ "${v[$DEV_NAME_Field]}" "${v[$DISK_NAME_Field]}" \ "${v[$NSD_PRIMARY_NODE_Field]}" "${v[$NSD_BACKUP_NODE_Field]}" fi # end of if [[ -n $Lflag ]] IFS=":" # Change the separator back to ":" for the next iteration. done # end while read -u3 diskLine fi # end of if [[ -n $Mflag ]] IFS="$IFS_sv" # Restore the default IFS settings. # Add a blank line for nicer formatting. print "" # If any nodes could not be reached, tell the user which ones. if [[ -s $unreachedNodes ]] then # The following nodes could not be reached: . . . printErrorMsg 270 $mmcmd $cat $unreachedNodes 1>&2 fi cleanupAndExit 0