#  $Header: fileMonitoring1.pl 06-jul-2007.01:29:01 sejain Exp $
#
# Copyright (c) 2004, 2007, Oracle. All rights reserved.  
#
#    NAME
#      fileMonitoring1.pl
#
#    DESCRIPTION
#      Metric script that checks whether certain file or directory 
#      exists and prints out various attributes about it
#
#
#    OUTPUT:
#         em_result=<name>|file_compute_status|<permissions>|<size in KB>
#         where file_compute_status =
#                0 if all attributes were successfully computed
#                <error_message> if an error is encountered
#
#   Input: agentConditionContext environment variables, which 
#          specifies the criteria for file monitoring
#
#    sejain      07/05/07 - bug-6165864: getDirSize giving errors on Solaris
#    sreddy      06/21/05 - fix bug#4442004
#    sreddy      06/21/05 - add pathSeperator support
#    sreddy      10/04/04 - enhanced the error handling
#    sreddy      10/03/04 - fix getFiles routine by replacing with expandPath
#    sreddy      10/03/04 - eliminate need for agent state 
#    sacgoyal    09/22/04 - sacgoyal_condition_contexts
#    sacgoyal    08/05/04 - Creation for Agent Condition Context, Enterprise Manager, 10.2
# 
use strict;
use hostGenFunctions;
use File::Basename;
require "emd_common.pl";
require "semd_common.pl";
require "conditionContext.pl";

my %em_result = ();
my @filesystems = ();

my $fileFoundMessage = '0';
my $fileNotFoundMessage = 'File or Directory not found: ';
my $sizeErrorMessage = 'Error in computing size for: ';
my $statErrorMessage = 'Error in stat call for: ';
my $pathExpansionFailedMessage = 'No matching file(s) or directory(ies) found for pattern: ';

my @perlRegExpColumns = ('file_name');
my $conditionContextAref = getConditionContext(@perlRegExpColumns);
$conditionContextAref = &addDefaultConditionContext( $conditionContextAref );

exit 0 if ($#$conditionContextAref < 0);

# Getting all the files from conditionContexts and then
# processing them one by one

foreach my $conditionHref (@$conditionContextAref)
{
  my $keysAref = ${$conditionHref}{"keyColumnAref"};

  if ($#{$keysAref} < 0 )
  {
    next;
  }
  
  my ($fileKeyToMatch,$fileKeyToReturn,$fileKeyOperator)=("","","");
  my $keyHref = ${$keysAref}[0];
  if (${$keyHref}{"keyName"} eq "file_name")
  {
    $fileKeyToMatch = ${$keyHref}{"keyValueToMatch"};
    $fileKeyToReturn = ${$keyHref}{"keyValueToReturn"};
    $fileKeyOperator = ${$keyHref}{"keyOperator"};
  }
  else
  {
    EMD_PERL_ERROR("Unknown Key Column: ${$keyHref}{'keyName'}");
  }
  EMD_PERL_DEBUG("fileKeyToMatch=$fileKeyToMatch, fileKeyOperator=$fileKeyOperator, fileKeyToReturn=$fileKeyToReturn");

  if ($fileKeyToReturn eq "")
  {
    EMD_PERL_ERROR("Skipping, Required Key Column is null"); 
    next;
  }

  if ($fileKeyOperator eq "0") # EQ is defined as 0
  {
    computeAndAddResult ($fileKeyToReturn);
  }
  elsif ($fileKeyOperator eq "1")  # LIKE is defined as 1
  { 
    my @files = expandPath($fileKeyToReturn);
    
    if( $#files == -1 )
    {
      $em_result{$fileKeyToReturn} = $fileKeyToReturn. '|'. $pathExpansionFailedMessage . $fileKeyToReturn . '|||';
      EMD_PERL_DEBUG($em_result{$fileKeyToReturn});
    }
    else
    {
      foreach my $file (@files) 
      {
        computeAndAddResult ($file);
      }
    }
  }
}

while (my ($fname, $result) = each %em_result)
{
    print "em_result=$result\n";
    EMD_PERL_DEBUG("fileMonitoring.pl em_result=$result");
}

#############################################################################
#-----------------------getValueString--------------------      
#############################################################################
sub getValueString
{
  my ($file) = @_;
  my @attr = stat($file);
  if ($#attr == -1)
  {
    return '|' . $statErrorMessage . $file . '|||';
  }
  my $mode_s = mode_to_sum($attr[2]);
  my $osize = $attr[7];
  my $size = $osize;

  if (-d $file)
  {

# first match against file system information
# reason: du may fail or take very long if it runs into
# access errors but df will succeed

    $size = getSizeFromAllFileSystems($file);

    if ($size == -1)
    {

# given that there is no match with mounted file systems, try du now
# du can take very long if it runs into access errors
# this is the reason for trying df based matching above

     my $exitStatus = 0;
     ($size, $exitStatus) = getDirSize($file);
     EMD_PERL_ERROR($sizeErrorMessage . $file) if ($exitStatus != 0);
    }
  }
  
  if ($size == -1)
  {
    return '|' . $sizeErrorMessage . $file . '|'. $mode_s . '||';
  }

# bug-6165864: Since for Solris we returning in size of K
# so no need to divide by 1024.
#  my $size_KB = $size/1024;
  my $os = '';
  my $size_KB = 0;
  chomp ($os = `uname -s`) or die "Failed to run the uname command";
  if ($os eq "SunOS")
  {
  $size_KB = $size;
  }
  else
  {
  $size_KB = $size/1024;
  }
  return '|' . $fileFoundMessage . '|' . $mode_s . '|' . $size_KB;
}

#############################################################################
#-----------------------mode_to_sum--------------------      
#############################################################################
sub mode_to_sum 
{
    my $mode = shift;
    my $myNum;

    my $or = $mode & 0400 ? '4' : '0'; 
    my $ow = $mode & 0200 ? '2' : '0';
    my $ox = $mode & 0100 ? '1' : '0';

    my $gr = $mode &  040 ? '4' : '0'; 
    my $gw = $mode &  020 ? '2' : '0'; 
    my $gx = $mode &  010 ? '1' : '0';

    my  $otr = $mode &    4 ? '4' : '0';
    my  $otw = $mode &    2 ? '2' : '0'; 
    my  $otx = $mode &    1 ? '1' : '0';

    my  $op = $or + $ow + $ox;
    my  $gp = $gr + $gw + $gx;
    my  $otp = $otr + $otw + $otx;


    return $op.$gp.$otp;
}


#############################################################################
#-----------------------addDefaultConditionContext--------------------
#    By default, $EMSTATE/sysman/log/emagent.log file is monitored
#    to provide an example of generic file and directory monitoring.
#    EMSTATE points to Agent Home, which can be different from ORACLE_HOME.
#############################################################################

sub addDefaultConditionContext ()
{
  my $os;

  if (($os = get_osType()) eq "-1")
  {
    &raise_error_and_exit("Unsupported OS", 20);
  }

  my $pathSeperator = '/'; #default to UNIX path seperator

  $pathSeperator = '\\' if($os eq "WIN");

  my $defaultFile = "$ENV{EMSTATE}"."$pathSeperator"."sysman"."$pathSeperator"."log"."$pathSeperator"."emagent.log";
  
  return if (! -e $defaultFile);

  my  ($conditionContextAref)= @_;

  my @currentKeys = ();

  my %currentKey = ("keyName" => "file_name",
                    "keyOperator" => "0",  # EQ is defined as 0
                    "keyValueToReturn" => "$defaultFile",
                    "keyValueToMatch" => "$defaultFile");
  push(@currentKeys, \%currentKey); 

  my %currentCondition = ("conditionColumnName" => "",
                          "conditionOperator" => "",
                          "criticalThreshold" => "",
                          "warningThreshold" => "",
                          "keyColumnAref" => \@currentKeys);
                          
  push @{$conditionContextAref}, \%currentCondition;
  
  return $conditionContextAref;
}

#############################################################################
#-----------------------  computeAndAddResult  --------------------
#############################################################################
sub computeAndAddResult
{
  my ($file) = @_;

  if (-e  $file)
  {
    $em_result{$file} =  $file . getValueString($file);
  }
  else
  {
    $em_result{$file} =  $file . '|' .  $fileNotFoundMessage . $file . '|||';
  }
  EMD_PERL_DEBUG($em_result{$file});
}

sub getSizeFromAllFileSystems
{
  my ($dirname) = @_ ;
  my @attr = stat($dirname);

  return -1 if ($#attr == -1);

  my $dirDeviceNumber = $attr[0];
  my $dirInode = $attr[1];

  @filesystems = getDiskInfo('ALL') if ($#filesystems == -1);

  foreach my $line (@filesystems)
  {
    my @fields = split(m/[\t\s]+/, $line);
    my $mntpt = $fields[5];

# try name match

    return $fields[2] * 1024 if ($mntpt eq $dirname);

    my @attr = stat($mntpt);

# try deviceNumber and inode match

    return $fields[2] * 1024 if ($#attr != -1 && $attr[0] eq $dirDeviceNumber && $attr[1] eq $dirInode);
  }
  return -1;
}

sub raise_error_and_exit()
{
  my ($message, $exit_status) = @_;
  EMD_PERL_ERROR($message);
  print STDERR "$message \n";
  exit $exit_status;
}
