#!/usr/bin/perl

use strict;
use warnings;

sub find_tw_cli {
	my $tw_cli = -1;
	
	if(-x "/usr/local/sbin/tw_cli") {
		$tw_cli = "/usr/local/sbin/tw_cli";
	}
	elsif(-x "/usr/sbin/tw_cli") {
		$tw_cli = "/usr/sbin/tw_cli";
	} else {
		die "Error finding tw_cli: $tw_cli\n";
	}

	return $tw_cli;
}

sub get_number_of_controllers( $ ) {
	my($tw_cli) = @_;
	my $controllers;
	my $i = 0;
	my $rc = 0;

	while($rc eq 0) {
		$i++;
		system("$tw_cli /c$i show >& /dev/null");
		$rc = $?;
	}
	$controllers = $i - 1;

	return $controllers;
}

sub get_controller_list( $ ) {
	my($tw_cli) = @_;
	my @controllers;
	my $rc;
	my $i;

	# Check for zeroth controller - deals with numbering differences in tw_cli
	system("$tw_cli /c0 show >& /dev/null");
	$rc = $?;
	if($rc == 0) {
		push(@controllers,0);
	}

	$i = 1;
	$rc = 0;
	while($rc eq 0) {
		system("$tw_cli /c$i show >& /dev/null");
		$rc = $?;
		if($rc == 0) {
			push(@controllers,$i++);
		}
	}

	return @controllers;
}

sub get_tw_show( $$ ) {
	my($tw_cli,$controller) = @_;
	my $tw_show;

	$tw_show = `$tw_cli /c$controller show 2> /dev/null`;

	return $tw_show;
}

sub get_tw_batt( $$ ) {
	my($tw_cli,$controller) = @_;
	my($rc,$tw_batt);

	$tw_batt = `$tw_cli /c$controller/bbu show 2> /dev/null`;
	$rc = $?;
	if($rc > 0) {
		return(-1,$tw_batt);
	}
	return ($rc,$tw_batt);
}

sub get_controller_status( $$ ) {
	my($tw_cli,$controller) = @_;
	my %controller_status;
	my(@tw_show,@tw_batt,%unit_status,%disk_status,%batt_status,$is_batt);

	@tw_show = split_line(get_tw_show($tw_cli,$controller));
	($is_batt,@tw_batt) = get_tw_batt($tw_cli,$controller);

	%unit_status = parse_unit_status(@tw_show);
	%disk_status = parse_disk_status(@tw_show);

	if($is_batt > 0) {
		%batt_status = parse_batt_status(@tw_batt);
	}

	%controller_status = (%unit_status,%disk_status,%batt_status);

	return %controller_status;
}

sub parse_batt_status( @ ) {
	my(@tw_batt) = @_;

	print STDERR "Battery parser not written yet!\n";
}

sub print_hash ( % ) {
	my(%h) = @_;
	my $k;

	foreach $k (sort keys %h) {
		print "$k => $h{$k}\n";
	}
}

sub parse_unit_status( @ ) {
	my(@tw_show) = @_;
	my $line;
	my %unit_status;
	
	foreach $line ( @tw_show ) {
		if($line =~ /^(u\d)\s+.*?\s+(\w+)/) {
			$unit_status{"$1"} = "$2";
		}
	}
	return %unit_status;
}

sub parse_disk_status( @ ) {
	my(@tw_show) = @_;
	my $line;
	my %disk_status;

	foreach $line ( @tw_show ) {
		if($line =~ /^(p\d+)\s+(.*?)\s+(u\d+)/) {
			$disk_status{"$3/$1"} = "$2";
		}
	}

	return %disk_status;
}

sub split_line ( $ ) {
	my($stream) = @_;
   
	return split '\n', $stream;
}

sub rc_ok( $ ) {
	my($rc) = @_;

	return $rc;
}

sub rc_warn( $ ) {
	my($rc) = @_;

	if($rc < 1) {
		$rc = 1;
	}

	return $rc;
}

sub rc_crit( $ ) {
	my($rc) = @_;

	if($rc < 2) {
		$rc = 2;
	}

	return $rc;
}

sub generate_output( $$$% ) {
	my($controller,$output,$rc,%controller_status) = @_;
	my $k;

	foreach $k (sort keys %controller_status) {
		if( $k =~ /^u/ ) {
			if( $controller_status{$k} =~ /OK/ ) {
				$rc = rc_ok($rc);
			}
			elsif( $controller_status{$k} =~ /(REBUILD.*)/ ) {
				$output .= "/c".$controller."/".$k." is $1 ";
				$rc = rc_warn($rc);
			}
			elsif( $controller_status{$k} =~ /DEGRADE/ ) {
				$output .= "/c".$controller."/".$k." is DEGRADED ";
				$rc = rc_crit($rc);
			}
		}
		elsif( $k =~ /^u\d+\/p\d+/ ) {
			if( $controller_status{$k} =~ /(OK|NOT-PRESENT)/ ) {
				$rc = rc_ok($rc);
			}
			elsif( $controller_status{$k} =~ /(DEGRADED)/ ) {
				$output .= "/c".$controller.$k." is $1 ";
				$rc = rc_warn($rc);
			}
		}
	}

	return ($output,$rc);
}

my %status;
my($tw_show,$rc,$output,$controller);
$rc = 0;

my $tw_cli = find_tw_cli();
#my $controllers = get_number_of_controllers($tw_cli);
my @controllers = get_controller_list($tw_cli);

foreach $controller ( @controllers ) {
	%status = get_controller_status($tw_cli,$controller);
	($output,$rc) = generate_output($controller,$output,$rc,%status);
}

if( (!$output) && ($rc == 0) ) {
	$output = "Arrays OK.";
} elsif( (!$output) && ($rc != 0) ) {
	$output = "Something unknown happened! rc = $rc\n";
}

print "$output\n";
exit($rc);
