hotsanic |
Subversion Repositories: |
Compare with Previous - Blame - Download
#!/usr/bin/env perl
use strict;
use warnings;
use diagnostics;
#
# $Id: rrdtimer.pl,v 1.3 2003/10/16 10:25:36 bernisys Exp $
#
# use Getopt::Long;
use FindBin;
use lib "./lib";
use lib $FindBin::RealBin;
use HotSaNICparser;
use subs qw(main_loop call_modules call_module_read daemonize);
# let all outputs be flushed directly
$|=1;
# set commandline correctly
$0="rrdtimer";
(my $CALLDIR=$FindBin::RealBin) =~ s/\/rrdtimer//g;
(my $VERSION = '$Revision: 1.3 $') =~ s/.*(\d+\.\d+).*/$1/;
(my $IDENTIFIER = '$Id: rrdtimer.pl,v 1.3 2003/10/16 10:25:36 bernisys Exp $') =~ s/.*,v (.*) \$/$1/;
print "reading & checking config ($CALLDIR/settings) ...\n";
my %CONFIG=HotSaNICparser::get_config($CALLDIR);
$CONFIG{MODULEDIR}=$CONFIG{DAEMONDIR}."/modules";
$CONFIG{SCHEDULED}=1;
print "evaluating cmdline arguments...\n";
my ($debuglevel,$runmode)=check_for_args(@ARGV);
if ($debuglevel>$CONFIG{"DEBUGLEVEL"}) { $CONFIG{"DEBUGLEVEL"}=$debuglevel; }
if ($CONFIG{DEBUGLEVEL} >0) { foreach my $k (keys %CONFIG) { print "$k=$CONFIG{$k}\n"; }}
if ($runmode < 128) { exit 0; }
my $PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL},$CONFIG{PIDFILE},"rrdtimer");
if ( $PID>0 ) {
print "\nAnother process is running on PID $PID - daemon stopped.\n\n";
exit 1;
}
my $debug="";
if (($runmode&1)>0) { print "Debug mode enabled!\nIdentifier: $IDENTIFIER,\nLogdir: ",$CONFIG{LOGDIR},"\nPIDfile: ",$CONFIG{PIDFILE},"\n\n"; $debug="d"; }
my @PIDs;
my %PIDs;
daemonize();
$SIG{TERM} = \&signalhandler;
$SIG{HUP} = \&signalhandler;
$SIG{USR1} = \&signalhandler;
$SIG{USR2} = \&signalhandler;
main_loop();
######################################################################
# #
# SUBROUTINES BEGIN HERE #
# #
######################################################################
######################################################################
#
# signal-handler
# TERM -> terminate daemon and modules
# HUP -> re-configure
# USR1 -> kill daemon only
# USR2 -> kill modules only
#
sub signalhandler {
my ($sig)=@_;
if (defined $sig) {
if (($sig eq "TERM") ||($sig eq "USR2")) {
print time,"Stopping all running modules.\n";
if (@PIDs) { kill "TERM", @PIDs; @PIDs=(); }
}
if (($sig eq "TERM") || ($sig eq "USR1")) {
print time,"Daemon exiting normally.\n";
if (-e $CONFIG{PIDFILE}) {
unlink $CONFIG{PIDFILE};
print "PID-file removed.\n";
}
close STDIN;
close STDOUT;
close STDERR;
exit 0;
}
if ($sig eq "HUP") {
print time," HUP signal received - signal not implemented yet...\n";
foreach (keys %CONFIG) { print $_," -> ",$CONFIG{$_},"\n"; }
# TODO:
#
# - kill unused modules
# - start configured modules (if necessary)
# - re-configure all modules
#
}
}
}
######################################################################
#
# the main loop executes all timed scripts:
#
# modules/*/read-data every >=10 sec. (hardcoded)
# modules/*/diagrams every $DTIME
# convert() every $CTIME if $CONVERTMETHOD is other than "HTML"
# scan_for_modules() every $STIME
#
sub main_loop {
my ($now,$last,$sleeptime,$lastscan,$lastdiagram,$lastconvert,@modules);
$now=time;
$last=$now-100;
$lastscan=$now;
$lastdiagram=int($now/$CONFIG{DTIME})*$CONFIG{DTIME};
$lastconvert=int($now/$CONFIG{CTIME})*$CONFIG{CTIME};
@modules=HotSaNICparser::scan_for_modules($CONFIG{MODULEDIR},$CONFIG{DEBUGLEVEL},$CONFIG{RUN});
if ($CONFIG{DEBUGLEVEL} > 0) { print time,": initializing modules...\n"; }
initialize_modules(@modules);
%PIDs=call_modules(@modules);
@PIDs=keys(%PIDs);
while () {
$now=time;
# if ($last+10 <= $now) {
if ($CONFIG{DEBUGLEVEL} > 0) { print "$now: main loop running\n"; }
# scan for modules and (re-)start them if necessary
#
if ($lastscan+$CONFIG{STIME} <= $now) {
@modules=HotSaNICparser::scan_for_modules($CONFIG{MODULEDIR},$CONFIG{DEBUGLEVEL},$CONFIG{RUN});
%PIDs=call_modules(@modules);
@PIDs=keys(%PIDs);
$lastscan=$now;
if ($CONFIG{DEBUGLEVEL} < 0) { logrotate(); }
}
# for each module call the read-data script.
#
if ($CONFIG{DEBUGLEVEL} > 0) { print "$now: signaling ",join " ",@PIDs,"\n"; }
if (@PIDs) {
if ($CONFIG{SCHEDULED} == 0) { kill "SIGUSR1", @PIDs; }
else {
foreach (@PIDs) {
kill "SIGUSR1", $_;
my $wait=int($CONFIG{SCHEDULE_MIN}+rand($CONFIG{SCHEDULE_MAX}-$CONFIG{SCHEDULE_MIN}))/1000;
if ($CONFIG{DEBUGLEVEL} >3) { print "$wait($PIDs{$_}) "; }
select(undef,undef,undef,$wait);
}
if ($CONFIG{DEBUGLEVEL} >3) { print "\n"; }
}
}
$last=$now;
# }
# check if diagrams have to be built.
#
if ($lastdiagram+$CONFIG{DTIME} <= $now) {
my $append;
if ($CONFIG{DIAGRAMLOG} eq "all") { $append=1; }
call_script($CONFIG{DAEMONDIR},"diagrams.pl",5,$CONFIG{LOGDIR}."/diagram.log",$append);
$lastdiagram+=$CONFIG{DTIME};
# check if mainpage-diagrams have to be generated.
#
if (($lastconvert+$CONFIG{CTIME} <= $now) && ($CONFIG{CONVERTMETHOD} ne "HTML")) {
call_script($CONFIG{DAEMONDIR},"convert.pl",0);
$lastconvert+=$CONFIG{CTIME};
}
}
$sleeptime=10-(time % 10);
sleep $sleeptime;
}
}
######################################################################
#
# call init script in each module (if available)
#
sub initialize_modules {
my (@modules)=@_;
my ($name,$ouser,$osystem,$user,$system,$utime,$stime);
print time," Initializing modules...\n";
for $name (@modules) {
unlink $CONFIG{MODULEDIR}."/$name/*.dat";
# unlink $CONFIG{MODULEDIR}."/$name/*.pid";
unlink $CONFIG{MODULEDIR}."/$name/*.old";
if ( -e $CONFIG{MODULEDIR}."/$name/init" ) {
print time," initializing ",$name,"\n";
system "cd ".$CONFIG{MODULEDIR}."/$name; ./init";
print time," initializing of ",$name," DONE!\n\n";
}
}
print time," END Initializing modules...\n","-" x 50,"\n\n";
}
######################################################################
#
# start read-data.pl script in each module
#
sub call_modules {
my (@modules)=@_;
my %PIDs;
my $nicelevel="0";
# iterate through all configured modules...
#
for my $module (@modules) {
chdir $CONFIG{MODULEDIR}."/$module";
my $PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL});
# if not running, start the module and wait for PIDfile to be generated
#
if ($PID == 0) {
my $count=-1;
print "\nstarting module: \"$module\"\n";
if (-e "./running.pid") {
if ($CONFIG{DEBUGLEVEL}>1) { print "removing old PIDfile...\n"; }
unlink "./running.pid";
}
if (-e "./read-data-wrapper.pl") { system("nice -$nicelevel ./read-data-wrapper.pl start $module"); }
else { system("nice -$nicelevel ./read-data.pl start $module"); }
$count=0;
while ( ($count<20) && (! -s "./running.pid") ) {
$count++;
print ".";
sleep 1;
}
$PID=HotSaNICparser::get_pid($CONFIG{DEBUGLEVEL});
}
if ($PID >0) {
print "$module running on PID $PID\n\n";
$PIDs{$PID}=$module;
}
}
return %PIDs;
}
######################################################################
#
# call external script (incl. sanity checking etc)
#
sub call_script {
my ($path,$script,$nicelevel,$output,$append)=@_;
if (! defined $append) { $append=0; }
if ( index("1 yes",lc $append) < 0) { rename $output,"$output.old"; }
if (! defined $output) { $output=""; }
if (! defined $nicelevel) { $nicelevel=0; }
if ( (defined $path) && (defined $script) ) {
print time,": executing $path/$script with nice $nicelevel\n";
if ( -e "$path/$script") {
if ($output ne "") {
if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script >$output &"); }
else {system ("cd \"$path\"; ./$script >$output &"); }
}
else {
if ($nicelevel ne 0) {system ("cd \"$path\"; nice -$nicelevel ./$script &"); }
else {system ("cd \"$path\"; ./$script &"); }
}
}
else { print time.": script not found! Check your installation.\n"; }
}
}
######################################################################
#
# fork into background
#
sub daemonize {
print "entering daemon mode...\n";
if ($debug eq "") {
close STDIN;
close STDOUT;
close STDERR;
if (open(DEVTTY, "/dev/tty")) { ioctl(DEVTTY,0x20007471,0); close DEVTTY; }
open STDIN,"/dev/null";
open STDOUT,">>".$CONFIG{LOGDIR}."/HotSaNIC.log";
open STDERR,">&STDOUT";
chdir "/";
fork && exit 0;
print "\n\n----------------------------------------\n";
print time,": archiver successfully forked into background and running on PID $$\n";
}
else { print time,": archiver running in debug-mode on PID $$\n"; }
open FILE,">".$CONFIG{PIDFILE};
print FILE $$;
close FILE;
}
######################################################################
#
# rotate logfiles
#
sub logrotate {
my ($size,$file);
if ((defined $CONFIG{DEBUGLEVEL}) && ($CONFIG{DEBUGLEVEL} < 0)) {
$file=$CONFIG{LOGDIR}."/HotSaNIC.log";
(undef,undef,undef,undef,undef,undef,undef,$size,undef,undef,undef,undef,undef) = stat($file);
if (defined $size) {
if ($size > $CONFIG{LOGSIZE}) {
print time," $file exceeding ",$CONFIG{LOGSIZE}," bytes - rotating - keeping ",$CONFIG{LOGBACKUPS}," backups.\n";
for (my $nn=$CONFIG{LOGBACKUPS};$nn>1;$nn--) {
if ( -e "$file.$nn" ) { unlink "$file.$nn"; }
if ( -e "$file.".($nn-1) ) { rename "$file.".($nn-1),"$file.".$nn; }
}
close STDOUT;
rename $file,"$file.1";
open STDOUT,">>$file";
close STDERR;
rename $file,"$file.1";
open STDERR,">>$file";
}
}
}
}
######################################################################
#
# evaluate commandline arguments
#
sub check_for_args {
my @args=@_;
# set initial values
#
my $debuglevel=-1;
my $runmode=0;
# Check if we were called with any options
#
foreach my $arg (@args) {
if (index($arg,"d") >= 0) { $runmode|=1; }
if (index($arg,"D") >= 0) { $runmode|=128; }
if (index($arg,"?") >= 0) { $runmode|=256; }
$arg=~ s/[a-zA-Z]//g;
if ($arg =~ /[0-9]/) { if ($arg > 0) { $debuglevel=$arg; } }
}
if (($runmode == 0) || ($runmode > 255)) {
print "rrdtimer - CVS version $VERSION ($IDENTIFIER) - OS: $^O\n";
print "usage:\nrrdtimer [options[debuglevel]]\n options:\n";
print " D - enter daemon-mode (i.e. start the main loop)\n";
print " d - enter debugging mode (don't fork into background)\n";
print "\n";
exit 0;
}
return ($debuglevel,$runmode);
}