#!/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 ($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'});
if ($config{'sched_smtp'}) {
	# Connect to SMTP server
	local $from = $config{'sched_from'} ? $config{'sched_from'}
					    : "webmin\@".&get_system_hostname();
	&open_socket($config{'sched_smtp'}, 25, MAIL);
	&smtp_command(MAIL);
	&smtp_command(MAIL, "helo ".&get_system_hostname()."\n");
	&smtp_command(MAIL, "mail from: $from\n");
	foreach $t (split(/,/, $config{'sched_email'})) {
		&smtp_command(MAIL, "rcpt to: $t\n");
		}
	&smtp_command(MAIL, "data\n");
	print MAIL "From: $from\n";
	print MAIL "To: $config{'sched_email'}\n";
	print MAIL "Subject: $_[1]\n";
	print MAIL "\n";
	print MAIL $_[0];
	print MAIL "\n";
	&smtp_command(MAIL, ".\n");
	&smtp_command(MAIL, "quit\n");
	close(MAIL);
	}
else {
	# Run sendmail executable
	local %sconfig = &foreign_config("sendmail");
	if ($config{'sched_from'}) {
		open(MAIL, "|$sconfig{'sendmail_path'} -t -f$config{'sched_from'} >/dev/null 2>&1");
		print MAIL "From: $config{'sched_from'}\n";
		}
	else {
		open(MAIL, "|$sconfig{'sendmail_path'} -t >/dev/null 2>&1");
		print MAIL "From: webmin\n";
		}
	print MAIL "To: $config{'sched_email'}\n";
	print MAIL "Subject: $_[1]\n";
	print MAIL "\n";
	print MAIL $_[0];
	print MAIL "\n";
	close(MAIL);
	}
}

# send_status_pager(text)
sub send_status_pager
{
  return if (!$config{'sched_pager'});
  return if (!&has_command($config{'pager_cmd'}));
  local $msg = $_[0];
  $msg =~ s/\\/\\\\/g;
  $msg =~ s/\'/\\\'/g;
  system("$config{'pager_cmd'} $config{'sched_pager'} '$msg'  >/dev/null 2>&1 </dev/null");
}

# smtp_command(handle, command)
sub smtp_command
{
local ($m, $c) = @_;
print $m $c;
local $r = <$m>;
if ($r !~ /^[23]\d+/) {
	&error(&text('sched_esmtpcmd', "<tt>$c</tt>", "<tt>$r</tt>"));
	}
}

# 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");
	}
}

