# # Copyright (c) 2004, 2007, Oracle. All rights reserved. # # NAME # conditionContext.pl # # DESCRIPTION # This script contains generic functions for host-metric-collection scripts, like getConditionContext etc # # MODIFIED (MM/DD/YY) # sreddy 05/08/07 - Backport sreddy_bug-5139454 from main # sreddy 05/02/07 - fix Windows Platform Handling # sreddy 05/02/07 - stop handling _ as a regexp character # Fix for bug#5917834 removed _ as regexp character # from the EM OMS/Agent framework as well # sacgoyal 01/24/05 - .? changed to . for regexp meaning of _ wild # character # sreddy 10/05/04 - # sreddy 10/04/04 - add expandPath routine for UNIX systems # sacgoyal 07/22/04 - Creation for Agent Condition Context, Enterprise Manager, 10.2 # use strict; #--------------getConditionContext subroutine-------------- # # This takes value of following agentConditionContext environment variables- # EMAgentConditionContextNum [n] # EMAgentConditionContext0 [column_name1;operator1;criticalThreshold1;warningThreshold1;key1,operator,key_value01;key2,operator,key_value02] # EMAgentConditionContext1 [column_name1;operator1;criticalThreshold1;warningThreshold1;key1,operator,key_value11;key2,operator,key_value12] # ...so on # + # It also takes a list of names as input that should be interpreted # as perl regular expressions, not sql expressions # # Returns an aref of hrefs, where each href has the following keys # conditionColumnName - value is scalar # conditionOperator - value is scalar # criticalThreshold - value is scalar # warningThreshold - value is scalar # keyColumnAref - value is an aref of hrefs, where each href has the keys below # keyName - value is scalar # keyOperator - value is scalar # keyValueToReturn - value is scalar # keyValueToMatch - value is scalar # # Where INTERPRETED_key_values are :-> # - URLdecoded, (ie. %25 %26 %3b converted to % & ; respectively) # - PERL special characters are escaped # - And if operator is "LIKE" then "% and _" are interpreted to # their special meaning of ".* and ." # ############################################################################## sub getConditionContext () { my @conditions = (); if (!defined($ENV{EMAgentConditionContextNum}) || $ENV{EMAgentConditionContextNum} == 0) { EMD_PERL_DEBUG("getConditionContext: No user specified conditions passed in"); return \@conditions; } my @perlRegExpColumns = @_; EMD_PERL_DEBUG("getConditionContext: perlRegExpColumns = @perlRegExpColumns"); for (my $i = 0; $i < $ENV{EMAgentConditionContextNum}; $i++) { my $envName = "EMAgentConditionContext" . $i; EMD_PERL_DEBUG("getConditionContext: User specified condition context is $ENV{$envName}"); next if (!defined($ENV{$envName}) && EMD_PERL_ERROR("$envName not set\n")); my @conditionInfo = split (';', $ENV{$envName}); my @currentKeys = (); for (my $j = 4; $j <= $#conditionInfo; $j++) { my @keyColumnInfo = split ('&', $conditionInfo[$j]); my $keyValueToReturn = &decodeUrl($keyColumnInfo[2]); my $keyValueToMatch = $keyValueToReturn; my $isPerlRegExpColumn = 0; foreach my $perlRegExpColumn (@perlRegExpColumns) { if ($perlRegExpColumn eq $keyColumnInfo[0]) { $isPerlRegExpColumn = 1; last; } } if (!$isPerlRegExpColumn) { # Need to support SQL reg expressions for this column ##################################################### # quotemeta() escapes all PERL's special characters. # sql specific conversions include the following # % => \% # \ => \\ ##################################################### $keyValueToMatch = quotemeta($keyValueToMatch); if (uc($keyColumnInfo[1]) eq "1" ) #LIKE is defined as 1 { $keyValueToMatch = &interpretPattern($keyValueToMatch); } } if (!defined($keyValueToMatch) || $keyValueToMatch eq "") { $keyValueToMatch = ".*"; } my %currentKey = ("keyName" => $keyColumnInfo[0], "keyOperator" => $keyColumnInfo[1], "keyValueToReturn" => $keyValueToReturn, "keyValueToMatch" => $keyValueToMatch); push(@currentKeys, \%currentKey); } my %currentCondition = ("conditionColumnName" => $conditionInfo[0], "conditionOperator" => $conditionInfo[1], "criticalThreshold" => $conditionInfo[2], "warningThreshold" => $conditionInfo[3], "keyColumnAref" => \@currentKeys); push @conditions, \%currentCondition; } return \@conditions; } ############################################################################# #---------------------sub interpretPattern----------------------------------- # # It does following conversions # empty string => .* # \\\% ==> % # match literal % # \\\\ ==> \\ # match literal \ # \\[?] ==> \\[?] # \% ==> .* # match 0 or more characters # ############################################################################# sub interpretPattern { my $pattern1 = shift @_; my $intpString = ""; my @pattern = split("",$pattern1); if($pattern1 eq "") { $intpString = ".*"; #interpreting Empty string to .* } else { while(@pattern) { my $char1 = shift @pattern; if( $char1 eq "\\") { my $char2 = shift @pattern; if( $char2 eq "%") { $intpString = $intpString.".*"; #converting \% to .* } elsif( $char2 eq "\\" ) { my $char3 = shift @pattern; if( $char3 eq "\\" ) { my $char4 = shift @pattern; if( $char4 eq "%" ) { $intpString = $intpString."%"; #converting \\\% to % } elsif($char4 eq "\\") { $intpString = $intpString."\\\\"; #converting \\\\ to \\ } else { $intpString = $intpString."\\\\\\$char4"; } } else { $intpString = $intpString."\\\\$char3"; } } else { $intpString = $intpString."\\$char2"; } } else { $intpString = $intpString."$char1"; } } #end while } return $intpString; }#end sub ############################################################################# #---------------------sub decodeUrl----------------------------------- # # It does following conversions-> [%25 -> %] [ %26 -> &] [%3b -> ;] ############################################################################# sub decodeUrl { my $decodedUrl = shift @_; $decodedUrl =~ s/%25/%/g; #converting %25 to % $decodedUrl =~ s/%26/&/g; #converting %26 to & $decodedUrl =~ s/%3b/;/g; #converting %3b to ; return $decodedUrl; } ########################################################################## # ------------- expandPath subroutine ---------------------------------- # Inputs: # $pathToExpand - path pattern to be expanded on the target host # - should be the first parameter in the list passed # - path can contain SQL regexp characters (%, _) # - % matches 0 or more chacters of the given directory content # - _ matches any one character of the directory content # - (%, _, \) can be escaped with \ # Outputs: # Returns an array of paths matching $pathToExpand that exist on the host # # Note: This routine is implemented for UNIX systems at this point. ########################################################################## sub expandPath { my ($pathToExpand) = shift @_; return expandWindowsPath($pathToExpand) if (($^O eq "MSWin32") || ($^O eq "Windows_NT")); my @expandedPaths = (''); my $fpSep = '/'; my $skipDirEntries = '(\.)|(\.\.)'; # EMD_PERL_DEBUG ("expandPath: pathToExpand = $pathToExpand"); my @splitPath = splitIntoTokens ($pathToExpand , $fpSep); # EMD_PERL_DEBUG ("expandPath: #splitPath = $#splitPath"); for (my $i = 0; $i <= $#splitPath; $i++) { my $subPath = $splitPath[$i]; my @curExpandedPaths = @expandedPaths; # EMD_PERL_DEBUG ("expandPath: subPath = $subPath"); next if ($subPath eq ""); @expandedPaths = (); if ($subPath eq $fpSep) { foreach my $curExpandedPath (@curExpandedPaths) { my $newPath = $curExpandedPath . $subPath; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } next; } my $filePattern = $subPath; $filePattern = quotemeta($subPath); $filePattern = interpretPattern($filePattern); # EMD_PERL_DEBUG ("expandPath: filePattern = $filePattern"); if ($subPath eq $filePattern) { foreach my $curExpandedPath (@curExpandedPaths) { my $newPath = $curExpandedPath . $subPath; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } next; } foreach my $curExpandedPath (@curExpandedPaths) { opendir(DH, $curExpandedPath); my @present_files = readdir(DH); closedir(DH); foreach my $file (@present_files) { # EMD_PERL_DEBUG ("expandPath: file = $file"); next if $file =~ /^$skipDirEntries$/; if ($file =~ /^$filePattern$/) { my $newPath = $curExpandedPath . $file; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } } } } # foreach my $path (@expandedPaths) # { # EMD_PERL_DEBUG("expanded_paths: $pathToExpand: $path\n"); # } return @expandedPaths; } sub expandWindowsPath { my ($pathToExpand) = shift @_; my @expandedPaths = (''); my $fpSep = '\\'; my $skipDirEntries = '(\.)|(\.\.)'; # EMD_PERL_DEBUG ("expandWindowsPath: pathToExpand = $pathToExpand"); if ($pathToExpand =~ /^\\\\/) { EMD_PERL_ERROR("Invalid Path[0]: UNC path expansion not supported: $pathToExpand"); return @expandedPaths; } if ($pathToExpand =~ /^\\/) { EMD_PERL_ERROR("Invalid Path[1]: Path must start with a valid drive: $pathToExpand"); return @expandedPaths; } my @splitPath = splitIntoTokens ($pathToExpand , $fpSep); if ($#splitPath < 0) { EMD_PERL_ERROR("Invalid Path[2]: $pathToExpand"); return @expandedPaths; } if ($splitPath[0] eq "" || $splitPath[0] eq $fpSep) { EMD_PERL_ERROR("Invalid Path[3]: $pathToExpand"); return @expandedPaths; #this should never happen } # EMD_PERL_DEBUG ("expandWindowsPath: #splitPath = $#splitPath"); for (my $i = 0; $i <= $#splitPath; $i++) { my $subPath = $splitPath[$i]; my @curExpandedPaths = @expandedPaths; # EMD_PERL_DEBUG ("expandWindowsPath: subPath = $subPath"); next if ($subPath eq ""); @expandedPaths = (); if ($subPath eq $fpSep) { foreach my $curExpandedPath (@curExpandedPaths) { my $newPath = $curExpandedPath . $subPath; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } next; } my $filePattern = $subPath; $filePattern = quotemeta($subPath); $filePattern = interpretPattern($filePattern); # EMD_PERL_DEBUG ("expandWindowsPath: filePattern = $filePattern"); if ($subPath eq $filePattern) { if ($i == 0) { my $drive = $subPath . '\\'; # EMD_PERL_DEBUG ("expandPath: matching Drive: $drive") and push (@expandedPaths, $drive) if (-d $drive); } else { foreach my $curExpandedPath (@curExpandedPaths) { my $newPath = $curExpandedPath . $subPath; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } } next; } foreach my $curExpandedPath (@curExpandedPaths) { if ($i == 0) { my @drives = getWindowsDrives(); foreach my $drive (@drives) { # EMD_PERL_DEBUG ("drive: $drive, filePattern: $filePattern"); if ($drive =~ /^$filePattern$/) { my $newPath = $drive . '\\'; # EMD_PERL_DEBUG ("matched drive: $drive") and push (@expandedPaths, $drive) if (-d $newPath); } } } else { opendir(DH, $curExpandedPath); my @present_files = readdir(DH); closedir(DH); foreach my $file (@present_files) { # EMD_PERL_DEBUG ("expandWindowsPath: file = $file"); next if $file =~ /^$skipDirEntries$/; if ($file =~ /^$filePattern$/) { my $newPath = $curExpandedPath . $file; push (@expandedPaths, $newPath) if ($newPath eq "" || -e $newPath); } } } } } # foreach my $path (@expandedPaths) # { # EMD_PERL_DEBUG("expanded_paths: $pathToExpand: $path\n"); # } return @expandedPaths; } sub splitIntoTokens($$) { my ($path, $matchCharacter) = @_; my @result = (); my $word=""; my $pending = 1; my $escapedLiteralPercent = '\\%'; my $escapedLiteralBackslash = '\\\\'; my $literalBackslash = '\\'; my $literalPercent = '%'; my $encodeLiteralPercent = 'P1E2R3C4E5N6T7'; my $encodedLiteralBackslash = 'B1A2C3K4S5L6A7S8H9'; my $savedPath = $path; my $qEscapedLiteralPercent = quotemeta($escapedLiteralPercent); my $qEscapedLiteralBackslash = quotemeta($escapedLiteralBackslash); $path =~ s/$qEscapedLiteralBackslash/$encodedLiteralBackslash/g; $path =~ s/$qEscapedLiteralPercent/$encodeLiteralPercent/g; $path =~ s/$encodedLiteralBackslash/$literalBackslash/g; my @letters = split ("", $path); if ($#letters == -1) { return @result; } for (my $i = 0; $i <= $#letters; $i++) { if ($letters[$i] eq $matchCharacter) { $word =~ s/$encodeLiteralPercent/$escapedLiteralPercent/g; push @result, $word; push @result, $matchCharacter; $word = ""; $pending = 0; next; } $word .= $letters[$i]; $pending = 1; } if ($pending) { $word =~ s/$encodeLiteralPercent/$escapedLiteralPercent/g; push @result, $word; } my $buffer=""; foreach (@result) { $buffer .= "$_ "; } EMD_PERL_DEBUG("splitIntoTokens[$savedPath]: $buffer"); return @result; } my $initWindowsDrives=0; my @windowsDrives=(); sub getWindowsDrives() { return @windowsDrives if ($initWindowsDrives == 1); $initWindowsDrives=1; if (($^O eq "MSWin32") || ($^O eq "Windows_NT")) { my $nmupm = $ENV{ORACLE_HOME}.'\\bin\\nmupm.exe'; if ( -f $nmupm ) { $ENV{EM_MONITOR_ALL_DISKS}="TRUE"; my @results = `$nmupm filesystems`; if ($#results >= 0) { foreach my $result (@results) { # EMD_PERL_DEBUG("$result"); if ($result =~ /^em_result=/) { my @parts = split('=',$result); if ($#parts == 1) { my @subParts = split(':',$parts[1]); if ($#subParts == 1) { my $drive = $subParts[0]; push @windowsDrives, "$drive:" # and EMD_PERL_DEBUG("add $drive:") if ( -d "$drive:\\" ); } } } } } } else { EMD_PERL_ERROR("$nmupm does not exist"); } } return @windowsDrives; } sub isRegexpValid($) { my ($path) = @_; my $escapedLiteralPercent = '\\%'; my $escapedLiteralBackslash = '\\\\'; my $literalBackslash = '\\'; my $qEscapedLiteralPercent = quotemeta($escapedLiteralPercent); my $qEscapedLiteralBackslash = quotemeta($escapedLiteralBackslash); my $qLiteralBackSlash = quotemeta($literalBackslash); my $encodeLiteralPercent = 'P1E2R3C4E5N6T7'; my $encodedLiteralBackslash = 'B1A2C3K4S5L6A7S8H9'; # replace '\\\\' with 'B1A2C3K4S5L6A7S8H9' $path =~ s/$qEscapedLiteralBackslash/$encodedLiteralBackslash/g; # replace '\\%' with 'P1E2R3C4E5N6T7' $path =~ s/$qEscapedLiteralPercent/$encodeLiteralPercent/g; if ($path =~ /$qLiteralBackSlash/) { # It is an error to have single backslash in the path at this point return 0; } return 1; } 1;