#!/s/std/bin/perl -w
# -*- perl -*-
#
# $Revision: 1.12 $
package host;

require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(&print_usage &print_version &service_test);
use lib $main::runtimedir;
use csl_utils qw($TIMEOUT %ERRORS);
use strict;

use Socket;
use POSIX;

sub print_usage ();
sub print_version ();
sub service_test (%);

sub error () {
    print "CRITICAL: ", shift;
    return $ERRORS{'CRITICAL'};
}

sub usage () {
    print shift;
    print_usage();
}

sub print_usage () {
    print "
Usage:  Check local service.
Options:
  -H <hostname> [-v -P <port> -o <os> -d <disk> -l <load> -u <user> -k <kernel>
         -t <uptime> ( -a <partition> ) ( -i <ignore_disk> ) ( -w <warn_disk> )]
  --help
  --version
  --usage
";
    return $ERRORS{'OK'};
}

sub print_version () {
    my $version = '$Revision: 1.12 $';
    $version =~ s/^\$Revision: //;
    $version =~ s/ \$\s*$//;

    print "host.pm - $version\n";
    return $ERRORS{'OK'};
}


sub service_test (%) {
    # grab options
    my %options = @_;

    # Set all the default variables

    my %alldisks = ( "warn" => 90, "crit" => 95 );
    my %ignoredisks = ( ".*vice/cache.*" => 1,
                        "/local.*" => 1,
                        "/media.*" => 1,
                        "/mnt.*" => 1,
                        "/scratch.*" => 1,
                        ".*cdrom.*" => 1,
                        ".*/s/sushi.*/mountpoints.*" => 1, );

    my %load = ( "warn" => 6, "crit" => 12 );
    my %user = ( "warn" => 20, "crit" => 40 );
    my %uptime = ( "min" => 0, "max" => 10000 );

    # get the variables ready to use
    my %diskpartition;
    my $output = "";
    my $state = "OK";
    my $msg = "";

    # Start processing those options...
    if ( $options{verbose} ) {
        foreach my $opt ( sort keys(%options) ) {
            if ( $options{$opt} ) {
                print "$opt - $options{$opt}\n";
            }
        }
    }

    my $host = $options{opt_H};
    if ( !$host || ( $host eq "" ) ) {
        print "\nHost name not specified.\n";
        &print_usage();
        return $ERRORS{'OK'};
    }

    my $port = $options{opt_P} ? $options{opt_P} : 49187;
    my $os = $options{opt_o} ? $options{opt_o} : "Unknown";

    # DISK INFO
    if ( $options{opt_d} ) {
        my @newignoredisks;
        $options{opt_d} =~ s/\%//;
        ( $alldisks{warn}, $alldisks{crit}, @newignoredisks ) =
                                                split(",", $options{opt_d});
        foreach ( @newignoredisks ) {
            $ignoredisks{$_} = 1;
        }
    }
    &usage("Bad Disks\n") if ((!$alldisks{warn}) ||
                                (!$alldisks{crit}) ||
                                     ($alldisks{warn} > $alldisks{crit}));

    if ( $options{opt_i} ) {
        foreach ( split(",", $options{opt_i}) ) {
            $ignoredisks{$_} = 1;
        }
    }

    if ( $options{opt_w} ) {
        foreach my $test ( split( ",", $options{opt_w} ) ) {
            foreach my $ignore (keys %ignoredisks) {
                if ( $test =~ /$ignore/ ) {
                    delete $ignoredisks{$ignore};
                }
            }
        }
    }

    # INDIVIDUAL PARTITION SETTING
    foreach (@{$options{opt_a}}) {
        my ($warn, $crit, $name) = split(",");
        &usage("Bad partition info\n") if ( (!$name) || ($warn > $crit) );

        $diskpartition{$name}->{warn} = $warn;
        $diskpartition{$name}->{crit} = $crit;
    }

    # LOAD INFO
    ( ($load{warn}, $load{crit}) =
                    split(",", $options{opt_l}) ) if ( $options{opt_l} );
    &usage("Bad Load\n") if ((!defined($load{warn})) ||
                                (!defined($load{crit})) ||
                                             ($load{warn} > $load{crit}));

    # NUMBER OF USER INFO
    ( ($user{warn}, $user{crit}) =
                    split(",", $options{opt_u}) ) if ( $options{opt_u} );
    &usage("Bad User\n") if ((!defined($user{warn})) ||
                                (!defined($user{crit})) ||
                                     ($user{warn} > $user{crit}));

    # UPTIME INFO
    ( ($uptime{min}, $uptime{max}) =
                        split(",", $options{opt_t})) if ($options{opt_t});
    &usage("Bad Uptime\n") if ((!defined($uptime{min})) ||
                                (!defined($uptime{max})) ||
                                         ($uptime{min} > $uptime{max}));

# Tell the people what we've done if they really want to know.

    if ( $options{verbose} ) {
        print "Hostname: $host
Port: $port
Disk: $alldisks{warn} - $alldisks{crit}
Load: $load{warn} - $load{crit}
User: $user{warn} - $user{crit}
Ignored disks: 
";

        foreach (keys %ignoredisks) {
            print "\t$_\n";
        }

        print "\nSpecial Disk Partition Values:\n";
        foreach (keys %diskpartition) {
            print "\t$_:\t$diskpartition{$_}->{warn} warn, $diskpartition{$_}->{crit} crit\n";
        }
    }

    print "\nSetting up network socket\n\n" if ( $options{verbose} );

    # magic socket stuff
    my $remoteaddr = inet_aton("$host");
    my $paddr = sockaddr_in($port, $remoteaddr) ||
                        return &error("Can't create info for connection: $!\n");
    my $proto = getprotobyname('tcp');
    socket(Server, PF_INET, SOCK_STREAM, $proto) ||
                                    return &error("Can't create socket: $!\n");
    setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1);
    connect(Server, $paddr) || return &error("Can't connect to server: $!\n");
    select(Server);
    $| = 1;

    my ($s_hostname, $s_os, $s_kernel, $s_uptime, $s_load, $s_cpu, $s_user, $s_logins, $s_kdump, @s_disks) = <Server>;

    # more socket magic
    close(Server);
    select(STDOUT);

    print "Received: $s_hostname$s_os$s_kernel$s_uptime$s_load$s_cpu$s_user$s_logins$s_kdump@s_disks" if $options{verbose};

    # If we don't get all of the absolutely default info, go ahead and die
    unless ($s_disks[0]) {
        print "CRITICAL:Wrong format # Didn't get correct response\n";
        exit $ERRORS{CRITICAL};
    }

#
# Hostname
#

    if ($s_hostname =~ /localhost.localdomain/) {
        $state = "WARNING";
        $msg = "<u>Wrong Hostname (localhost)</u>, ";
    }

#
# OS
#

    if ( $options{opt_o} && ( $s_os !~ /Sysname: $options{opt_o}/ ) ) {
        chomp $s_os;
        $state = "CRITICAL";
        $msg = "<u>Wrong $s_os instead of $options{opt_o}</u>, ";
    }

#
# Kernel
#

    chomp $s_kernel;
    $output .= "$s_kernel, ";
    if ( $options{opt_k} && ( $s_kernel !~ /Kernel: $options{opt_k}/ ) ){
        $state = "WARNING" if ($state eq "OK");
        $msg .= "<u>Wrong $s_kernel instead of $options{opt_k}</u>, ";
    }

#
# Uptime
#

    chomp $s_uptime;
    $output .= "$s_uptime, ";
    if ( $options{opt_t} ) {
        # get unix uptime:
        my $day = 0;
        $day = $1 if ($s_uptime =~ / (\d+)D /);
        my $hour = 0;
        $hour = $1 if ($s_uptime =~ / (\d+)h /);
        my $minute = 0;
        $minute = ($1/60) if ($s_uptime =~ / (\d+)m$/);

        my $uptime = int ( 10 * (($day*24) + $hour + $minute) ) / 10;
        if (($uptime < $uptime{min}) || ($uptime > $uptime{max})) {
            $state = "WARNING" if ($state eq "OK");
            $msg .= "<u>$uptime hours uptime not $uptime{min}->$uptime{max}</u>, ";
        }
    }

#
# Load
#

    chomp $s_load;
    chomp $s_cpu;
    $output .= "$s_load, $s_cpu, ";
    if ( $options{opt_l} ) {
        my $load = ( split (": ", $s_load) ) [1];
        my $cpu = ( split (": ", $s_cpu) ) [1];
        $load = int(10 * $load / $cpu)/10;
        if ($load >= $load{crit}) {
            $state = "CRITICAL";
            $msg .= "<u>Load Average $load over critical of $load{crit}</u>, ";
        } elsif ($load >= $load{warn}) {
            $state = "WARNING" if ($state eq "OK");
            $msg .= "<u>Load Average $load over warning of $load{warn}</u>, ";
        }
    }

#
# Users
#

    chomp $s_user;
    chomp $s_logins;
    $output .= "$s_user, $s_logins, ";
    if ( $options{opt_u} ) {
        my $users = ( split (": ", $s_user) ) [1];
        if ($users >= $user{crit}) {
            $state = "CRITICAL";
            $msg .= "<u>Users ($users) over critical of $user{crit}</u>, ";
        } elsif ($users >= $user{warn}) {
            $state = "WARNING" if ($state eq "OK");
            $msg .= "<u>Users ($users) over warning of $user{warn}</u>, ";
        } 
    }

#
# KDump
#

    if ( $options{opt_K} ) {
        chomp $s_kdump;
        if ( $s_kdump =~ /KDump: Crash files found/ ) {
            $state = "CRITICAL";
            $msg .= "<u>$s_kdump</u>, ";
        }
    }

#
# DISK
#

    $output =~ s/, $//g;
    $output .= "<br>Disks: ";
    PARTITION: foreach ( @s_disks ) {
        my ($name, $percent, $remaining, $error) = /Disk-(.*): (\d+), ([\d\.]+\w*)(.*)$/;

        print "$name: $percent: $remaining: $error\n" if $options{verbose};

        # formating error check
        unless ( defined($remaining) ) {
            $state = "CRITICAL";
            $msg .= "<u>Wrong info for $name</u>, ";
            next PARTITION;
        }

        $output .= "$name=$percent%, ";

        # if there's an error, warn even if we ignore the partition
        if ($error) {
            $error =~ s/, /mounted /;
            $state = "CRITICAL";
            $msg .= "<u>$name is $error</u>, ";
        }

        if ($name eq "/scratch") {
            if ($options{opt_s}) {
                $state = "CRITICAL";
                $msg = "<u>Found /scratch</u>, ";
            }
        }

        foreach my $ignorepartition (keys %ignoredisks) {
            next PARTITION if ( ($name =~ /$ignorepartition/) && (! defined($diskpartition{$name}) ) );
        }

        # default partition info
        my $warn = $diskpartition{$name}->{warn} ?
                         $diskpartition{$name}->{warn} : $alldisks{warn};
        my $crit = $diskpartition{$name}->{crit} ?
                         $diskpartition{$name}->{crit} : $alldisks{crit};

        if ( $percent && ($percent >= $crit) ) {
#            if ( $remaining =~ /G/ ) {
#                $state = "WARNING" if ( $state eq "OK" );
#                $msg .= "<u>$name is $percent% full (crit is $crit%)</u>, ";
#            } else {
                $state = "CRITICAL";
                $msg .= "<u>$name is $percent% full (crit is $crit%)</u>, ";
#            }
#        } elsif ( ($percent >= $warn ) && ( $remaining !~ /G/ ) ){
        } elsif ( $percent >= $warn ){
            $state = "WARNING" if ($state eq "OK");
            $msg .= "<u>$name is $percent% full (warn is $warn%)</u>, ";
        }

    }


    print "$state: ";

    $output =~ s/\|/-OR-/g;
    $output =~ s/, $//g;
    $output =~ s/: $//g;
    $msg =~ s/\|/-OR-/g;
    $msg =~ s/, $//g;

    print "$msg<hr>" if $msg;
    print "$output|perfdataignore\n";

    exit $ERRORS{$state};

}

