#!/usr/bin/perl -w
#
# $Id: xserve-raid-log.in,v 1.5 2005/05/11 01:37:59 rader Exp $
#

use strict;
use Time::Local;

my $have_gnu_date = 1;

my $prefix = "/usr/local";
my $lib_dir = "$prefix/lib/xserve-raid-tools";
my $etc_dir = "$prefix/etc";
my $conf_file = "xserve-raid-tools.conf";
my $log_template = "xserve-event-log.template";
my $port = '80';
my $debug = 0;
my $level = 3;

my %cf;
my $addr;
my $passwd;
my %entries;

#------------------------------------------------------------------------------

&read_conf_file;
$addr = $cf{'addr'};
$passwd = $cf{'passwd'};

#------------------------------------------------------------------------------

while ( $ARGV[0] && $ARGV[0] =~ /^-/ ) {
  if ( $ARGV[0] eq '-d' || $ARGV[0] eq '--debug' ) { 
    $debug++;
    shift @ARGV;
    next;
  }
  if ( $ARGV[0] eq '-a' || $ARGV[0] eq '--address' ) { 
    shift @ARGV;
    if ( ! $ARGV[0] ) { &usage; exit 1; }
    $addr = $ARGV[0];
    shift @ARGV;
    next;
  }
  if ( $ARGV[0] eq '-l' || $ARGV[0] eq '--level' ) { 
    shift @ARGV;
    if ( ! $ARGV[0] ) { &usage; exit 1; }
    CASE: { 
      if ( $ARGV[0] =~ /^c/i ) { $level = 1; last CASE; }
      if ( $ARGV[0] =~ /^w/i ) { $level = 2; last CASE; }
      if ( $ARGV[0] =~ /^i/i ) { $level = 3; last CASE; }
      &usage; exit 1;
    } 
    shift @ARGV; next;
  }
  if ( $ARGV[0] eq '-p' || $ARGV[0] eq '--passwd' ) {
    shift @ARGV;
    if ( ! $ARGV[0] ) { &usage; exit 1; }
    $passwd = $ARGV[0];
    shift @ARGV;
    next;
  }
  &usage;
  exit 1;
}
if ( $ARGV[0] ) {
  &usage;
  exit 1;
}

#------------------------------------------------------------------------------

&parse_log('top','Upper');
&parse_log('bottom','Lower');

#------------------------------------------------------------------------------

for my $s (sort {$a <=> $b} (keys %entries)) {
  print $entries{$s};
}

exit;

#==============================================================================

sub parse_log {
  my ($controller,$Controller) = @_;

  #----------------------------------------
  open(IN,"<$lib_dir/$log_template");
  open(OUT,">/tmp/xserve-raid-query.$$");
  while(<IN>) { 
    $_ =~ s/_ADDR_/$addr/;
    $_ =~ s/_CONTROLLER_/$controller/;
    $_ =~ s/_PASSWD_/$passwd/;
    print OUT $_;
  }
  close(OUT);
  close(IN);
  
  #----------------------------------------
  if ( $debug ) { 
    if ( $debug > 1 ) { print "=" x 78, "\n"; }
    print "** DEBUG: WEB PAGE ** /bin/nc $addr $port < /tmp/xserve-raid-query.$$  **\n";
  }
  open(IN,"/bin/nc $addr $port < /tmp/xserve-raid-query.$$ |");
  
  #----------------------------------------
  # no XML::Parser here... maybe i'm just old, but 
  # sucking the entire log into memory seems like
  # a bad thing...
  
  while(<IN>) {
   if ( $debug > 1 ) { print $_; }
   if ( $_ =~ /<key>status<\/key>/ ) {
     my $status = <IN>;
     if ( $status =~ /<integer>-16<\/integer>/ ) {
       print "$addr: incorrect password\n";
       close(IN);
       unlink("/tmp/xserve-raid-query.$$");
       exit 1;
     } 
     if ( $status =~ /<integer>-6745<\/integer>/ ) {
       print "$addr is in standby power mode.\n";
       close(IN);
       unlink("/tmp/xserve-raid-query.$$");
       exit 1;
     }
     if ( $status =~ /<integer>(-.*)<\/integer>/ ) {
       print "$addr: unknown status error: $1\n";
       close(IN);
       unlink("/tmp/xserve-raid-query.$$");
       exit 1;
      }
   }
   if ( $_ =~ /^\t\t\t\t\t\<string>(.*)<\/string>/ ) {
     my ($date,$id,$prio,$unknown,$txt) = split(/,/,$1);
     $date =~ /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;
     my ($s,$m,$h,$D,$M,$Y) = ($6,$5,$4,$3,$2,$1);
     $M--;
     my $stamp = timegm($s,$m,$h,$D,$M,$Y);
     $date = scalar localtime($stamp);
     $date =~ s/ \d\d\d\d$//;
     if ( $prio > 7000 || $txt =~ /fail/i || $txt =~ /error/i ) { 
       $entries{$stamp} .= "$date $Controller Critical $txt\n";
       next;
     }
     if ( $level > 1 && ( $prio > 3000 || $txt =~ /warn/i ) ) {
       $entries{$stamp} .= "$date $Controller Warning  $txt\n";
       next;
     }
     if ( $level > 2 ) { 
       $entries{$stamp} .= "$date $Controller Info     $txt\n"; 
     }
   }
  }
}
  
#----------------------------------------
unlink("/tmp/xserve-raid-query.$$");
if ( ! close(IN) ) { 
  print "could not contact Xserve RAID at $addr\n";
  exit 1;
}

#==============================================================================

sub read_conf_file {
  my $s = '';
  my $cf_file = "$etc_dir/$conf_file";
  if ( $debug ) { print "** DEBUG CONF ** $cf_file **\n"; }
  if ( ! open(IN,"<$cf_file") ) {
    print "xserve-raid-status: $etc_dir/$conf_file: $!\n";
    exit 1;
  }
  while (<IN>) {
    if ( $_ =~ /^\s*$/ ) { next; }
    chop; $_ =~ s/(.*?)\#.*/$1/;
    $s .= $_;
    while ( $_ !~ /;/ && !(eof(IN)) ) {
      $_ = <IN>;
      chop; $_ =~ s/(.*?)\#.*/$1/;
      $s .= $_;
    }
    if ( $s !~ /;/ ) {
      print "xserve-raid-status: $cf_file: syntax error: no semicolon for the last entry\n";
      exit 5;
    }
    $s =~ s/(.*?);.*/$1/;
    if ( $s =~ /(\S+)\s*=\s*(.*)/ ) {
      my $k = $1; my $v = $2;
      if ( $k =~ /_list$/ ) {
        $cf{$k} = [ split(/\s+/,$v) ];
        if ( $debug > 1 ) {
          print "  \$cf{\'$k\'} = wq( ";
          print join " ", @{ $cf{$k} };
          print " );\n";
        }
      } else {
        $cf{$k} = $v;
        if ( $debug > 1 ) { print "  \$cf{\'$k\'} = $v;\n"; }
      }
    } else {
      print "xserve-raid-status: $cf_file: $s: syntax error\n";
      exit 5;
    }
    $s = '';
  }
  close(IN);
}

#==============================================================================

sub usage {
print <<EOT
usage: xserve-raid-log [args] 
 --passwd passwd    encrypted passwd (default is $passwd aka "public")
 --level level      where level is critical, warning or info (default is "info")
 --address a.b.c.d  fetch log from raid at a.b.c.d (default is $addr)
 --debug            for debug output (use twice to get source xml output)
EOT
}
