#!/usr/bin/perl -w

# check-config - verify the configuration, make directories and
#	create new RRDs.
# $Id: check-config.pl,v 1.14 2001/08/28 15:22:24 remstats Exp $

# Copyright 1999, 2000, 2001 (c) Thomas Erskine <thomas.erskine@sourceworks.com>
# See the COPYRIGHT file with the distribution.

# - - -   Configuration   - - -

use strict;

# What is this program called, for messages and files
$main::prog = 'check-config';
# Where is the default config dir
$main::config_dir = '/etc/remstats/config';
# Which type of shell is this, for writing environment variables
$main::shell_type = 'sh';

# - - -   Version History   - - -

(undef, $main::version) = split(' ', '$Revision: 1.14 $');

# - - -   Setup   - - -

use lib '.', '/usr/lib/remstats/lib', '/usr/lib/perl5/';
require "remstats.pl";
#use Data::Dumper;
use Getopt::Std;
use RRDs;
require "private.pl";
require "alertstuff.pl";

my (@list);
my %opt = ();
getopts('cC:d:eDf:Fhl:s:t', \%opt);

if (defined $opt{'h'}) { &usage; } # no return
if (defined $opt{'c'}) { $main::write_communities = 1; } else { $main::write_communities = 0; }
if (defined $opt{'C'}) { $main::config_debug = $opt{'C'}; } else { $main::config_debug = 0; }
if (defined $opt{'d'}) { $main::debug = $opt{'d'}; } else { $main::debug = 0; }
if (defined $opt{'D'}) { $main::dumpit = 1; } else { $main::dumpit = 0; }
if (defined $opt{'e'}) { $main::write_environment = 1; } else { $main::write_environment = 0; }
if (defined $opt{'f'}) { $main::config_dir = $opt{'f'}; }
if (defined $opt{'F'}) { $main::force = 1; } else { $main::force = 0; }
if (defined $opt{'l'}) { @list = split(',', $opt{'l'}); }
if (defined $opt{'s'}) { $main::shell_type = $opt{'s'}; }
if (defined $opt{'t'}) { $main::testonly = 1; } else { $main::testonly = 0; }

if ($main::debug > 1) { $main::config_debug = 1; }
else { $main::config_debug = 0; }

if ($main::shell_type =~ /csh$/i) { $main::shell_type = 'csh'; }
elsif ($main::shell_type =~ /sh$/i) { $main::shell_type = 'sh'; }
else { &abort("unknown shell type ($main::shell_type); not sh or csh"); }

my ($list_hosts, $list_ips, $list_rrds, $do_list);

$list_hosts = $list_ips = $list_rrds = $do_list = 0;
foreach my $list (@list) {
	if ($list =~ /^hosts?$/i) { $list_hosts = 1; }
	elsif ($list =~ /^ips?$/i) { $list_ips = 1; }
	elsif ($list =~ /^rrds?$/i) { $list_rrds = 1; }
	$do_list = 1;
}

if ($do_list and $main::write_environment) {
	print STDERR "-e and -l aren't compatible\n";
	&usage; # no return
}

# - - -   Mainline   - - -

&read_config_dir($main::config_dir, 'general', 'html', 'times',
	'colors', 'archives', 'links', 'tools', 'remotepings',
	'scripts', 'alerts', 'oids', 'rrds', 'customgraphs',
	'groups', 'host-templates', 'hosts', 'view-templates', 'views',
	'availability', 'alert-destination-map', 'discovery');

#print Dumper(\%main::config) if ($main::dumpit);

my ($host, $ip, $dir, $realrrd, $file);

# Make the required directories
unless (-d '/var/lib/remstats') {
	&make_a_dir('/var/lib/remstats');
}

# A place to put the data
unless (-d $main::config{DATADIR}) {
	&make_a_dir($main::config{DATADIR});
}

# A place to put the pages
unless (-d $main::config{HTMLDIR}) {
	&make_a_dir($main::config{HTMLDIR});
}

# A place to put the custom graphs
$dir = $main::config{HTMLDIR}.'/CUSTOM';
unless (-d $dir) {
	&make_a_dir($dir);
}

# Make a place to store the snmp pages
unless (-d $main::config{DATAPAGEDIR}) {
	&make_a_dir($main::config{DATAPAGEDIR});
}

# Make a place to store the last collected data
unless (-d $main::config{DATADIR}. '/LAST') {
	&make_a_dir($main::config{DATADIR} .'/LAST');
}

# Make a directory for logs
unless (-d $main::config{LOGDIR}) {
	&make_a_dir($main::config{LOGDIR});
}

# Make the temp directory
unless (-d $main::config{TEMPDIR}) {
	&make_a_dir($main::config{TEMPDIR});
}

# Make the views directory
unless (-d $main::config{HTML}{VIEWDIR}) {
	&make_a_dir($main::config{HTML}{VIEWDIR});
}

# Make the alert-templates directory
$dir = $main::config_dir .'/alert-templates';
unless (-d $dir) { &make_a_dir( $dir); }

# Make the host-templates directory
$dir = $main::config_dir .'/host-templates';
unless (-d $dir) { &make_a_dir( $dir); }

# Make _remstats directories
$dir = $main::config{DATADIR} .'/_remstats_';
unless (-d $dir) { &make_a_dir( $dir); }
$dir = $main::config{HTMLDIR} .'/_remstats_';
unless (-d $dir) { &make_a_dir( $dir); }

# Has the config-file changed since last time check-config was run?
my ($last_change_logged, $config_dir_changed, $config_changed);
($last_change_logged) = &get_status('LAST', 'CONFIGCHANGE');
if ((!defined $last_change_logged) or $last_change_logged !~ /^\d+\s*$/) {
	$last_change_logged = 0;
}
$config_dir_changed = time - int((-M $main::config_dir)*24*60*60);
if ($last_change_logged < $config_dir_changed) {
	$config_changed = 1;
	&put_status('LAST', 'CONFIGCHANGE', $config_dir_changed);
	&debug("config-file changed ". &timestamp($config_dir_changed)) if ($main::debug);
}
else {
	$config_changed = 0;
	&debug("config-file hasn't changed since $config_dir_changed") if ($main::debug);
}

if ($main::write_environment) {
	&write_env( $main::shell_type, 'PAGESAS', 'cgi');
	&write_env( $main::shell_type, 'DATADIR', $main::config{DATADIR});
	&write_env( $main::shell_type, 'HTMLDIR', $main::config{HTMLDIR});
	&write_env( $main::shell_type, 'CONFIGDIR', $main::config_dir);
	&write_env( $main::shell_type, 'CONFIGCHANGED', $config_changed);
	&write_env( $main::shell_type, 'DATAPAGEDIR', $main::config{DATAPAGEDIR});
	&write_env( $main::shell_type, 'WATCHDOGTIMER', $main::config{WATCHDOGTIMER});
	if ($main::shell_type eq 'sh') {
		print "export PAGESAS DATADIR CONFIGDIR CONFIGCHANGED DATAPAGEDIR WATCHDOGTIMER\n";
	}
}

# Make sure the directories are there for each host
my ($listing, $community, $wildrrd, $fixedrrd);
foreach $host (sort keys %{$main::config{HOST}}) {
	&debug("checking $host") if ($main::debug);
	$ip = &get_ip($host);
	unless (defined $ip) {
		&debug("can't get IP number for $host; skipped") if ($main::debug);
		next unless ($main::force);
	}
	$listing = '';
	if ($list_hosts) { $listing .= ' '. $host; }
	if ($list_ips) { $listing .= ' '. $ip; }

	$dir =  $main::config{DATADIR} .'/'. $host;
	unless (-d $dir) {
		print STDERR "making $dir\n";
		next unless (&make_a_dir($dir));
	}
	$dir =  $main::config{HTMLDIR} .'/'. $host;
	unless (-d $dir) {
		print STDERR "making $dir\n";
		next unless (&make_a_dir($dir));
	}

# Make sure that the html flags exist
	foreach ('UPTIMEFLAG.html', 'ALERTFLAG.html', 'STATUS.html') {
		$file = $dir .'/'. $_;
		next if (-f $file);
		if (open (FILE, ">$file")) {
			close(FILE);
		}
		else { &error("can't open $file: $!"); }
	}

# SNMP community listing?
	if ($main::write_communities) {
		if (defined $main::config{HOST}{$host}{COMMUNITY}) {
			$community = $main::config{HOST}{$host}{COMMUNITY};
		}
		elsif (defined $main::config{COMMUNITY}) {
			$community = $main::config{COMMUNITY};
		}
		else { undef $community; }
		if (defined $community) {
			print "$host $community\n";
		}
	}

# Now make any missing RRDs
	&debug("making missing RRDs for $host") if ($main::debug);
	foreach $realrrd (@{$main::config{HOST}{$host}{RRDS}}) {
		($wildrrd, undef, undef, $fixedrrd) = &get_rrd($realrrd);
		&debug("  rrd $realrrd") if ($main::debug);
		if ($list_rrds) { $listing .= ' '. $realrrd; }
		if (defined $wildrrd) {
			my $rrdfile = $main::config{DATADIR}.'/'.$host.'/'.$fixedrrd.'.rrd';
			unless (-f $rrdfile) {
				&make_rrd($rrdfile, $host, $realrrd, $wildrrd);
			}
		}
	}
	if ($do_list) { print substr($listing,1) ."\n"; }
}

# Save new version of the ip_cache
&write_ip_cache;

# Make sure that all the view directories are there
my $viewdir;
foreach my $view (keys %{$main::config{VIEW}}) {
	$viewdir = $main::config{HTML}{VIEWDIR} .'/'. 
		&to_filename($view);
	unless (-d $viewdir) { &make_a_dir($viewdir); }
}

# Make an empty ALERTS file, if it's missing
$file = $main::config{DATADIR} .'/ALERTS';
unless (-f $file) {
	open (FILE, ">$file") or &abort("can't create $file: $!");
	print FILE "VERSION $main::alert_version\n";
	close (FILE);
	&debug("created ALERTS file") if ($main::debug);
}

# Say everything's OK
&put_status('_remstats_', 'STATUS.html', 'Checked');

#------------------------------------------------------ debug ---
sub debug {
	my $msg = join('', @_);
	if ($main::debug>0) {
		print STDERR "DEBUG: $msg\n";
	}
}

#------------------------------------------------------ error ---
sub error {
	my $msg = join('', @_);
	print STDERR "$main::prog: ERROR: $msg\n";
}

#------------------------------------------------------ abort ---
sub abort {
	my $msg = join('', @_);
	print STDERR "$main::prog: ABORT: $msg\n";
	exit 1;
}

#------------------------------------------------------- usage ---
sub usage {
	print STDERR <<"EOD_USAGE";
$main::prog version $main::version
usage: $main::prog [options]
where options are:
	-c      write SNMP communities
	-C CCC  set configuration-debugging output to level 'CCC'
	-d ddd  enable debugging output at level 'ddd'
	-D      dump configuration (must have DEBUG enabled in fixup.config)
	-e      print environment variables to stdout
	-f fff  use config-dir 'fff' [$main::config_dir]
	-h      show this help
	-l lll	list 'lll' on stdout (comma-separated list of: host, ip, rrd)
	-s sss  shell type to use for -e [$main::shell_type]
	-t      test-mode; don't make any changes
EOD_USAGE
	exit 0;
}

#------------------------------------------------------ make_rrd ---
sub make_rrd {
	my ($rrdfile, $host, $realrrd, $wildrrd) = @_;
	my ($data, @args, $ds, $archive);

	if (defined $main::testmode and $main::testmode) {
		&testout("make_rrd($rrdfile, $host, $realrrd, $wildrrd) skipped; test-mode");
		return 1;
	}

# Now collect the info to create the database
	unless (defined $main::config{RRD}{$wildrrd}{STEP}) {
		&error("rrd $wildrrd has no step size defined; skipped creation");
		return;
	}
	@args = ( '--start', (time - $main::config{RRD}{$wildrrd}{STEP}), 
		'--step', $main::config{RRD}{$wildrrd}{STEP});
		
# Add on the Data-Source descriptions
	foreach $data (@{$main::config{RRD}{$wildrrd}{DATANAMES}}) {
		$ds = 'DS:' . $data . ':' . 
			$main::config{RRD}{$wildrrd}{$data}{DS};
		push @args, $ds;
	}

# And the archive descriptions
	foreach $archive (@{$main::config{RRD}{$wildrrd}{ARCHIVES}}) {
		if (defined $main::config{ARCHIVE}{$archive}) {
			push @args, ('RRA:'.$main::config{ARCHIVE}{$archive});
		}
		else {
			&error("make_rrd: $realrrd($wildrrd) wants archive '$archive', but it's not defined; skipped create");
			return 0;
		}
	}

# Now create it; anticlimax after the build-up
	RRDs::create $rrdfile, @args;
	my $error = RRDs::error;
	if ($error) {
		&error("make_rrd: couldn't create $rrdfile: $error");
		return 0;
	}
	else {
		print STDERR "created $rrdfile for $host\n";
	}
1;	
}

#---------------------------------------------------------- write_env ---
sub write_env {
	my ($shell_type, $var, $value) = @_;

	if ($shell_type eq 'sh') { print "$var='$value'\n"; }
	elsif ($shell_type eq 'csh') { print "setenv $var '$value'\n"; }
	else { &abort("unknown shell-type ($shell_type)"); }

}

#-------------------------------------------------------- keep_strict_happy ---
sub keep_strict_happy {
	$main::alert_version = 0; 
}
