#  $Header: emagent/sysman/admin/scripts/semd_common.pl /st_emagent_10.2.0.4.3db11.2.0.2/1 2010/05/28 12:44:54 mnihalan Exp $
#
# Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      semd_common.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      This file contains common subroutines.
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#      mnihalan  05/26/10 - Fix bug 9738590
#      shnavane  08/27/07 - Fix bug #6367252
#      shnavane  09/02/07 - Backport shnavane_bug-6367252 from main
#      svrrao    10/10/06 - Porting Changes, HPUX fix to delete LD_LIBRARY_PATH, bug 5451889
#      vnukal    01/26/06 - Fix get_disk_usage to return KB on Win 
#      xuliu     11/29/05 - fix 4765569 
#      xuliu     06/28/05 - 4395222
#      kduvvuri  06/17/05 - fix illegal division by zero. 
#      jstone    04/26/05 - add set/get complete shared lib path
#      xuliu     01/27/05 - 4145563: 64-bit cemutls 
#      xuliu     11/08/04 - getCRSNameNHome()
#      aaitghez  11/02/04 - bug 3843531. add Mac OS support 
#      kduvvuri  09/17/04 - take out some trace statements. 
#      kduvvuri  09/16/04 - add tracing. 
#      xuliu     05/12/04 - 3412986
#      mbhoopat  03/11/04 - merge from pl_main_gen 
#      rlal      02/21/04 - Fix for bug 3459807 
#      xuliu     11/05/03 - add getClusterName() 
#      pbantis   09/03/03 - Remove DIR declaration from get_disk_usage() 
#      vnukal    08/25/03 - disk_usage accepts dirnames 
#      vnukal    06/19/03 - fix error
#      vnukal    06/13/03 - adding win impl of get_disk_usage
#      lhan      04/24/03 - More Window's support
#      lhan      04/22/03 - Add NT support for get_disk_usage
#      aholser   03/12/03 - add windows check
#      xxu       06/25/02 - remove /usr/local/bin/perl
#      xxu       10/12/01 - set shared library path
#      xxu       05/29/01 - moved system dependent subroutines from emd_common.
#      xxu       05/29/01 - moved system dependent subroutines from emd_common.pl
#      xxu       05/29/01 - Creation
# 
#

use strict;
use Oraperl;
require "emd_common.pl";

# This subroutine returns the platform.
# For unsupport platforms, -1 will be returned.
sub get_osType
{
    if (( $^O eq "Windows_NT") ||
	( $^O eq "MSWin32")) {
	return "WIN";
    }

    my $os = `uname -s`;
    my $ver = `uname -r`;
    chomp ($os);

    if ( $os eq "SunOS" ) {
        if ( chomp($ver) !~ /^4./ ) {
            return "SOL";
        }
    } elsif ( $os eq "HP-UX" ) {
        return "HP";
    } elsif ( $os eq "Linux" ) {
        return "LNX";
    } elsif ( $os eq "AIX" ) {
        return "AIX";
    } elsif ( $os eq "OSF1" ) {
        return "OSF1";
    } elsif ( $os eq "Darwin" ) {
        return "MAC OS X";
    } else {
        # Unsupported Operating System
        return -1;
    }
}

# Returns the name of the shared library path environment variable
# for the current platform
sub get_shared_lib_path_name
{
    my $lib_path_name = "";

    if ( get_osType() eq "SOL" || 
         get_osType() eq "LNX" || 
         get_osType() eq "OSF1" ) {
        $lib_path_name = 'LD_LIBRARY_PATH' ;
    } elsif ( get_osType() eq "HP" ) {
        $lib_path_name = 'SHLIB_PATH' ;
	delete $ENV{LD_LIBRARY_PATH};
    } elsif ( get_osType() eq "AIX" ) {
        $lib_path_name = 'LIBPATH' ;
    } elsif ( get_osType() eq "MAC OS X" ) {
        $lib_path_name = 'DYLD_LIBRARY_PATH' ;
    }

    return( $lib_path_name );
}

sub get_shared_lib_path_separator
{
    # The following value may be platform dependent.
    # Currently, this is correct for all supported platforms.
    my $sep_token = ':';         # reset as needed by the os

    return( $sep_token );
}

# uniq_path removes redundant fields from the input path,
# while preserving left to right order.  The first occurrance
# of each field is preserved, but all duplicates are removed.
sub uniq_path
{
    my ($sep_token, $inpath) = @_;

    my $outpath = $inpath;
    my @fields = split( $sep_token, $inpath ) ;
    unless (@fields) { return($outpath); }

    my @unique_fields ;
    my %is_known_field;

    foreach my $field (@fields) { 
        unless ( $is_known_field{$field} ) {
            $is_known_field{$field} = 1 ;
            push( @unique_fields, $field );
        }
    }

    if (@unique_fields) {
        $outpath = join( $sep_token, @unique_fields ) ;
    }

    return( $outpath );
}

# Sets the input string as the complete shared library path
sub set_complete_lib_path
{
    my ($new_lib_path) = @_;
    unless ( defined($new_lib_path) && length($new_lib_path) ) {
        return;
    }
    
    my $lib_path_name = get_shared_lib_path_name;
    if ( defined($lib_path_name) && length($lib_path_name) ) {
        $ENV{$lib_path_name} = $new_lib_path ;
    }
}

# Gets the current complete shared library path
sub get_complete_lib_path
{
    my $complete_lib_path = "";
    
    my $lib_path_name = get_shared_lib_path_name;
    if ( defined($lib_path_name) && 
         length($lib_path_name)  &&
         defined($ENV{$lib_path_name} ) ) {
        $complete_lib_path = $ENV{$lib_path_name} ;
    }

    return( $complete_lib_path );
}

# This subroutine takes the target oracle home, then add $OH/lib
# at the beginning of the shared library path.
sub set_lib_path
{
    my ($oh) = @_;

    my $lib_path_name;

    my $new_field = "$oh/lib" ;
    my $sep_token = get_shared_lib_path_separator;

    my $current_lib_path = get_complete_lib_path();
    my $new_lib_path = 
        "$new_field"."$sep_token"."$current_lib_path" ;
    set_complete_lib_path( "$new_lib_path" );

}

# This subroutine takes the target name and the metric script name,
# and returnd a unique file name under $TEMP directory.
# For most unix platfoems, $TEMP directory will be /tmp;
# need to find out the $TEMP directory on Windows NT.
sub get_tmp_filename
{
    my ($target_name, $script_name) = @_;

    my $fn = "/tmp/$target_name\_$script_name";
    $fn =~ s/ /_/g;

    return $fn;
}

# This subroutine takes the disk name, and returns the usage in kbytes.
# -1 will be returned for invalid directory or permission denied
# Need special attention to port this routine to other platforms,
# since df may not be supported on that platform (like Windows NT),
# or the output format could be different.
sub get_disk_usage
{
    my ($disk) = @_;
    my $osType = get_osType();

    EMD_PERL_DEBUG("Getting the disk usage for $disk on $osType");

    if ( opendir(DIR, $disk) ) {
        close (DIR);


        if ( get_osType() eq "SOL" || get_osType() eq "LNX" || get_osType() eq "OSF1" || get_osType() eq "MAC OS X" ) {
            my $df_out  = `df -k $disk`;
            EMD_PERL_DEBUG("on $osType, df returned $df_out");
            my @temp = split(/\s+/, $df_out);
            my $total = $temp[$#temp - 4];
            my $used  = $temp[$#temp - 3];
            my $avail = $temp[$#temp - 2];
            my $usage = $temp[$#temp - 1];
            $usage =~ s/%$//g;

            return ($total, $used, $avail, $usage);
        } elsif ( get_osType() eq "HP" || get_osType() eq "AIX" ) {
            my $df_out  = "";
            if (get_osType() eq "HP")
            {
               $df_out  = `bdf $disk`;
            }
            else
            {
               $df_out  = `df -Pk $disk`;
            }
            EMD_PERL_DEBUG("on $osType df returned $df_out");
            my @temp = split(/\s+/, $df_out);
            my $total = $temp[$#temp - 4];
            my $used  = $temp[$#temp - 3];
            my $avail = $temp[$#temp - 2];
            my $usage = $temp[$#temp - 1];
            $usage =~ s/%$//g;

            return ($total, $used, $avail, $usage);
        } elsif ( get_osType() eq "WIN") {
	    #normalize to back-slashes for comparison purposes
	    $disk =~ s/\//\\/g;
            my @nmupmOut  = `$ENV{EMDROOT}/bin/nmupm FileSystems`;
	    foreach(@nmupmOut) {
		chomp;
		my @filesys = split /=/ ;
		#extract drive information from nmupm output
		my $drive = (split /\|/, $filesys[1])[0] ;
		if (( index (lc($disk), lc($drive)) != -1) && ($drive ne "")) {
                    EMD_PERL_DEBUG("match found for: $disk");
		    my @diskstat = split(/\|/, $filesys[1]);
		    my $total = $diskstat[1] * 1024 ; # convert to KB
		    my $used  = $diskstat[2] * 1024 ; # convert to KB
		    my $avail = $total - $used;
                    my $usage = 0;
		    # calculate usage % and round to nearest interger.
                    if( $total > 0 ) {
		      $usage = sprintf("%.0f", ($used *100)/ $total);
                    }
		    return ($total, $used, $avail, $usage);
		} 
	    }
            EMD_PERL_DEBUG("No match found for: $disk");
	    return (-1) ;
        } else {
            EMD_PERL_DEBUG("disk info not suppored on this platform $osType");
            # unsupport platforms
            return (-1);
        }

    } else {
        EMD_PERL_DEBUG("Invalid directory or permission problems for $disk");
        # invalid directory or permission denied
        return (-1);
    }
}

#
# If it's in a cluster, return the cluster name
# else return empty
#
sub getClusterName
{
    my ($emdRoot, $crsHome) = @_;
    my $clusterName;
    
    EMD_PERL_DEBUG("Args to getClusterName,emdRoot=$emdRoot,crsHome=$crsHome"); 
    if (!defined ($crsHome))
    {
        $crsHome = "";
    }
    
    if ($crsHome eq "")
    {
        if (defined($ENV{CRS_HOME}))
        {
            if ($ENV{CRS_HOME} ne "#CRS_HOME#")
            {
                $crsHome = $ENV{CRS_HOME};
            }
        }    
    }    

    EMD_PERL_DEBUG("crsHome is determined to be : $crsHome"); 
    
    $clusterName = '';
    if ($crsHome ne "") {
        if ( -f "$crsHome/bin/cemutlo" || -f "$crsHome/bin/cemutlo.exe") 
        {
            # set OH to crshome (bug 4395222)
            my $oldOH = $ENV{ORACLE_HOME};
            $ENV{ORACLE_HOME} = $crsHome;
            chomp($clusterName = `$crsHome/bin/cemutlo -n 2>&1`);
            $ENV{ORACLE_HOME} = $oldOH;
            
            if ($?) {
                $clusterName ='';
            }
            EMD_PERL_DEBUG("After executing cemutlo,clusertName=$clusterName"); 
        }    
    }
    
    # Attempt to search OUI inventory for the CRS Home 
    if ($clusterName eq "")
    {
        my @crsHomes = getCRSHomes();
        my $h;
        foreach $h (@crsHomes)
        {
            EMD_PERL_DEBUG("Checking $h ...");
            if ( -f "$h/bin/cemutlo" ||  -f "$h/bin/cemutlo.exe" ) 
            {
                # set OH to crshome (bug 4395222)
                my $oldOH = $ENV{ORACLE_HOME};
                $ENV{ORACLE_HOME} = $h;
                chomp($clusterName = `$h/bin/cemutlo -n 2>&1`);
                $ENV{ORACLE_HOME} = $oldOH;
                
                if ($?) {
                    $clusterName ='';
                }
                
                if ($clusterName ne "")
                {
                    EMD_PERL_DEBUG("cemutlo works fine in $h. Found ($clusterName, $h)"); 
                    $crsHome = $h;
                    last;
                }    
            }    
        }    
    }
    
    if ($clusterName eq "")
    {
        # still empty, check cemutls in case of 92 cluster
        my $cemutlsExe = getCemutls();
        if ( -f "$emdRoot/bin/$cemutlsExe" || -f "$emdRoot/bin/${cemutlsExe}.exe") 
        {
            chomp($clusterName = `$emdRoot/bin/$cemutlsExe -n 2>&1`);
            if ($?) {
                $clusterName ='';
            }
            EMD_PERL_DEBUG("After executing $cemutlsExe,clusertName=$clusterName"); 
            
            if ($clusterName ne "")
            {
                # it's a 9.2 cluster, setting crsHome to emtpy.
                $crsHome = "";
            }
        }    
    }
    
    EMD_PERL_DEBUG("Returning clusterName:($clusterName, $crsHome)"); 
    return wantarray? ($clusterName, $crsHome) : $clusterName;
}    


# The following code is used to search oracle inventory for all valid crs homes
#
# Return all the crs homes on the local host
sub getCRSHomes
{
   my $invf = getInventoryXmlPath();
   my @crsHomes;
   if ($invf ne "")
   {
        @crsHomes = getCRSHomesFromInventory($invf);
   }
   
   return @crsHomes;
}

# read the NT registry for the inst_loc
sub readInst_LocFromRegistry
{
   no strict;
   eval 'use Win32::TieRegistry;';
   $Registry->Delimiter("/"); 
   my $instLoc = $Registry->{"LMachine/Software/Oracle/inst_loc"};
   EMD_PERL_DEBUG("LMachine/Software/Oracle/inst_loc=$instLoc");
   return $instLoc;
}


# checkInventoryXml($inst_loc)
# return $inst_loc/ContentsXML/inventory.xml if it exists
# otherwise, empty
sub checkInventoryXml
{
    my $inventoryXmlFile = "$_[0]/ContentsXML/inventory.xml";
    
    if (-f $inventoryXmlFile)
    {
        EMD_PERL_DEBUG("inventory.xml is determined at $inventoryXmlFile ");
        return $inventoryXmlFile;
    } 
    else
    {
        EMD_PERL_DEBUG("$inventoryXmlFile doesn't exist.");
    }  
    
    return "";
}

# Determine the location of the inventory.xml
sub getInventoryXmlPath 
{
    my $inventoryXmlFile = "";
        
    # Check if ORATAB env is specified
    if ( defined $ENV{INVENTORY_LOC} )
    {
      EMD_PERL_DEBUG("ENV{INVENTORY_LOC} = $ENV{INVENTORY_LOC}");
      $inventoryXmlFile = checkInventoryXml($ENV{INVENTORY_LOC});
      return $inventoryXmlFile if ($inventoryXmlFile ne "");
    }
    
    if(get_osType() eq 'WIN')
    {
        $inventoryXmlFile = checkInventoryXml(&readInst_LocFromRegistry());
        return $inventoryXmlFile if ($inventoryXmlFile ne "");
    }
    else
    {
        my ($f, $ln);
        my @lns;
        
        my @oraInstFileList = ("/var/opt/oracle/oraInst.loc", "/etc/oraInst.loc");
        
        foreach $f (@oraInstFileList) 
        {
            if ( open(ORAINST, "<$f") )
            {
                @lns = <ORAINST>;
                close(ORAINST);
                foreach $ln (@lns)
                {
                    $ln =~ s/\n$//;
                    if ($ln =~ /inventory_loc\s*=\s*([^\s]+)\s*$/i)
                    {
                       $inventoryXmlFile = checkInventoryXml($1);
                       return $inventoryXmlFile if ($inventoryXmlFile ne "");
                    }     
                }    
            }
       }
   }
      
   EMD_PERL_ERROR("No valid inventory.xml found.");
   
   return "";
}

# getCRSHomesFromInventory($path_of_inventory_xml)
#
# Parse the given inventory.xml and return all the homes that satisfy:
# 1. CRS="true"
# 2. ! REMOTE="true"
sub getCRSHomesFromInventory
{
   my $inventoryXml = $_[0];
   
   my @crshomes;
   
   if (open(INVXML, "<$inventoryXml"))
   {
      my @lns = <INVXML>;
      close(INVXML);
      my $bigL;
      
      my $beginHomeList = 0;
      my $endHomeList = 0;
      
      my $ln;
      foreach $ln (@lns)
      {
        $ln =~ s/\n$//;
        
        if ($ln =~ /<HOME_LIST>(.*)/i)
        {
            $ln = $1;
            $beginHomeList = 1;
        }
        
        if ($ln =~ /(.*)<\/HOME_LIST>/i)
        {
            $ln = $1;
            $endHomeList = 1;
        }
        
        if ($beginHomeList)
        {
            $bigL .= $ln;
        }
        
        if ($endHomeList)
        {
            last;
        }
      }   
      
      # rid of comments
      $bigL =~ s/<!--.*?-->//g;

      my @homes = split /<HOME\s+/, $bigL;
      my $h;
      foreach $h (@homes)
      {
         if ($h =~ /crs\s*=\s*\"true\"/i)
         {
            if ($h !~ /remote\s*=\s*\"true\"/i)
            {
                # this is a valid crshome
                if ($h =~ /loc\s*=\s*\"(.*?)\"/i)
                {
                    push @crshomes, $1;
                }
            }    
         }           
      }
   }   
   
   @crshomes;
 }   

#
# getCemutls
# 
# return the cemutls64 on 64-bit solaris. otherwise return cemutls
#
sub getCemutls
{
    if (get_osType() eq "SOL")
    {
        my $o = `file /opt/ORCLcluster/lib/libskgxn2.so 2>&1`;
        if ($o =~ /64-bit/)
        {
            return "cemutls64";
        }
    }
    return "cemutls";
}

1;

