#!/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 
# @(#)14 1.44.1.1 src/avs/fs/mmfs/ts/admin/mmglobfuncs.Linux.sh, mmfs, avs_rgpfs24, rgpfs24s007a 9/20/06 11:22:24
#############################################################
#
#  This file contains declarations and functions that are
#  unique to the Linux operating system environment.
#
#############################################################

sourceFile="mmglobfuncs.Linux.sh"
[[ -n $DEBUGmmglobfuncsLinux ]] && set -x

#-----------------------------------------------------------
# Constants and global variables for internal mm command use.
#-----------------------------------------------------------
fsDeviceType='b'
defaultMajorNumber=239
minMinorNumber=100
maxMinorNumber=255
currentMajorNumber=$defaultMajorNumber
neededMajorNumber=$defaultMajorNumber

# Find out if this is 2.4 or earlier version.
[[ $(/bin/uname -r) = 2.[0-4].* ]] && version24=yes || version24=""


#-----------------------------------------------------------
# Return codes and constants for internal mm command use.
#-----------------------------------------------------------
MM_Remotefs2=66         # remote file system (EREMOTE)
MM_UnknownCluster2=101  # unknown cluster (ENETUNREACH)
MM_ConnAborted=103      # connection aborted (ECONNABORTED)
MM_ConnectionReset2=104 # connection reset (ECONNRESET)
MM_TimedOut2=110        # connection timed out (ETIMEDOUT)
MM_HostDown2=112        # host is down (EHOSTDOWN)
MM_DaemonDown2=127      # daemon not running (second value)


#-----------------------------------------------------------
# Full path names for Linux system commands
#-----------------------------------------------------------
automount=/usr/sbin/automount
awk=/bin/awk
cat=/bin/cat
chmod=/bin/chmod
chown=/bin/chown
cp=/bin/cp
cut=cut          # /bin/cut or /usr/bin/cut depending on the RH release
date=/bin/date
dd=/bin/dd
df=/bin/df
diff=/usr/bin/diff
egrep=/bin/egrep
find=/usr/bin/find
fgrep=/bin/fgrep
grep=/bin/grep
head=/usr/bin/head
# host=/usr/bin/host
host="host_aixformat"  # internal function to convert the host output
hostname=/bin/hostname
id=/usr/bin/id
ifconfig=/sbin/ifconfig
insmod=/sbin/insmod
join=/usr/bin/join
kill=/bin/kill
locale=/usr/bin/locale
ln=/bin/ln
ls=/bin/ls
lsmod=/sbin/lsmod
lssrc=/usr/bin/lssrc
mkdir=/bin/mkdir
mknod=/bin/mknod
mount=/bin/mount
mv=/bin/mv
nm=/usr/bin/nm
openssl=/usr/bin/openssl
perl=/usr/bin/perl
ping=/bin/ping
ps=/bin/ps
rcp=/usr/bin/rcp
rm=/bin/rm
rmdir=/bin/rmdir
rmmod=/sbin/rmmod
rpm=/bin/rpm
rsh=/usr/bin/rsh
sed=/bin/sed
sleep=/bin/sleep
sort=/bin/sort
srcmstr=/sbin/srcmstr
startsrc=/usr/bin/startsrc
stopsrc=/usr/bin/stopsrc
sum=/usr/bin/sum
sync=/bin/sync
tail=/usr/bin/tail
tee=/usr/bin/tee
touch=/bin/touch
tr=/usr/bin/tr
umount=/bin/umount
uname=/bin/uname
unmount=/bin/umount   # synonym for umount
wc=/usr/bin/wc


#-----------------------------------------------------------
# Well-known file names
#-----------------------------------------------------------
etcFilesystems="/etc/fstab"    # Filesystem stanzas used by the mount command
etcHosts="/etc/hosts"          # Local host name resolution file
etcHostConf="/etc/host.conf"   # Resolver configuration file
auto_master="/etc/auto_master" # master input for the automount daemon
autoMaster="/etc/auto.master"  # master input for the automount daemon


#-------------------------------
# Commands with common options
#-------------------------------

# Command to extract a specific field from a line.
#   Example: print -- $line | $GETVALUE $NODE_NAME_Field
GETVALUE="$cut -d: -f "

# Command to sort the mmsdrfs file prior to storing it.
#   Example: LC_ALL=C $SORT_MMSDRFS $sdrfs -o $sdrfs
# The sorting is based on the following keys:
# - the primary key is the nodeset id
# - the secondary key is the stripe group id
# - the next key is the line type
# - the last key is the line number
# The sorting is based on the ASCII collating sequence,
# except for the fourth field, which is sorted in
# arithmetic order.
SORT_MMSDRFS="$sort -t: -k 1,1 -k 3,3 -k 2,2 -k 4,4n "


#-------------------------------
# Frequently used functions
#-------------------------------


####################################################################
#
# Function:  In the Linux environment, function host_aixformat
#            looks up a name using both /etc/hosts and the Linux
#            host command.  This function determines the order
#            in which the name is resolved.
#
# Input:     None.
#
# Output:    "hosts" - check first the /etc/hosts file.
#            "bind"  - start with the host command.
#
# Returns:   Always zero.
#
####################################################################
function setHostResolveOrder
{
  typeset sourceFile="mmglobfuncs.Linux.sh"
  [[ -n $DEBUG || -n $DEBUGsetHostResolveOrder ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset order

  # Find out the host lookup order.  Our rules are:
  # If 'hosts' is specified first on the order line in /etc/host.conf,
  # search for the name in /etc/hosts before issuing the host command.
  # Otherwise, start with the host command.
  if [[ -f $etcHostConf ]]
  then
    order=$($awk '                                        \
      BEGIN { order = "bind" }                            \
      $1 == "order" && $2 ~ /^hosts/ { order = "hosts" }  \
      END { print order }                                 \
    ' $etcHostConf 2>/dev/null)
  else
    order=bind
  fi

  print $order
  return 0

}  #-------------- end of function setHostResolveOrder ------------------


####################################################################
#
# Function:  Issues the Linux host command and converts the output
#            to make it look as if it came from an AIX host command.
#            If the host command does not resolve the name, try
#            looking up the name in the local /etc/hosts file.
#
# Input:     $1 - hostname or IP address
#
# Output:    A line similar to the following:
#               esj.austin.ibm.com is 9.53.145.122
#
# Returns:   0 - hostname resolved
#            non-zero - name not resolved
#
####################################################################
function host_aixformat  # <hostname|ipa>
{
  typeset sourceFile="mmglobfuncs.Linux.sh"
  [[ -n $DEBUG || -n $DEBUGhost_aixformat ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset inValue=$1

  typeset nameResolved=no
  typeset etcHostsChecked=no
  typeset hostOutput=${tmpDir}hostOutput.${mmcmd}.$$
  typeset hostErrMsg=${tmpDir}hostErrMsg.${mmcmd}.$$
  typeset rc awkRc hostResult

  [[ -z $inValue ]] && return 1

  # If still not known, determine the lookup order.
  [[ -z $resolveOrder ]] && \
    resolveOrder=$(setHostResolveOrder)

  # If it is OK to do so, see if the host name appears in /etc/hosts.
  if [[ $resolveOrder = hosts && -f $etcHosts ]]
  then
    $awk '                                           \
       BEGIN { entriesFound = 0 }                    \
       # Skip comment, empty and short lines.        \
       $1 ~ /^#/ || NF <= 1  { next }                \
       # Compare the inValue to each of the fields.  \
       { for ( i = 1;  i <= NF; i++ ) {              \
           if ( $i == "'$inValue'" ) {               \
             { print $2 " is " $1 }                  \
             { entriesFound += 1 }                   \
             { next }                                \
           }                                         \
           # Ignore in-line comments.                \
           if ( $i ~ /^#/ ) {                        \
             { break }                               \
           }                                         \
         }                                           \
         { next }                                    \
       }                                             \
       END {                                         \
         if ( entriesFound == 1 ) { exit 0 }         \
         if ( entriesFound == 0 ) { exit 1 }         \
         { exit 2 }                                  \
       }                                             \
    ' $etcHosts
    awkRc=$?

    if [[ $awkRc -eq 0 ]]
    then
      # Name successfully resolved using /etc/hosts.
      nameResolved=yes
      rc=0
    elif [[ $awkRc -eq 2 ]]
    then
      # There is more than one matching entry in /etc/hosts.
      # Give up - multiple names are not allowed.
      printErrorMsg 498 $mmcmd "$inValue ($etcHosts)"
      return 1
    else
      # Name not found in /etc/hosts but keep going.
      etcHostsChecked=yes
      rc=1
    fi  # end of if [[ $awkRc -eq 0 ]]
  fi  # end of if [[ $resolveOrder = hosts ]]


  # If the name is not resolved yet (because it is not in /etc/hosts
  # or because we have to start with the host command), try to resolve
  # the name using the Linux host command.
  if [[ $nameResolved = no ]]
  then
    # The output of the host command, and as a result the way we parse it,
    # depends on whether the input parameter is a hostname or an IP address.
    if [[ $inValue = +([0-9]).+([0-9]).+([0-9]).+([0-9])?(.) ]]
    then
      # We start with an IP address.  The host command output looks like this:
      #   122.145.53.9.IN-ADDR.ARPA domain name pointer esj.austin.ibm.com
      hostResult=$(LC_ALL=C /usr/bin/host -t a $inValue 2>$hostErrMsg)
      rc=$?
      if [[ $rc -eq 0 ]]
      then
        set -f ; set -- $hostResult ; set +f
        if [[ -z $5 || -n $6 || $3 = not && $4 = found* ]]
        then
          # Something is wrong.  Collect error information to be later
          # displayed to the user if the name cannot be resolved.
          # Note: Linux sends the 'not found' message to stdout and returns 0.
          #       This forces us to do the funny test for $3 and $4 above.

          # Unexpected output from the host command.
          printErrorMsg 499 $mmcmd $inValue 2> $hostErrMsg
          /usr/bin/host -t a $inValue >>$hostErrMsg 2>&1
          rc=1
        else
          # Things seem to have worked.
          print -- "${5%.} is $inValue"
          nameResolved=yes
        fi
      fi

    else
      # We start with a hostname.  The host command output looks like this:
      #   esj.austin.ibm.com has address 9.53.145.122
      # It is possible to have nickname line and more than one address line.
      LC_ALL=C /usr/bin/host -t a $inValue >$hostOutput 2>$hostErrMsg
      rc=$?
      if [[ $rc -eq 0 ]]
      then
        # Strip any nickname lines and eliminate duplicates
        hostResult=$($cat $hostOutput | $grep ' has address ' | $sort -u)
        set -f ; set -- $hostResult ; set +f
        if [[ -z $4 || -n $5 || $3 = not && $4 = found* ]]
        then
          # Something is wrong.  Collect error information to be later
          # displayed to the user if the name cannot be resolved.
          # Note: Linux sends the 'not found' message to stdout and returns 0.
          #       This forces us to do the funny test for $3 and $4 above.

          # Unexpected output from the host command.
          printErrorMsg 499 $mmcmd $inValue 2> $hostErrMsg
          /usr/bin/host -t a $inValue >>$hostErrMsg 2>&1

          # Cannot handle multiple interfaces for host $inValue
          [[ -n $5 ]] && printErrorMsg 498 $mmcmd "$inValue"
          rc=1
        else
          # Things seem to have worked.
          print -- "${1%.} is $4"
          nameResolved=yes
        fi
      fi
    fi  # end of if [[ $inValue = +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]]
  fi  # end of if [[ $nameResolved = no ]]


  # If the name is still not resolved, and we haven't tried it yet,
  # try resolving the name by looking up /etc/hosts.
  if [[ $nameResolved = no ]]
  then
    if [[ $etcHostsChecked = no ]]
    then
      $awk '                                           \
         BEGIN { entriesFound = 0 }                    \
         # Skip comment, empty and short lines.        \
         $1 ~ /^#/ || NF <= 1  { next }                \
         # Compare the inValue to each of the fields.  \
         { for ( i = 1;  i <= NF; i++ ) {              \
             if ( $i == "'$inValue'" ) {               \
               { print $2 " is " $1 }                  \
               { entriesFound += 1 }                   \
               { next }                                \
             }                                         \
             # Ignore in-line comments.                \
             if ( $i ~ /^#/ ) {                        \
               { break }                               \
             }                                         \
           }                                           \
           { next }                                    \
         }                                             \
         END {                                         \
           if ( entriesFound == 1 ) { exit 0 }         \
           if ( entriesFound == 0 ) { exit 1 }         \
           { exit 2 }                                  \
         }                                             \
      ' $etcHosts
      awkRc=$?
    fi  # end of if [[ $etcHostsChecked = no ]]

    if [[ $awkRc -eq 0 ]]
    then
      # Name successfully resolved using /etc/hosts.
      rc=0
    elif [[ $awkRc -eq 2 ]]
    then
      # There is more than one matching entry in /etc/hosts.
      printErrorMsg 498 $mmcmd "$inValue ($etcHosts)"
    elif [[ -s $hostErrMsg ]]
    then
      # Name not found in /etc/hosts. Show the error information
      # from the Linux host command above.
      $cat $hostErrMsg 1>&2
    else
      # Name not found in /etc/hosts and there is no other error information.
      printErrorMsg 500 $mmcmd $inValue
    fi  # end of if [[ $awkRc -eq 0 ]]
  fi  # end of if [[ $nameResolved = no ]]

  $rm -f $hostOutput $hostErrMsg
  return $rc

}  #-------------- end of function host_aixformat ------------------


##################################################################
#
# Function:  Remap ts return codes to OS-independent values.
#
# Input:     $1 - the return code to be mapped.
#
# Output:    the remapped input return code
#
# Returns:   always zero
#
# Example:
#   tstatus -m fsname
#   rc=$(remapRC $?)
#
##################################################################
function remapRC  # <returnCode>
{
  typeset sourceFile="mmglobfuncs.Linux.sh"
  [[ -n $DEBUG || -n $DEBUGremapRC ]] && set -x
  $mmTRACE_ENTER "$*"
  typeset rcIn=$1
  typeset rcOut

  case $rcIn in

    $MM_DaemonDown2      )  rcOut=$MM_DaemonDown ;;
    $MM_HostDown2        )  rcOut=$MM_HostDown ;;
    $MM_TimedOut2        )  rcOut=$MM_TimedOut ;;
    $MM_Remotefs2        )  rcOut=$MM_Remotefs ;;
    $MM_UnknownCluster2  )  rcOut=$MM_UnknownCluster ;;
    $MM_ConnectionReset2 )  rcOut=$MM_ConnectionReset ;;
    $MM_ConnAborted      )  rcOut=$MM_DaemonDown ;;

    *                    )  rcOut=$rcIn ;;

  esac  # end of case $rcIn in

  # Return the new value.
  print -- "$rcOut"
  return 0

}  #------- end of function remapRC --------------------

