#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r714 src/43haes/usr/sbin/cluster/utilities/cllsvgdata.sh 1.16 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2000,2011 
# 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 
# @(#)13	1.12 src/43haes/usr/sbin/cluster/utilities/cllsvgdata.sh, hacmp.utils, 53haes_r560 10/3/07 13:52:21
###############################################################################
#
#  Name:  main program
#
#  This program runs on individual nodes in the cluster. It does an 'lspv'
#  followed by a call to 'lvlstmajor'. All output goes to the screen - 
#  dsh/cspoc pick up this and concatenate into a single file.
#
#  Arguments:   -
#
#  Returns:     
#
################################################################################
# Set the ENV PATH variable
$dirname = `/usr/bin/dirname $0`;
chop($dirname);
$getpath_cmd = "$dirname/../utilities/cl_get_path all";
$path = `$getpath_cmd`;
$ENV{'PATH'} = "$path";

# Set the ENV ODMDIR variable
$HA_DIR = `cl_get_path`;
$odmdir = "/etc/$HA_DIR/objrepos";
$ENV{'ODMDIR'} = "$odmdir";

#-------------------------------------------------------------------------------
# Create Device Major and Volume Group Data hash tables here for later usage.
# We determine all VGs up front via 'lsvg' so gathering the device major numbers
# up front for all known VGs is a performance measure to prevent us from
# repeatedly querying the same information. The performance benefits vary,
# depending upon the specific system configurations, but makes for cleaner and
# more efficient code regardless.
#
# Physical volumes not assigned to a Volume Group are effectively inactive and
# will be tagged "None" below. Accordingly, we also obtain appropriate lsvg
# output for VG "None" as well as create an associated 0 device major.
#-----------------------------------------------------------------------------

%dev_major = ();
%vg_data = ();
$dev_major{"None"} = 0;
$vg_data{"None"} = `/usr/sbin/lsvg -L None 2>&1`;

$lsvg_out = `/usr/sbin/lsvg`;
foreach $vg (split(/\n/, $lsvg_out))
{
  $lsvg_output = `/usr/sbin/lsvg -L $vg 2>&1`;
  $vg_data{$vg} = $lsvg_output;

  if (!exists($dev_major{$vg}))
  {
    $dev_output = `/usr/bin/ls -al /dev/$vg`;
    if ($? == 0)
    {
      @dev_output_array = split(/\s+/, $dev_output);
      chop($dev_major{$vg} = $dev_output_array[4]);
    }
    else
    {
      # All VGs should have a device major number and this should be
      # unreachable!!
      # Directing the error to STDERR, to avoid interference with STDOUT messages.
      print STDERR "Error : **************\n";
      # Set the device major number to Error.
      $dev_major{$vg} = "Error";
    }
  }
}

#-------------------------------------------------------------------------------
# Get local pv data
#-------------------------------------------------------------------------------
$LOCAL="1" ;
$lspv_out = `/usr/es/sbin/cluster/utilities/cl_lspv`;
foreach $pv_line (split("\n", $lspv_out))
{
  ($cl_phydisk, $cl_pvid, $cl_vgname, $leftovers) = split(/\s+/, $pv_line, 4);

  # Get the device type for this device and skip it if it is a rpvclient
  # The RPV devices are being printed below so there is no need to print them
  # here.
  $dev_type = `/usr/sbin/lsdev -r type -l $cl_phydisk`;
  chop $dev_type;

  if ( $dev_type eq "rpvclient" )
  {
      next ;
  }

  # Get the size of the disk
  $dev_size=`/usr/sbin/bootinfo -s $cl_phydisk` ;
  chomp $dev_size;

  # Retrieve the device major number for the volume group.
  $cl_major_number = $dev_major{$cl_vgname};
  # Exclude the VG from the list, if major number is set to Error
  if ($cl_major_number eq "Error") {
        next;
  }

  # Parse previously retrieved VG status
  ($cl_concurrency, $cl_active, $cl_quorum, $cl_vg_type) = ck_vg_status($cl_vgname);


  print "$cl_phydisk:$cl_pvid:$cl_vgname:$cl_major_number:$cl_concurrency:$cl_active:$cl_quorum:$LOCAL:$cl_vg_type:$dev_size\n";
}

# Get the RPV site name
my $rpv_server_sitename = "";
if ( -x '/usr/sbin/rpvsitename' )
{
    $rpv_server_sitename = `/usr/sbin/rpvsitename` ;
    chop $rpv_server_sitename;
}

if (-x '/usr/sbin/lsrpvclient')
{
  my $local_addresses;
  my $server_addresses;

  #-----------------------------------------------------------------------------
  # Get RPV data
  #-----------------------------------------------------------------------------
  $LOCAL="0";
  $lsrpvclient_out = `/usr/sbin/lsrpvclient`;
  foreach $rpv_line (split("\n", $lsrpvclient_out))
  {
    $rpv_line =~ s/^\s+//;
    ($cl_phydisk, $cl_pvid, $leftovers) = split(/\s+/, $rpv_line, 3);

    $cl_vgname = `/usr/bin/odmget -q"value LIKE $cl_pvid*" CuAt | grep -w name | grep -v hdisk | cut -d'"' -f2`;
    if ($cl_vgname eq "")
    {
      # Physical Volume is not allocated to a VG
      $cl_vgname = "None";
    }
    else
    {
      # Strip '\n' from ODM retrieved VG name
      chomp($cl_vgname);
    }

    $cl_major_number = $dev_major{$cl_vgname};
    # Exclude the VG from the list, if major number is set to Error
    if ($cl_major_number eq "Error") {
        next;
    }

    ($cl_concurrency, $cl_active, $cl_quorum, $cl_vg_type) = ck_vg_status($cl_vgname);

    # Get the size of the disk
    $dev_size=`/usr/sbin/bootinfo -s $cl_phydisk` ;
    chomp $dev_size;

    ( $local_addresses, $server_addresses ) = get_ip_addresses_for_rpvclient( $cl_phydisk );

    # Output the results for RPV
    if ($cl_active eq "active")
    {
      print "$cl_phydisk:$cl_pvid:$cl_vgname:$cl_active:$cl_major_number:$cl_concurrency:$cl_active:$cl_quorum:$LOCAL:$cl_vg_type:$dev_size:$rpv_server_sitename:$local_addresses:$server_addresses\n";
    }
    else
    {
      print "$cl_phydisk:$cl_pvid:$cl_vgname:$cl_major_number:$cl_concurrency:$cl_active:$cl_quorum:$LOCAL:$cl_vg_type:$dev_size:$rpv_server_sitename:$local_addresses:$server_addresses\n";
    }
  }
}

# Get RPV server information
if (-x '/usr/sbin/lsrpvserver')
{
  my $cl_rpv_devname;
  my $lsrpvserver_out;
  my $cl_backing_dev;

  #-----------------------------------------------------------------------------
  # Get RPV data
  #-----------------------------------------------------------------------------
  $lsrpvserver_out = `/usr/sbin/lsrpvserver` ;
  foreach $rpv_line (split("\n", $lsrpvserver_out))
  {
    $rpv_line =~ s/^\s+//;
    ($cl_rpv_devname, $cl_pvid, $cl_backing_dev) = split(/\s+/, $rpv_line, 3);

    # remove white-spaces
    $cl_backing_dev =~ s/\s//g ;

    # Get client IP addresses associated with this RPV server
    $client_addresses = get_client_addr_for_rpvserver( $cl_rpv_devname );

    print "$cl_rpv_devname:$cl_pvid:$cl_backing_dev";
    print ":::::0:::$rpv_server_sitename:$client_addresses\n";
  }
}

$freemajor = `/usr/sbin/lvlstmajor`;
print "FREEMAJORS:$freemajor";

$migfile1 = "/usr/sbin/cluster/.mig";
$migfile2 = "/usr/es/sbin/cluster/.mig";

if (-e $migfile1)
{
   print "NxN_in_progress\n";
}
elsif (-e $migfile2)
{
   print "NxN_in_progress\n";
}


# this is the end of the main program ....

#===============================================================================
# Name: get_client_addr_for_rpvserver
#
# Returns the list of IP addresses that are listed as the "clients" for a RPV
# server.
#
# Arguments:    $rpv_devname (RPV server's device name)
#
# Returns:      list of IP addresses (delimited by ",")
#           
#===============================================================================
sub get_client_addr_for_rpvserver
{
    my ($rpv_server_dev) = @_;
    my $client_addr_list;
    my $output;
    my @dev_attrs;
    my $i;
    $output = ` /usr/sbin/lsattr -E -l $rpv_server_dev -O | tail -1 `;

    @dev_attrs = split(/:/, $output);

    #===========================================================================
    #  RPV server attributes are implemented in a weird manner. Instead of 
    #  using a fixed-num of attributes, the number of attributes returned for a
    #  RPV server device name (by lsattr command) would vary depending on the
    #  number of client IP addresses that are associated with the RPV server
    #  device.
    #===========================================================================
    $client_addr_list = "@dev_attrs[1..($#dev_attrs - 1)]";
    $client_addr_list =~ s/\s/,/g ;

    return $client_addr_list;
}

#===============================================================================
# Name: get_ip_addresses_for_rpvclient
#
# Returns the local and server addresses associated with a RPV client disk.
# server.
#
# Arguments:    $rpv_devname (RPV client device name)
#
# Returns:      list of Local IP addresses (delimited by ",")
#               list of Server IP addresses (delimited by ",")
#           
#===============================================================================
sub get_ip_addresses_for_rpvclient
{
    my ($rpv_client_dev) = @_;

    my $output;

    $output = `/usr/sbin/lsattr -E -O -l $rpv_client_dev | tail -1 `;
    @dev_attrs = split(/:/, $output);

    $local_addr = "@dev_attrs[1..4]";
    $local_addr =~ s/\s/,/g ;

    $server_addr = "@dev_attrs[6..9]";
    chomp ($server_addr); # get rid of trailing white space
    $server_addr =~ s/\s/,/g ;

    return ("$local_addr", "$server_addr" );
}

###############################################################################
#
#  Name:  ck_vg_status
#
#  Finds whether or not a VG is concurrent-capable and what state it's in.
#
#  Arguments:  $vg    volume group to check
#
#  Returns:    @retval  2-element list.
#                       1st element contains: 0 for concurrent-capable.
#                                             1 for not concurrent-capable.
#
#                       2nd element contains: active, inactive, or concurrent.
#
 ###############################################################################
sub ck_vg_status {

   my($vg) = $_[0];

   # Initialize "local" variables to null.
   # ---------------------------------------
   my ($conc_cap_status, $activity_status,
       $tmprawout, $junk1, $junk2, $cl_quorum) = "";

   my (@vgmode) = ();
   my (@lsvgout) = ();
   my (@vgmodeline) = ();
   my (@retval) = ();

   my ($vg_type) = "Unknown" ;
   my (@max_pvs_line) = ();
   my ($max_pvs) = "";

   $tmprawout = $vg_data{$vg};
   @lsvgout = split('\n', $tmprawout);

   # -----------------------------------------------------------------
   # if VG is not defined.  (i.e. if it's "None" in lspv output.)
   # bail now.
   # -----------------------------------------------------------------
   if ($lsvgout[0] =~ /^0516-306\b/ ) {
      $activity_status = "inactive";
      $conc_cap_status = "0";
      $cl_quorum = "0";
      @retval = ($conc_cap_status, $activity_status, $cl_quorum, $vg_type);
      return @retval;
   }

   # if VG is varied off...
   # ------------------------
   if ($lsvgout[0] =~ /^0516-010\b/ ) {
      $activity_status = "inactive";
   }
   # elsif other error(s), bail now.
   # ---------------------------------
   elsif ($lsvgout[0] =~ /^[0-9]{4}-[0-9]{3}\b/ ) {
      $thisnode = `hostname`;
      chop($thisnode);
      print "$thisnode: ";
      foreach (@lsvgout) {print "$_\n";}

      # Do we really want to set $activity_status = "inactive" for this
      # case?  Will do so for now.

      $activity_status = "inactive";
      $conc_cap_status = "0";
      $cl_quorum = "0";
      @retval = ($conc_cap_status, $activity_status, $cl_quorum, $vg_type);
      return @retval;
   }
   # otherwise we'll assume it to be active.
   # -----------------------------------------
   else {
      $activity_status = "active";
      # Note: If the VG is varied on concurrently, this will get
      #       overidden to "concurrent" in some code below.
   }

   $tmprawout = `/usr/bin/odmget -q "name = $vg AND attribute = quorum AND value = n" CuAt`;
   if ($tmprawout eq "") { $cl_quorum = "1"; }
   else                  { $cl_quorum = "0"; }

   # ************************************************************************
   # #  Code for  "inactive"  VG starts here.
   # ************************************************************************

   if ($activity_status eq "inactive") {
      # -------------------------------------------------------
      # Use odmget to determine if it's concurrent-capable.
      # -------------------------------------------------------
      $tmprawout = "";
      $tmprawout = `/usr/bin/odmget -q "name = $vg AND attribute = conc_capable AND value = y" CuAt`;

      if ($tmprawout eq "") { $conc_cap_status = "0"; }
      else                  { $conc_cap_status = "1"; }
   }

   # ************************************************************************
   # #  Code for  "active"  VG starts here.
   # ************************************************************************

   if ($activity_status eq "active") {
      # -------------------------------------------------------
      # If we're still here, we KNOW it's active.
      # The code for this block just parses the lsvg output.
      # No more system calls are needed.
      # -------------------------------------------------------

      @vgmodeline = grep /VG Mode:/, @lsvgout;

      if (scalar(@vgmodeline) < 1) {
         # If it's not even "Concurrent:  Capable",
         # there will be no "VG Mode: " line.
         # ------------------------------------------
         $conc_cap_status = "0";
      }
      # else we know it's concurrent-capable.  But is it concurrent?
      # --------------------------------------------------------------
      else {
         $conc_cap_status = "1";
         @vgmode = split(':', $vgmodeline[0]);
         if ($vgmode[1] !~ /Non-Concurrent/) {
            if ($vgmode[1] =~ /Concurrent/) {
               $activity_status = "concurrent";
            }
         }
      }

      # For all active VGs, we return the type of the VG. That is, if the VG is
      # "Original", "Big" or "Scalable" type.
      # 
      # lsvg -L <vgname> command returnt the information in the following
      # format.
      # MAX PPs per PV:     1016                     MAX PVs:        32
      
      @max_pvs_line = grep /MAX PVs:/, @lsvgout;
      @max_pvs_line = split(':', $max_pvs_line[0]);

      $max_pvs = $max_pvs_line[2];

      # Trim leading white-space characters
      $max_pvs =~ s/^\s+//g;
      if ( $max_pvs == "1024" )
      {
          $vg_type = "Scalable";
      }
      elsif ( $max_pvs == "32" )
      {
          $vg_type = "Original" ;
      }
      elsif ( $max_pvs == "128" )
      {
          $vg_type = "Big" ;
      }
   }  # end:  $activity_status eq "active" block.

   # All processing done, put the results into an array and return them.
   # --------------------------
   @retval = ($conc_cap_status, $activity_status, $cl_quorum, $vg_type );
   return @retval;

}  # end of ck_vg_status()
