#
# Copyright (c) 2001, 2009, Oracle and/or its affiliates.All rights reserved. 
#
#  $Id: sRawmetrics.pm /stpl_db_11.2_aix.ppc64/1 2009/02/25 23:08:53 rajverma Exp $
#
#
# NAME
#  sRawmetrics.pm
#
# DESC
# AIX storage info
#
#
# FUNCTIONS
#
#
# NOTES
#
#
# MODIFIED      (MM/DD/YY)
# rajverma 	02/23/09 - Add config file changes.
# sejain  10/03/07 - bug-6398412 : changing call to /usr/sysv/bin/df via nmhs
# svrrao  09/13/07 - Porting merge for bug fix 6002107, hang with df -P
# sejain  06/13/07 - bug-6111302 : lsattr getting picked from the wrong path
# sejain  02/01/07 - bug:5738360 - fixing hard coded path for lsdev & lsvg
# nsharma	04/07/06 - Ignore offline volume groups
# ssreenat	05/10/05 - Disk Metrics implementation
# ssreenat 	08/08/05 - Added filesystems,lvm metrics
# ssreenat      11/08/05 - Created
#
#
#

# Initialize the environment variables at compile time
BEGIN
{
	$ENV{PATH} = "$ENV{ORACLE_HOME}/bin:$ENV{ORACLE_HOME}/emagent/bin:/etc:/usr/sbin:/usr/bin" 
}

package storage::sRawmetrics;

require v5.6.1;

use strict;
use warnings;
use locale;
use File::Basename;
use File::Spec::Functions;
use File::Path;
use Cwd;
use URI::file;
use storage::sUtilities;
use constant NIL => '';

#------------------------------------------------
# Global package variable to hold sub name

our $AUTOLOAD;

#------------------------------------------------
# subs declared
#-----------------------------------------------
sub get_disk_metrics;
sub get_filesystem_metrics ( );
sub get_virtualization_layer_metrics();
sub lvmMetrics();
sub runShowmount ( $ );

#-------------------------------------------------
# Variables in package scope
#------------------------------------------------
# Variable for logical to physical map for all disk slices

#------------------------------------------------------------------------------------
# Static Configuration
#------------------------------------------------------------------------------------


#--------------------------------------------------------
# Filesystem metric specific configuration
#--------------------------------------------------------

$storage::Register::config{key}{default}=
"serial_no fc_id";

# df shows swap filesystems only as "swap". `swapinfo` shows a list of
# filesystems that are used for swap space.
$storage::Register::config{filesystem}{command}{swap}  = "lsps -a";

# NFS equivalent filetypes
$storage::Register::config{filesystem}{nfsfstypes} = "nfs3";

# Filesystems to skip, need not instrument metrics for these filesystems
$storage::Register::config{filesystem}{skipfilesystems} =
  "mvfs|procfs|fd|mntfs|tmpfs|cachefs|shm|cdfs|hsfs|lofs|afs";


#-----------------------------------------------------------------------------------------
# FUNCTION : get_disk_metrics
#
# DESC
# return a pointer to a array of references to hashes for all volume manager metrics
#
# ARGUMENTS
#
#-----------------------------------------------------------------------------------------
sub get_disk_metrics
{
	my @diskdevices;
	my %disklist;    # Hash of disks and partitions
	my %disks;       # Hash of disks
        my $major;
        my $minor;
        my $name;
        my $vendor;
        my $product;
        my $size;
        my $sizeb;
        my $rev;
	my $state;
	my $serial_no;
	my $bus;
	my $block_name;
	my $char_name;
	my $driver;
	my $desc;
	my $pdevname;

	 my %empartition ; # Hash for the empartitions.
        my @em_rows;

        my  @partitions =  storage::Utilities::getConfig("Disks");
        my  @cnt    =  storage::Utilities::getConfig("Collection Size");
        # Retrieve the maximum number of disks to be monitorerd from the config file
        my $temp;
        my $cnt_obj;
        my $dsk_cnt = 100;
        for my $res (@cnt)
        {
            ($temp , $cnt_obj) = split(/=/,$res) ;
            if ($temp =~ /Disk/i)
            {
                $dsk_cnt=$cnt_obj;
                last;
            }
        }

         foreach my $ptn (@partitions)
         {
            chomp $ptn;
              # Skip Blank Lines
            next unless $ptn;
            $ptn =~ s/^\s+|\s+$//g;
            $empartition{$ptn} = $ptn;
         }

        my @disk_rows = run_system_command("/etc/lsdev -Cc disk -F'name;status;description'");


    # If the number of disks being monitored is greated than Disk count then
    # display warning message and request the user to edit the file.
    if (( $#disk_rows >= $dsk_cnt) && !(keys(%empartition) ))
     {

        storage::Utilities::setConfig("Disks","0");
        storage::Register::log_error_message("The number of Disks to be monitored is larger than $dsk_cnt. Please add the disks to be monitored in the config file  emagent_storage.config");

     }
    else
     {
        storage::Utilities::setConfig("Disks","1");

     }

# AIX doesnt have physical partitions on disk. They use LVM to partition.So we are not instrumenting physical partition info

# Get the lists of disks with status and description
         for my $disk_row (@disk_rows)
	{
		 last if (@diskdevices == $dsk_cnt);

                chomp $disk_row;
                next unless $disk_row;
                $disk_row =~ s/^\s+|\s+$//g;
		$major = NIL;
		$serial_no = NIL;
                $name = NIL;
                $minor = NIL;
                $vendor = NIL;
                $product = NIL;
                $size = NIL;
                $sizeb = NIL;
                $rev = NIL;
		$bus = NIL;
		$block_name = NIL;
		$char_name = NIL;
		$driver = NIL;
		$desc = NIL;
		$pdevname = NIL;
		my $char_prefix = "/dev/r";
		my %devinfo;	

                my @col=split /;/,$disk_row;
                $name = $col[0];
		$state = $col[1];
		$desc = $col[2];
		$block_name = "/dev/$name";
		$char_name="$char_prefix$name";

 		next  if( (keys( %empartition ) > 0) && ($empartition{$name} ne $name) );

		# Instrument only if the disk is available
		if ($state ne "Available")
		{
			next;
		}
		# Get the major and minor number of the disk
		for my $istat_row (run_system_command("istat $block_name"))
		{
			chomp $istat_row;		
			next unless $istat_row;
			$istat_row =~ s/^\s+|\s+$//g;	
			if ($istat_row =~ /Major/i)
			{
				my @col = split /\s+/, $istat_row;
				$major = $col[2];	
				$minor = $col[5];
				last;
			}
		}
		# Instrument the bus type/driver info
		if ($disk_row =~ /SCSI/)
		{
			$bus = "SCSI";
			$driver = "scdisk";
		}	
		if ($disk_row =~ /SSA/)
		{
			my $connwhere_shad_value;
			my $conn_flag=0;
			$bus = "SSA";	
			$driver = "ssadisk";
			$connwhere_shad_value = NIL;
			$pdevname = NIL;
			for my $ssa_row (run_system_command("odmget -qname=$name CuAt"))	
			{
				if ($ssa_row =~ /connwhere_shad/)
				{
					$conn_flag = 1;	
					next;	
				}
				if ($conn_flag eq 1)
				{
					$conn_flag = 0;
					if ($ssa_row =~ /value/)
					{
						my $ignore;
						($ignore, $connwhere_shad_value) = split("=", $ssa_row);
						$connwhere_shad_value =~ s/"//g;
						$connwhere_shad_value = trim($connwhere_shad_value);
						last;
					}
				}
				$conn_flag = 0;
			}
			if ($connwhere_shad_value ne NIL)
			{
				for my $ssa_row (run_system_command("odmget -qvalue=$connwhere_shad_value CuAt"))
				{
					if ($ssa_row =~ /pdisk/)				
					{
						my $ignore;
						($ignore, $pdevname) = split("=",$ssa_row);
						$pdevname =~ s/"//g;	
						$pdevname = trim($pdevname);
						last;
					}
				}
			}
		}
		# This corresponds to fibre Channel Disk Array device
		if ($disk_row =~ /Disk Array Device/)
		{
			my $dac;
			$bus = "FAStT";
			$driver = "fcd";
			my $model = $desc;			
			$model =~ s/ .*//;	
                        $pdevname = run_system_command("lsdev -C | grep $model| grep dac | tail -1");
                        $pdevname =~ s/ .*//;
			for ($dac = run_system_command("lsdev -C | grep $model| grep dac"))
			{
				my @col=split /\s+/,$dac;
				if ($col[1] =~ /Available/)
				{	
					$pdevname = $col[0];
					last;	
				}
			}
		}

		if ($driver)
		{
			$devinfo{driver} = $driver;
		}
		$devinfo{name} = $block_name;
		$devinfo{major} = $major;
		$devinfo{minor} = $minor;
		$devinfo{nameinstance} = $name;
		$devinfo{type} = 'DISK';
		$devinfo{partition} = 0;
		$devinfo{filetype} = get_file_type($devinfo{name});
		$devinfo{char_name} = $char_name;
		
		# Vendor Information retrieval
		my $cmd;

		if (($bus eq "SSA" || $bus eq "FAStT") && $pdevname ne '')		
		{
			$cmd = "lscfg -vpl $pdevname";
		}
		else
		{
			$cmd = "lscfg -vpl $name";
		}
# Use the lscfg command to get the device specific info , vendor, product, ROS level and Serial Number (vendor specific)
# The serial number  is the only unique tag for each disk 

		for my $diskinfo (run_system_command("$cmd"))
		{
			chomp($diskinfo);
			next unless $diskinfo;	
			$diskinfo =~ s/^\s+|\s+$//g;
			if ($diskinfo =~ /Manufacturer/)
			{
				$diskinfo =~ s/.*\.//g;
				$vendor = $diskinfo;
				next;
			}
			if ($diskinfo =~ /Machine Type and Model/)
			{
				$diskinfo =~ s/.*\.//g;
				$product = $diskinfo;
				next;	
			}	
			if ($diskinfo =~ /ROS Level and ID/)
			{
				$diskinfo =~ s/.*\.//g;
				$rev = $diskinfo;	
				next;
			}
			if ($diskinfo =~ /Serial Number/)
			{
				$diskinfo =~ s/.*\.//g;
				$serial_no = $diskinfo;
				next;
			}
		}
		if ($vendor ne '')
		{
			$devinfo{vendor} = $vendor;		
		}
		if ($product ne '')
		{
			$devinfo{product} = $product;
		}
		if ($rev ne '')
		{
			$devinfo{rev_level} = $rev;
		}
		if ($serial_no ne '')
		{
			$devinfo{serial_no} = $serial_no;
		}
		else
		{
			# For FAStT type, we dont have the serial number instead the scsi id and LUN type 
			if ($bus eq "FAStT")	
			{
				my $lun_id= NIL;
				my $scsi_id= NIL;
				for my $lsattr_row (run_system_command("lsattr -El $name"))
				{
				        chomp($lsattr_row);
                        		next unless $lsattr_row;
                        		$lsattr_row =~ s/^\s+|\s+$//g;
					if ($lsattr_row =~ /lun_id/)
					{
						my @col = split /\s+/,$lsattr_row;
						$lun_id = $col[1];
						next;
					}
					if ($lsattr_row =~ /scsi_id/)
					{
						my @col = split /\s+/,$lsattr_row;
						$scsi_id = $col[1];
						next;
					}
				}
				$devinfo{fc_id} = "$lun_id-$scsi_id";
			}
		}
		# Calculate Size of a disk. This returns in MB
		$size = run_system_command("nmhs get_disk_size $name");		
		if ($size =~ /error::/)
		{
			warn "DEBUG: Unable to get device specific info for $name\n";
			$size = 0;
		}
		$sizeb = $size *1024 * 1024;	
		$devinfo{sizeb} = $sizeb;
		$devinfo{usedb} = $sizeb;
		$devinfo{freeb} = 0;

		$disks{$devinfo{nameinstance}} = \%devinfo
			if $devinfo{type} eq 'DISK';

                # Keep an list indexed on nameinstance and type
                push @{$disklist{$devinfo{type}}{$devinfo{nameinstance}}}, \%devinfo;
                push @diskdevices, \%devinfo;
	}

	generateKeys( \%disks )
	or warn "Failed to generate uniquely identifying disk_keys\n"
        and return;

        #----------------------------------------------
        # Create slice keys and validate null fields
        # for disk records
        #----------------------------------------------
        for my $dref ( values %disks )
        {
                # Generate a slicekey for the disk
                $dref->{slice_key}  =  "$dref->{disk_key}";
        }

        for my $diskref ( values %disks )
        {

                # This is an error that should be handled
                warn "No nameinstance for disk $diskref->{name}\n"
                and next
                unless $diskref->{nameinstance};

                #----------------------------------------------------------------
                # if there is more than one disk for the name instance copy the
                # common fields
                #----------------------------------------------------------------
                for my $dref( @{$disklist{DISK}{$diskref->{nameinstance}}} )
                {

                        # skip if its the same record as in diskref
                        next if $dref eq $diskref;

                        # Copy the common fields between disk record and current record
                        for ( @{$storage::Register::config{diskfields}{DISK}} )
                        {
                                $dref->{$_} = $diskref->{$_} if $diskref->{$_};
                        }

                }
        }

        #----------------------------------------------
        # Copy the required fields for all records
        #----------------------------------------------
        for my $entity_ref ( @diskdevices )
        {

                $entity_ref->{key_value} = $entity_ref->{slice_key};

                $entity_ref->{storage_layer} = 'OS_DISK';

                $entity_ref->{entity_type} = 'Disk Partition'
                if $entity_ref->{type} =~ /PARTITION/i; ;

                $entity_ref->{entity_type} = 'Disk'
                if $entity_ref->{type} =~ /^DISK$/i;

                $entity_ref->{os_identifier} = $entity_ref->{name};

                $entity_ref->{global_unique_id} = $entity_ref->{disk_key}
                if $entity_ref->{type} =~ /^DISK$/i;

        }
	return \@diskdevices;
}

#-----------------------------------------------------------------------------------------
# FUNCTION : get_virtualization_layer_metrics
#
# DESC
# return a array of hashes for all storage virtualization layers deployed on the host
# Logical volume manager, Veritas VM etc
#
# ARGUMENTS
#
#-----------------------------------------------------------------------------------------
sub get_virtualization_layer_metrics ( )
{
   my @results;

   for my $function_pointer ( \&lvmMetrics, \&get_veritas_volume_metrics)
   {

     my $results_ref = $function_pointer->();

     next unless $results_ref and @{$results_ref};

     push @results,@{$results_ref};

   }

   return [()] unless @results;

   return \@results;
}

#-----------------------------------------------------------------------------------------
# FUNCTION : lvmMetrics
#
# DESC
# Returns an array with Hash Tables of each LVM Volume Logical Volumes
#
# ARGUMENTS
# none
#-----------------------------------------------------------------------------------------
sub lvmMetrics()
{
	my @aixlvmarray;
	my %emvolumes ; # Hash for the volumes form emagent_storage.config.
        my @volumes ;
        @volumes  =  storage::Utilities::getConfig("Volumes");
        my @cnt  =  storage::Utilities::getConfig("Collection Size");

        #Retrieve the maximum number of volume groups to be monitored
        my $temp;
        my $cnt_obj;
        my $vol_cnt = 10;
        for my $res (@cnt)
        {
           ($temp , $cnt_obj) = split(/=/,$res) ;
           if ($temp =~ /Volume/i)
           {
                $vol_cnt=$cnt_obj;
                last;
           }
        }

        foreach my $vol (@volumes)
        {
            chomp $vol;
              # Skip Blank Lines
            next unless $vol;
            $vol =~ s/^\s+|\s+$//g;
            $emvolumes{$vol} = $vol;
         }

	        my @volume_rows = run_system_command("lsvg -o");


        # If the number of Volumes  being monitored is greater than Volumes count then
        # display warning message and request the user to edit the file.

        if (( $#volume_rows >= $vol_cnt)  && !(keys(%emvolumes) ))
        {

         storage::Utilities::setConfig("Volumes","0");
         storage::Register::log_error_message("The number of Volume groups to be monitored is larger than $vol_cnt. Please add the Volume groups to be monitored in the config file  emagent_storage.config");
        }
        else
        {
           storage::Utilities::setConfig("Volumes","1");
        }

        my $vg_proc=0;

        warn "DEBUG: Unable to find executable /usr/sbin/lsvg for AIX LVM \n" and return unless -e '/usr/sbin/lsvg';
	for (@volume_rows)
	 {
		last if ($vg_proc == $vol_cnt);

		chomp;
		
		s/^\s+|\s+$//g;
		
		next unless $_;
		
		my %volume_group;
		( $volume_group{name} ) = /(\S+)$/g;
		
		 # Process only the  volumes in the config file.
                 next  if( (keys( %emvolumes ) > 0) && ($emvolumes{$volume_group{name}} ne $volume_group{name} ) );

		$volume_group{vendor} = 'AIX';
		$volume_group{product} = 'LVM';
		$volume_group{storage_layer} = 'VOLUME_MANAGER';
		$volume_group{entity_type} = 'Volume Group';
		$volume_group{key_value} = "aix_lvm_vg_$volume_group{name}";
		$volume_group{sizeb} = 0;
   		# all entities belonging to the volume
    		push @{$volume_group{child_entity_criteria}} ,
    		{
     			volume_group => $volume_group{name},
     			product => $volume_group{product}
    		};
		push @aixlvmarray,\%volume_group;
		 $vg_proc++;
	
		# Instrument Physical Volume
		for (run_system_command("lsvg -p $volume_group{name}"))	
		{
			chomp;
			s/^\s+|\s+$//g;
			my % physical_volume;
			next if /^(PV_NAME|$volume_group{name})/i;
			my @columns = split;
			$physical_volume{name} = $columns[0];
			$physical_volume{status} = $columns[1];
			$physical_volume{status} = uc($physical_volume{status});
			$physical_volume{petotal} = $columns[2];	
			$physical_volume{pefree} = $columns[3];
			$physical_volume{peallocated} = $physical_volume{petotal} - $physical_volume{pefree};
			$physical_volume{vendor} = 'AIX';
			$physical_volume{product} = 'LVM';
			$physical_volume{storage_layer} = 'VOLUME_MANAGER';
			$physical_volume{entity_type} = 'Physical Volume';
			$physical_volume{os_identifier} = "/dev/$physical_volume{name}";
			$physical_volume{volume_group} = $volume_group{name};
			$physical_volume{key_value} = "aix_lvm_pv_$volume_group{name}_$physical_volume{name}";
 		        # physical entities on the physical volume
		        push @{$physical_volume{parent_entity_criteria}},
      			{
       				entity_type  => 'Physical Entity',
       				volume_group => $volume_group{name} ,
       				product => $volume_group{product},
       				disk_name    => $physical_volume{name}
      			};
			for my $pvrecord (run_system_command("lspv $physical_volume{name}"))
                        {
                            chomp $pvrecord;
                            $pvrecord =~ s/^\s+|\s+$//g;
                            next unless $pvrecord;
                            if ($pvrecord =~ /PP\sSIZE/i)
                            {
                                my @col=split /\s+/,$pvrecord;
                                $physical_volume{ppsize} = $col[2];
                                if ($col[3] =~ /megabyte/i)
                                {
                                        $physical_volume{ppsize} *= 1048576 ;
                                }
                                if ($col[3] =~ /kilobyte|kb/i)
                                {
                                        $physical_volume{ppsize} *= 1024;
                                }
                            }
                        }
			my $pe_count = 0;
			# Disk slice instrumentation	
			# Physical Entity
                        for my $dsrecord (run_system_command("lspv -l $physical_volume{name}"))
                        {
                                my %disk_slice;
                                chomp $dsrecord;
                                $dsrecord =~ s/^\s+|\s+$//g;
                                next unless $dsrecord;
                                next if $dsrecord =~ /^(LV\sNAME|$physical_volume{name})/i;
                                my @col=split /\s+/,$dsrecord;
                                $pe_count++;
				$disk_slice{sizeb} = 0;
                                $disk_slice{start} = $pe_count;
                                $disk_slice{volume_name} = "/dev/$col[0]";
                                $disk_slice{pe} = $col[2];
                                $disk_slice{le} = $col[1];
                                $disk_slice{sizeb} = $disk_slice{pe} * $physical_volume{ppsize};
                                $disk_slice{disk_name} = $physical_volume{name};
				$disk_slice{vendor} = 'AIX';
				$disk_slice{product} = 'LVM';
				$disk_slice{storage_layer} = 'VOLUME_MANAGER';
				$disk_slice{entity_type} = 'Physical Entity';
				$disk_slice{status} = $physical_volume{status};
				$disk_slice{key_value} = "aix_lvm_pe_$volume_group{name}_$physical_volume{name}_$disk_slice{start}";
				$disk_slice{volume_group} = $volume_group{name};
				$disk_slice{name} = "$volume_group{name}_$physical_volume{name}_$disk_slice{start}";	
		                # Physical volumes used by the physical entity
          			push @{$disk_slice{child_entity_criteria}},
          			{
           				entity_type => 'Physical Volume',
           				volume_group => $volume_group{name},
           				product => $volume_group{product},
           				name=> $disk_slice{disk_name}
          			};
	    	                # Volumes using the physical entity
          			push @{$disk_slice{parent_entity_criteria}},
          			{
           				entity_type => 'Volume',
           				volume_group => $volume_group{name},
           				product => $volume_group{product},
           				os_identifier => $disk_slice{volume_name}
          			};
				push @aixlvmarray,\%disk_slice;
			}
			$physical_volume{sizeb} = $physical_volume{petotal} * $physical_volume{ppsize};	
			push @aixlvmarray, \%physical_volume;
			# Update the size of the volume group as sum of all disks
 			$volume_group{sizeb} += $physical_volume{sizeb}
       			if $physical_volume{sizeb};
		}
		
		# Instrument Logical volume belonging to the  Volume group
		for (run_system_command("lsvg -l $volume_group{name}")) 	
		{
			chomp;
			s/^\s+|\s+$//g;
			my %logical_volume;
			next if /^(LV\sNAME|$volume_group{name})/i;
			my @columns = split;	
			$logical_volume{vendor} = 'AIX';	
			$logical_volume{product} = 'LVM';
			$logical_volume{storage_layer} = 'VOLUME_MANAGER';
			$logical_volume{entity_type} = 'Logical Volume';
			$logical_volume{name} = $columns[0];
			$logical_volume{os_identifier} = "/dev/$logical_volume{name}";	
			$logical_volume{volume_group} = $volume_group{name};
			$logical_volume{key_value} = "aix_lvm_v_$volume_group{name}_$logical_volume{name}";
			$logical_volume{status} = $columns[5];		
			
			for my $lvrecord (run_system_command("lslv $logical_volume{name}"))
			{
    			    chomp $lvrecord;
        		    $lvrecord =~ s/^\s+|\s+$//g;
        		    next unless $lvrecord;
			    if ( $lvrecord =~ /PERMISSION/i)
		            {	
				my @col=split /\s+/,$lvrecord;	
				if ($col[4] =~ /write/i)
				{
					$logical_volume{access} = "READ_WRITE";
				}	
				else
				{
					$logical_volume{access} = "READ";
				}
			    }
			    if ( $lvrecord =~ /STRIPE\sSIZE/i)
			    {	
				
				my @col=split /\s+/,$lvrecord;	
				$logical_volume{configuration} = "stripes - $col[2]";
			    }
				
			    if ($lvrecord =~ /^LPs:/) 
			    {
				if ($lvrecord =~ /PPs:/)
				{
					my @col=split /\s+/,$lvrecord;
					$logical_volume{pps} = $col[3];	
				}
			    }
			    if ($lvrecord =~ /PP\sSIZE/i)
			    {
				my @col=split /\s+/,$lvrecord;
				$logical_volume{ppsize} = $col[5];	
				if ($col[6] =~ /megabyte/i)
				{
					$logical_volume{ppsize} *= 1048576 ;
				}
				if ($col[6] =~ /kilobyte|kb/i)
				{
					$logical_volume{ppsize} *= 1024;
				}
			    }
			}
			$logical_volume{sizeb} = $logical_volume{ppsize} * $logical_volume{pps}
			if $logical_volume{ppsize} and $logical_volume{pps};
			
			$logical_volume{sizeb} = 0 
			unless $logical_volume{sizeb};

			$logical_volume{configuration} = 'CONCAT'
       			unless $logical_volume{configuration};
			if ($logical_volume{status} =~ /open/i)
			{
				$logical_volume{status} = "OPENED";
				$logical_volume{status} = "$logical_volume{status}_$logical_volume{access}" if ($logical_volume{access});
			}
			else
			{
				$logical_volume{status} = "CLOSED";		
			}
		        # Physical entities used by the volume
      		      	push @{$logical_volume{child_entity_criteria}},
      			{
			       volume_group => $volume_group{name},
			       product => $volume_group{product},
			       entity_type => 'Physical Entity',
			       volume_name => $logical_volume{os_identifier}
      			};
			push @aixlvmarray,\%logical_volume;
		}
	}
	return \@aixlvmarray;
}


#------------------------------------------------------------------------------
# FUNCTION : getVolumeMetrics
#
# DESC
# return a array of hashes for all volume manager metrics
#
# ARGUMENTS
#
#-------------------------------------------------------------------------------
sub get_veritas_volume_metrics ( )
{
	# Not yet implemented for HPUX
        # It is a dummy function as of now
	return ;
}

#------------------------------------------------------------------------------------
# FUNCTION : get_filesystem_metrics
#
#
# DESC
# Returns a array of hashes of filesystem metrics
#
# ARGUMENTS:
#
#
#-----------------------------------------------------------------------------
sub get_filesystem_metrics ( )
{
        return \@storage::Register::filesystemarray
          if @storage::Register::filesystemarray;

        my %fsarray;
	
	my %emfiles; # Hash for the files.
        my @filesys ;

        @filesys =  storage::Utilities::getConfig("FileSystems");
        my @cnt =  storage::Utilities::getConfig("Collection Size");
        # Get the Filesystem limit from the config file. Maximum 
        # number of filesystems to delete
        my $temp;
        my $cnt_obj;
        my $fs_cnt = 100;
        for my $res (@cnt)
        {
           ($temp , $cnt_obj) = split(/=/,$res) ;
           if ($temp =~ /Filesystem/i)
           {
                $fs_cnt=$cnt_obj;
                last;
           }
        }

        foreach my $file (@filesys)
         {
            chomp $file;
             # Skip Blank Lines
             next unless $file;
             $file =~ s/^\s+|\s+$//g;
             $emfiles{$file} = $file;
         }
	
	


        # -P df information in portable format, Gives out in block size of 512 bytes
        # Build a hash of the filesystem information on keys filesystem type
        # and mount point
        # Execute command twice, bug in df leaves out some nfs file systems
        # the first time
        # Fix for bug 6002107, hang with df -P. If the commad fails then 
        # continue with the next dont exit
	 my @dummy = run_system_command("df -P",120,1,1);	
        my @file_rows = run_system_command("nmhs run_sysv_df -n");

        storage::Utilities::setConfig("FileSystems",1);
        my $fs_proc = 0;

	for my $fsdata (@file_rows)
	{

	 if ($fs_proc == $fs_cnt)
           {
              if (!(keys(%emfiles)))
              {
                  storage::Utilities::setConfig("FileSystems",0);
                  storage::Register::log_error_message("The number of File Systems to be monitored is larger than $fs_cnt. Please add the File Systems to be monitored inthe config file  emagent_storage.config");
              }
              last;
            }

		chomp $fsdata;
		$fsdata =~ s/^\s+|\s+$//g;
		next unless $fsdata;
		my @col=split /:/,$fsdata;
		my $mnt = $col[0];
		my $type = $col[1];
	        $type =~ s/^\s+|\s+$//g;
        	$mnt =~ s/^\s+|\s+$//g;

                # Filter the files based on the config file read.
                # for nfs Split the server name and file system
                ( my $nfs_serv, my $exported_filesystem ) =
                  ( $mnt =~ /^\s*([^:]*)\s*:\s*(.+)\s*$/ )
                  if $mnt =~ /^([^:]*):(.+)$/;

                if ($nfs_serv)
                {
                    next if ((keys (%emfiles) > 0) && ($emfiles{$mnt} ne $mnt) && ($emfiles{$nfs_serv} ne $nfs_serv));
                }
               else
                {
                   next if ((keys (%emfiles) > 0) && ($emfiles{$mnt} ne $mnt));
                }

        	$type = 'nfs' if $type =~ /($storage::Register::config{filesystem}{nfsfstypes})/;
        	next
            	if $type =~ /^($storage::Register::config{filesystem}{skipfilesystems})$/i;	

		for my $fsrec (run_system_command("df -Pk $mnt",120,1,1))
		{
			last if ($fs_proc == $fs_cnt);

			my %fsinfo = ();
			chomp $fsrec;
			$fsrec =~ s/^\s+|\s+$//g;
			next unless $fsrec;
			next if $fsrec =~ /^(Filesystem)/i;
	               	my @col=split /\s+/,$fsrec;
       		        $fsinfo{filesystem} = $col[0];
                	$fsinfo{size} = $col[1] * 1024;
                	$fsinfo{used} = $col[2] * 1024;
                	$fsinfo{free} = $col[3] * 1024;
                	$fsinfo{fstype} = $type;
                	$fsinfo{mountpoint} = $col[5];
                	( $fsinfo{nfs_server}, $fsinfo{nfs_exported_filesystem} ) =
                	( $fsinfo{filesystem} =~ /^\s*([^:]*)\s*:\s*(.+)\s*$/ )
                        if $fsinfo{fstype} eq 'nfs' and
                        $fsinfo{filesystem} =~ /^([^:]*):(.+)$/;
			push @{$fsarray{$fsinfo{fstype}}},\%fsinfo;
			$fs_proc++;
		}
	}
	
     if ($fs_proc < $fs_cnt)
      {

	for my $fsrec (run_system_command("lsps -a"))	
	{
             if ($fs_proc == $fs_cnt)
              {
		 if (!(keys(%emfiles)))
                   {
                        storage::Utilities::setConfig("FileSystems",0);
                        storage::Register::log_error_message("The number of File Systems to be monitored is larger than $fs_cnt. Please add the File Systems to be monitored inthe config file  emagent_storage.config");
                   }
                   last;
                }

        	my %fsinfo = ();
        	chomp $fsrec;
        	$fsrec =~ s/^\s+|\s+$//g;
        	next unless $fsrec;
        	next if $fsrec =~ /^(Page)/i;
        	my @col=split /\s+/,$fsrec;
        	$fsinfo{filesystem} = "/dev/$col[0]";
		 # Filter the files based on the config file read.
                next if ((keys (%emfiles) > 0) && ($emfiles{$fsinfo{filesystem}} ne $fsinfo{filesystem}));

        	( $fsinfo{size} ) = ($col[3] =~ /(\d+)/);
        	$fsinfo{size} = $fsinfo{size} * 1024 * 1024;
        	$fsinfo{used} = $fsinfo{size};
        	$fsinfo{free} = 0;
        	$fsinfo{fstype} = "swap";
        	push @{$fsarray{$fsinfo{fstype}}},\%fsinfo;
		 $fs_proc++;
	}
      }
    
 	my %nfsservers;

 	# For each file system type
 	for my $fstype( keys %fsarray )
 	{

   		#-------------------------------------------------------
   		# Build the nfs server list and server information
   		#-------------------------------------------------------
   		if ( $fstype eq 'nfs' )
   		{

     			# build Unique list of nfs servers for fstype = nfs,
     			# filesystem for nfs is server:filesystem
     			%nfsservers = map{$_->{nfs_server} => 1
      			if $_->{nfs_server} } @{$fsarray{$fstype}};

     			#Get the identifier for each of the nfs server , build a
     			#hash of hashes for nfs configuration
			# NOTE: AIX support for get_server_identifier to be done
     			map
      			{my %reslt = storage::sUtilities::get_server_identifier($_);
        	 	  $nfsservers{$_} = \%reslt;
      			}
       			keys %nfsservers;

   		}

                for my $fsref ( @{$fsarray{$fstype}} )
                {
                        my %nfs;
                        my %mountpoint;
                        my %filesystem;

                        # Get the nfs(vendor,product,server) hash if filesystem
			# Note : mount privilege to be done for AIX
			$fsref->{nfs_mount_privilege} =
			storage::sUtilities::get_mount_privilege($fsref->{mountpoint})		
			if $fsref->{fstype} eq 'nfs'
			and $fsref->{mountpoint};
		
			$fsref->{nfs_server_net_interface_address} =
       			$nfsservers{$fsref->{nfs_server}}->{nfs_server_net_interface_address}
			if $fsref->{fstype} eq 'nfs'
			and $fsref->{nfs_server}
			and $nfsservers{$fsref->{nfs_server}}
			and $nfsservers{$fsref->{nfs_server}}->{nfs_server_net_interface_address};

			$fsref->{nfs_server_ip_address} =
			$nfsservers{$fsref->{nfs_server}}->{nfs_server_ip_address}
			if $fsref->{fstype} eq 'nfs'
 			and $fsref->{nfs_server}
	                and $nfsservers{$fsref->{nfs_server}}
           		and $nfsservers{$fsref->{nfs_server}}->{nfs_server_ip_address};

			# Create the mozart metrics that are required

 			# The mountpoint storage entity if there is a mountpoint
		      	if ( $fsref->{mountpoint} )
      			{

			        $mountpoint{storage_layer} = 'LOCAL_FILESYSTEM';
			        $mountpoint{entity_type} = 'Mountpoint';
			        $mountpoint{key_value} = $fsref->{mountpoint};
			        $mountpoint{os_identifier} = $fsref->{mountpoint};
			        $mountpoint{sizeb} = $fsref->{size};
			        $mountpoint{usedb} = $fsref->{used};
			        $mountpoint{freeb} = $fsref->{free};
			        $mountpoint{filesystem_type} = $fsref->{fstype};
			        $mountpoint{filesystem} = $fsref->{filesystem};
			        $mountpoint{mountpoint} = $fsref->{mountpoint};
			        $mountpoint{name} = $fsref->{mountpoint};
			        # Extra metric columns for NFS
        			if ( $fsref->{fstype} eq 'nfs' )
        			{

          				$mountpoint{storage_layer} = 'NFS';
          				# Copy all the nfs_fields
 				        for my $nfskey ( keys %{$fsref} )
          				{
            					next
             					unless $nfskey =~ /^nfs_/;
            					next
					        unless  $fsref->{$nfskey};
            					$mountpoint{$nfskey} = $fsref->{$nfskey};
          				}
        			}
				push @storage::Register::filesystemarray,\%mountpoint;
			}
		      	$filesystem{key_value} = $fsref->{filesystem};
      			$filesystem{sizeb} = $fsref->{size};
      			$filesystem{usedb} = $fsref->{size};
      			$filesystem{filesystem_type} = $fsref->{fstype};
      			$filesystem{filesystem} = $fsref->{filesystem};
      			$filesystem{name} = $fsref->{filesystem};
      			$filesystem{os_identifier} = $fsref->{filesystem}
     				if $fsref->{fstype} ne 'nfs'
         			and -e $fsref->{filesystem};
      			$filesystem{mountpoint} = $fsref->{mountpoint}
       				if $fsref->{mountpoint};

		      	# Who are its parents
      			# The current mountpoint
  		    	# Since these are OS entities any other cached filesystem mounts or
      			# filesystem based swap  will be discovered by the analysis program
      			# There is no need to define the parent key criteria for these
      			$filesystem{parent_key_value} = $mountpoint{key_value}
       				if $fsref->{mountpoint}
        			and $mountpoint{mountpoint};

      			$filesystem{storage_layer} = 'LOCAL_FILESYSTEM';
      			$filesystem{entity_type} = 'Filesystem';

		 	# If the filesystem is a regular file or directory not a block device then its a file
 			my $fs_file_type = storage::Register::get_file_type( $filesystem{os_identifier} )
 				if $filesystem{os_identifier};

 			$filesystem{entity_type} = 'File'
 				if $fs_file_type
 				and $fs_file_type =~ /_REGULAR/i;

 			$filesystem{entity_type} = 'Directory'
 				if $fs_file_type
 				and $fs_file_type =~ /_DIRECTORY/i;

		      	# Extra metric columns for NFS
      			if  ( $fsref->{fstype} eq 'nfs' )
      			{
        			$filesystem{storage_layer} = 'NFS';
        			$filesystem{entity_type} = 'Filesystem';
			        # copy all the nfs_ fields
        			for my $nfskey ( keys %{$fsref} )
        			{
          				next
           				unless $nfskey =~ /^nfs_/;
          				next
    				       	unless  $fsref->{$nfskey};
          				$filesystem{$nfskey} = $fsref->{$nfskey};
        			}
			        # Generate a default global unique id for the server based on the
        			# server identification obtained
        			# if post processing cannot find a matching server this can be used
        			if ( $filesystem{nfs_server_net_interface_address} )
        			{
         				$filesystem{global_unique_id} =
          				"$filesystem{nfs_server_net_interface_address}::$filesystem{filesystem}";
        			}
        			elsif ( $filesystem{nfs_server_ip_address} )
        			{
     				    	$filesystem{global_unique_id} =
          				"$filesystem{nfs_server_ip_address}::$filesystem{filesystem}";
        			}
        			elsif ( $filesystem{nfs_server} )
        			{
         				$filesystem{global_unique_id} =
          				"$filesystem{nfs_server}::$filesystem{filesystem}";
        			}
			        else
                             	{
                               		my $target_id =  get_target_id();
                              		$filesystem{global_unique_id} =
                   	                "no_gid::$target_id::$filesystem{filesystem}"
                          	        if $target_id;
                             	}

				$filesystem{global_unique_id} =
 				"no_targetid::$filesystem{filesystem}"
 				unless $filesystem{global_unique_id};
			}
			push @storage::Register::filesystemarray,\%filesystem;
		}	
	}
	return \@storage::Register::filesystemarray;
}


#-------------------------------------------------------------------------------
# FUNCTION : runShowmount
#
#
# DESC
# run showmount
#
# ARGUMENTS:
#
#------------------------------------------------------------------------------
sub runShowmount ( $ )
{
 return run_system_command("showmount -a $_[0]",120);
}

#-----------------------------------------------------------------------------
# FUNCTION : AUTOLOAD
#
# DESC
# If sub is not defined here then look for it in sUtilities.pm
#
# ARGUMENTS
# Args to be passed to the sub
#
#----------------------------------------------------------------------------
sub AUTOLOAD
{
  my ( @args ) = @_;

  my $sub = $AUTOLOAD;

  $sub =~ s/.*:://;

  my $sub_path = "storage::sUtilities::$sub";

  my $sub_ref = \&$sub_path;

  return &$sub_ref(@args);

}



1;
#-----------------------------------------------------------------