# 
# $Header: oracledbUtl.pl 22-jul-2005.08:06:21 jstone Exp $
#
# oracledbUtl.pl
# 
# Copyright (c) 2002, 2005, Oracle. All rights reserved.  
#
#    NAME
#      oracledbUtl.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      This file contains Unix related oracle DB and listener discovery
#      subroutines.
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    jstone      07/12/05  - adds declaration of $Registry to support iAS fix 
#                            for bug 4486097 
#    jsutton     04/15/04  - Clean up warnings 
#    dkapoor     02/19/04  - fix for ecm bug#3440972 
#    dkapoor     02/16/04  - use winRegistry 
#    dkapoor     01/30/04 -  enable win32 registry 
#    dkapoor     10/31/03 - add logging 
#    dkapoor     10/27/03 - add logging 
#    dkapoor     04/17/03 - move run command to net
#    dkapoor     11/14/02 - remove obs code
#    dkapoor     11/14/02 - add windows SID collection
#    dkapoor     11/04/02 - add utl methods
#    dkapoor     11/02/02 - use the last OHome for sid
#    xuliu       08/20/02 - fix set $oratabFile "" ;
#    dkapoor     07/24/02 - dkapoor_fix2296998
#    dkapoor     07/22/02 - Creation
# 

use strict;
our $Registry;
require "$ENV{EMDROOT}/sysman/admin/scripts/semd_common.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/emd_common.pl";
if(get_osType() eq 'WIN')
{
  require "$ENV{EMDROOT}/sysman/admin/discover/utl/winRegistry.pl";
  eval 'use Win32::TieRegistry';
  $Registry->Delimiter("/");
}

#Discovery LOG CATEGORY
my $LOG_CATEGORY = "DB_LISTENER_DISCOVERY: ";

#Get Oracle Homes and Sids
#Returns oracle Home and sid references
#OhomeRef---> Array of Homes like ("/private/oracle817", "/private/oracle92");
#SidRef---> Hash of SID and its Home like 
#     { 
#         "orcl817" =>"/private/oracle817",
#         "orcl92" =>"/private/oracle92"
#     }  
# THIS IS AN OS DEPENDENT Function.
sub getOracleHomesAndSids
{
    if(get_osType() eq 'WIN')
    {
      return getOracleHomesAndSidsNT();
    }
    return getOracleHomesAndSidsUnix();
}


#Get Oracle Homes and Sids for NT
#Returns oracle Home and sid references
#OhomeRef---> Array of Homes like ("/private/oracle817", "/private/oracle92");
#SidRef---> Hash of SID and its Home like 
#     { 
#         "orcl817" =>"/private/oracle817",
#         "orcl92" =>"/private/oracle92"
#     }  
# THIS IS AN OS DEPENDENT Function.
sub getOracleHomesAndSidsNT
{
  my @oracleHomes;	
  my %sidOhomes;	
  @oracleHomes = getOracleHomesNT();

  %sidOhomes = getServicesEntriesNT();
  #match the Oracle Homes from OUI registry to the SID home.
  #bug#3440972
  for my $sid (keys %sidOhomes)
  {
	my $quoteHome = quotemeta($sidOhomes{$sid});
  	foreach my $home (@oracleHomes)
	{
		if( $home =~ /^$quoteHome$/i)
		{
			$sidOhomes{$sid} = $home;
			last;
		}
	}	
  }

  return (\@oracleHomes,\%sidOhomes);
}

#Get Oracle Homes and Sids for Unix
#Returns oracle Home and sid references
#OhomeRef---> Array of Homes like ("/private/oracle817", "/private/oracle92");
#SidRef---> Hash of SID and its Home like 
#     { 
#         "orcl817" =>"/private/oracle817",
#         "orcl92" =>"/private/oracle92"
#     }  
# THIS IS AN OS DEPENDENT Function.
sub getOracleHomesAndSidsUnix
{
  my @db_entries = getOratabEntries();
  my @oracleHomes;	
  my %sidOhomes;	

  foreach my $entry (@db_entries) 
  {
    my ($sid, $oracleHome , $remain) = split(/:/ , $entry , 3);
    #remove leading and trailing white space.
    #sid is already stripped of leading white space. Remove trailing spaces 
    EMD_PERL_DEBUG("$LOG_CATEGORY Oratab entry=$entry: SID=$sid; OH=$oracleHome");
    $sid =~ s/\s*$//g;
    $oracleHome =~ s/^\s*|\s*$//g;
 	
    if(!(-e $oracleHome))
    {
       EMD_PERL_DEBUG("$LOG_CATEGORY $oracleHome does not exists, excluded from discovery");
       next;
    }
    if($sid ne "*")
    {
      my $ohome = $sidOhomes{$sid};
      EMD_PERL_DEBUG("$LOG_CATEGORY previous Home = $ohome") if defined($ohome);
      if(!(defined $ohome) || -M $oracleHome  < -M $ohome)
      {		
        if(defined $ohome)
        {
    	    EMD_PERL_DEBUG("$LOG_CATEGORY Use new home as it is current = $oracleHome. Old home last time:". (-M $ohome) . " new home last time :" . (-M $oracleHome));
        }
        EMD_PERL_DEBUG("$LOG_CATEGORY Add SID=$sid for discovery");
        $sidOhomes{$sid} = $oracleHome;
      }
    }
    my $processHome = 1; 	
    foreach my $oHome (@oracleHomes)
    {
        if($oHome eq $oracleHome)
      	{
          $processHome = 0;			
      	}
    }
    if($processHome)
    {		
	push(@oracleHomes,$oracleHome);	
        EMD_PERL_DEBUG("$LOG_CATEGORY Add OH=$oracleHome for discovery");
    }
  }
  return (\@oracleHomes,\%sidOhomes);
}

#Get the oratab file entries
# A typical oratab entry is of the form
# orcl:/private1/oracle/804orcl:N
#
# Returns list of the form
# { Sid1:Oracle_home1 Sid2:Oracle_home2 ... SidN:Oracle_homeN }
sub getOratabEntries {

  my (@entries,$oratabFile,$Oratab,$oraLine); 

  $oratabFile = getOratabFile();
  EMD_PERL_DEBUG("$LOG_CATEGORY Oratab file = $oratabFile");
  
  if ( $oratabFile ne "" ) {
    if ( open(Oratab, $oratabFile) ) {
      while ($oraLine=<Oratab>) {
        chomp($oraLine);
        #strip all leading  white space characters.
        $oraLine =~ s/^\s*//;
        if( ($oraLine =~ /^\#/ ) || ( length($oraLine) <= 0 ) ) {
          next;
        }
        EMD_PERL_DEBUG("$LOG_CATEGORY add oratab entry = $oraLine");
        push @entries,$oraLine;
      } 
      close(Oratab);
    }
  }
  return @entries;
}

# Get the oratab file location.
# The oratab file contains the oracle homes and the installed databases
# Note: The location of oratab file is port specific
sub getOratabFile {
  my @oratabFileList = ("/var/opt/oracle/oratab", "/etc/oratab");
  my $oratabFile = "";

  #$^O is supposed to yield the name of the OS, like Sloaris , but 
  #currently it is not giving any value. This value probably should come 
  #from emctl.
  if ( $^O =~ "VMS" )
  {
    #TODO VMS specific code 
  }
  else
  {
    # Check if ORATAB env is specified
    if ( defined $ENV{ORATAB} )
    {
      $oratabFile = trim ( $ENV{ORATAB} );
      EMD_PERL_DEBUG("$LOG_CATEGORY ORATAB env = $oratabFile");
      if (! -e $oratabFile )
      {
        $oratabFile = "";
      } 
      elsif ( -d $oratabFile ) 
      {
        $oratabFile = "";
      }
      else 
      {
        #log "Using ORATAB file $oratabFile";
        return $oratabFile;
      }
    }
  }
  #trace Processing prospective ORATAB locations of %s" $oratabFileList;
  foreach $oratabFile (@oratabFileList) {
    if ( -d $oratabFile ) 
    {
      #warning "$oratabFile can not be a directory";
    }
    elsif ( -e $oratabFile )
    {
      #log "Using oratab file $oratabFile";
      EMD_PERL_DEBUG("$LOG_CATEGORY Using oratab file $oratabFile");
      return $oratabFile
    }
  }
  #log "Warning: Found no valid oratab file";
  EMD_PERL_ERROR("$LOG_CATEGORY NO ORATAB FILE FOUND");
  $oratabFile = "" ;
  return $oratabFile;
}


sub commify_series 
{
    (@_ == 0) ? ''                                      :
    (@_ == 1) ? $_[0]                                   :
    (@_ == 2) ? join(" and ", @_)                       :
                join(", ", @_[0 .. ($#_-1)], "and $_[-1]");
}

sub getListenerControl
{
    my ($oracleHome) = @_;
    if(get_osType() eq 'WIN')
    {
      return $oracleHome . "\\bin\\lsnrctl.exe";
    }
    return $oracleHome . "/bin/lsnrctl";
}

sub getDefaultTNSAdmin
{
    my ($oracleHome) = @_;
    if(get_osType() eq 'WIN')
    {
	# get the TNS_ADMIN from the registry
	# read the home registry from <home>/bin/oracle.key file
        if(open (OUT_PUT, "$oracleHome/bin/oracle.key"))
        {
          my @homeKeyContent = <OUT_PUT>;
          my $homeKey = "@homeKeyContent";
          close OUT_PUT;
	  #remove leading and trailing spaces.
          $homeKey =~ s/^\s*|\s*$//g;
	  #convert backslashes to forward slashes
          $homeKey =~ s/\\/\//g;
  	  my $homeTNS_ADMIN= $Registry->{"LMachine/$homeKey/TNS_ADMIN"}
          	  or  EMD_PERL_DEBUG("$LOG_CATEGORY Can't find the TNS_ADMIN for LMachine/$homeKey/TNS_ADMIN: $^E\n");
	  if(defined $homeTNS_ADMIN)
  	  {
		return $homeTNS_ADMIN;
	  }
        }
        #return the default key
        return $oracleHome . "\\network\\admin";
    }
    return $oracleHome . "/network/admin";
}

# On Windows the sid is case insensitive
# We will process sids with upper case in this OS
sub convertSIDForOS
{
    my ($sid) = @_;
    if(get_osType() eq 'WIN')
    {
      return uc($sid);
    }
    return $sid;
}

1;
