#!/usr/local/bin/perl
# 
# $Header: hostGenFunctions.pm 27-mar-2008.01:56:12 sejain Exp $
#
# hostGenFunctions.pm
# 
# Copyright (c) 2004, 2008, Oracle. All rights reserved.  
#
#    NAME
#      hostGenFunctions.pm - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    sejain      03/27/08 - bug-6899782: adding gpfs filesystem
#    sejain      11/30/07 - bug-6447781:remove usage of lsfs as forbidden on AIX
#    ajere       07/28/05 - Fix bug# 4503778
#    sacgoyal    01/25/05 - add getCpuCount() method 
#    aodwyer     11/05/04 - merging EMAGENT_MAIN_SOLARIS_041017 
#    aodwyer     11/05/04 - merging EMAGENT_MAIN_SOLARIS_041017 
#    rzkrishn    06/11/04 - rzkrishn_add_host_gen_func_pl
#    rzkrishn    06/11/04 - Creation
# 

use strict;

package hostGenFunctions;

require Exporter;

#*********************************
# Export Subroutines
#*********************************

@hostGenFunctions::ISA =  ('Exporter');
@hostGenFunctions::EXPORT = qw(
  &trim
  &getDiskInfo
  &getDirSize
  &getCpuCount
  );




#*********************************
#  Global Variables
#*********************************

$hostGenFunctions::DF        =  '/bin/df';
$hostGenFunctions::DATALOC   =  '';
$hostGenFunctions::TAIL      =  '/usr/bin/tail';
$hostGenFunctions::SORT      =  '/bin/sort';
$hostGenFunctions::CAT       =  '/bin/cat';
$hostGenFunctions::DU       =  '/usr/bin/du';
$hostGenFunctions::EGREP     = '/bin/egrep';
$hostGenFunctions::LSFS      = '/usr/sbin/lsfs';
$hostGenFunctions::AWK       = '/usr/bin/awk';
$hostGenFunctions::FILE       =  '/usr/bin/file';
$hostGenFunctions::LANADMIN  =  '/usr/sbin/lanadmin';
$hostGenFunctions::NETSTAT   =  '/bin/netstat';


#*********************************
# Exported Subroutines
#*********************************

sub trim
{

  #Arguments:  string or array
  #Outputs  :  string or array
  #Function : trim

  my (@out) = @_;
  for (@out)
  {
     s/^\s+//;
     s/\s+$//;
  }

  return wantarray ? @out : $out[0];
}

sub getDiskInfo
{
    # Purpose: To get disk space/filesystem space

    my $datadir = $hostGenFunctions::DATALOC;
    my $cmd     = '';
    my $value   = '';
    my @diskinfo = ();
    my $DFLocalFileSystemsParams = '-lkP -x tmpfs -x none';
    my $DFAllFileSystemsParams = '-kP -x tmpfs -x none';
    my ($DFtype) = @_;
    my $DFparams = $DFLocalFileSystemsParams;

    if ($datadir eq '')
    {
        if ($^O eq "dec_osf")
        {
          my $rc = checkCmd($hostGenFunctions::DF) &
                   checkCmd($hostGenFunctions::EGREP) &
                   checkCmd($hostGenFunctions::TAIL);
          if ($rc == 1)
          {
             $DFparams = $DFAllFileSystemsParams if $DFtype eq 'ALL';
             $cmd = "$hostGenFunctions::DF $DFparams |
                     $hostGenFunctions::EGREP -v '\/proc' |
                     $hostGenFunctions::TAIL +2";
          }
        }
        elsif ($^O eq "aix")
        {
          my $rc = checkCmd($hostGenFunctions::DF) &
                   checkCmd($hostGenFunctions::TAIL);
          if ($rc == 1)
          {
             $cmd = "dummy";
          }
        }
        elsif ($^O eq "darwin")
        {
          my $rc = checkCmd($hostGenFunctions::DF) & 
                   checkCmd($hostGenFunctions::TAIL);
          if ($rc == 1)
          {
             $cmd = "$hostGenFunctions::DF -lk |
                      $hostGenFunctions::TAIL +2";
          }
        }
        else
        {
          my $rc = checkCmd($hostGenFunctions::DF) & 
                   checkCmd($hostGenFunctions::TAIL) & 
                   checkCmd($hostGenFunctions::SORT);
          if ($rc == 1)
          {
              
              $cmd = "$hostGenFunctions::DF -lk -x tmpfs -x none | 
                      $hostGenFunctions::TAIL +2 | 
                      $hostGenFunctions::SORT -u";
          }
        }
    }
    else
    {
        $cmd = catCmd('dfFufsk.out');
    }

    return @diskinfo if ($cmd eq '');

    if ($^O eq "aix")
    {
        $value = getAixFilesystemRows();
        $value = execCmd("$hostGenFunctions::DF -kP $value |
                          $hostGenFunctions::TAIL +2");
    }
    else
    {
        $value = execCmd($cmd);
    }
     
    @diskinfo = split("\n", $value);
    chomp(@diskinfo);

    return @diskinfo;
}

#*****************************************************************
# getAixFilesystemRows() routine
#
# It takes the file /etc/filesystems of aix as input parameter.
# Returns list of filesystems is a row.
#*****************************************************************
sub getAixFilesystemRows()
{
        open(FilesystemsFh, "/etc/filesystems") ;
        my $found_entry ;
        my $return_string = '' ;

        while(<FilesystemsFh>)
        {
          next if (m/^\*/s);
          next unless /\s*:$/;
          chomp($_);
          chop($_);
          $found_entry = $_;

          while(<FilesystemsFh>)
          {
            if($_ =~ /vfs.*=/)
            {
               if($_ =~ /jfs|mmfs/)
               {
                  $return_string = $return_string .' '.$found_entry ;
               }
               last;
            }
          }
    }
close FilesystemsFh;
return $return_string;
}


#*****************************************************************
# getDirSize() routine
#
# It takes the name of the directory as input parameter.
# Returns list of (allocated size in bytes, exitStatus).
# exitStatus will be 0 upon success.
#*****************************************************************

sub getDirSize
{
  my ($dirname)   = @_ ;
  my $cmd         = '';
  my $exitStatus  = 1;
  my $size        = -1;

  my $rc = checkCmd($hostGenFunctions::DU);
  return ($size, $exitStatus) if ($rc != 1);

  my $du_result = `$hostGenFunctions::DU -xsb $dirname`;
  $exitStatus = $?;
  chomp $du_result;
  if ($du_result ne "")
  {
    my @du_result = split( /\s+/, $du_result);
    $size = $du_result[0];
    chomp($size);
  }
  return ($size, $exitStatus);
}


sub getCpuCount()
{
        if ($^O eq "hpux")
        {
		my $count= ` /sbin/ioscan/ -kC processor | grep processor | wc -l`;
  		if ($? != 0)
  		{
		    my $exitStatus  = $?;
		    return (1, $exitStatus);
  		}
    		return ($count, 0);
  	}
	elsif ($^O eq "aix")
	{
		my $count = `lsdev -C|grep Process|wc -l`;		
                if ($? != 0)
                {
                    my $exitStatus  = $?;
                    return (1, $exitStatus);
                }
                return ($count, 0);	
	}
  	else
  	{
    		return(1, 0)
        }
  
}


#******************************************
#   Non-Exported Subroutines
#******************************************

sub catCmd($)
{
    return join ($hostGenFunctions::DATALOC, 
                 $hostGenFunctions::CAT . ' ', $_[0]);
}

sub checkCmd($)
{
    # Purpose: To check whether the given command is present and executable

    my ($cmd) = @_;
    my $rc  = 1;
    if (!(-x "$cmd"))
    {
        $rc = 0;
    }

    return $rc;
}

sub execCmd($)
{
    # Purpose: To execute the given command checking for errors

    my ($cmd) = @_;
    my $value = '';
    chomp($value = `$cmd`);

    return $value;
}

#*****************************************************************
# isTextFile() routine 
# 
# It takes the fully qualified name of the file as input parameter.
# Returns 1 if text file, 0 otherwise
#*****************************************************************

# This table reflects a particular philosophy about what constitutes
# "text," and there is room for disagreement about it.
# This refers file_4.21.

use constant F => 0;   # character never appears in text
use constant T => 1;   # character appears in plain ASCII text
use constant I => 2;   # character appears in ISO-8859 text
use constant X => 3;   # character appears in non-ISO extended ASCII (Mac, IBM PC)

my @text_chars = (
        #                   BEL BS HT LF    FF CR
        F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F,  # 0x0X
        #                               ESC
        F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F,  # 0x1X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  # 0x2X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  # 0x3X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  # 0x4X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  # 0x5X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,  # 0x6X
        T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F,  # 0x7X
        #             NEL
        X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X,  # 0x8X
        X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X,  # 0x9X
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  # 0xaX
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  # 0xbX
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  # 0xcX
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  # 0xdX
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I,  # 0xeX
        I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I   # 0xfX
);

sub isTextFile($$)
{
  my $fileName = shift @_;
  my $osCmd    = shift @_;
  my $retVal     = 0;

  my @byteContents;
  my $Byte;

  my $windowsOsCmd      = "cmd";
  my $unixOsCmd         = "/bin/sh";

  #For a valid file, check if it's a text file
  if(-f $fileName)
  {
     if($osCmd eq $unixOsCmd)
     {
        if((checkCmd($hostGenFunctions::FILE))&&
           (`sh -c \"LC_ALL=C $hostGenFunctions::FILE $fileName\"` =~ / text/))
        {
           $retVal = 1;
        }
     }
     elsif($osCmd eq $windowsOsCmd)
     {
       local $/;

       open(FH,$fileName);
       binmode FH;

       #Initalize check maximum size as 1MB
       my $checkSizeByte = 1000000;

       #Get the file size
       my $fileSize = (-s $fileName);
       if($fileSize < ($checkSizeByte))
       {
          $checkSizeByte = $fileSize
       }
       #print "fileSize      = $fileSize\n";
       #print "checkSizeByte = $checkSizeByte\n";

       my $line = <FH>;

       @byteContents = unpack "C*", $line;

       #Close the file
       close FH;
       local $/;

       if(isUnicode($checkSizeByte, \@byteContents) || isTextCode($checkSizeByte, \@byteContents))
       {
         $retVal = 1;
       }
     }
  }

  return $retVal;
}

sub isTextCode($$)
{
  my ($checkSizeByte, $byteContentsRef) = @_;

  for (my $i = 0; $i < $checkSizeByte; $i++)
  {
    my $t = $text_chars[$byteContentsRef->[$i]];

    if ( $t != T && $t != I && $t != X)
    {
       return 0;
    }
  }
  return 1;
}

sub isUnicode($$)
{
  my ($checkSizeByte, $byteContentsRef) = @_;
  my $bigend;
  my @ubyteContents;
  my $ulen = 0;

  if ($checkSizeByte < 2)
  {
    return 0;
  }

  if ($byteContentsRef->[0] == 0xff && $byteContentsRef->[1] == 0xfe)
  {
     $bigend = 0;
  }
  elsif ($byteContentsRef->[0] == 0xfe && $byteContentsRef->[1] == 0xff)
  {
     $bigend = 1;
  }
  else
  {
    return 0;
  }

  for (my $i = 2; $i + 1 < $checkSizeByte; $i+=2)
  {
    # XXX fix to properly handle chars > 65536

    if($bigend)
    {
      $ubyteContents[$ulen++] = $byteContentsRef->[$i+1] + 256 * $byteContentsRef->[$i];
    }
    else
    {
      $ubyteContents[$ulen++] = $byteContentsRef->[$i] + 256 * $byteContentsRef->[$i+1];
    }

    if($ubyteContents[$ulen-1] == 0xfffe)
    {
      return 0;
    }

    if($ubyteContents[$ulen-1] < 128 && $text_chars[$ubyteContents[$ulen-1]] != T)
    {
      return 0;
    }
  }
  return 1;
}

1;

# End of Program
