#!/usr/bin/perl -w

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

# topology-monitor - say when path to a host has changed
# $Id: topology-monitor.pl,v 1.6 2001/08/28 15:22:24 remstats Exp $

# - - -   Configuration   - - -

use strict;

# What is this program called, for error-messages and file-names
$main::prog = 'topology-monitor';
# Where is the config dir?
$main::config_dir = '/etc/remstats/config';

# - - -   Version History   - - -

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

# - - -   Setup   - - -

use Getopt::Std;
use lib '.', '/usr/lib/remstats/lib', '/usr/lib/perl5/';
require "remstats.pl";

# Parse the command-line
getopts('d:f:h');

if (defined $main::opt_h) { &usage; } # no return
if (defined $main::opt_d) { $main::debug = $main::opt_d; } else { $main::debug = 0; }
if (defined $main::opt_f) { $main::config_dir = $main::opt_f; }

unless ($#ARGV == 1) { &usage; } # no return
my $oldfile = shift @ARGV;
my $newfile = shift @ARGV;

# Get the host->ip mapping from the config
&read_config_dir( $main::config_dir, 'general', 'groups', 'rrds', 
	'host-templates', 'hosts');

my ($host, $ip, %hosts, @old, @new, $oldhops, $newhops);
foreach $host (keys %{$main::config{HOST}}) {
	$ip = &get_ip($host);
	unless (defined $ip) {
		&debug("load: unknown IP number for $host; skipped") if ($main::debug);
		next;
	}
	$hosts{$ip} = $host;
}

# Read in the topology files
my %old = &read_topology($oldfile);
my %new = &read_topology($newfile);

# - - -   Mainline   - - -

foreach $ip (keys %new) {
	unless (defined $old{$ip}) {
		&debug("new host $ip; skipped") if ($main::debug);
		next;
	}

# Get the hostname
	if (defined $hosts{$ip}) {
		$host = $hosts{$ip};
	}
	else {
		&debug("no hostname for IP $ip; skipped") if ($main::debug);
		next;
	}
	&debug("doing host $host") if ($main::debug);

# Get the path
	@old = @{$old{$ip}};
	@new = @{$new{$ip}};
	$oldhops = $#old + 1;
	$newhops = $#new + 1;

# Must be different if it's a different length
	if ($oldhops != $newhops) {
		&debug("  hop count changed, old=$oldhops, new=$newhops") if ($main::debug);
		&logit('TOPOLOGY', $host, undef, undef, undef,
			"hops old=$oldhops, new=$newhops");
	}

# Darn.  I've got to actually compare them.
	else {
		for (my $i=0; $i<=$#new; $i++) {
			unless (defined $old[$i]) {
				&debug("missing old data for $host at hop $i") if ($main::debug);
				next;
			}
			next if ($old[$i] eq $new[$i]);
			++$i;
			&debug("  path changed at hop $i") if ($main::debug);
			&logit('TOPOLOGY', $host, undef, undef, undef,
				"path change at hop $i");
			last;
		}
	}
}

exit 0;

#----------------------------------------------------------------- usage ---
sub usage {
	print STDERR <<"EOD_USAGE";
$main::prog version $main::version
usage: $main::prog [options] oldfile newfile
where options are:
	-d	enable debugging output
	-f fff use 'fff' for config-dir [$main::config_dir]
	-h	show this help
EOD_USAGE
	exit 0;
}

#----------------------------------------------------------------- debug ---
sub debug {
	my ($msg) = @_;

	if ($main::debug) { print STDERR "DEBUG: $msg\n"; }
0;
}

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

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

#--------------------------------------------------------- read_topology ---
# Reads a file of lines produced by make-path into a hash by IP number
sub read_topology {
	my ($file) = @_;
	my %hash = ();

	open (FILE, "<$file") or &abort("can't open $file: $!");
	while (<FILE>) {
		chomp;
		next if (/^\s*$/ or /^#/);
		my (undef, $ip, @path) = split(' ',$_);
		$hash{$ip} = [@path];
	}
	close (FILE);
%hash;
}

#----------------------------------------------- keep_strict_happy ---
sub keep_strict_happy {
	$main::opt_h = 0;
	%main::config = ();
}
