#!/usr/local/bin/perl # # $Header: emdb/sysman/admin/scripts/db/net/listenerUtil.pl /st_emdbsa_11.2/2 2011/01/12 21:33:34 mappusam Exp $ # # listenerUtil.pl # # Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. # # NAME # listenerUtil.pl - # # DESCRIPTION # # # NOTES # # # MODIFIED (MM/DD/YY) # mappusam 01/10/11 - Backport mappusam_bug-9934831 from main # prjaiswa 04/06/09 - bug .8398455. # vivsharm 01/02/07 - XbranchMerge vivsharm_bug-5714860 from main # vivsharm 12/22/06 - ifile fix had got rolled back after strict # checking for listener parameter file # mkiran 07/31/06 - 4774824: restore shared lib path # vivsharm 02/15/06 - NT porting # vivsharm 07/04/05 - for 4433810 # vivsharm 01/26/05 - for fix of bug 4133345 # vivsharm 12/20/04 - take care of warnings # rmadampa 11/29/04 - getResult to take ref to array of commands # usinha 09/10/04 - BugFix # 3798597 -- IFILE issue resolution # usinha 05/26/04 - BugFix # 3639863 -- do file symlink comparison # dkapoor 03/08/04 - workaround for net manager password in # dkapoor 01/30/04 - use quotemeta # dkapoor 12/18/03 - remove file in result # dkapoor 12/09/03 - revert NLS_LANG # dkapoor 12/02/03 - convert path to canonical before comparing # dkapoor 11/03/03 - fix listener response # dkapoor 10/28/03 - fix bug3221435 # dkapoor 10/03/03 - add method to check if param has quotes # rasundar 09/12/03 - use own temp files for NT # dkapoor 05/28/03 - use upper case param names # dkapoor 05/14/03 - make params uc before accessing contents # dkapoor 05/08/03 - remove trace # dkapoor 05/07/03 - add host to db detail # dkapoor 04/23/03 - dkapoor_fix_2846571 # dkapoor 04/23/03 - add method to run lsnrctl command # dkapoor 04/08/03 - Creation # require 5.8.2; require "$ENV{EMDROOT}/sysman/admin/scripts/semd_common.pl"; require "$ENV{EMDROOT}/sysman/admin/scripts/emd_common.pl"; require "db/esaDbUtils.pl"; require "db/esaUtils.pl"; use File::Temp qw(tempfile); #Parse listener.ora file # and return a hashtable containing #LHS and RHS sub parseOracleConfigFile { my ($configFile) = @_; my ($paramOrder,$hashtable) = parseOracleConfigFileWithOrder($configFile); return $hashtable; } #Parse listener.ora file # and return a hashtable containing #LHS and RHS sub parseOracleConfigFileWithOrder { my ($configFile) = @_; my %hashtable; my @paramOrder; my $paramName; if(!-e $configFile) { #print "File does not exist[$configFile]\n"; return (@paramOrder,%hashtable); } open(CONFIG_FILE_READER, $configFile); if(!(defined CONFIG_FILE_READER)) { #print "File cound not be open for reading [$configFile]\n"; return (@paramOrder,%hashtable); } my @lines; while($line = ) { chomp($line); push(@lines,$line); } close CONFIG_FILE_READER; my $nvElem = ""; foreach $line (@lines) { if (length($line) == 0 || $line =~ /^[#]/) #ignore empty lines and comment lines { next; } elsif($line =~ /^[ |\t|)]/ ) #continued input on new line { if (length($nvElem) == 0) { #Eat WS(White Space) characters $line = EatNLPWS($line); } #Before creating or appending to NV Element check strip off any comments. $line =~ s/\s*\#.*//; #Now create/append to NV elem. $nvElem = $nvElem . $line; } else # new NV Element starting here { #encountered a new parameter # There are 4 cases if (length($nvElem) == 0) { $line =~ s/\s*\#.*//; $nvElem = $nvElem . $line; } elsif(length($nvElem) != 0) { $paramName = addNLPListElement($nvElem,\%hashtable); # Add Parameter to Hashtable if(defined $paramName ) { push(@paramOrder,$paramName); } $nvElem = ""; #Clear first, before storing current line $line =~ s/\s*\#.*//; $nvElem = $nvElem . $line; } } } $len = length($nvElem); if (length($nvElem) != 0) # at eof, still one more parameter to read { $paramName = addNLPListElement($nvElem,\%hashtable); # Add Parameter to Hashtable if(defined $paramName ) { push(@paramOrder,$paramName); } } return (\@paramOrder,\%hashtable); } #Adds an NV string to the Hashtable. sub addNLPListElement { my ($elem,$hashtable) = @_; $_ = $elem; my $paramName; /[=]/; if(length($&) != 0) { $paramName = uc (trim ( $` )); $hashtable->{$paramName} = $'; } return $paramName; } #Given a string, this method checks for the first non-whitespace #character. If EOL(End of Line) is reached before a valid character, #a null is returned, else the rest of the line from the non-WS #character is returned. sub EatNLPWS { my ($str) = @_; if( $str =~/#/) { return $'; } return $str; } #Get the list of listeners in the specified listenersInfo hashtable #A key is a listener is it contains any entry of type # DESCRIPTION_LIST # DESCRIPTION # ADDRESS_LIST # ADDRESS sub getListenerNames { my ($listenersInfo) = @_; my @listeners; while ( ($param, $value) = each (%$listenersInfo)) { if($value =~ /DESCRIPTION_LIST|DESCRIPTION|ADDRESS_LIST|ADDRESS/i) { push(@listeners,$param); } } return @listeners; } #Get addresses from a NV String sub getAddresses { my ($line) = @_; return getParamValueListFor($line,ADDRESS); } #Get sids from a NV String sub getSIDS { my ($line) = @_; return getParamValueListFor($line,SID_DESC); } #Gets the parameter values for a quoted string #For example: # Given $argument as below: #$argument = "'oracle_home=/oraclehome,oracle_sid=sid'" #OR, $argument = "'(oracle_home=/oraclehome,oracle_sid=sid)'" #OR, $argument = "(oracle_home=/oraclehome,oracle_sid=sid)" #OR replace single quote (') with double quote ("). # # then this routine will return a Hashtable like # ( # oracle_home => /oraclehome, # oracle_sid => sid # ) # #Special Case: # Given $argument as below: #$argument = "'oracle_home,oracle_sid'" #Or, its variations. # # # then this routine will return a Hashtable like # ( # VALUE0=> oracle_home, # VALUE1=> oracle_sid, # ) sub getParamValues { my ($argument) = @_; if($argument =~ /\s*\'(.*)\'\s*/) { $argument = $1; } if($argument =~ /\s*\"(.*)\"\s*/) { $argument = $1; } if($argument =~ /\s*\((.*)\)\s*/) { $argument = $1; } my %params; my @delimiters = (',','='); my @toknizedLiterals = tokenize($argument,@delimiters); my $currWord; my $curPoint = 0; my $paramName; my $added = 0; my $wildParamCount = 0; while ( ($currWord = getNextWord($curPoint++,@toknizedLiterals)) ne "") { if ($currWord eq "=" ) { $currWord = getNextWord($curPoint++,@toknizedLiterals); if($currWord ne "") { $params{uc $paramName} = $currWord; $paramName = ""; $added = 1; } } elsif ($currWord eq "," ) { if($added) { $added = 0; } else { $params{"VALUE".$wildParamCount++} = $paramName; } next; } else { $paramName = $currWord; } } if($paramName ne "") { $params{"VALUE".$wildParamCount++}=$paramName; } return \%params; } #Gets the parameter values for a give parameter and given NV String #For example: # Given $line as below: #$line = "SID_LIST_LISTENER12 = (SID_LIST = (SID_DESC = # (SID_NAME = emdw1) (ORACLE_HOME = home2) ) # (SID_DESC = (GLOBAL_DBNAME = gdbname) (SID_NAME = orcl) (ORACLE_HOME = home1))) # And $paramName = SID_DESC, # then this routine will return an array of two Hashes like # ( # { # SID_NAME => emdw1, # ORACLE_HOME => home2 # }, # { # GLOBAL_DBNAME => gdbname, # SID_NAME => orcl # ORACLE_HOME => home1 # }, # ) sub getParamValueListFor { my ($line,$paramName) = @_; my @delimiters = ('(','=',')'); my @toknizedLiterals = tokenize($line,@delimiters); $paramName = uc ($paramName); my $expectingParam = 0; my $expectingValue = 0; my $paramStartFound = 0; my $currWord; my $paramFound = 0; my $paramValueMarker = 0; my %tempParamValue; my @retParamValueList; my $curPoint = 0; my $tempParamName; my $bError; while ( ($currWord = getNextWord($curPoint++,@toknizedLiterals)) ne "") { if ($currWord eq "(" ) { $expectingParam = 1; $expectingValue = 0; if($paramFound) { $paramFound++; $paramStartFound = 1; } } elsif ($currWord eq ")" ) { $expectingParam = 0; $expectingValue = 0; if($tempParamName ne "") { # Need to add empty paramvalue $tempParamValue{uc $tempParamName} = ""; $tempParamName = ""; } if($paramFound) { $paramFound--; #if($paramStartFound eq 0) if(!$paramFound) { #end of param found; push(@retParamValueList, {%tempParamValue}); } else { $paramStartFound = 0; } } } elsif ($currWord eq "=") { $expectingValue = 1; $expectingParam = 0; } else { if($paramFound) { if($expectingParam) { $tempParamName = $currWord; } else { $tempParamValue{uc $tempParamName} = $currWord; $tempParamName = ""; } } elsif($expectingParam && $paramName eq uc ($currWord)) { $paramFound = 1; %tempParamValue = {}; foreach $key (keys %tempParamValue) { delete $tempParamValue{$key}; } } }#End of Else } return \@retParamValueList; } #This subroutine tokenizes the given line based on the specified delimiters # For the following delimiters # ( , = and ) # and #$line = "(SID_LIST = (SID_DESC = # (SID_NAME = emdw1) (ORACLE_HOME = home2) ) # (SID_DESC = (GLOBAL_DBNAME = gdbname) (SID_NAME = orcl) (ORACLE_HOME = home1))) # the return value will be and array as follows # ( #"(", "SID_LIST", "=", "(" , "SID_DESC", "=" , #"(" , "SID_NAME", "=","emdw1", ")", "(" , "ORACLE_HOME", "=" , "home2" , ")", ")", #"(", "SID_DESC", "=", "(" , "GLOBAL_DBNAME", "=" , "gdbname", ")", #"(" , "SID_NAME", "=","orcl", ")", "(" , "ORACLE_HOME", "=" , "home1" , ")", ")", ")" ) sub tokenize { my ($line,@delimiters) = @_; if(!defined @delimiters) { @delimiters = ('(','=',')'); } my $quotedLiteral = 0; my $quoteChar; my $currChar; my @parsedChars = parseStrToChars($line); my $curPoint = 0; my @paramValue; my $tempLiteral; my $literalFound; my $backSlashFound; while ( ($currChar = getNextWord($curPoint++,@parsedChars)) ne "") { if($currChar =~ /\s/) { next; } elsif (contains($currChar,@delimiters)) { push(@paramValue,$currChar); } else { $tempLiteral = $currChar; if($currChar eq "\"" || $currChar eq "'") { $quotedLiteral = 1; $quoteChar = $currChar; } else { $quotedLiteral = 0; } $backSlashFound = 0; $literalFound = 0; while ( ($currChar = getNextWord($curPoint++,@parsedChars)) ne "") { #On a backslash (escaped character), save the backslash and #following character into the literal. if ($currChar eq "\\") { $tempLiteral .= $currChar; $backSlashFound = 1; next; } if($backSlashFound) { #don't process this char and reset the back slash found flag $backSlashFound = 0; } else { if ($quotedLiteral) # literal wrapped with quotes { if ($currChar eq $quoteChar) # quote terminator found { $tempLiteral .= $currChar; $literalFound = 1; last; } } else { #did we hit unescaped meta character ( ) or = if (contains($currChar,@delimiters)) { #terminate string - do NOT increment POS, or it will #swallow the metacharacter into the literal $curPoint--; # if($currChar eq ")" || $currChar eq "=") { $literalFound = 1; } last; } } }#End of if($backSlashFound) $tempLiteral .= $currChar; }#End of while ( ($currChar = getNextChar($curPoint++,@parsedChars)) ne "") if($currChar eq "") { $literalFound = 1; } #String.substring() is exclusive for end (does not include end # character. if($literalFound) { push(@paramValue,trim($tempLiteral)); } }#else }#while return @paramValue; } #parse line into characters #for $line=(SID_NAME = emdw1) # the return value will be and array as follows # ( #"(", "S", "I" , "D", "_" , "N" , "A" , "M" , "E", " ", "=", " " ,"e","m","d","w","1",")" # ). sub parseStrToChars { my ($parseStr) = @_; my @parsedChars; # #print "In parseStrToChars\n"; while ($parseStr =~ /(.)/g) { # #print "[$1]\n"; push(@parsedChars,$1); } return @parsedChars; } #Gets the next word in an array of words or strings #if end of array is reached empty char "" is returned. sub getNextWord { my ($curPoint,@parsedChars) = @_; my $char = ""; if ($curPoint < @parsedChars) { $char = $parsedChars[$curPoint]; } return $char; } #Strips leading and trailing spaces and returns the string sub trim { my $origStr = $_[0]; #Strip trailing and leading $origStr =~ s/^\s*|\s*$//g; return $origStr; } # Given the output from the services command in raw mode # from the lsnrctl, this subroutine # returns a hashtable for sids found and itss correponding details # For lsnrctl services output in raw mode like: #LSNRCTL> services (ADDRESS=(PROTOCOL=TCP)(HOST=dkapoor-pc3)(PORT=1234)) #Connecting to (ADDRESS=(PROTOCOL=TCP)(HOST=dkapoor-pc3)(PORT=1234)) #Services Summary... #(SERVICE=(SERVICE_NAME=orclServiceName)(INSTANCE=(INSTANCE_NAME=orcloid)(NUM=1)(IN #STANCE_STATUS=UNKNOWN)(HANDLER=(HANDLER_DISPLAY=DEDICATED SERVER)(HANDLER_INFO=L #OCAL SERVER)(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)(HANDLE #R_ID=B94B489DEB84-11D6-B6FD-0002A517EED1)(PRE=any)(HANDLER_NAME=DEDICATED)(SESSI #ON=NS)(ADDRESS=(PROTOCOL=beq)(PROGRAM=extproc)(ENVS='ORACLE_HOME=d:\oracle92\test #,ORACLE_SID=orcloid')(ARGV0=extprocPLSExtProc)(ARGS='(LOCAL=NO)')))(NUMREL= #1)))\n" #(SERVICE=(SERVICE_NAME=orcl92.abc.xyz.com)(INSTANCE=(INSTANCE_NAME=orcl92)(NUM #=1)(INSTANCE_STATUS=UNKNOWN)(HANDLER=(HANDLER_DISPLAY=DEDICATED SERVER)(HANDLER_ #INFO=LOCAL SERVER)(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)( #HANDLER_ID=B94B489EEB84-11D6-B6FD-0002A517EED1)(PRE=any)(HANDLER_NAME=DEDICATED) #(SESSION=NS)(ADDRESS=(PROTOCOL=beq)(PROGRAM=oracle)(ENVS='ORACLE_HOME=d:\oracle9 #2\ora92,ORACLE_SID=orcl92')(ARGV0='oracleorcl92')(ARGS='(LOCAL=NO)')))(NUMREL=1))) # # Following hashtable is returned: # ( # orcl92 => # { # SERVICE_NAME => orcl92.abc.xyz.com, # ORACLE_HOME => d:\oracle92\ora92, # PORT => 1234 (obtained from the first address description) # }, # orcloid => # { # SERVICE_NAME => orclServiceName, # ORACLE_HOME => d:\oracle92\test, # PORT => 1234 # }, # ) # #Assuptions: # 0. The entry for INSTANCE_NAME = *extproc* (ignoring case) is not returned. # 1. If no ORACLE_SID or ORACLE_HOME found , the entry is not returned # sub getDBDetails { my ($result,$port,$lsnrHost,@dynamicDiscoveredSids) = @_; my %dbDetails; if($result !~ /(ORACLE_HOME)|(ORACLE_SID)/i || (!defined $port || $port eq "")) { return \%dbDetails; } my @resultArray = split /\n/, $result; foreach $line (@resultArray) { if($line !~ /^\s*\(SERVICE/i) { next; } if($line !~ /(ORACLE_HOME)|(ORACLE_SID)/i) { next; } my $serviceName, $oracleHome,$oracleSid, $instanceName; if($line =~ /\(ENVS='.*ORACLE_SID=(.*?)(,|')/i) { $oracleSid = convertSIDForOS($1); } if ($oracleSid =~ /extproc/i) { #filter out sids containing with extproc next; } if(contains($oracleSid,@dynamicDiscoveredSids)) { next; } if($line =~ /\(ENVS='.*ORACLE_HOME=(.*?)(,|')/i) { $oracleHome = $1; } if($line =~ /\(SERVICE_NAME=(.*?)\)/i) { $serviceName = $1; } if( defined $oracleSid && $oracleSid ne "" && defined $oracleHome && $oracleHome ne "" ) { my $sidDetails = { ORACLE_HOME=> $oracleHome, SERVICE_NAME => $serviceName, PORT => $port,HOST => $lsnrHost} ; $dbDetails{$oracleSid} = $sidDetails; } } return \%dbDetails; } #Returns the listener endpoint string sub getListenerAddresses { my ($listener,$listenersInfo) = @_; my $addressesStr; while ( ($param, $value) = each (%$listenersInfo)) { if($param eq $listener) { $addressesStr = $value; last; } } return getAddresses($addressesStr); } #Returns the listener static registered SIDs sub getStaticSIDs { my ($listener,$listenersInfo) = @_; my $sidListStr = getParamValue($listenersInfo,"SID_LIST_".$listener); return getSIDS($sidListStr); } #Get the array of password from the listener.ora file sub getPasswordsFromFile { my ($listener,$listenerFile) = @_; my @passwordList=(); if(-e $listenerFile) { my $listenersInfo = parseOracleConfigFile($listenerFile); if(defined $listenersInfo) { @passwordList= getPasswords($listener,$listenersInfo); } } return @passwordList; } #Get the array of password for the spwcified listener sub getPasswords { my ($listener,$listenersInfo) = @_; my $passwords = getParamValue($listenersInfo,"PASSWORDS_".$listener); my $nvPairs = getParamValues($passwords); my @passwords; while ( ($param,$value) = each %$nvPairs) { #bug#3473397: Net Manager sets listener #password with trailing null characters ("\0"). #need to remove that character before using it. if( $value =~ /\0$/) { $value =~ s/\0*$|$//g; } push(@passwords,$value); } return @passwords; } #Get the parameter value for listener sub getParamValue { my ($listenersInfo,$parameterName) = @_; return $listenersInfo->{ uc ($parameterName)}; } sub getRunCommandOutput { my ($oracleHome,$executable,@commands) = @_; $ENV{ORACLE_HOME}=$oracleHome; my $bkup_path = get_complete_lib_path(); set_lib_path($oracleHome); my $filename; my $fh; my $OSNAME = get_osType(); if($OSNAME eq 'WIN') { my $TEMP = "C:\\TEMP"; #A temp solution &mkDir($TEMP); $filename = "$TEMP\\"."net.$$"; } else { ($fh, $filename) = tempfile(UNLINK => 1); } my $output_string; my $oldNLS_LANG = $ENV{NLS_LANG}; #Unset ORA_NLS variables if in the environment my $oldORA_NLS = $ENV{ORA_NLS}; if(defined $oldORA_NLS) { delete ($ENV{ORA_NLS}); } my $oldORA_NLS32 = $ENV{ORA_NLS32}; if(defined $oldORA_NLS32) { delete ($ENV{ORA_NLS32}); } my $oldORA_NLS33 = $ENV{ORA_NLS33}; if(defined $oldORA_NLS33) { delete ($ENV{ORA_NLS33}); } $ENV{NLS_LANG} = "american_america.utf8"; if(open(EXEC_WRITER, "|$executable > $filename")) { my $cmd; foreach $cmd (@commands) { print EXEC_WRITER "$cmd\n"; } close EXEC_WRITER ; { if(open (OUT_PUT, "$filename")) { my @output_content = ; $output_string = "@output_content"; close OUT_PUT; } } } if(defined $oldNLS_LANG) { $ENV{NLS_LANG} = $oldNLS_LANG; } else { delete ($ENV{NLS_LANG}); } if(defined $oldORA_NLS) { $ENV{ORA_NLS} = $oldORA_NLS; } if(defined $oldORA_NLS32) { $ENV{ORA_NLS32} = $oldORA_NLS32; } if(defined $oldORA_NLS33) { $ENV{ORA_NLS33} = $oldORA_NLS33; } #close($fh); if($OSNAME eq 'WIN') { unlink $filename } set_complete_lib_path($bkup_path); return $output_string; } #checks if an array contains an item sub contains { my ($item,@array) = @_; foreach $anItem (@array) { if ($anItem eq $item) { return 1; last; } } return 0; } #Check if the passed file is present in the given list of files sub containsFile { my ($file,@listOfFiles) = @_; foreach $aFile (@listOfFiles) { if(isSameFileSystemEntity($aFile,$file)) { return 1; } } return 0; } sub containsIgnoreCase { my ($item,@array) = @_; my $quotedItem = quotemeta($item); foreach $anItem (@array) { if ($anItem =~ /^\s*$quotedItem\s*$/i) { return 1; } } return 0; } #Get the result of running a lsnrctl command #if dontUsePswdFirst is set sub getResult { my ($executable, $command, $listenerFile, $name,$dontUsePswdFirst) = @_; if(!defined $dontUsePswdFirst) { $dontUsePswdFirst = 0; } my $r; my @passwordList=(); #read the password from the file only is dontUsePwd is not set if(!$dontUsePswdFirst) { @passwordList = getPasswordsFromFile($name,$listenerFile); } my @commands ; my $totalPswd = @passwordList; my $currPswdInex = 0; do { @commands = (); my $pswd; #Add password if present if($currPswdInex < $totalPswd) { push(@commands,"set password ".$passwordList[$currPswdInex++]); } #Adding capability to take multiple commands also if (ref ($command) eq "ARRAY") { push(@commands, @{$command}); } else { push(@commands,$command); } push(@commands,"exit"); $r = getRunCommandOutput($ENV{LSNR_ORACLE_HOME},$executable,@commands); #if there is a password error try the next password, #TNS-01169: The listener has not recognized the password if($r =~ /TNS-01169/i) { #Got password error, get passwords if dontUsePswdFirst is set if($dontUsePswdFirst) { @passwordList = getPasswordsFromFile($name,$listenerFile); $totalPswd = @passwordList; $dontUsePswdFirst = 0; $currPswdInex = 0; } } }while($r =~ /TNS-01169/i && $currPswdInex < $totalPswd); return $r; } #return hostName is listener host is "localhost", empty or local ip #127.0.0.1 sub resolveLsnrHostName { my ($lsnrHost,$hostName) = @_; $lsnrHost = trim($lsnrHost); if( uc ($lsnrHost) eq uc ("localhost") || $lsnrHost eq "" || $lsnrHost eq "127.0.0.1" ) { return $hostName; } return $lsnrHost; } #Get the default initialization file location sub getDefaultInitFileLocation { my ($OracleHome) = @_; my $initDir; if((get_osType() eq 'WIN')) { $initDir = $OracleHome . "/database"; } else { $initDir = $OracleHome . "/dbs"; } return $initDir; } #Returns 1 if the argument is a quoted string like # 'param1' or "param". sub isQuoted { my ($argument) = @_; if($argument =~ /\s*\'(.*)\'\s*/ || $argument =~ /\s*\"(.*)\"\s*/) { return 1; } return 0; } #Returns an upper cased value if the argument is not quoated sub convertToUcIfNotQuoted { my ($argument) = @_; if(!isQuoted ($argument)) { if($argument =~ /\s*\'(.*)\'\s*/) { $argument = $1; } if($argument =~ /\s*\"(.*)\"\s*/) { $argument = $1; } $argument = uc $argument; } return $argument; } sub isThisListenerRunning { my ($statusResult,$listenerOraDir,$name) = @_; my $line; my $nameMatches = 0; #due to IFILE entries , the listener might not o/p parameter file entries #for such cases we default it to UP status # No more keeping the DEFAULT as UP here, because in case the Listener at port 1521 # is started without a listener.ora file, we need to show that as down. At the same time # our Alert message will say that although there is a listener at port 1521, it does not use # any "listener.ora" file. Please make it use some "listener.ora". # ideal fix would be to open the listener.ora and look for IFILE entry there # but in case the listener.ora does not exist at this location then this check will fail # even if the listener.ora exists and we dont even have read permissions then # also this check will fail. # hence setting the default back to 1 - this will fix IFILE issue, but will also report # other kind of listeners started without a listener.ora on the same host-port my $tnsadminMatches = 1; my @info = split(/\n/, $statusResult); my $quotedName = quotemeta($name); my $quotedListenerOraDir = quotemeta($listenerOraDir); foreach $line (@info) { #match the listener Alias if ($line =~ /^(.*)\s+$quotedName\s*$/i) { $nameMatches = 1; } #look for a line which contains listener.ora if ($line =~ /^(.*)\s+(.*)(.)listener.ora\s*$/i) { #check if the listener ora dir is same as the one in the pattern if ($line =~ /^(.*)\s+$quotedListenerOraDir(.)listener.ora\s*$/i) { $tnsadminMatches= 1; } else { #BugFix 3639863 : append "listener.ora" to allow file symlink comparison my $sym_file1 = $2."/listener.ora"; my $sym_file2 = $listenerOraDir."/listener.ora"; if(isSameFileSystemEntity($sym_file1,$sym_file2)) { $tnsadminMatches= 1; } else { $tnsadminMatches= 0; } } } } if($nameMatches && $tnsadminMatches) { return 1; } return 0; } #Checks if the two files are same. #In Windows, match the files. #In Unix, match the device and inode of the files. sub isSameFileSystemEntity { my ($file1,$file2) = @_; if(!(get_osType() eq 'WIN')) { my ($dev, $ino) = stat $file1; my ($dev1, $ino1) = stat $file2; if($dev == $dev1 && $ino == $ino1) { return 1; } } else { #Convert to windows slashes $file2 =~ s/\//\\/g; $file1 =~ s/\//\\/g; my $quotedFile2 = quotemeta($file2); if($file1 =~ /^\s*$quotedFile2\s*$/i) { return 1; } } return 0; } sub getErrorIfAny { my ($lsnrctlResult) = @_; my $errorMsg; if ($lsnrctlResult =~ /^*TNS-[0-9]*/i) { my @info = split(/\n/, $lsnrctlResult); my $line; foreach $line (@info) { if ($line =~ /^*TNS-[0-9]*/i) { $errorMsg =$line; last; } } } return $errorMsg; } # Create a specified directory. # Return OK if succeed, otherwise, return NOK. # OK is returned if the specified directory already exists. # mkDir(dirName) sub mkDir { my ($dirName) = @_; my $dirExist = &dirExists($dirName); if($dirExist eq "OK") { return "OK"; } my (@create); push(@create, $dirName); #create parent directories if necessary my($parent) = dirname($dirName); while(! -e "$parent") { push(@create, $parent); $parent = dirname($parent); } while($dirName = pop(@create)) { if(!mkdir($dirName, 0755)){ ## Actually want this error to come out in the job output return "NOK"; } } return "OK"; } # Check if a specified directory exists # Return OK if the directory exists, otherwise, return NOK. # dirExists(dirName) sub dirExists { my ($dirName) = @_; if(! -e "$dirName") { return "NOK"; } elsif(! -d "$dirName") { return "NOK"; } return "OK"; } # We work with a result in a format as below: # ###################################################################################### # lsnrctl status '(ADDRESS=(PROTOCOL=TCP)(HOST=host)(PORT=2449))' # # LSNRCTL for Linux: Version 10.2.0.0.0 - Beta on 04-JUL-2005 01:37:27 # # Copyright (c) 1991, 2011, Oracle and/or its affiliates. All rights reserved. # # Connecting to (ADDRESS=(PROTOCOL=TCP)(HOST=stadm18)(PORT=2449)) # STATUS of the LISTENER # ------------------------ # Alias LISTENER_NAME # Version TNSLSNR for Linux: Version 10.2.0.0.0 - Beta # Start Date 04-JUL-2005 01:36:48 # Uptime 0 days 0 hr. 0 min. 38 sec # Trace Level user # Security ON: Local OS Authentication # SNMP OFF # Listener Parameter File /scratch/private/oracle/ora10g/network/admin/listener.ora # Listener Trace File /scratch/private/oracle/ora10g/network/trace/listener5.trc # Listening Endpoints Summary... # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host.domain)(PORT=2249))) # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host.domain)(PORT=2349))) # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host.domain)(PORT=2449))) # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host.domain)(PORT=2549))) # The listener supports no services # The command completed successfully # # ######################################################################################### sub isAnyListenerRunning { my ($statusResult, $lsnrHost, $lsnrPort, $name) = @_; my $line; my $nameMatches = 0; my $hostPortMatches = 0; my @info = split(/\n/, $statusResult); my $quotedName = quotemeta($name); foreach $line (@info) { #match the listener Alias if ($line =~ /^(.*)\s+$quotedName\s*$/i) { $nameMatches = 1; #print "\n NAME MATCHED \n"; } #look for a line which contains: # (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=host.domain)(PORT=2249))) # $1 will contain host name "host.domain" # $2 will contain port "2249" if(($nameMatches eq 1) && ($hostPortMatches eq 0)) { if ($line =~ /^\s+\(DESCRIPTION=\(ADDRESS=\(PROTOCOL=.*\(HOST=(.*)\)\(PORT=(.*)\)\)\)\s*$/) { if ($2 eq $lsnrPort) { $hostPortMatches = matchHost($1, $lsnrHost); if($hostPortMatches eq 0) #one more try - In case we got an IP instead of host name { my $convertedHostName = ip2host($lsnrHost); if(!($convertedHostName eq "")) { $hostPortMatches = matchHost($1, $convertedHostName); } } #one last try - In case RESULT displays an IP instead of host name if($hostPortMatches eq 0) { # This should never happen. my $convertedHostName = ip2host($1); if(!($convertedHostName eq "")) { $hostPortMatches = matchHost($convertedHostName, $lsnrHost); } } } } } } if($nameMatches && $hostPortMatches) { return 1; } return 0; } sub matchHost { my ($hostInResult, $lsnrHost) = @_; $hostInResult = trimwhitespace($hostInResult); $lsnrHost = trimwhitespace($lsnrHost); my $hostMatches = 0; if($hostInResult eq $lsnrHost) { $hostMatches = 1; } else #There is still hope, maybe $1 is "host.domain.com", but $quotedHost = "host" { if($hostInResult =~ /^$lsnrHost\..*/i) { $hostMatches = 1; } else #REMOTE CHANCE OF THIS: $1 is "host", but $quotedHost = "host.domain.com" { if($lsnrHost =~ /^$hostInResult\..*/i) { $hostMatches = 1; } } } return $hostMatches; } # Remove whitespace from the start and end of the string sub trimwhitespace { my ($mstring) = @_; my $retString = $mstring; $retString =~ s/^\s+//; $retString =~ s/\s+$//; return $retString; } # In case we got am IP addr, but the output of "lsnrctl status" shows FQDN etc... sub ip2host { my ($ip) = @_; my $hostName = trimwhitespace($ip); my @numbers = split(/\./, $ip); my $ip_number = pack("C4", @numbers); $hostName = (gethostbyaddr($ip_number, 2))[0]; return $hostName; } # This method does not check the HOST and PORT, it assumes you already did that by calling: # isAnyListenerRunning() # Here we just check for a matching LISTENER name and then check for a line saying: # 'Listener Parameter File SPACE ' # we return the listener.ora location from this method. sub getCurrentListenerOraFile { my ($statusResult, $name) = @_; my $line; my $nameMatches = 0; my $listenerOraFound = 0; my $listenerOraFile = ""; my @info = split(/\n/, $statusResult); my $quotedName = quotemeta($name); foreach $line (@info) { #match the listener Alias if ($line =~ /^(.*)\s+$quotedName\s*$/i) { $nameMatches = 1; } #look for a line which contains: # Listener Parameter File /scratch/private/oracle/ora10g/network/admin/listener.ora if($nameMatches eq 1) { if ($line =~ /^(.*)\s+(.*)(.)listener.ora\s*$/i) { if(!(get_osType() eq 'WIN')) { $listenerOraFile = $2 . "/listener.ora"; } else { $listenerOraFile = $2 . "\\listener.ora"; } return $listenerOraFile; } } } return $listenerOraFile; } sub isExecutionPossible { my $lsnrname = $ENV{LSNR_NAME}; EMD_PERL_DEBUG(" lsnrdebug :: isExecutionPossible"); my ($pcommand) = @_; if(isPriviligeCommand($pcommand)) { if(isPriviligeUser()) { return 1; } else { if(isPasswordSet()) { return 1; } else { EMD_PERL_DEBUG("listenerUtil.isExecutionPossible :: Skipping execution of privilege command @{$pcommand} :: $pcommand as the listener $lsnrname is not password protected and user emagent is not a listener oracle home owner "); return 0; } } } else { return 1; } } sub isPasswordSet { my $paswd = $ENV{'LSNR_PASSWORD'}; if(!($paswd eq "")) { EMD_PERL_DEBUG(" lsnrdebug :: isPasswordSet :: password is set"); return 1; } else { EMD_PERL_DEBUG(" lsnrdebug :: isPasswordSet :: password is not set"); return 0; } } sub isPriviligeCommand { EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeCommand"); my ($pcommand) = @_; EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeCommand :: @{$pcommand} :: $pcommand"); #List of privilige commands my @priviligeComands = ("save_config","stop","trace","spawn","reload","set log_file","set log_status","set inbound_connect_timeout", "set save_config_stop_on","set trc_file","set trc_level","set log_directory","set startup_waittime","show rules","show trc_directory", "show log_file","show log_status","show inbound_connect_timeout","show snmp_visible","show trc_file","show trc_level","show log_directory", "show startup_waittime","show save_config_stop_on"); #Adding capability to take multiple commands also if (ref ($pcommand) eq "ARRAY") { foreach my $val2 (@{$pcommand}) { foreach my $val1 (@priviligeComands) { $val2 = trim($val2); #use case insensitive match if($val1 =~ m/$val2/i) { EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeCommand :: Command val :: $val1"); return 1; } } } } else { foreach my $val (@priviligeComands) { $pcommand = trim($pcommand); #use case insensitive match if ($val =~ m/$pcommand/i) { EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeCommand :: Command val :: $val"); return 1; } } } } sub isPriviligeUser { my $lsnrhome = $ENV{'LSNR_ORACLE_HOME'}; #my $agenthome = $ENV{'EMDROOT'}; my $agenthome = $ENV{'PLUGIN_ROOT'}; my $listeneruser = file_owner($lsnrhome); my $agentuser = file_owner($agenthome); if ($listeneruser eq $agentuser) { EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeUser :: agent user $agentuser and listener user $listeneruser matches"); return 1; } else { EMD_PERL_DEBUG(" lsnrdebug :: isPriviligeUser :: agent user $agentuser and listener user $listeneruser does not match"); return 0; } } sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; }