package Agent;

#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

#  $Id: Agent.pm,v 1.37 2002/07/31 17:34:33 ccadieux Exp $

use CIM;
use strict;
use PDM;
use Util;
use Catalog;
use Timer;
use Carp;
use vars qw($AUTOLOAD);
use System;
use Scheduler;
use Timelapse;
use Debug;
use Data::Dumper;
use Thresholds;
use Report;
use Catalog;


use vars qw(%_FIELDS %LOGFILES %DEVICES %CACHES $WWNINFO $ERROR);

%_FIELDS = ('can_be_turned_off', undef);

#
# $agent = Agent->new({data => $DATA, today => $today, opt_T => $opt_T,
#                   });
# Usage:
# $agent->last_run
#       ->new
#       ->read_log_file 
#       ->format_dev_info 
#       ->ping 
#       ->telnet
#       ->diff 
#       ->load_cache
#       ->save_cache
#

sub new {
  my($this) = {};
  bless($this, 'Agent');
  my $hostid   = `/bin/hostid`; chomp($hostid);

  $this->{hostid} = $hostid;
  return $this;
}

sub init {
  my($agent,$vals) = @_;
  my($x);

  foreach $x (keys %$vals) {
    $agent->{$x} = $vals->{$x};
  }
}

sub copyDev {
  my($class, $dev, $report) = @_;

  foreach my $x (keys %$dev) {
     next if (substr($x,0,1)eq "_");
     $report->{"id.device_$x"} = $dev->{$x};
  }
}

sub newId {
  my($class, $reportCat, $key, $logfile, $displayName) = @_;

  return {category   => $reportCat,
          deviceName => $key,
          logFile    => $logfile,
          display    => $displayName,
         };
}

# sun or brocade

sub switchFCCounters {
  my($class, $TYPE, $arg) = @_;

  my($renv, $devs, $host,$notifs) = PDM::ConfigFile->read;
  my(%SW, %DONE);
  my $masterLoc  = Util->findMaster();

  foreach my $d (@$devs) {
    next if ($d->{type} ne $TYPE);
    next if ($DONE{$d->{wwn}});
    $DONE{$d->{wwn}} = 1;

    next if (!$d->isMineToMonitor() );

    Debug->print2("FC-Switch: Reading switch $d->{name}");

    my $db = $class->FCfromDevice($d);
    next if (!$db);

    foreach my $l (keys %{$db->{enc}}) {
        $SW{enc}{$l} = $db->{enc}{$l};
    }
    foreach my $l (keys %{$db->{data}}) {
        $SW{data}{$l} = $db->{data}{$l};
    }
  }
  return \%SW;
}



sub stor_conflicts {
  my($class) = @_;
  my $STOR_PROCS =",stexpert,stresstest,linktest,a3500fctest,a5ktest,fcdisktest,t3test,a5ksestest,ifptest,qlctest,socaltest,switchtest,disktest,fctapetest,t3ofdg,t3volverify,sve_probe,vediag,sve_sudiag,sve_sddiag,daktest,daksestest,brocadetest,d2disktest,daktest,daksestest,switch2test,veluntest,linktest";

  my $l;
  my($renv)     = System->get_renv();

  my $list = Scheduler->processList("ST", "*", {status => 'O'});
  my (%SC, $sc_list);
  foreach my $l (@$list) {
    $SC{$l->{command}} = 1;
  }
  foreach my $x (keys %SC) {
    $sc_list .= "$x,";
  }

  my ($err, $ras) = Util->run_command("/usr/bin/ps -ef", "ps", 30);
  foreach my $x0 (@$ras) {
     my $x = Util->ltrim($x0);
     my @a = split(/\s+/, $x);
     my $pname  = $a[7];

     my $ix  = index($pname, " ") ;
     $pname = substr($pname, 0, $ix) if ($ix >= 0);
     $ix = rindex($pname, "/");
     $pname = substr($pname, $ix+1) if ($ix >= 0);

     if (index($STOR_PROCS, ",$pname,") >= 0) {
        $sc_list .= "$pname,";
     }

     #Grab the name of the perl module since stresstest will show here
     $pname  = $a[9];
     $ix  = index($pname, " ") ;
     $pname = substr($pname, 0, $ix) if ($ix >= 0);
     $ix = rindex($pname, "/");
     $pname = substr($pname, $ix+1) if ($ix >= 0);

     if (index($STOR_PROCS, ",$pname,") >= 0) {
          $sc_list .= "$pname,";
     }

  }
  return $sc_list;

# N/U

  my ($time1,$ltime1) = Util->last_message($renv->{st4logfile} . "/sunvts.info");
  my ($time2,$ltime2) = Util->last_message($renv->{st4logfile} . "/stexpert.log");

  if ($time1 && $time1 <= $renv->{frequency}) {
      return "last message on $ltime1";

  } elsif ($time2 && $time2 <= $renv->{frequency}) {
      return "last message on $ltime2";
  }
  return "";
}

sub findSelectableAgents {
  my($class, $solution) = @_;
  my(@MODS, @dirs, $x);

  my($list) = Util->findMethods("Agent",undef, "isSelectable");
  my $L = ",t4,t3,switch,switch2,host,san,brocade,";
  foreach my $f (sort @$list) {
    my(@b) = split(/=/, $f);
    if ($b[1]) {
      my $ag = lc($b[0]);
      next if ($solution eq "Y" && index("$L,ve,", ",$ag,") < 0);
      push(@MODS, $ag . "=$b[1]" );
    }
  }
  return \@MODS;
}




sub hostInfo {
  my($class) = @_;
  my($h) = PDM->getCacheHandle("HostInfo");

  if (Timer->isXdays("hostInfo", 1) || !$h->{hostid}) {
    $h->{hostid}   = System->hostid();
    $h->{hostinfo} = System->hostinfo();
    $h->{hostname} = System->hostname();
    $h->{os}       = System->os();
    $h->{os_version} = System->os_version();
    $h->{model}    = System->model();
    $h->{swap}     = System->swap();
    $h->{memory}   = System->memory();
    $h->{domain}   = System->domain();
    $h->{cpus}     = System->cpus();
    $h->{ip}       = Util->name2ip($h->{hostname} );
    $h->{tz}       = CIM->tz();
  }
  return $h;
}



#
# find details about a wwn from OLD_REPORTS

sub wwnInfo {
  my($class, $wwn) = @_;
  my($report, $details, $l, $VAR1);

  my($grepf) = System->get_home() . "/DATA/tmp/WWNINFO";
  my($dir)   = System->get_home() . "/DATA/OLD_REPORTS";

  if (!$WWNINFO) {
     chdir(System->get_home() . "/DATA/OLD_REPORTS/");
     open(O, "/usr/bin/grep -i wwn *:*|");
     open(W, ">$grepf");
     while ($l = <O>) {
       print W $l;
     }
     close(O);
     close(W);
     $WWNINFO= 1;
  }
  open(O, $grepf);
  my(@a);
  while ($l = <O>) {
     if ($l =~ /$wwn/i) {
       @a = split(/:/, $l);
       next if (index("host,backup,brocade,switch2,", $a[0]) >= 0);
       $report = "$a[0]:$a[1]";
       my $ix = index($l, "=>");
       my $st = length($report);
       if ($ix > $st) {
         $details = Util->ltrim(substr($l, $st+1, $ix - $st - 1));
         $details =~ s/\.portWWN//;
         $details =~ s/\.volWWN//;
       }
       last;
     }
  }
  close(O);
  if ($report) {
     if (open(O, "$dir/$report")) {
       my @b = <O>; close(O);
       eval "@b";
       if ($VAR1) {
         return ($VAR1->category(), $VAR1->name(), $details, $report);
       }
     } else {
         return ($a[0], $a[1], $details, $report);
     }
  }
  return ();
}



##########################
#   FIND DISKS paths
#  Agent->luxadmDiskPaths({ type => "Tape"})
##########################
sub luxadmDiskPaths {
  my($class, $arg) = @_;
  my @PATHS;
  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};
  my $flag   = 0;
  my $type = $arg->{type} || "Disk";

  my($lux) = "/usr/sbin/luxadm";
  my ($err,$probe) = Util->run_command("$lux probe -p","", $TO);

  $ERROR = $err;
  return undef if ($err);
  my($in, $l);
  my($hbalist, $ix, $h2, $h3);

  for ($ix=0; $ix <= $#$probe; $ix++) {
      $l = $probe->[$ix];
      if ($l =~ / Node WWN:(.+)\s+Device Type:$type/) { # t3 or internal..
         my($wwn) = Util->trim($1);
         my $path;
         if ($probe->[$ix+1] =~ /Logical Path:(.*)/) {
             $path = $1;
         }
         push(@PATHS, [$path, $wwn]);
      }
   }
   return \@PATHS;
}
#  OLD FORMAT
#  luxadm display /dev/rdsk/c1t29000060220041F96257354230303068d0s2
#  DEVICE PROPERTIES for disk: /dev/rdsk/c1t29000060220041F96257354230303068d0s2
#    Status(Port A):       O.K.
#    Status(Port B):       O.K.
#    Vendor:               SUN     
#    Product ID:           SESS01          
#    WWN(Node):            2a000060220041f9
#    WWN(Port A):          2b000060220041f9
#    WWN(Port B):          2b000060220041f4
#    Revision:             0811
#    Serial Num:           Unsupported
#    Unformatted capacity: 121856.000 MBytes
#    Write Cache:          Enabled
#    Read Cache:           Enabled
#      Minimum prefetch:   0x0
#      Maximum prefetch:   0x0
#    Device Type:          Disk device
#    Path(s):
#    /dev/rdsk/c1t29000060220041F96257354230303068d0s2
#    /devices/scsi_vhci/ssd@g29000060220041f96257354230303068:c,raw
#     Controller           /devices/pci@c,2000/pci@2/SUNW,qlc@5/fp@0,0
#       Device Address     2b000060220041f9,4
#       Class              primary
#       State              ONLINE
#     Controller           /devices/pci@f,2000/pci@2/SUNW,qlc@5/fp@0,0
#       Device Address     2b000060220041f4,4
#       Class              primary
#       State              ONLINE

# NEW FORMAT
#  
#  DEVICE PROPERTIES for disk: /dev/rdsk/c15t2B00006022004188d1s2
#    Vendor:               SUN     
#    Product ID:           SESS01          
#    Revision:             0811
#    Serial Num:           Unsupported
#    Unformatted capacity: 1073.742 MBytes
#    Write Cache:          Enabled
#    Read Cache:           Enabled
#      Minimum prefetch:   0x0
#      Maximum prefetch:   0x0
#    Device Type:          Disk device
#    Path(s):
#  
#    /dev/rdsk/c15t2B00006022004188d1s2
#    /devices/sbus@8,0/SUNW,qlc@1,30000/fp@0,0/ssd@w2b00006022004188,1:c,raw
#      LUN path port WWN:          2b00006022004188
#      Host controller port WWN:   210000e08b049858
#      Path status:                O.K.
#    /dev/rdsk/c18t2B00006022004193d1s2
#    /devices/sbus@9,0/SUNW,qlc@0,30400/fp@0,0/ssd@w2b00006022004193,1:c,raw
#      LUN path port WWN:          2b00006022004193
#      Host controller port WWN:   210000e08b249758
#      Path status:                O.K.
#    /dev/rdsk/c19t2B00006022004188d1s2
#    /devices/pci@e,2000/pci@2/SUNW,qlc@4/fp@0,0/ssd@w2b00006022004188,1:c,raw
#      LUN path port WWN:          2b00006022004188
#      Host controller port WWN:   210000e08b01608d
#      Path status:                O.K.
#  


sub luxadmDisplay {
  my($class, $path) = @_;
  my @DIS;
  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};
  my $flag   = 0;

  my($lux) = "/usr/sbin/luxadm";
  my ($err,$probe) = Util->run_command("$lux display $path","", $TO);

  return undef if ($err);
  my $ix = -1;
  my ($current, $x);
  if ("@$probe" =~ /WWN\(Node\)/) {  # OLD FORMAT
    for ($x=0; $x <= $#$probe; $x++) {
      my $l = $probe->[$x];
      if ($l =~ /DEVICE PROPERTIES/) {
          $ix++;
      } elsif (index("Status,Vendor,Produc,WWN(No,WWN(Po,Revisi,Serial,", substr($l,2,6)) >= 0) {
         $l =~ /\s+([^:]+)\:\s+(.+)/;
         my $name = $1; 
         next if (!$name);
         my $val = $2;
         $name =~ s/[\(\)]//g;
         $name =~ s/ //g;
         $DIS[$ix]{$name} = Util->trim($val);
      } elsif ($l =~ /^  \/dev/) {
         if (exists($DIS[$ix]{logical})) {
           $DIS[$ix]{physical}  = Util->ltrim($l);
         } else {
           $DIS[$ix]{logical}  = Util->ltrim($l);
         }
      }
    }
  } else {
    my (%SAVE, $status);
    for ($x=0; $x <= $#$probe; $x++) {
      my $l = $probe->[$x];
      if ($l =~ /DEVICE PROPERTIES/) {
          $ix++; $status = 0;
          %SAVE = ();
      } elsif (index("Vendor,Produc,Revisi,Serial,", substr($l,2,6)) >= 0) {
         $l =~ /\s+([^:]+)\:\s+(.+)/;
         my $name = $1; 
         next if (!$name);
         my $val = $2;
         $name =~ s/[\(\)]//g;
         $name =~ s/ //g;
         $SAVE{$name} = Util->trim($val);
         $DIS[$ix]{$name} = Util->trim($val);

      } elsif ($l =~ /^  \/dev/) {
         if ($status && $l =~ /\/dev\// ) {
           $ix++  ;
           $DIS[$ix]{ProductID} = $SAVE{ProductID};
           $DIS[$ix]{Vendor}    = $SAVE{Vendor};
           $DIS[$ix]{Revision}  = $SAVE{Revision};
         }
         if (exists($DIS[$ix]{logical})) {
           $DIS[$ix]{physical}  = Util->ltrim($l);
         } else {
           $DIS[$ix]{logical}  = Util->ltrim($l);
         }
      } elsif ($l =~ /LUN path port WWN:\s+(.*)/) {
         $DIS[$ix]{"WWNPort"} = $1;
      } elsif ($l =~ /Host controller port WWN:\s+(.*)/) {
         $DIS[$ix]{"WWNNode"} = $1;
      } elsif ($l =~ /Path status:\s+(.*)/) {
         $DIS[$ix]{"StatusPortA"} = $1;
         $status = 1;
      }
    }
  }
  
  return \@DIS;
}
  





##########################
#  A5K
##########################

sub luxadmA5KPaths {
  my($class, $arg) = @_;

  my($renv) = System->get_renv();
  my($TO) = $renv->{'timeout.luxadm'};

  my($encs)   = $arg->{encs};
  my($lux)    = "/usr/sbin/luxadm";
  my($err,$probe, $l);

#
# Find ENCLOSURES AND PATHS with PROBE
#
  ($err,$probe) = Util->run_command("$lux probe -p","luxprobe", $TO);

  my($hbalist, $ix, $a5);
  my($MPX, $in);
  my(%WWN2E, %ENC, @HBA);

  for ($ix=0; $ix <= $#$probe; $ix++) {
      $l = $probe->[$ix];
      if ($l =~ /Found/) {
        $in = 1;
      } elsif ($in) {
        if ($l =~ / Name:(.+)\s+Node WWN:([^\s]+)/) {
          my($off) = 2;
          my($name) = Util->trim($1);
          my($wwn) = Util->trim($2);
          $off = 1 if ($l =~ /Logical Path/);
          if ($encs && index(",$encs,", ",$name,") >= 0) {
            $WWN2E{$wwn} = $name;
            $ENC{$wwn} = 1;
          } else {
            $WWN2E{$wwn} = $name;
            $ENC{$wwn} = 1;
          }

          while ($probe->[$ix+$off] =~ /Physical Path:(.*)/ &&
                  $probe->[$ix+1] !~ /Node WWN:/ ) {
             my($hba) = $1;
             if ($hba =~ /\/devices\/scsi_/) { # MPX
               $MPX = 1;
             } else {
               my($ix2) = rindex($hba, "/");
               $hba = substr($hba,0, $ix2);
               if (index($hbalist, "$hba,") < 0) {
                 push(@HBA, $hba);
                 $hbalist .= "$hba,";
               }
             }
             $ix+= $off;
          }
        }
      }
  }

  return (\@HBA, \%ENC, \%WWN2E, $MPX, $hbalist);
}



#############################################################
#       READK_LOG_FILE
#############################################################

%LOGFILES = ();

# flag = NEW : new lines since last run
#        24  : lines written in the ast 24 hours.
#
# << Oct092000_16:31:20 >>
# Oct 11 14:52:05
#
  
sub read_log_file {
  my($agent, $file, $flag, $is24) = @_;
  my(@lines, $startdate, $seek, $size, $tell, $size0, $clear_seek);
  return ('',undef) if (!$file);

  my($cache) = PDM->getCacheHandle("read_log_file");

  if ($LOGFILES{$file}) {
    return ('', $LOGFILES{$file});
  }

  if (!(-r $file && -f $file)) {
    $LOGFILES{$file} = [];
    return ("CANNOT_READ $file", undef);
  }

  my $today = Util->today;
  if ($cache->{START}{$file}) {
      $startdate = $cache->{START}{$file};
  } else {
      $startdate= substr($today,0,5) . " 00:00:00";
  }
  
  Debug->print('READING_MESSAGE_FILE', $file);

  open(FILE_F1, $file); 
  my $cnt=0;
  $seek = $cache->{SEEK}{$file};

  if ($flag eq "NEW") {    # find new stuff.
    $size = (stat($file))[7];
    if ($seek) {
      if ($seek < $size) {
         seek(FILE_F1, $seek, 0);

      } elsif ($seek == $size) {
         close(FILE_F1);
         $LOGFILES{$file} = [];
         return ('',undef);     # found nothing

      } elsif (-f "$file.0") {
         $size0 = (stat("$file.0"))[7];
         if ($size0 > $seek) {  # do this one also
            open(FILE_F1, "$file.0"); 
            seek(FILE_F1, $seek, 0);
            $clear_seek = 1;
         }
      }
    }         
  }
  my($line, $current);
  my $count;
  for ($tell = tell(FILE_F1); $line = <FILE_F1>; $tell = tell(FILE_F1)) { 
      chop($line);
      last if ($line eq "exit"); # for tests only

      my @a = split(/ +/, $line,6);
      if ($a[0] eq "<<") {
        $current = sprintf("%2.2d-%2.2d %s", Util->MTH(substr($a[1],0,3)), 
                       substr($a[1],3,2), substr($a[1],10) );
      } else {
        $current = sprintf("%2.2d-%2.2d %s", Util->MTH($a[0]), $a[1], $a[2]);
      }

      next if (substr($current,0,5) gt substr($today,0,5)); # if too big, probably the wrong year.
      if ($flag eq "NEW" &&  $current ge $startdate) {
           push(@lines, $line);
           last if ($count++ > 7000);
      }
      if ($flag eq "24") {
        if ($is24 && $current ge $is24 ) { # find 24 hours for thresholds
          push(@lines , $line);
          last if ($count++ > 7000);
        }
      }
  }
  Debug->print2("Found $count lines") if ($count > 0);
  if ($clear_seek) {
    $cache->{SEEK}{$file} = 0;
  } elsif ($tell && $tell != $seek) {
    $cache->{SEEK}{$file} = $tell;
  }
  close(FILE_F1);
  $LOGFILES{$file} = \@lines;  # save for next request.
  $cache->{START}{$file} = $current; # move pointer to end of file.

  return ('', \@lines);
}

# sp monitor their devices, master monitor non-sp devices only.
#
sub NUresponsibleForDevice {
  my($class, $d, $masterLoc, $renv) = @_;

  if ($renv->{solution} eq "Y") {
    return 0 if (!$d->isMineToMonitor());

  } elsif (!$masterLoc) {  #master
    return 0 if ($d->isInSolution());
  }

  return 1;
}


#
# select devices to monitor

sub deviceList {
  my($class) = @_;
  my(@LIST);
  my(@a) = split(/=/, $class);
  
  my $prefix = lc($a[0]);
  $prefix = substr($prefix,7) ;

  my($devs) = System->get_configDevices();
  foreach my $d (@$devs) {
     next if ($d->{type} ne $prefix);
     next if (!Util->isMineToMonitor($d));
     push(@LIST, $d);
  }
  return @LIST;
}


sub get_pdm {
  my($class) = @_;

  return $class->{pdm};
}

sub reportHead {
  my($class, $id, $report, $cols) = @_;
  my ($name, $cat);
  $cols = 4 if (!$cols);

  if ($report) {
    $name = $report->name();
    $cat = $report->value('id.device_userLabel') || uc($report->category());

  }
  return "
   <table border=1 cellspacing=0 cellpadding=2 width=95% bgcolor=white>
     <tr><td bgcolor=#666699 colspan=$cols><font color=white><b>$cat $name
   ";
}
  

sub format_dev_info {
  my($device) = @_;
  my($info);
  if ($device->{serial}) {
     $info = "S" . $device->{serial};
  } else {
     $info = "N" . $device->{type} . "-" . $device->{_name} . "-" . $device->{name} . "-" . $device->{ip};
  }
  $info;
}

sub addIdentification {
  my($agent, $report) = @_;

  my($env) = System->get_renv();
  $report->{'location.customerNo'}   = $env->{cust_no};
  $report->{'location.customerName'} = $env->{customer};
  $report->{'location.contractNo'}   = $env->{contract};
  $report->{'location.hostId'}        = System->hostid;

  $report->{'location.siteName'}      = $env->{site_name};
  $report->{'location.siteAddress'}   = $env->{site_address};
  $report->{'location.siteCity'}      = $env->{site_city};
  $report->{'location.siteState'}     = $env->{site_state};
  $report->{'location.siteCountry'}   = $env->{site_country};
  $report->{'location.siteZip'}       = $env->{site_zip};
  $report->{'location.siteContact'}   = $env->{site_contact};
  $report->{'location.siteEmail'}     = $env->{site_email};
  $report->{'location.ticker'}        = $env->{ticker};
  $report->{'location.production'}    = $env->{production};

}


#######################################################
#                 DISK_ INQUIRY STORE
#######################################################
%DEVICES = ();

sub di_register {
  my($agent, $key_type, $key, $a) = @_;

  $key_type = uc($key_type);

  $DEVICES{$key_type}{$key} = $a; 
}

sub di_list {
  my($agent, $key_type) = @_;
  my($x, @list, $p);
  $key_type = uc($key_type);
  $p = $DEVICES{$key_type};
  foreach $x (keys %$p ) {
    push(@list, $x);
  }
  return @list;
}

sub di_lookup {
  my($agent, $key_type, $key) = @_;
  
  $key_type = uc($key_type);

  if ($DEVICES{$key_type}{$key}) {
     return $DEVICES{$key_type}{$key};
  } else {
     return undef;
  }
}

########################################################
#                  ERRORS
########################################################

sub system_error {
   my($agent, $device, $object, $type) = @_;
   my($o, $now, $serial, %V);
   
   %V = ();
   $now = Util->get_today;
   $o =<<EOF;
<elem elem_type=\"system_error\" system_name="$device->{name}" id="$device->{_name}" date="$now" error_type="$type" device_type=\"$device->{type}\" />
EOF
  return $o;
}

sub reconnect_info {
   my($agent, $device, $object, $kt, $k) = @_;
   my($o, $now, $serial, %V);
   
   %V = ();
   $now = Util->get_today;
   $o =<<EOF;
<elem elem_type=\"connect_info\" system_name="$device->{name}" key_type="$kt" key="$k" ip="$device->{ip}" date="$now" error_type="RECONNECTED" device_type=\"$device->{type}\"/>
EOF
  return $o;
}




########################################################
#                  SOCKETS
########################################################

sub pingXX {
  my($agent, $host_ip, $prompt, $timeout) = @_;
  my($t);
  $timeout = 10 if (!$timeout);
  $t = new Net::Telnet (
                  errmode   => "return",
                  Timeout   => $timeout,
                  Prompt    => $prompt,
           );
  if (!defined($t->open($host_ip))) {
     return 0;
  }
  $t->close;
  return 1;
}

sub telnetXX {
  my($agent, $host_ip, $cmd,  $timeout, $prompt, $login,$static) = @_;
  my($t, @lines, $i);
  my($pass) = "";

  if (System->get_testMode() && $static) {
     return Util->as_array(Util->readf(System->get_home() . "/Test/$static"));
  }
  if (($i = index($login,"/")) > 0) {
     $pass = substr($login,$i+1);
     $login = substr($login,0, $i);
  }
  $timeout = 60 if (!$timeout);

#'/' . $prompt . ':\/:\<\d+\>/',

  $t = new Net::Telnet (
                  errmode => "return",
                  Timeout   => $timeout,
                  Prompt    => $prompt,
           );
  if (!defined($t->open($host_ip))) {
     return undef;
  }
  $t->login($login, $pass);
  @lines = $t->cmd($cmd);
  $t->close;
# my($x) = join(/\n/, @lines); 
# open(O, ">" . System->get_home()  . "/Test/$static"); print O $x; close(O);
  return \@lines;

}

####################################################
#             DIFF
####################################################
sub get_category {
  my($agent) = @_;
  my($cat) = ref($agent);
  $cat =~ s/Agent//;
  return $cat;
}

sub connect_error {
   my($agent, $device, $object, $kt, $k) = @_;
   my($o, $now, $serial);
   
   my %V = ();
   $now = Util->get_today;
   $o =<<EOF;
<elem elem_type=\"connect_error\" system_name="$device->{name}" key_type="$kt" key="$k" ip="$device->{ip}" date="$now" error_type="CANNOT_CONNECT" device_type=\"$device->{type}\"/>
EOF
  return $o;
}

# $id = [name, ip, key_type, key, key_type2, key2 ]
#
sub xml_event_holder {
  my($agent, $event_type, $id, $class) = @_;
  my($head, $cat, $type, $today, $altkey, $key, $es);

  $cat = $agent->get_category;
  $class = "compare" if (!$class);

  $type = Event->get_xml_name($event_type);
  $today =  Util->today("YMDH");
  if ($id->[3]) {
    $key = " key_type=\"$id->[2]\" key=\"$id->[3]\" ";
  }
  if ($id->[5]) {
    $altkey = " key_type2=\"$id->[4]\" key2=\"$id->[5]\" ";
  }
  $head = "<event event_type=\"$type\" message_sequence=\"$agent->{sequence}\">
  <event_info category=\"$cat\" name=\"$id->[0]\" hostid=\"$agent->{hostid}\" ip=\"$id->[1]\" $key $altkey date=\"$today\" />";
  return ($head, "</event>");
}


sub save_current_run {
  my($agent, $event_type, $data, $id) = @_;
  my($file, $head, $tail);

  my($cat) = $agent->get_category;
  $file = "$agent->{data}/RUN/$cat:$event_type:$id->[0]";

  ($head,$tail) = $agent->xml_event_holder($event_type, $id);
  if (ref($data) eq "ARRAY") {
    if ($#$data >= 0) {
      $data = join("\n", @$data);
    }
  }
  return undef if (!$data);
  $data = $head . "\n" . $data . "\n" . $tail;
  if (open(O, ">$file")) {
    print O $data;
    close(O);
    chmod 0666, $file;
  } else {
    Debug->err(CANNOT_WRITE =>  "$file: $!");
  }
}

sub add_mode {
  my($agent, $p, $m) = @_;
  my($head);

  my($ix) = index($$p, ">\n");

  $head = substr($$p, 0, $ix) . " modes=\"$m\">\n" . substr($$p, $ix+2);
  $$p = $head;
}

sub xml_add_sequence {
  my($agent, $p) = @_;
  my($head);

  my($ix) = index($$p, ">\n");

  my($es) = "12";
  $head = substr($$p, 0, $ix) . " event_no=\"$es\">\n" . substr($$p, $ix+2);
  $$p = $head;
}

# new: a string with \n in it
# returns: a pointer to an array of differences
# n=new, i=insert, d=delete, u=update
# flags : {xml => 1, ignorePattern=> "Temp,other", hash => 1, rawdata => 1, block => 1, 
#          xml_key=>}
# block : the content is compare as ablack, not line by line
# xml_key: xml key to help comparing the right lines
# DIFF saves the current values to TMP_DIFF
# Hash : Only report differences to entry with same hash value
#     needs 3 values Key | value | 0/1   0=bad, 1=good

sub diff_entry {
  my($agent, $type, $key, $value, $info, $error) = @_;
  return "<elem elem_type=\"$type\" key=\"$key\" value=\"$value\" info=\"$info\" error=\"$error\" />\n";
}








#####################################################
#           CACHE DATABASE OPERATIONS
#####################################################
#
# Load values from a cache-file into a hash
# Cache file usually stores device specific data about each devices.

%CACHES = ();

sub load_cache {
   my($agent, $f)  = @_;
   my(%starts, $l, @a);

   return $CACHES{$f} if ($CACHES{$f});

   if (open(O, "$agent->{data}/$f")) {
      while ($l = <O>) {
        chop($l);
        @a = split(/=/, $l);
        $starts{$a[0]} = $a[1];
      }
      close(O);
   }
   $CACHES{$f} = \%starts;
   return \%starts;
}

# STORE data in TMP, save_cache will save permanently

sub clear_diff_cache {
  my($agent, $data) = @_;
  my(@f1, $file1, $l);

  opendir(O, "$data/TMP_DIFF");
  @f1 = readdir(O);
  closedir(O);
  foreach $file1 (@f1) {
     unlink("$data/TMP_DIFF/$file1");
  }
}



#
# Write the hash back in the cache-file
#
sub save_cache {
  my($agent, $starts, $f) = @_;
  my($x, $type);
  my($data) = $agent->{data};
#  return if ($agent->test_mode); save nothing on tests.

  if ($starts) {  # if 'starts' is specified, save one cache-file.
    if (open(O, ">$data/$f")) {
      foreach $x (keys %$starts) {
        print O "$x=$starts->{$x}\n";
      }
      close(O);
      chmod 0666, "$data/$f";
    } else {
      Debug->err(WRITE_HASH_FAILED => "$data/$f",  $! );
    }
    return;
  }
}

sub save_all_caches {
  my($agent,$util) = @_;

# SAVE ALL CACHES IF starts not specified.
  my($data) = $util->{data};

  foreach my $type (keys %CACHES) {
    my $starts = $CACHES{$type};
    if (open(O, ">$data/$type")) {
      foreach my $x (keys %$starts) {
        print O "$x=$starts->{$x}\n";
      }
      close(O);
      chmod 0666, "$data/$type";
    } else {
      Debug->err(WRITE_HASH_FAILED => "$data/$type",  $! );
    }
  }
  &copy($data, "TMP_DIFF", "DIFF");
}

sub copy {
  my($data ,$from, $to) = @_;

  opendir(O, "$data/$from");

  my(@f1, $file1, $l);
  @f1 = readdir(O);
  closedir(O);
  foreach $file1 (@f1) {
     next if (substr($file1,0,1) eq ".");
     next if (!-f "$data/$from/$file1");
     open(R, "$data/$from/$file1");
     open(W, ">$data/$to/$file1");
     while ($l = <R>) {
        print W $l;
     }
     close(R); close(W);
     chmod 0666 , "$data/$to/$file1";
  }

}

sub AUTOLOAD {
  my $self = shift;
  my $type = ref($self) || croak "$self is not an object";

  my $name = $AUTOLOAD;
  $name =~ s/.*://;   # strip fully-qualified portion

  unless (exists $_FIELDS{$name} ) {
   croak "Can't access `$name' field in class $type";
  }
  if (@_) {
     return $self->{$name} = shift;
  } else {
     return $self->{$name};
  }
}

#####################################################
#           XML operations
#####################################################
#

sub getXML { 
  my($agent, $o) = @_;
  my($e, $l, $x);
  my($s) = XMLout($o, (rootname => ''));
  my(@a) = split(/\n/, $s);
  for ($x=0; $x <= $#a; $x++) {
    $l = $a[$x];
    if (substr($l,0,4) eq "  </") {
       $a[$x] = "  </elem>";
    } elsif ($l =~ /^  <(\w+)[ >]/) {
       $e = $1;
       $a[$x] = "  <elem elem_type=\"$e\" " . substr($l,length($e)+4);
    }
  }
  return join("\n", @a);
}
      
  

sub found_pattern {
  my($list, $el) = @_;
  my($v);
  my(@a) = split(/,/, $list);
  foreach $v (@a) {
    if ($el =~ /$v/) {
print STDERR "     Ignoring $el in $list \n";
      return 1;
    }
  }
  return 0;
}




#########################################################################
#    CONFIG FILE UTILITIES
#########################################################################

#
# find the right devices in Config for a certain Agent module
# modules are called a5k, a35k, t3, switch, switch.brocade etc..
# types from configfile are
#
sub get_config_devices {
  my($agent) = @_;
  my($d, @results, $type);
  my($ag) = lc(ref($agent));
  $ag = substr($ag, 0, -5) if (substr($ag, -5) eq "agent");

  foreach $d (@{$agent->{devices}} ) {
#     next if ($d->{active} eq "N"); # active is set by the GUI start/stop monitoring
#     and it should only impact the emailing of events, not the monitoring.

     push(@results, $d) if (lc($d->{type}) eq $ag);
  }
  return \@results;
}

sub category_selected {
  my($agent,$cat) = @_;

  my($renv) = System->get_renv();
  my $list = lc($renv->{categories}) . "|message";
  $cat = substr($cat,0,-5) if (substr($cat,-5) eq "Agent");

  if (index($list, lc($cat)) >= 0) {
     return 1;
  } else {
     return 0;
  }
}



#/usr/sbin/osa/lad
#c1t5d0 1T80703654 LUNS: 0 1 2


# $ lad
# c2t5d0 1T93000132 LUNS: 0 1 
# c3t4d2 1T70211709 LUNS: 2
# $ rdacutil
#  A3500FC_array_1:   active/passive
#     Active    controller a (c2t5d0)               units:    0 1 2 
#     Failed    controller b (1T70211709)           units:    none

sub get_RM6Devices {
  my($q) = @_;
  my($type) = $q->{type};
  my(@out, $f, $l, $name, $hba, $in , $wwn, $x, $i, $path, $out, $out2, $err);
  my($details, $dev, $vendor, %A3, %WWN);

  my($di) = "/usr/sbin/osa/lad";

  ($err,$out) = Util->run_command($di, "luxprobe.txt", 20);

  return "ERR $err" if ($err);
  return "ERR @$out" if ("@$out" =~ /No RAID devices/);
  my %SER;
  for ($x=0; $x <= $#$out; $x++) {
    $l= $out->[$x];
    my(@a) = split(/\s+/, $l);
    $dev = $a[0]; $wwn = $a[1];

    my($di2) = "/usr/sbin/osa/raidutil -c $dev -i";
    ($err,$out2) = Util->run_command($di2, "luxprobe.txt", 20);
    if ("@$out2" !~ /$type/) {
       next;
    }

    my($err,$rdac) =
       Util->run_command("/usr/sbin/osa/rdacutil -i $dev", "luxprobe.txt", 20);
    my(@b) = split(/\:\s+/, $rdac->[1]);
    my $enc_name = $b[0];
    if ($enc_name) {
       $A3{$enc_name}{dev} = $dev;
       if (exists($A3{$enc_name}{wwn1})) {
          $A3{$enc_name}{wwn2} = $wwn;
       } else {
          $A3{$enc_name}{wwn1} = $wwn;
       }
    }
  }
  foreach my $k (keys %A3) {
     $f .= "$k=$A3{$k}{dev}=$A3{$k}{wwn1}=$A3{$k}{wwn2}\n";
  }
  if ($q->{print}) {
    print "OK $f\n";
  } else {
    return "OK $f";
  }
}






   

1;
