#!/usr/local/bin/perl
# monitor.pl
# Check all the monitors and send email if something is down

$no_acl_check++;
delete($ENV{'FOREIGN_MODULE_NAME'});
delete($ENV{'SCRIPT_NAME'});
delete($ENV{'SERVER_ROOT'});
require './status-lib.pl';

# Check if the monitor should be run now
@tm = localtime(time());
@hours = split(/\s+/, $config{'sched_hours'});
!@hours || &indexof($tm[2], @hours) >= 0 || exit;
@days = split(/\s+/, $config{'sched_days'});
!@days || &indexof($tm[6], @days) >= 0 || exit;

# Check for services that are down
&lock_file("$module_config_directory/oldstatus");
&read_file("$module_config_directory/oldstatus", \%oldstatus);
$now = localtime(time());
$host = &get_system_hostname();
@services = &list_services();
foreach $serv (@services) {
	if ($serv->{'nosched'} == 1) {
		# Scheduled checking totally disabled
		delete($oldstatus{$serv->{'id'}});
		next;
		}
	$warn = $serv->{'nosched'} == 0 ? $config{'sched_warn'} :
		$serv->{'nosched'} - 2;
	$stat = &service_status($serv);
	$o = $oldstatus{$serv->{'id'}};
	if ($warn == 0 && $stat->{'up'} == 0 && $o) {
		# Service has just gone down
		$email .= "Monitor on $host for '$serv->{'desc'}'\n".
		 "has detected that the service has gone down at $now\n\n";
		$subj = "$serv->{'desc'} down on $host";
		$pager_msg .= "$host: \"$serv->{'desc'}\" is down $now! ";
		&run_on_command($serv, $serv->{'ondown'});
		}
	elsif ($warn == 1 && $stat->{'up'} != $o &&
	       (defined($o) || $stat->{'up'} == 0)) {
		# Service has changed status
		if ($stat->{'up'} == 0) {
			$email .= "Monitor on $host for '$serv->{'desc'}'\n".
			 "has detected that the service has gone down at $now\n\n";
			$subj = "$serv->{'desc'} down on $host";
		        $pager_msg .= "$host: \"$serv->{'desc'}\" is down $now! ";
			&run_on_command($serv, $serv->{'ondown'});
			}
		elsif ($stat->{'up'} == 1) {
			$email .= "Monitor on $host for '$serv->{'desc'}'\n".
			 "has detected that the service has gone back up at $now\n\n";
			$subj = "$serv->{'desc'} back up on $host";
		        $pager_msg .= "$host: \"$serv->{'desc'}\" is back up $now! ";
			&run_on_command($serv, $serv->{'onup'});
			}
		elsif ($stat->{'up'} == -1) {
			$email .= "Monitor on $host for '$serv->{'desc'}'\n".
			 "has detected that the service is uninstalled at $now\n\n";
			$subj = "$serv->{'desc'} uninstalled on $host";
		        $pager_msg .= "$host: \"$serv->{'desc'}\" uninstalled $now! ";
			}
		elsif ($stat->{'up'} == -2) {
			$email .= "Monitor on $host for '$serv->{'desc'}'\n".
			 "has detected that Webmin is down at $now\n\n";
			$subj = "$serv->{'desc'} Webmin down on $host";
		        $pager_msg .= "$host: \"$serv->{'desc'}\" Webmin down $now! ";
			}
		elsif ($stat->{'up'} == -3) {
			$email .= "Monitor on $host for '$serv->{'desc'}'\n".
			 "has timed out at $now\n\n";
			$subj = "$serv->{'desc'} timed out on $host";
		        $pager_msg .= "$host: \"$serv->{'desc'}\" timed out $now! ";
			}
		}
	elsif ($warn == 2 && $stat->{'up'} == 0) {
		# Service is down now
		$email .= "Monitor on $host for '$serv->{'desc'}'\n".
		 "has detected that the service is down at $now\n\n";
		$subj = "$serv->{'desc'} down on $host";
		$pager_msg .= "$host: \"$serv->{'desc'}\" is down $now! ";
		&run_on_command($serv, $serv->{'ondown'});
		}
	$oldstatus{$serv->{'id'}} = $stat->{'up'};
	if ($config{'sched_single'} && $email) {
		# Force the sending of one email per report
		&send_status_email($email, $subj);
		undef($email);
		}
	}
&write_file("$module_config_directory/oldstatus", \%oldstatus);
&unlock_file("$module_config_directory/oldstatus");

# Send the email if necessary
if ($email) {
	&send_status_email($email, 'Service monitor');
	&send_status_pager($pager_msg);
	}

# send_status_email(text, subject)
sub send_status_email
{
return if (!$config{'sched_email'});
&foreign_require("mailboxes", "mailboxes-lib.pl");

# Construct and send the email
local $from = $config{'sched_from'} ? $config{'sched_from'}
				    : &mailboxes::get_from_address();
local $mail = { 'headers' =>
		[ [ 'From', $from ],
		  [ 'To', $config{'sched_email'} ],
		  [ 'Subject', $_[1] ] ],
		'attach' =>
		[ { 'headers' => [ [ 'Content-type', 'text/plain' ] ],
		    'data' => &entities_to_ascii($_[0]) } ] };
&mailboxes::send_mail($mail, undef, 0, 0, $config{'sched_smtp'});
}

# send_status_pager(text)
sub send_status_pager
{
  return if (!$config{'sched_pager'});
  return if (!&has_command($config{'pager_cmd'}));
  system("$config{'pager_cmd'} ".quotemeta($config{'sched_pager'})." ".
         quotemeta($_[0])." >/dev/null 2>&1 </dev/null");
}

# run_on_command(&serv, command)
sub run_on_command
{
return if (!$_[1]);
if ($_[0]->{'runon'} && $_[0]->{'remote'}) {
	# Run on the remote host
	local $cmd = $_[1];
	$cmd =~ s/\\/\\\\/g;
	$cmd =~ s/'/\\'/g;
	&remote_eval($_[0]->{'remote'}, "status",
		     "system('($cmd) >/dev/null 2>&1 </dev/null')");
	}
else {
	# Just run locally
	system("($_[1]) >/dev/null 2>&1 </dev/null");
	}
}

