#!/usr/bin/perl
#    Big Sister network monitor
#    Copyright (C) 1998  Thomas Aeby
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

#=============================================================================
#
$BigSister::common::Usage	  = "[-D level] [-d display[:port]] [-t timeout] [-b basedir] [-f commandfile] [command [arg1] [...]]

Commands

join group group1 ...
leave group group1 ...
remove host.check [host.check] [...]
displayname group name ...
savelogs [tag]
archivelogs directory [days]
status host.check color text
disable host.check|host.* duration|forever text
enable host.check|host.* text
";
#
#=============================================================================
@BigSister::common::options = ( "t:i", "f:s", "d:s" );
use lib "."; use lib "uxmon"; use lib "platforms"; use lib "tools"; 		#inslib
use BigSister::common;
proginit();

use FileHandle;
use strict;
use parse;
use Monitor::bb;

my $dl = $BigSister::common::dl;
my $commfile = $BigSister::common::opt_f;
my $timeout = 10;
($timeout = $BigSister::common::opt_t) if( $BigSister::common::opt_t );
my $display = $BigSister::common::opt_d;
$display = "localhost" unless( $display );

my $bbconn;
my $bbdisp;
my $error = 0;

$ENV{PATH} = "$BigSister::common::fs{'bin'}:".$ENV{PATH};

if( $#ARGV >= 0 ) {
    command( @ARGV );
}

if( $commfile ) {
    unless( open( CMD, "<$commfile" ) ) {
	print STDERR "$man::prog: cannot open command file $commfile\n";
	exit(1);
    }
    while( <CMD> ) {
	chomp;
	next if( /^#/ || ! $_ );
	while( $_ =~ /\\$/ ) {
	    s/\\$/\n/;
	    chomp( $_ .= <CMD> );
	}
	command( parse( $_ ) );
    }
}
exit( $error );


sub command {
    my( $cmd, @args ) = @_;
    my( %cmds ) = (
	"status" => \&status,
	"remove" => \&remove,
	"join" => \&join,
	"leave" => \&leave,
	"displayname" => \&displayname,
	"savelogs" => \&savelogs,
	"archivelogs" => \&archivelogs,
	"enable" => \&enable_check,
	"disable" => \&disable_check
    );

    unless( defined $cmds{$cmd} ) {
	print STDERR "$BigSister::common::prog: unknown command: $cmd\n";
	return;
    }
    my $do = $cmds{$cmd};
    my $err = &$do( @args );
    if( $err ) {
	print STDERR "$BigSister::common::prog: $cmd command failed with: $err\n";
	$error = 1;
    }
}



sub status {
    my( $check, $color, $text ) = @_;

    unless( grep( $color eq $_, keys %BigSister::common::status_codes ) ) {
	return "unknown status color: $color";
    }
    unless( $check =~ /\./ ) {
	return( "$check should be hostname.check" );
    }
    return send_cmd( $display, "status $check $color (".time.") ".(scalar localtime)." ".$text );
}



sub remove {
    my( @check ) = @_;

    foreach my $check (@check) {
	unless( $check =~ /\./ ) {
	    return( "$check should be hostname.check" );
	}
        my $error = send_cmd( $display, "remove $check" );
	return( $error ) if( $error );
    }
}


sub leave {
    my( $group, @groups ) = @_;
    return join_or_leave( "leave", $group, @groups );
}


sub join {
    my( $group, @groups ) = @_;
    return join_or_leave( "join", $group, @groups );
}


sub join_or_leave {
    my( $mode, $group, @groups ) = @_;

    return send_cmd( $display, "$mode $group ".join(" ",@groups) );
}


sub displayname {
    my( $group, @name ) = @_;

    return send_cmd( $display, "displayname $group ".join(" ",@name) );
}


sub savelogs {
    my( $tag ) = @_;
    return send_cmd( $display, "savelogs".($tag?" $tag":"") );
}


sub disable_check {
    my( $check, $duration, $text ) = @_;
    my $user = getpwuid( $> ) or "unknown";
    $duration = "forever" if( $duration eq "*" );
    unless( $duration =~ /^(\d+:\d+|forever)/ ) {
        print STDERR "duration must either be 'hours:minutes' or 'forever'";
	exit(1);
    }
    return send_cmd( $display, "ack $check $duration $user maint $text" );
}


sub enable_check {
    my( $check ) = @_;
    my $user = getpwuid( $> ) or "unknown";
    return send_cmd( $display, "ack $check 0:00 $user ign" );
}



sub archivelogs {
    my( $dir, $days ) = @_;

    unless( -w $dir ) {
	print STDERR "Usage: archivelogs directory [days]\n";
	return "You did not pass me a writable directory";
    }
    unless( $days>0 ) {
	$days = 7;
    }
    my $now = time;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);  
    print "bundling $days days: last boundary is ".($yday%$days)." day(s) back\n" if( $BigSister::common::dl>2 );
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now-($yday%$days)*24*3600);  
    $year += 1900;
    my $tag = sprintf( "%04d%02d%02d", $year, $mon+1, $mday );
    print "current tag is $tag\n" if( $BigSister::common::dl>1 );
    my $file = $dir."/".$display.".$tag";
    return if( -f $file );
    send_cmd( $display, "savelogs $tag" );
    send_cmd( $display, "sendlogs $tag" );
    open( OUT, ">$file.$$" );
    my $socket = $bbconn->socket();
    print "now retrieving logs tagged $tag\n" if( $BigSister::common::dl );
    eval {
        $SIG{'ALRM'} = sub { die "timed out" };
	Platform::bsalarm(30);
		 
	while( <$socket> ) {
	    if( /^--END/ ) {
		Platform::bsalarm(0);
		rename( $file.".$$", $file );
		print "received end tag - transmission complete\n" if( $BigSister::common::dl );
		last;
	    }
	    print OUT;
	}
    };
    Platform::bsalarm(0);
    close OUT;
    unlink( $file.".$$" );
    return();
}





sub send_cmd {
    my( $display, $text ) = @_;
    my( $port );

    unless( $display eq $bbdisp ) {
	if( $display =~ /:(.*)/ ) {
	    $display = $`;
	    $port = $1;
	}
	$bbconn = Monitor::bb->new( $display, $timeout, $port );
	$bbdisp = $display;
    }
    print "sending $text\n" if( $BigSister::common::dl );
    $text =~ s/\n/\|\>/g;
    return( $bbconn->sysreport( $text ) ? "" : "connection to $display failed" );
}

