#!/usr/bin/env perl

# Use mandatory external modules
use strict;
use Cwd;
use File::Basename;
use Data::Dumper;
use POSIX;
use Config;

# Determine installation dir name
our $SELF_DIR = dirname(dirname(dirname(Cwd::abs_path(__FILE__))));

# Include parts of the system
require $SELF_DIR . '/lib/config.pm';

# Unbuffered io
$| = 1;

# Read config file
my $postfix = "";
if (scalar(@ARGV) && $ARGV[0] =~ /^@(.*)/) {
    shift(@ARGV);
    $postfix = "_$1";
}

my $cfg_file = "mmm_mon$postfix.conf";
our $config = ReadConfig($cfg_file);

MyExit("ERROR: Usage: $0 [\@cluster_name] <check_name>") if (scalar(@ARGV) < 1);

# Get checker name
my $check_name = $ARGV[0];

# Load checker module
my $module_file = "$SELF_DIR/lib/check_modules/$check_name.pm";
my $res = do $module_file;
MyExit("ERROR: Can't load checker module '$check_name'") if (!$res);

# Read timeout from config file
our $timeout = $config->{check}->{$check_name}->{timeout};

# Read max_checks
our $checks_to_restart = $config->{check}->{$check_name}->{restart_after};

# Workaround to prevent checker from hanging in case of unnoticed broken pipe errors
our $max_empty_commands = 100;
our $empty_commands = 0;

our $log_debug = ($config->{debug} =~ /^(on|yes|1)$/i);

# Process loop
while (!eof(STDIN)) {
    # Check if it is time to die
    if (defined($checks_to_restart) && --$checks_to_restart < 1) {
        CheckerLog("Max checks performed, restarting...");
        last;
    }
    CheckerLogDebug("Waiting for a command...");

    # Get command
    chomp(my $cmd = <STDIN>);
    CheckerLogDebug("Got cmd = '$cmd'");

    # Die if there are too many empty commands in a row
    if ($cmd eq '') {
        if (++$empty_commands > $max_empty_commands) {
            CheckerLog("WARNING: Too many empty commands ($empty_commands) in a row - looks like pipe is broken! Exiting!");
            last;
        }
        next;
    } else {
        $empty_commands = 0;
    }
    
    my @command = split(/\s+/, $cmd);
    if ($cmd eq 'ping') {
        CheckerLogDebug("Ping received");
        print "OK: Pong!\n";
        next;
    }
    
    if ($cmd ne '' && (scalar(@command) < 1 || scalar(@command) > 2)) {
        CheckerLog("Invalid command format! Command was: '$cmd'");
        print "Invalid command format. Use <command> [param]\n";
        next;
    }
    
    # Exit if asked
    last if ($command[0] =~ /^quit/i);
    
    # Process command and output result
    if ($command[0] eq 'check') {
        print PerformCheck($timeout, $command[1]) . "\n";
        next;
    }

    print "ERROR: Invalid command ($cmd)\n";
}

CheckerLog("Exit");

print("OK: Finished\n");
exit(0);

#-------------------------------------------------
sub MyExit($) {
    $res = shift;
    print "$res\n";
    CheckerLog("EXIT: $res");
    exit(0);
}

#-------------------------------------------------
sub CheckerLogDebug($) {
    my $msg = shift;
    if ($log_debug) { CheckerLog($msg); }
}

#-------------------------------------------------
sub CheckerLog($) {
    my $msg = shift;
    my $now = strftime("%Y-%m-%d %H:%M:%S", localtime);
    
    my $cluster = $postfix;
    $cluster ||= "_default";
    
    my $f = "$SELF_DIR/var/checker/$check_name$cluster.log";

    if (open(LOG, ">>$f")) {
        print LOG "[$now]: $$: $msg\n";
        close(LOG);
    }
}
