[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 #! /usr/bin/perl -w 2 # -*- mode: cperl -*- 3 4 ################################################################### 5 # MRTG 2.10.13 Multi Router Traffic Grapher 6 ################################################################### 7 # Created by Tobias Oetiker <oetiker@ee.ethz.ch> 8 # and Dave Rand <dlr@bungi.com> 9 # 10 # For individual Contributers check the CHANGES file 11 # 12 ################################################################### 13 # 14 # Distributed under the GNU General Public License 15 # 16 ################################################################### 17 18 # Adaptation SambaEdu Philippe Chadefaux 19 20 # $Id: mrtg-se3 6654 2011-11-27 16:35:54Z dbo $ # 21 22 my @STARTARGS=($0,@ARGV); 23 24 @main::DEBUG=qw(); 25 # DEBUG TARGETS 26 # cfg - watch the config file reading 27 # dir - directory mangeling 28 # base - basic program flow 29 # tarp - target parser 30 # snpo - snmp polling 31 # repo - track confcache repopulation 32 # fork - forking view 33 # time - some timing info 34 # log - logging of data via rateup or rrdtool 35 $main::GRAPHFMT="png"; 36 # There older perls tend to behave peculiar with 37 # large integers ... 38 require 5.005; 39 40 use strict; 41 42 BEGIN { 43 # Automatic OS detection ... do NOT touch 44 if ( $^O =~ /^(ms)?(dos|win(32|nt)?)/i ) { 45 $main::OS = 'NT'; 46 $main::SL = '\\'; 47 $main::PS = ';'; 48 } elsif ( $^O =~ /^VMS$/i ) { 49 $main::OS = 'VMS'; 50 $main::SL = '.'; 51 $main::PS = ':'; 52 } elsif ( $^O =~ /^os2$/i ) { 53 $main::OS = 'OS2'; 54 $main::SL = '/'; 55 $main::PS = ';'; 56 } else { 57 $main::OS = 'UNIX'; 58 $main::SL = '/'; 59 $main::PS = ':'; 60 } 61 if ( $ENV{LANG} and $ENV{LANG} =~ /UTF-8/i ){ 62 print <<ERR; 63 ----------------------------------------------------------------------- 64 ERROR: Mrtg will most likely not work propperly when the environment 65 variable LANG is set to UTF-8. Please run mrtg in an environment 66 where this is not the case: 67 68 env LANG=C $0} ... 69 ----------------------------------------------------------------------- 70 ERR 71 exit 0; 72 } 73 } 74 75 76 use FindBin; 77 use lib "$FindBin::Bin}"; 78 use lib "$FindBin::Bin}$main::SL}..$main::SL}lib$main::SL}mrtg2"; 79 use Getopt::Long; 80 use Math::BigFloat; 81 82 # search for binaries in the bin and bin/../lib directory 83 use MRTG_lib "2.100001"; 84 use SNMP_util '0.97'; 85 # $SNMP_Session::suppress_warnings = 2; 86 use locales_mrtg "0.07"; 87 88 # Import IPv6 libraries if available, as (unfortunately) they are 89 # necessary for dead host detection (for IPv6 name lookups). 90 BEGIN { 91 if (eval {require Socket6;}) { 92 import Socket; 93 import Socket6 94 } 95 } 96 97 $main::STARTTIME = time; 98 99 if ($MRTG_lib::OS eq 'OS2') { 100 # in daemon mode we will pause 3 seconds to be sure that parent died 101 require OS2::Process; 102 if (OS2::Process::my_type() eq 'DETACH') {sleep(3);} 103 } 104 105 if ($MRTG_lib::OS eq 'UNIX') { 106 $SIG{INT} = $SIG{TERM} = 107 sub { unlink $main::Cleanfile} 108 if defined $main::Cleanfile; 109 unlink $main::Cleanfile2} 110 if defined $main::Cleanfile2; 111 unlink $main::Cleanfile3} 112 if defined $main::Cleanfile3; 113 warn "ERROR: Bailout after SIG $_[0]\n"; 114 exit 1; 115 }; 116 $SIG{HUP} = sub { 117 unlink $main::Cleanfile} 118 if defined $main::Cleanfile; 119 unlink $main::Cleanfile2} 120 if defined $main::Cleanfile2; 121 unlink $main::Cleanfile3} 122 if defined $main::Cleanfile3; 123 die "ERROR: Bailout after SIG $_[0]\n"; 124 }; 125 } 126 127 128 END { 129 local($?, $!); 130 unlink $main::Cleanfile} if defined $main::Cleanfile; 131 unlink $main::Cleanfile2} if defined $main::Cleanfile2; 132 } 133 134 &main; 135 136 exit(0); 137 138 #### Functions ################################################ 139 140 sub main { 141 142 debug 'time', "prog start ".localtime(time); 143 144 # read in the config file 145 my @routers; 146 my %cfg; 147 my %rcfg; 148 my %opts; 149 GetOptions(\%opts, 'user=s', 'group=s', 'lock-file=s','confcache-file=s','logging=s', 'check', 'fhs', 'daemon', 'pid-file=s','debug=s'); 150 151 if (defined $opts{debug}){ 152 @main::DEBUG = split /\s*,\s*/, $opts{debug} 153 } 154 155 my $uid = $<; 156 my $gid = $(; 157 158 if (defined $opts{group}) { 159 $gid = getgrnam($opts{group}) or die "ERROR: Unknown Group: $opts{group})\n"; 160 } 161 162 if (defined $opts{user}) { 163 $uid = getpwnam($opts{user}) or die "ERROR: Unknown User: $opts{user})\n"; 164 } 165 166 # If we've specified using FHS (http://www.pathname.com/fhs/) on the command line, 167 # use the relevant path definitions (can be overridden later): 168 169 my $confcachefile; 170 my $pidfile; 171 my $lockfile; 172 my $templock; 173 my $logfile; 174 175 if (defined $opts{"fhs"}) { 176 $confcachefile = "/var/cache/mrtg/mrtg.ok"; 177 $pidfile = "/var/run/mrtg.pid"; 178 $lockfile = "/var/cache/mrtg/mrtg.lck"; 179 $templock = "/var/cache/mrtg/mrtg.lck.$$"; 180 $logfile = "/var/log/mrtg.log"; 181 } 182 183 my $cfgfile = shift @ARGV; 184 185 if ( !defined $cfgfile and -r "/etc/mrtg.cfg" ) { $cfgfile = "/etc/mrtg.cfg"; } 186 187 printusage() unless defined $cfgfile; 188 189 # PID file code, used later if daemonizing... 190 if ( !defined($pidfile) ) { 191 $pidfile = $cfgfile; 192 $pidfile =~ s/\.[^.\/]+$//; 193 $pidfile .= '.pid'; 194 } 195 $pidfile = $opts{"pid-file"} || $pidfile; 196 197 # Run as a daemon, specified on command line (required for FHS compliant daemon) 198 if (defined $opts{"daemon"}) { 199 # Create a pidfile, then chown it so we can use it once we change user 200 &create_pid($pidfile); 201 chown $uid, $gid, $pidfile; 202 } 203 204 ($(,$)) = ($gid,$gid) ; 205 ($<,$>) = ($uid,$uid) ; 206 die "ERROR failed to set UID to $uid\n" unless ($< == $uid and $> == $uid); 207 208 $logfile = $opts{logging} || $logfile; 209 if (defined $logfile){ 210 setup_loghandlers $logfile; 211 warn "Started mrtg\n"; 212 } 213 214 # lets make sure that there are not two mrtgs running in parallel. 215 # so we lock on the cfg file. Nothing fancy, just a lockfile 216 217 $lockfile = $opts{"lock-file"} || $lockfile; 218 my @cfgfile = split(/\//, $cfgfile); 219 220 if (! defined $lockfile) { 221 #DEB $lockfile = $cfgfile."_l"; 222 $lockfile = "/var/lock/mrtg/" . join('_', @cfgfile) . "_l"; 223 } 224 if (! defined $templock) { 225 $templock = $lockfile."_" . $$ ; 226 #DEB $templock = "/var/lock/mrtg/" . join('_', @cfgfile) . "_l_" . $$ ; 227 } 228 229 debug('base', "Creating Lockfiles $lockfile,$templock"); 230 &lockit($lockfile,$templock); 231 232 debug('base', "Reading Config File: $cfgfile"); 233 readcfg($cfgfile,\@routers,\%cfg,\%rcfg); 234 235 # Enable or disable IPv6 236 if(defined $cfg{enableipv6}) { 237 $cfg{enableipv6} = lc($cfg{enableipv6}); 238 } else { 239 $cfg{enableipv6} = 'no'; 240 } 241 242 # Check we have the necessary libraries for IPv6 support 243 if ($cfg{enableipv6} eq 'yes') { 244 if ( (eval {require Socket6;}) and (eval {require IO::Socket::INET6;}) ) { 245 debug('base', "IPv6 libraries found, IPv6 enabled."); 246 } else { 247 warn "WARNING: IPv6 libraries not found, IPv6 disabled.\n"; 248 $cfg{enableipv6} = 'no'; 249 } 250 } 251 252 # from our last run we kept some info about 253 # the configuration of our devices around 254 debug('base', "Reading Interface Config cache"); 255 $confcachefile = $opts{"confcache-file"} || $confcachefile; 256 if ( !defined($confcachefile) ) { 257 $confcachefile = $cfgfile; 258 $confcachefile =~ s/\.[^.\/]+$//; 259 $confcachefile .= ".ok"; 260 my @cachefile = split(/\//, $cfgfile); 261 $confcachefile = "/var/lib/mrtg/" . join('_', @cachefile); 262 } 263 my $confcache = readconfcache($confcachefile); 264 265 # Check the config and create the target object 266 debug('base', "Checking Config File"); 267 my @target; 268 cfgcheck(\@routers, \%cfg, \%rcfg, \@target); 269 270 # exit here if we only check the config file 271 # in case of an error, cfgcheck() already exited 272 if (defined $opts{check}) { 273 debug('base', "Remove Lock Files"); 274 close LOCK; unlink ($templock, $lockfile); 275 debug('base', "Exit after successful config file check"); 276 exit 0; 277 } 278 279 # postload rrdtool support 280 if ($cfg{logformat} eq 'rrdtool'){ 281 debug('base', "Loading RRD support"); 282 require 'RRDs.pm'; 283 } 284 285 # set the locale 286 my $LOC; 287 if ( $cfg{'language'} and defined($lang2tran::LOCALE{"\L$cfg{'language'}\E"})) { 288 debug('base', "Loading Locale for ".$cfg{'language'}); 289 $LOC=$lang2tran::LOCALE{"\L$cfg{'language'}\E"}; 290 } else { 291 debug('base', "Loading default Locale"); 292 $LOC=$lang2tran::LOCALE{'default'}; 293 } 294 295 # Daemon Code 296 my $last_time=0; 297 my $curent_time; 298 my $sleep_time; 299 if (defined $opts{"daemon"}) { $cfg{'runasdaemon'} = "yes"; } 300 &demonize_me($pidfile,$cfgfile) if defined $cfg{'runasdaemon'} and $cfg{'runasdaemon'} =~ /y/i and $MRTG_lib::OS ne 'VMS'; 301 # auto restart on die if running as demon 302 303 $SIG{__DIE__} = sub { 304 warn $_[0]; 305 warn "*** Restarting after 10 seconds in an attempt to recover from the error above\n"; 306 sleep 10; 307 exec @STARTARGS; 308 } if $cfg{'runasdaemon'}; 309 310 debug('base', "Starting main Loop"); 311 do { # Do this loop once for native mode and forever in daemon mode 312 my $router; 313 debug 'time', "loop start ".localtime(time); 314 315 #if we run as daemon, we sleep in between collection cycles 316 $sleep_time= ($cfg{interval}*60)-(time-$last_time); 317 if ($sleep_time > 0 ) { #If greater than 0 the sleep that amount of time 318 debug('time', "Sleep time $sleep_time seconds"); 319 sleep ($sleep_time); 320 } elsif ($last_time > 0) { 321 warn "WARNING: data collection did not complete within interval!\n"; 322 } 323 $last_time=time; 324 325 # set meta expires if there is an index file 326 # 2000/05/03 Bill McGonigle <bill@zettabyte.net> 327 if (defined $cfg{'writeexpires'}) { 328 my $exp = &expistr($cfg{'interval'} ? $cfg{'interval'} : 5); 329 my $fil; 330 $fil = "$cfg{'htmldir'}index.html" if -e "$cfg{'htmldir'}index.html"; 331 $fil = "$cfg{'htmldir'}index.htm" if -e "$cfg{'htmldir'}index.htm"; 332 if (defined $fil) { 333 open(META, ">$fil.meta"); 334 print META "Expires: $exp\n"; 335 close(META); 336 } 337 } 338 339 340 # Use SNMP to populate the target object 341 debug('base', "Populate Target object by polling SNMP and". 342 " external Datasources"); 343 debug 'time', "snmp read start ".localtime(time); 344 readtargets($confcache,\@target, \%cfg); 345 346 # collect data for each router or pseudo target (`executable`) 347 debug 'time', "target loop start ".localtime(time); 348 foreach $router (@routers) { 349 debug('base', "Act on Router/Target $router"); 350 if (defined $rcfg{'setenv'}{$router}) { 351 my $line = $rcfg{'setenv'}{$router}; 352 while ( $line =~ s/([^=]+)=\"([^\"]*)\"\s*// ) 353 { 354 $ENV{$1}=$2; 355 } 356 } 357 my($savetz) = $ENV{'TZ'}; 358 if (defined $rcfg{'timezone'}{$router}) { 359 $ENV{'TZ'} = $rcfg{'timezone'}{$router} 360 } 361 362 my ($inlast, $outlast, $uptime, $name, $time) = 363 getcurrent(\@target, $router, \%rcfg, \%cfg); 364 debug('base', "Get Current values: in:".( defined $inlast ? $inlast : "undef").", out:". 365 ( defined $outlast? $outlast : "undef").", up:". 366 ( defined $uptime ? $uptime : "undef").", name:". 367 ( defined $name ? $name : "undef").", time:". 368 ( defined $time ? $time : "undef")); 369 370 #abort, if the router is not responding. 371 if ($cfg{'logformat'} ne 'rrdtool') { 372 # undefined values are ok for rrdtool ! 373 #if ( not defined $inlast or not defined $outlast){ 374 # warn "WARNING: Skipping Update of $router, inlast is not defined\n" 375 # unless defined $inlast; 376 # warn "WARNING: Skipping Update of $router, outlast is not defined\n" 377 # unless defined $outlast; 378 # next; 379 #} 380 381 if (defined $inlast and $inlast < 0) { 382 $inlast += 2**31; 383 # this is likely to be a broken snmp counter ... lets compensate 384 } 385 if (defined $outlast and $outlast < 0) { 386 $outlast += 2**31; 387 # this is likely to be a broken snmp counter ... lets compensate 388 } 389 } 390 391 my ($maxin, $maxout, $maxpercent, $avin, $avout, $avpercent,$avmxin, $avmxout, 392 $cuin, $cuout, $cupercent); 393 debug('base', "Create Graphics"); 394 if ($rcfg{'options'}{'dorelpercent'}{$router}) { 395 ($maxin, $maxout, $maxpercent, $avin, $avout, $avpercent, 396 $cuin, $cuout, $cupercent, $avmxin, $avmxout) = 397 writegraphics($router, \%cfg, \%rcfg, $inlast, $outlast, $time,$LOC); 398 } else { 399 ($maxin, $maxout ,$avin, $avout, $cuin, $cuout, $avmxin, $avmxout) = 400 writegraphics($router, \%cfg, \%rcfg, $inlast, $outlast, $time,$LOC); 401 } 402 # skip this update if we did not get anything usefull out of 403 # writegraphics 404 next if not defined $maxin; 405 406 debug('base', "Check for Thresholds"); 407 threshcheck(\%cfg,\%rcfg,$cfgfile,$router,$cuin,$cuout); 408 409 if ($cfg{logformat} eq 'rateup'){ 410 debug('base', "Check for Write HTML Pages"); 411 writehtml($router, \%cfg, \%rcfg, 412 $maxin, $maxout, $maxpercent, $avin, $avout, $avmxin, $avmxout, $avpercent, 413 $cuin, $cuout, $cupercent, $uptime, $name, $LOC) 414 } 415 416 #put TZ things back in shape ... 417 if ($savetz) { 418 $ENV{'TZ'} = $savetz; 419 } else { 420 delete $ENV{'TZ'}; 421 } 422 ; 423 } 424 } while ($cfg{'runasdaemon'} and $cfg{'runasdaemon'} =~ /y/i ); #In daemon mode run forever 425 debug('base', "Exit main Loop"); 426 # OK we are done, remove the lock files ... 427 428 debug('base', "Remove Lock Files"); 429 close LOCK; unlink ($templock, $lockfile); 430 431 debug('base', "Store Interface Config Cache"); 432 delete $$confcache{___updated} if exists $$confcache{___updated}; # make sure everything gets written out not only the updated entries 433 writeconfcache($confcache,$confcachefile); 434 435 } 436 437 # ( $inlast, $outlast, $uptime, $name, $time ) = 438 # &getcurrent( $target, $rou, $rcfg, $cfg ) 439 # Calculate monitored data for device $rou based on information in @$target 440 # and referring to configuration data in %$rcfg and %$cfg. In the returned 441 # list, $inlast and $outlast are the input and output monitored data values, 442 # $uptime is the device uptime, $name is the device name, and $time is the 443 # current time when the calculation was performed. 444 sub getcurrent { 445 my( $target, $rou, $rcfg, $cfg ) = @_; 446 # Hash indexed by $mode for conveniently saving $inlast and $outlast 447 my %last; 448 # Initialize uptime, device name, and data collection time to empty strings 449 my $uptime = ''; 450 my $name = ''; 451 my $time = ''; 452 453 # Calculate input and output monitored data 454 foreach my $mode( qw( _IN_ _OUT_ ) ) { 455 # Initialize monitored data, warning message, and death message 456 # to empty strings 457 my $data; 458 my $warning; 459 my $death; 460 { 461 # Code block used to calculate monitoring data 462 # Localize warning and death exception handlers to capture 463 # error message less any leading and trailing white space 464 local $SIG{ __WARN__ } = 465 sub { $_[0] =~ /^\s*(.+?)\s*$/; $warning = $1; }; 466 local $SIG{ __DIE__ } = 467 sub { $_[0] =~ /^\s*(.+?)\s*$/; $death = $1; }; 468 # Calculate monitoring data. $rcfg->{ target }{ $rou } contains 469 # a Perl expression for the calculation. 470 $data = eval "$rcfg->{target}{$rou}"; 471 } 472 # Test for various exceptions occurring in the calculation 473 if( $warning ) { 474 warn "ERROR: Target[$rou][$mode] '$$rcfg{target}{$rou}' (warn): $warning\n"; 475 $data = undef; 476 } elsif( $death ) { 477 warn "ERROR: Target[$rou][$mode] '$$rcfg{target}{$rou}' (kill): $death\n"; 478 $data = undef; 479 } elsif( $@ ) { 480 warn "ERROR: Target[$rou][$mode] '$$rcfg{target}{$rou}' (eval): $@\n"; 481 $data = undef; 482 } elsif( not defined $data ) { 483 warn "ERROR: Target[$rou][$mode] '$$rcfg{target}{$rou}' did not eval into defined data\n"; 484 $data = undef; 485 } elsif( $data and $data !~ /^[-+]?\d+(\.\d*)?([eE][+-]?[0-9]+)?$/ ) { 486 warn "ERROR: Target[$rou][$mode] '$$rcfg{target}{$rou}' evaluated to '$data' instead of a number\n"; 487 $data = undef; 488 } elsif( length( $data ) > 190 ) { 489 warn "ERROR: $mode value: '$data' is way to long ...\n"; 490 $data = undef; 491 } else { 492 # At this point data is considered valid. Round to an integer 493 # unless RRDTool is in use and this is a gauge 494 if (not ( $cfg->{ logformat } eq 'rrdtool' 495 and defined $rcfg->{ options }{ gauge }{ $rou })){ 496 if (ref $data and ref $data eq 'Math::BigFloat') { 497 $data->ffround( 0 ) 498 } else { 499 $data = sprintf "%.0f", $data; 500 } 501 } 502 # Remove any leading plus sign 503 $data =~ s/^\+//; 504 } 505 $last{ $mode } = $data; 506 } 507 508 # Set $u to the unique index of the @$target array referred to in the 509 # monitored data calculation for the current device. $u will be set to 510 # -1 if that index is not unique. 511 my $u = $rcfg->{ uniqueTarget }{ $rou }; 512 513 # Get the uptime, device name, and data collection time from the @$target 514 # array if the monitored data calculation refers only to one target. 515 # Otherwise it doesn't make sense to do this. 516 if( $rcfg->{ uniqueTarget }{ $rou } >= 0 ) { 517 $uptime = $target->[ $u ]{ _UPTIME_ }; 518 $name = $target->[ $u ]{ _NAME_ }; 519 $time = $target->[ $u ]{ _TIME_ }; 520 } 521 522 # Set the time to the current time if it was not set above 523 $time = time unless $time; 524 525 # Get the uptime and device name from the alternate location 526 # (community@host) that may have been specified with the RouterUptime 527 # target keyword 528 if( defined $rcfg->{ routeruptime }{ $rou } ) { 529 ( $uptime, $name ) = snmpget( 530 v4onlyifnecessary( $rcfg->{ routeruptime }{ $rou }, 531 $rcfg->{ ipv4only }{ $rou } ), 532 $cfg->{ snmpoptions }, 'sysUptime', 'sysName'); 533 } 534 535 # Get the device name from the alternate location (OID or 536 # OID:community@host) that may have been specified with the RouterName 537 # target keyword 538 if( defined $rcfg->{ routername }{ $rou } ) { 539 my( $noid, $nloc ) = split( /:/, $rcfg->{ routername }{ $rou }, 2 ); 540 # If no location (community@host) was specified use values from the 541 # unique target referred to in the monitored data calculation 542 if( $u >= 0 and not $nloc ) { 543 my $comm = $target->[ $u ]{ Community }; 544 my $host = $target->[ $u ]{ Host }; 545 my $opt = $target->[ $u ]{ SnmpOpt }; 546 $nloc = "$comm\@$host$opt"; 547 } 548 # Get the location from the RouterUptime keyword if that is defined 549 # and $nloc has not otherwise been specified 550 $nloc = $rcfg->{ routeruptime }{ $rou } 551 if defined $rcfg->{ routeruptime }{ $rou } and not $nloc; 552 # Get the device name if $nloc (community@host) has been specified 553 # one way or the other 554 ( $name ) = snmpget( $nloc, $$cfg{snmpoptions}, $noid ) if $nloc; 555 } 556 557 return ( $last{ _IN_ }, $last{ _OUT_ }, $uptime, $name, $time ); 558 } 559 560 sub rateupcheck ($) { 561 my $router = shift; 562 if ($?) { 563 my $value = $?; 564 my $signal = $? & 127; #ignore the most significant bit 565 #as it is always one when it is a returning 566 #child says dave ... 567 if (($MRTG_lib::OS ne 'UNIX') || ($signal != 127)) { 568 my $exitval = $? >> 8; 569 warn "WARNING: rateup died from Signal $signal\n". 570 " with Exit Value $exitval when doing router '$router'\n". 571 " Signal was $signal, Returncode was $exitval\n" 572 } 573 } 574 } 575 576 sub writegraphics { 577 my($router, $cfg, $rcfg, $inlast, $outlast, $time,$LOC) = @_; 578 579 my($absmax,$maxv, $maxvi, $maxvo, $i, $period, $res); 580 my(@exec, @mxvls, @metas); 581 my(%maxin, %maxout, %maxpercent, %avin, %avout, %avmxin, %avmxout, %avpercent, %cuin, %cuout, %cupercent); 582 583 @metas = (); 584 $maxvi = $$rcfg{'maxbytes1'}{$router}; 585 $maxvo = $$rcfg{'maxbytes2'}{$router}; 586 if ($maxvi > $maxvo) { 587 $maxv = $maxvi; 588 } else { 589 $maxv = $maxvo; 590 } 591 $absmax = $$rcfg{'absmax'}{$router}; 592 $absmax = $maxv unless defined $absmax; 593 if ($absmax < $maxv) { 594 die "ERROR: AbsMax: $absmax is smaller than MaxBytes: $maxv\n"; 595 } 596 597 598 # select whether the datasource gives relative or absolte return values. 599 my $up_abs="u"; 600 $up_abs='a' if defined $$rcfg{'options'}{'absolute'}{$router}; 601 $up_abs='g' if defined $$rcfg{'options'}{'gauge'}{$router}; 602 $up_abs='h' if defined $$rcfg{'options'}{'perhour'}{$router}; 603 $up_abs='m' if defined $$rcfg{'options'}{'perminute'}{$router}; 604 605 my $dotrrd = "$$cfg{'logdir'}$$rcfg{'directory'}{$router}$router.rrd"; 606 my $dotlog = "$$cfg{'logdir'}$$rcfg{'directory'}{$router}$router.log"; 607 my $reallog = $$cfg{logformat} eq 'rrdtool' ? $dotrrd : $dotlog; 608 609 if (defined $$cfg{maxage} and -e $reallog and time()-$$cfg{maxage} > (stat($reallog))[9]){ 610 warn "ERROR: skipping update of $router. As $reallog is older than MaxAge ($$cfg{maxage} s)\n"; 611 return undef; 612 } 613 614 if ($$cfg{logformat} eq 'rrdtool') { 615 debug('base',"start RRDtool section"); 616 # make sure we got some sane default here 617 my %dstype = qw/u COUNTER a ABSOLUTE g GAUGE h COUNTER m COUNTER/; 618 $up_abs = $dstype{$up_abs}; 619 # update the database. 620 621 # set minimum/maximum values. use 'U' if we cannot get good values 622 # the lower bound is hardcoded to 0 623 my $absi = $maxvi; 624 my $abso = $maxvo; 625 $absi = $abso = $$rcfg{'absmax'}{$router} 626 if defined $$rcfg{'absmax'}{$router}; 627 debug('base',"maxi:$absi, maxo:$abso"); 628 $absi = 'U' if $absi == 0; 629 $abso = 'U' if $abso == 0; 630 # maybe we can convert an .log file to the new rrd format 631 if (-e $dotlog and not -e $dotrrd) { 632 debug('base',"converting $dotlog to RRD format"); 633 if(defined $RRDs::VERSION and $RRDs::VERSION < 1.000271){ 634 die "ERROR: RRDtool version 1.0.27 or later required to perform log2rrd conversion\n"; 635 } 636 log2rrd($router,$cfg,$rcfg); 637 } elsif (! -e $dotrrd) { 638 #nope it seems we have to create a new one 639 debug('base',"create $dotrrd"); 640 # create the rrd if it doesn't exist 641 # don't fail if interval is not set 642 my $interval = $$cfg{interval} || 5; 643 my $minhb = int($$cfg{interval} * 60)*2; 644 $minhb = 600 if ($minhb <600); 645 my $rows = $$rcfg{'rrdrowcount'}{$router} || ( 4000 / $interval); 646 my @args = ($dotrrd, '-b', $time-10, '-s', int($interval * 60), 647 "DS:ds0:$up_abs:$minhb:0:$absi", 648 "DS:ds1:$up_abs:$minhb:0:$abso", 649 "RRA:AVERAGE:0.5:1:$rows", 650 ( $interval < 30 ? ("RRA:AVERAGE:0.5:".int(30/$interval).":800"):()), 651 "RRA:AVERAGE:0.5:".int(120/$interval).":800", 652 "RRA:AVERAGE:0.5:".int(1440/$interval).":800", 653 "RRA:MAX:0.5:1:$rows", 654 ( $interval < 30 ? ("RRA:MAX:0.5:".int(30/$interval).":800"):()), 655 "RRA:MAX:0.5:".int(120/$interval).":800", 656 "RRA:MAX:0.5:".int(1440/$interval).":800"); 657 RRDs::create(@args); 658 my $e = RRDs::error(); 659 die "ERROR: Cannot create logfile: $e\n" if $e; 660 debug('log', "Called: RRDs::create(@args)"); 661 } else { 662 # update the minimum/maximum according to maxbytes/absmax 663 # and (re)set the data-source-type to reflect cfg changes 664 # cost: 1 read/write cycle, but update will reuse the buffered data 665 my @args = ($dotrrd, '-a', "ds0:$absi", '-a', "ds1:$abso", 666 '-d', "ds0:$up_abs", '-d', "ds1:$up_abs"); 667 RRDs::tune(@args); 668 my $e = RRDs::error(); 669 warn "ERROR: Cannot tune logfile: $e\n" if $e; 670 debug('log', "Called: RRDs::tune(@args)"); 671 } 672 # update the rrd 673 $inlast = 'U' unless defined $inlast and $inlast =~ /\S/ and $inlast ne '##UNDEF##'; 674 $outlast = 'U' unless defined $outlast and $outlast =~ /\S/ and $outlast ne '##UNDEF##'; 675 debug('log', "Calling: RRDs::update($dotrrd, '$time:$inlast:$outlast')"); 676 RRDs::update("$dotrrd", "$time:$inlast:$outlast"); 677 my $e = RRDs::error(); 678 warn "ERROR: Cannot update $dotrrd with '$time:$inlast:$outlast' $e\n" if ($e); 679 680 # get the rrdtool-processed values back from rrdtool 681 # for the threshold checks (we cannot use the fetched data) 682 my $lasttime = RRDs::last($dotrrd); 683 debug('log', "Called: RRDs::last()"); 684 $e = RRDs::error(); 685 warn "ERROR: Cannot 'last' $dotrrd: $e\n" if ($e); 686 my $fetch = (RRDs::fetch($dotrrd,'AVERAGE','-s',$lasttime,'-e',$lasttime))[3]; 687 $e = RRDs::error(); 688 die "ERROR: Cannot 'fetch' $dotrrd: $e\n" if ($e); 689 debug('log', "Called: RRDs::fetch($dotrrd,'AVERAGE','-s',$lasttime,'-e',$lasttime)"); 690 my $in = $fetch->[0]->[0] ? $fetch->[0]->[0] : "NaN" ; 691 my $out = $fetch->[0]->[1] ? $fetch->[0]->[1] : "NaN" ; 692 debug('log', " got: $in/$out"); 693 $cuin{'d'}{$router} = $fetch->[0]->[0]; 694 $cuout{'d'}{$router} = $fetch->[0]->[1]; 695 # the html pages and the graphics are created at "call time" so that's it! 696 # (the returned hashes are empty, it's just to minimize the changes to mrtg) 697 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 698 return (\%maxin, \%maxout, \%maxpercent, \%avin, \%avout, \%avpercent, \%cuin, \%cuout, \%cupercent, \%avmxin, \%avmxout); 699 } 700 return (\%maxin, \%maxout, \%avin, \%avout, \%cuin, \%cuout, \%avmxin, \%avmxout ); 701 702 } 703 ########## rrdtool users have left here ############### 704 705 ((($MRTG_lib::OS eq 'NT' or $MRTG_lib::OS eq 'OS2') and (-e "$FindBin::Bin}$MRTG_lib::SL}rateup.exe")) or 706 (-x "$FindBin::Bin}$MRTG_lib::SL}rateup")) or 707 die "ERROR: Can't Execute '$FindBin::Bin}$MRTG_lib::SL}rateup'\n"; 708 709 # rateup does not know about undef so we make inlast and outlast ready for rateup 710 #warn "ERROR: inlast is undefined. Skipping $router\n" unless defined $inlast; 711 #warn "ERROR: outlast is undefined. Skipping $router\n" unless defined $outlast; 712 #return undef unless defined $inlast and defined $outlast; 713 714 # set values to -1 to tell rateup about unknown values 715 $inlast = -1 unless defined $inlast; 716 $outlast = -1 unless defined $outlast; 717 718 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 719 @exec = ("$FindBin::Bin}$MRTG_lib::SL}rateup", 720 "$$cfg{'logdir'}$$rcfg{'directory'}{$router}","$router", 721 $time, $$rcfg{'options'}{'unknaszero'}{$router} ? '-z':'-Z', 722 "$up_abs"."p", $inlast, $outlast, $absmax, 723 "C", $$rcfg{'rgb1'}{$router},$$rcfg{'rgb2'}{$router}, 724 $$rcfg{'rgb3'}{$router},$$rcfg{'rgb4'}{$router}, 725 $$rcfg{'rgb5'}{$router}); 726 } else { 727 728 @exec = ("$FindBin::Bin}$MRTG_lib::SL}rateup", 729 "$$cfg{'logdir'}$$rcfg{'directory'}{$router}","$router", 730 $time, $$rcfg{'options'}{'unknaszero'}{$router} ? '-z':'-Z', 731 "$up_abs", $inlast, $outlast, $absmax, 732 "c", $$rcfg{'rgb1'}{$router},$$rcfg{'rgb2'}{$router}, 733 $$rcfg{'rgb3'}{$router},$$rcfg{'rgb4'}{$router}); 734 } 735 736 # If this list grows anymore would it be more efficient to have an 737 # array to look up the command line option to send to rateup rather 738 # than have a long list to check? 739 push (@exec, '-t') if defined $$rcfg{'options'}{'transparent'}{$router}; 740 push (@exec, '-0') if defined $$rcfg{'options'}{'withzeroes'}{$router}; 741 push (@exec, '-b') if defined $$rcfg{'options'}{'noborder'}{$router}; 742 push (@exec, '-a') if defined $$rcfg{'options'}{'noarrow'}{$router}; 743 push (@exec, '-i') if defined $$rcfg{'options'}{'noi'}{$router}; 744 push (@exec, '-o') if defined $$rcfg{'options'}{'noo'}{$router}; 745 push (@exec, '-d') if defined $$rcfg{'options'}{'pngdate'}{$router}; 746 push (@exec, '-p') if defined $$rcfg{'options'}{'printrouter'}{$router}; 747 748 my $maxx = $$rcfg{'xsize'}{$router}; 749 my $maxy = $$rcfg{'ysize'}{$router}; 750 my $xscale = $$rcfg{'xscale'}{$router}; 751 my $yscale = $$rcfg{'yscale'}{$router}; 752 my $growright = 0+($$rcfg{'options'}{'growright'}{$router} or 0); 753 my $bits = 0+($$rcfg{'options'}{'bits'}{$router} or 0); 754 my $integer = 0+($$rcfg{'options'}{'integer'}{$router} or 0); 755 my $step = 5*60; 756 my $rop; 757 my $ytics = $$rcfg{'ytics'}{$router}; 758 my $yticsf= $$rcfg{'yticsfactor'}{$router}; 759 760 if (not defined $$rcfg{'ylegend'}{$router}){ 761 if ($bits){ 762 $$rcfg{'ylegend'}{$router} = &$LOC("Bits per minute") 763 if defined $$rcfg{'options'}{'perminute'}{$router}; 764 $$rcfg{'ylegend'}{$router} = &$LOC("Bits per hour") 765 if defined $$rcfg{'options'}{'perhour'}{$router}; 766 } else { 767 $$rcfg{'ylegend'}{$router} = &$LOC("Bytes per minute") 768 if defined $$rcfg{'options'}{'perminute'}{$router}; 769 $$rcfg{'ylegend'}{$router} = &$LOC("Bytes per hour") 770 if defined $$rcfg{'options'}{'perhour'}{$router}; 771 } 772 } 773 774 if ($$rcfg{'ylegend'}{$router}) { 775 push (@exec, "l", "[$$rcfg{'ylegend'}{$router}]"); 776 } 777 my $sign = ($$rcfg{'unscaled'}{$router} and $$rcfg{'unscaled'}{$router} =~ /d/) ? 1 : -1; 778 779 if ($$rcfg{'pngtitle'}{$router}) { 780 push (@exec, "T", "[$$rcfg{'pngtitle'}{$router}]"); 781 } 782 783 if ($$rcfg{'timezone'}{$router}) { 784 push (@exec, "Z", "$$rcfg{'timezone'}{$router}"); 785 } 786 787 if ($$rcfg{'kilo'}{$router}) { 788 push (@exec, "k", $$rcfg{'kilo'}{$router}); 789 } 790 if ($$rcfg{'kmg'}{$router}) { 791 push (@exec, "K", $$rcfg{'kmg'}{$router}); 792 } 793 if ($$rcfg{'weekformat'}{$router}) { 794 push (@exec, "W", $$rcfg{'weekformat'}{$router}); 795 } 796 if (not defined $$rcfg{'suppress'}{$router} or $$rcfg{'suppress'}{$router} !~ /d/) { 797 # VMS: should work for both now 798 push (@exec, "i", "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-day.$main::GRAPHFMT}", 799 $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, ,$xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf); 800 @mxvls = ("d"); 801 push (@metas, "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-day.$main::GRAPHFMT}", 802 $$cfg{'interval'} ? $$cfg{'interval'} : 5); 803 } 804 my $SAGE = (time - $main::STARTTIME) / 3600 / 24; # current script age 805 806 if (((not -e "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-week.$main::GRAPHFMT}") or 807 ((-M "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-week.$main::GRAPHFMT}") + $SAGE >= 0.5/24)) and 808 (not defined $$rcfg{'suppress'}{$router} or $$rcfg{'suppress'}{$router} !~/w/) 809 ) { 810 $step=30*60; 811 $sign = (defined $$rcfg{'unscaled'}{$router} and $$rcfg{'unscaled'}{$router} =~ /w/) ? 1 : -1; 812 push (@mxvls , "w"); 813 $rop =(defined $$rcfg{'withpeak'}{$router} and $$rcfg{'withpeak'}{$router} =~ /w/) ? "p" : "i"; 814 push (@exec, $rop ,"$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-week.$main::GRAPHFMT}", 815 $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf); 816 push (@metas, "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-week.$main::GRAPHFMT}", 30); 817 } 818 819 820 if (((not -e "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-month.$main::GRAPHFMT}") or 821 (( -M "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-month.$main::GRAPHFMT}") + $SAGE >= 2/24)) and 822 (not defined $$rcfg{'suppress'}{$router} or $$rcfg{'suppress'}{$router} !~ /m/)) { 823 $step=2*60*60; 824 $sign = (defined $$rcfg{'unscaled'}{$router} and $$rcfg{'unscaled'}{$router} =~ /m/) ? 1 : -1; 825 push (@mxvls , "m"); 826 $rop =(defined $$rcfg{'withpeak'}{$router} and $$rcfg{'withpeak'}{$router} =~ /m/) ? "p" : "i"; 827 push (@exec, $rop ,"$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-month.$main::GRAPHFMT}", 828 $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf); 829 push (@metas, "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-month.$main::GRAPHFMT}", 120); 830 } 831 832 if (((not -e "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-year.$main::GRAPHFMT}") or 833 (( -M "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-year.$main::GRAPHFMT}") + $SAGE >= 1)) and 834 (not defined $$rcfg{'suppress'}{$router} or $$rcfg{'suppress'}{$router} !~/y/)) { 835 $step=24*60*60; 836 $sign = (defined $$rcfg{'unscaled'}{$router} and $$rcfg{'unscaled'}{$router} =~ /y/) ? 1 : -1; 837 push (@mxvls , "y"); 838 $rop =(defined $$rcfg{'withpeak'}{$router} and $$rcfg{'withpeak'}{$router} =~ /y/) ? "p" : "i"; 839 push (@exec, $rop, "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-year.$main::GRAPHFMT}", 840 $sign*$maxvi, $sign*$maxvo, $maxx, $maxy, $xscale, $yscale, $growright, $step, $bits, $ytics, $yticsf) ; 841 push (@metas, "$$cfg{'imagedir'}$$rcfg{'directory'}{$router}$router}-year.$main::GRAPHFMT}", 1440); 842 } 843 844 # VMS: this might work now ... or does VMS NOT know about pipes? 845 # NT doesn't have fork() so an open(xxx,"-|") won't work 846 # OS2 fork() have bug with socket handles. In RunAsDaemon mode it fail 847 # after first loop (with "socket operation on non socket" message. 848 849 if ($MRTG_lib::OS eq 'VMS' or $MRTG_lib::OS eq 'NT' or $MRTG_lib::OS eq 'OS2'){ 850 map { s/"/\\"/; $_ = '"'.$_.'"' if /\s/ } @exec; 851 open (RATEUP, join (" ", @exec)."|") or 852 do { 853 warn "WARNING: rateup (".(join " ", @exec ). 854 ") did not work: $!\n"; 855 return; 856 } 857 } else { 858 $! = undef; 859 open (RATEUP,"-|") or 860 do { exec @exec or 861 warn "WARNING: rateup (".(join " ", @exec ). 862 ") did not work: $!\n"; 863 }; 864 865 } 866 867 debug('log', "Called @exec"); 868 869 imggen($$cfg{icondir} || $$cfg{imagedir}); 870 871 # SE3 872 my $fichier="$$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router".".php"; 873 if (open (HTML,"<$fichier")) { 874 # if (open (HTML,"<$$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router.$$rcfg{'extension'}{$router}")) { 875 for ($i=0 ; $i<200 ; $i++) { 876 last if eof(HTML); 877 $_= <HTML>; 878 if (/<!-- maxin ([dwmy]) (\d*)/) { 879 $maxin{$1}{$router}=$2 || 0; 880 } 881 882 if (/<!-- maxout ([dwmy]) (\d*)/) { 883 $maxout{$1}{$router}=$2 || 0; 884 } 885 886 if (/<!-- maxpercent ([dwmy]) (\d*)/) { 887 $maxpercent{$1}{$router}=$2 || 0; 888 } 889 890 if (/<!-- avin ([dwmy]) (\d*)/) { 891 $avin{$1}{$router}=$2 || 0; 892 } 893 894 if (/<!-- avout ([dwmy]) (\d*)/) { 895 $avout{$1}{$router}=$2 || 0; 896 } 897 898 if (/<!-- avpercent ([dwmy]) (\d*)/) { 899 $avpercent{$1}{$router}=$2 || 0; 900 } 901 902 if (/<!-- cuin ([dwmy]) (\d*)/) { 903 $cuin{$1}{$router}=$2 || 0; 904 } 905 906 if (/<!-- cuout ([dwmy]) (\d+)/) { 907 $cuout{$1}{$router}=$2 || 0; 908 } 909 910 if (/<!-- cupercent ([dwmy]) (\d+)/) { 911 $cupercent{$1}{$router}=$2 || 0; 912 } 913 if (/<!-- avmxin ([dwmy]) (\d*)/) { 914 $avmxin{$1}{$router}=$2 || 0; 915 } 916 917 if (/<!-- avmxout ([dwmy]) (\d*)/) { 918 $avmxout{$1}{$router}=$2 || 0; 919 } 920 } 921 close HTML; 922 } 923 924 foreach $period (@mxvls) { 925 $res = <RATEUP>; 926 if (not defined $res and eof(RATEUP)){ 927 warn "ERROR: Skipping webupdates because rateup did not return anything sensible\n"; 928 close RATEUP; 929 rateupcheck $router; 930 return; 931 }; 932 chomp $res; 933 $maxin{$period}{$router}=sprintf("%.0f",$res || 0); 934 chomp($res = <RATEUP>); 935 $maxout{$period}{$router}=sprintf("%.0f",$res || 0); 936 937 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 938 chomp($res = <RATEUP>); 939 $maxpercent{$period}{$router}=sprintf("%.0f",$res || 0); 940 } 941 942 chomp($res = <RATEUP>); 943 $avin{$period}{$router}=sprintf("%.0f",$res || 0); 944 chomp($res = <RATEUP>); 945 $avout{$period}{$router}=sprintf("%.0f",$res || 0); 946 947 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 948 chomp($res = <RATEUP>); 949 $avpercent{$period}{$router}=sprintf("%.0f",$res || 0); 950 } 951 952 chomp($res = <RATEUP>); 953 $cuin{$period}{$router}=sprintf("%.0f",$res || 0); 954 chomp($res = <RATEUP>); 955 $cuout{$period}{$router}=sprintf("%.0f",$res || 0); 956 957 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 958 chomp($res = <RATEUP>); 959 $cupercent{$period}{$router}=sprintf("%.0f",$res || 0); 960 } 961 962 chomp($res = <RATEUP>); 963 debug('avmx',"avmxin $res"); 964 $avmxin{$period}{$router}=sprintf("%.0f",$res || 0); 965 chomp($res = <RATEUP>); 966 debug('avmx',"avmxout $res"); 967 $avmxout{$period}{$router}=sprintf("%.0f",$res || 0); 968 969 } 970 close(RATEUP); 971 rateupcheck $router; 972 if ( defined $$cfg{'writeexpires'} and $$cfg{'writeexpires'} =~ /^y/i ) { 973 my($fil,$exp); 974 while ( $fil = shift(@metas) ) { 975 $exp = &expistr(shift(@metas)); 976 open(META, ">$fil.meta"); 977 print META "Expires: $exp\n"; 978 close(META); 979 } 980 } 981 982 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 983 return (\%maxin, \%maxout, \%maxpercent, \%avin, \%avout, \%avpercent, \%cuin, \%cuout, \%cupercent, \%avmxin, \%avmxout); 984 } else { 985 return (\%maxin, \%maxout, \%avin, \%avout, \%cuin, \%cuout, \%avmxin, \%avmxout); 986 } 987 } 988 989 #format 10*$kilo to 10 kB/s 990 sub fmi { 991 my($number, $maxbytes, $router, @foo) = @_; 992 return "?????" unless defined $number; 993 my($rcfg,$LOC)=@foo; 994 my @short; 995 my $mul = 1; 996 if ($$rcfg{'kmg'}{$router}) { 997 my($i); 998 if ($$rcfg{'options'}{'bits'}{$router}) { 999 @short = (); 1000 foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) { 1001 if ($$rcfg{'options'}{'perminute'}{$router}) { 1002 $short[$#short+1] = "$i".&$LOC("b/min"); 1003 } elsif ($$rcfg{'options'}{'perhour'}{$router}) { 1004 $short[$#short+1] = "$i".&$LOC("b/h"); 1005 } else { 1006 $short[$#short+1] = "$i".&$LOC("b/s"); 1007 } 1008 } 1009 $mul= 8; 1010 } else { 1011 @short = (); 1012 foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) { 1013 if ($$rcfg{'options'}{'perminute'}{$router}) { 1014 $short[$#short+1] = "$i".&$LOC ("B/min"); 1015 } elsif ($$rcfg{'options'}{'perhour'}{$router}) { 1016 $short[$#short+1] = "$i".&$LOC("B/h"); 1017 } else { 1018 $short[$#short+1] = "$i".&$LOC("B/s"); 1019 } 1020 } 1021 $mul= 1; 1022 } 1023 if (defined $$rcfg{'shortlegend'}{$router}) { 1024 @short = (); 1025 foreach $i (split(/,/, $$rcfg{'kmg'}{$router})) { 1026 $short[$#short+1] = "$i"." $$rcfg{'shortlegend'}{$router}"; 1027 } 1028 } 1029 } else { 1030 if (defined $$rcfg{'options'}{'bits'}{$router}) { 1031 if ($$rcfg{'options'}{'perminute'}{$router}) { 1032 @short = (&$LOC("b/min"),&$LOC("kb/min"),&$LOC("Mb/min"),&$LOC("Gb/min")); 1033 } elsif (defined $$rcfg{'options'}{'perhour'}{$router}) { 1034 @short = (&$LOC("b/h"),&$LOC("kb/h"),&$LOC("Mb/h"),&$LOC("Gb/h")); 1035 } else { 1036 @short = (&$LOC("b/s"),&$LOC("kb/s"),&$LOC("Mb/s"),&$LOC("Gb/s")); 1037 } 1038 $mul= 8; 1039 } else { 1040 if ($$rcfg{'options'}{'perminute'}{$router}) { 1041 @short = (&$LOC("B/min"),&$LOC("kB/min"),&$LOC("MB/min"),&$LOC("GB/min")); 1042 } elsif ($$rcfg{'options'}{'perhour'}{$router}) { 1043 @short = (&$LOC("B/h"),&$LOC("kB/h"),&$LOC("MB/h"),&$LOC("GB/h")); 1044 } else { 1045 @short = (&$LOC("B/s"),&$LOC("kB/s"),&$LOC("MB/s"),&$LOC("GB/s")); 1046 } 1047 $mul= 1; 1048 } 1049 if ($$rcfg{'shortlegend'}{$router}) { 1050 @short = ("$$rcfg{'shortlegend'}{$router}", 1051 "k$$rcfg{'shortlegend'}{$router}", 1052 "M$$rcfg{'shortlegend'}{$router}", 1053 "G$$rcfg{'shortlegend'}{$router}"); 1054 } 1055 } 1056 my $digits=length("".$number*$mul); 1057 my $divm=0; 1058 # 1059 # while ($digits-$divm*3 > 4) { $divm++; } 1060 # my $divnum = $number*$mul/10**($divm*3); 1061 my $divnum=$number*$mul*$$rcfg{'factor'}{$router}; 1062 # while ($divnum/$$rcfg{'kilo'}{$router} >= 10*$$rcfg{'kilo'}{$router} and $divnum<$#short) { 1063 while ($divnum >= 10*$$rcfg{'kilo'}{$router} and $divm<$#short) { 1064 $divm++; 1065 $divnum /= $$rcfg{'kilo'}{$router}; 1066 } 1067 my $perc; 1068 if ($number == 0 || $maxbytes == 0) { 1069 $perc = 0; 1070 } else { 1071 $perc = 100/$maxbytes*$number; 1072 } 1073 if (defined $$rcfg{'options'}{'integer'}{$router}) { 1074 if ($$rcfg{'options'}{'nopercent'}{$router}) { 1075 return sprintf("%.0f %s",$divnum,$short[$divm]); 1076 } else { 1077 return sprintf("%.0f %s (%2.1f%%)",$divnum,$short[$divm],$perc); 1078 } 1079 } else { 1080 if (defined $$rcfg{'options'}{'nopercent'}{$router}) { 1081 return sprintf("%.1f %s",$divnum,$short[$divm]); # Added: FvW 1082 } else { 1083 return sprintf("%.1f %s (%2.1f%%)",$divnum,$short[$divm],$perc); 1084 } 1085 return sprintf("%.1f %s (%2.1f%%)",$divnum,$short[$divm],$perc); 1086 } 1087 } 1088 1089 1090 sub writehtml { 1091 my($router, $cfg, $rcfg, $maxin, $maxout, $maxpercent, 1092 $avin, $avout, $avmxin, $avmxout, $avpercent, 1093 $cuin, $cuout, $cupercent, $uptime, $name, $LOC) = @_; 1094 1095 my($VERSION,$Today,$peri); 1096 1097 my($persec); 1098 1099 if (defined $$rcfg{'options'}{'bits'}{$router}) { 1100 $persec = &$LOC("Bits"); 1101 } else { 1102 $persec = &$LOC("Bytes"); 1103 } 1104 1105 # Work out the Colour legend 1106 my($leg1, $leg2, $leg3, $leg4, $leg5); 1107 if ($$rcfg{'legend1'}{$router}) { 1108 $leg1 = $$rcfg{'legend1'}{$router}; 1109 } else { 1110 if ($$rcfg{'options'}{'perminute'}{$router}) { 1111 $leg1=&$LOC("Incoming Traffic in $persec per Minute"); 1112 } elsif ($$rcfg{'options'}{'perhour'}{$router}) { 1113 $leg1=&$LOC("Incoming Traffic in $persec per Hour"); 1114 } else { 1115 $leg1=&$LOC("Incoming Traffic in $persec per Second"); 1116 } 1117 } 1118 if ($$rcfg{'legend2'}{$router}) { 1119 $leg2 = $$rcfg{'legend2'}{$router}; 1120 } else { 1121 if ($$rcfg{'options'}{'perminute'}{$router}) { 1122 $leg2=&$LOC("Outgoing Traffic in $persec per Minute"); 1123 } elsif ($$rcfg{'options'}{'perhour'}{$router}) { 1124 $leg2=&$LOC("Outgoing Traffic in $persec per Hour"); 1125 } else { 1126 $leg2=&$LOC("Outgoing Traffic in $persec per Second"); 1127 } 1128 } 1129 if ($$rcfg{'legend3'}{$router}) { 1130 $leg3 = $$rcfg{'legend3'}{$router}; 1131 } else { 1132 $leg3 = &$LOC("Maximal 5 Minute Incoming Traffic"); 1133 } 1134 if ($$rcfg{'legend4'}{$router}) { 1135 $leg4 = $$rcfg{'legend4'}{$router}; 1136 } else { 1137 $leg4 = &$LOC("Maximal 5 Minute Outgoing Traffic"); 1138 } 1139 if ($$rcfg{'legend5'}{$router}) { 1140 $leg5 = $$rcfg{'legend5'}{$router}; 1141 } else { 1142 $leg5 = "(($leg1)/($leg2))*100"; 1143 } 1144 # Translate the color names 1145 $$rcfg{'col1'}{$router}=&$LOC($$rcfg{'col1'}{$router}); 1146 $$rcfg{'col2'}{$router}=&$LOC($$rcfg{'col2'}{$router}); 1147 $$rcfg{'col3'}{$router}=&$LOC($$rcfg{'col3'}{$router}); 1148 $$rcfg{'col4'}{$router}=&$LOC($$rcfg{'col4'}{$router}); 1149 $$rcfg{'col5'}{$router}=&$LOC($$rcfg{'col5'}{$router}); 1150 1151 my $dirrel = "../" x ($$rcfg{'directory_web'}{$router} =~ tr|/|/|); 1152 1153 $Today=&$LOC(datestr(time)); 1154 $VERSION = "2.10.13"; 1155 1156 # SE3 1157 my $fichier="$$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router".".php"; 1158 open (HTML,">$fichier") || 1159 # open (HTML,">$$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router.$$rcfg{'extension'}{$router}") || 1160 do { warn ("WARNING: Writing $router.$$rcfg{'extension'}{$router}: $!"); 1161 next }; 1162 print HTML "<!-- Begin Head -->\n"; 1163 1164 print HTML "<?\n"; 1165 print HTML "include 'entete.inc.php';\n"; 1166 print HTML "include 'ldap.inc.php';\n"; 1167 print HTML "include 'ihm.inc.php';\n"; 1168 1169 print HTML "require_once 'lang.inc.php';\n"; 1170 print HTML "bindtextdomain('se3-infos',\"/var/www/se3/locale\");\n"; 1171 print HTML "textdomain ('se3-infos');\n"; 1172 1173 print HTML "\n\$login=isauth();\n"; 1174 print HTML "if (is_admin(\"se3_is_admin\",\$login)!=\"Y\") { exit; }\n"; 1175 print HTML "?>\n"; 1176 1177 print HTML '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' . "\n"; 1178 print HTML "<HTML>\n"; 1179 my $interval =$$cfg{'interval'} ? $$cfg{'interval'} : 5; 1180 my $expiration = &expistr($interval); 1181 my $refresh = $$cfg{'refresh'} ? $$cfg{'refresh'} : 300; 1182 my $namestring = &$LOC("the device"); 1183 print HTML <<"TEXT"; 1184 <HEAD> 1185 <TITLE>$$rcfg{'title'}{$router}</TITLE> 1186 <META HTTP-EQUIV="Refresh" CONTENT="$refresh"> 1187 <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> 1188 <META HTTP-EQUIV="Cache-Control" content="no-cache"> 1189 <META HTTP-EQUIV="Expires" CONTENT="$expiration"> 1190 <META HTTP-EQUIV="Generator" CONTENT="MRTG $VERSION"> 1191 <META HTTP-EQUIV="Date" CONTENT="$expiration"> 1192 1193 TEXT 1194 1195 print HTML 1196 '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; '.&$LOC('charset=iso-8859-1')."\">\n"; 1197 1198 foreach $peri (qw(d w m y)) { 1199 print HTML <<"TEXT"; 1200 <!-- maxin $peri $$maxin{$peri}{$router} --> 1201 <!-- maxout $peri $$maxout{$peri}{$router} --> 1202 TEXT 1203 if ($$rcfg{'options'}{'dorelpercent'}{$router} and defined $$maxpercent{$peri}{$router}) { 1204 print HTML <<"TEXT"; 1205 <!-- maxpercent $peri $$maxpercent{$peri}{$router} --> 1206 TEXT 1207 } 1208 print HTML <<"TEXT"; 1209 <!-- avin $peri $$avin{$peri}{$router} --> 1210 <!-- avout $peri $$avout{$peri}{$router} --> 1211 TEXT 1212 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 1213 print HTML <<"TEXT"; 1214 <!-- avpercent $peri $$avpercent{$peri}{$router} --> 1215 TEXT 1216 } 1217 1218 print HTML "<!-- cuin $peri $$cuin{$peri}{$router} -->" 1219 if defined $$cuin{$peri}{$router}; 1220 print HTML "<!-- cuout $peri $$cuout{$peri}{$router} -->" 1221 if defined $$cuout{$peri}{$router}; 1222 1223 if ($$rcfg{'options'}{'dorelpercent'}{$router} and $$cupercent{$peri}{$router} ) { 1224 print HTML <<"TEXT"; 1225 <!-- cupercent $peri $$cupercent{$peri}{$router} --> 1226 TEXT 1227 } 1228 print HTML <<"TEXT" if $$avmxin{$peri}{$router} and $$avmxout{$peri}{$router}; 1229 <!-- avmxin $peri $$avmxin{$peri}{$router} --> 1230 <!-- avmxout $peri $$avmxout{$peri}{$router} --> 1231 TEXT 1232 1233 } 1234 1235 $namestring = "<B>'$name'</B>" if $name; 1236 1237 # allow for \n in addhead 1238 defined $$rcfg{addhead}{$router} or $$rcfg{addhead}{$router} = ""; 1239 defined $$rcfg{backgc}{$router} or $$rcfg{backgc}{$router} = ""; 1240 defined $$rcfg{pagetop}{$router} or $$rcfg{pagetop}{$router} = ""; 1241 if (defined $$rcfg{bodytag}{$router}) { 1242 if (not defined $$rcfg{bodytag}{$router} or $$rcfg{bodytag}{$router} !~ /<body/i) { 1243 $$rcfg{bodytag}{$router} = "<BODY $$rcfg{bodytag}{$router}>"; 1244 } 1245 } else { 1246 $$rcfg{bodytag}{$router} = "<BODY $$rcfg{backgc}{$router}>"; 1247 } 1248 1249 $$rcfg{addhead}{$router} =~ s/\\n/\n/g if defined $$rcfg{addhead}{$router}; 1250 1251 print HTML <<"TEXT"; 1252 $$rcfg{'addhead'}{$router} 1253 </HEAD> 1254 $$rcfg{bodytag}{$router} 1255 $$rcfg{'pagetop'}{$router} 1256 <HR> 1257 TEXT 1258 1259 if (defined $$rcfg{'timezone'}{$router}){ 1260 print HTML 1261 &$LOC("The statistics were last updated <B>$Today $$rcfg{'timezone'}{$router}</B>"); 1262 } else { 1263 print HTML 1264 &$LOC("The statistics were last updated <B>$Today</B>"); 1265 } 1266 if ($uptime and ! $$rcfg{options}{noinfo}{$router}) { 1267 print HTML 1268 ",<BR>\n". 1269 &$LOC("at which time $namestring had been up for <B>$uptime</B>."). 1270 "\n<!-- End Head -->"; 1271 } 1272 1273 my %sample= ('d' => "`Daily' Graph (".$interval.' Minute', 1274 'w' => "`Weekly' Graph (30 Minute", 1275 'm' => "`Monthly' Graph (2 Hour", 1276 'y' => "`Yearly' Graph (1 Day"); 1277 1278 my %full = ('d' => 'day', 1279 'w' => 'week', 1280 'm' => 'month', 1281 'y' => 'year'); 1282 1283 $$rcfg{'rgb1'}{$router} = "" unless defined $$rcfg{'rgb1'}{$router}; 1284 $$rcfg{'rgb2'}{$router} = "" unless defined $$rcfg{'rgb2'}{$router}; 1285 $$rcfg{'rgb3'}{$router} = "" unless defined $$rcfg{'rgb3'}{$router}; 1286 $$rcfg{'rgb4'}{$router} = "" unless defined $$rcfg{'rgb4'}{$router}; 1287 $$rcfg{'rgb5'}{$router} = "" unless defined $$rcfg{'rgb5'}{$router}; 1288 $$rcfg{'rgb6'}{$router} = "" unless defined $$rcfg{'rgb6'}{$router}; 1289 1290 my $InCo; 1291 if (!(defined $$rcfg{'options'}{'noi'}{$router})) { 1292 if (exists $$rcfg{'legendi'}{$router}) { 1293 if ($$rcfg{'legendi'}{$router} ne "") { 1294 $InCo="<FONT COLOR=\"$$rcfg{'rgb1'}{$router}\">". 1295 "$$rcfg{'legendi'}{$router} </FONT>"; 1296 } 1297 } else { 1298 $InCo="<FONT COLOR=\"$$rcfg{'rgb1'}{$router}\">". 1299 &$LOC(" In:</FONT>"); 1300 } 1301 } 1302 1303 my $OutCo; 1304 if (!(defined $$rcfg{'options'}{'noo'}{$router})) { 1305 if (exists $$rcfg{'legendo'}{$router}) { 1306 if ($$rcfg{'legendo'}{$router} ne "") { 1307 $OutCo="<FONT COLOR=\"$$rcfg{'rgb2'}{$router}\">". 1308 "$$rcfg{'legendo'}{$router} </FONT>"; 1309 } 1310 } else { 1311 $OutCo="<FONT COLOR=\"$$rcfg{'rgb2'}{$router}\">". 1312 &$LOC(" Out:</FONT>"); 1313 } 1314 } 1315 my $PercentCo; 1316 if (defined $$rcfg{'legend5'}{$router}) { 1317 if ($$rcfg{'legend5'}{$router} ne "") { 1318 $PercentCo="<FONT COLOR=\"$$rcfg{'rgb5'}{$router}\">". 1319 "$$rcfg{'legend5'}{$router}</FONT>"; 1320 } 1321 } else { 1322 $PercentCo="<FONT COLOR=\"$$rcfg{'rgb5'}{$router}\">". 1323 &$LOC("Percentage </FONT>"); 1324 } 1325 1326 foreach $peri (qw(d w m y)) { 1327 next if defined $$rcfg{'suppress'}{$router} and $$rcfg{'suppress'}{$router} =~/$peri/; 1328 my $gifw; 1329 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 1330 $gifw=sprintf("%.0f",($$rcfg{'xsize'}{$router}*$$rcfg{'xscale'}{$router}+ 1331 +100+30) *$$rcfg{'xzoom'}{$router}); 1332 } else { 1333 $gifw=sprintf("%.0f",($$rcfg{'xsize'}{$router}*$$rcfg{'xscale'}{$router} 1334 +100) *$$rcfg{'xzoom'}{$router}); 1335 } 1336 my $gifh=sprintf("%.0f",($$rcfg{'ysize'}{$router}*$$rcfg{'yscale'}{$router}+35) 1337 *$$rcfg{'yzoom'}{$router}); 1338 1339 # take the image directory away from the html directory to give us relative links 1340 1341 1342 print HTML " 1343 <!-- Begin $sample{$peri} --> 1344 <HR> 1345 ".&$LOC("<B>$sample{$peri}").&$LOC(" Average)</B><BR>")." 1346 <IMG VSPACE=10 WIDTH=$gifw HEIGHT=$gifh ALIGN=TOP 1347 SRC=\"$dirrel$$cfg{imagehtml}$$rcfg{directory_web}{$router}$router-$full{$peri}.$main::GRAPHFMT}\" ALT=\"$full{$peri}\"> 1348 <TABLE CELLPADDING=0 CELLSPACING=0> 1349 "; 1350 my(@foo)=($rcfg,$LOC); 1351 print HTML "<TR> 1352 ".&$LOC("<TD ALIGN=right><SMALL>Max $InCo</SMALL></TD>")." 1353 <TD ALIGN=left><SMALL>".&fmi($$maxin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)." 1354 </SMALL></TD> 1355 <TD WIDTH=5></TD> 1356 ".&$LOC("<TD ALIGN=right><SMALL>Average $InCo</SMALL></TD>")." 1357 <TD ALIGN=left><SMALL>".&fmi($$avin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)." 1358 </SMALL></TD> 1359 <TD WIDTH=5></TD> 1360 ".&$LOC("<TD ALIGN=right><SMALL>Current $InCo</SMALL></TD>")." 1361 <TD ALIGN=left><SMALL>".&fmi($$cuin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo)." 1362 </SMALL></TD> 1363 </TR> 1364 " if $InCo; 1365 print HTML " 1366 <TR> 1367 ".&$LOC("<TD ALIGN=right><SMALL>Max $OutCo</SMALL></TD>")." 1368 <TD ALIGN=left><SMALL>".&fmi($$maxout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)." 1369 </SMALL></TD> 1370 <TD WIDTH=5></TD> 1371 ".&$LOC("<TD ALIGN=right><SMALL>Average $OutCo</SMALL></TD>")." 1372 <TD ALIGN=left><SMALL>".&fmi($$avout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)." 1373 </SMALL></TD> 1374 <TD WIDTH=5></TD> 1375 ".&$LOC("<TD ALIGN=right><SMALL>Current $OutCo</SMALL></TD>")." 1376 <TD ALIGN=left><SMALL>".&fmi($$cuout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo)." 1377 </SMALL></TD> 1378 </TR> " if $OutCo; 1379 print HTML " 1380 <TR> 1381 ".&$LOC("<TD ALIGN=right><SMALL>Max $PercentCo</SMALL></TD>")." 1382 <TD ALIGN=left><SMALL>".sprintf("%0.1f %%",($$maxpercent{$peri}{$router} || 0))." 1383 </SMALL></TD> 1384 <TD WIDTH=5></TD> 1385 ".&$LOC("<TD ALIGN=right><SMALL>Average $PercentCo</SMALL></TD>")." 1386 <TD ALIGN=left><SMALL>".sprintf("%0.1f %%",($$avpercent{$peri}{$router} || 0 ))." 1387 </SMALL></TD> 1388 <TD WIDTH=5></TD> 1389 ".&$LOC("<TD ALIGN=right><SMALL>Current $PercentCo</SMALL></TD>")." 1390 <TD ALIGN=left><SMALL>".sprintf("%0.1f %%",($$cupercent{$peri}{$router} || 0 ))." 1391 </SMALL></TD> 1392 </TR> " if ($$rcfg{'options'}{'dorelpercent'}{$router} and $PercentCo); 1393 1394 print HTML '<TD colspan="8"><small>',&$LOC("Average max 5 min values for $sample{$peri} interval): "), 1395 "$InCo ", &fmi($$avmxin{$peri}{$router}, $$rcfg{'maxbytes1'}{$router}, $router, @foo), "/", 1396 "$OutCo ", &fmi($$avmxout{$peri}{$router}, $$rcfg{'maxbytes2'}{$router}, $router, @foo), 1397 "</small></TD></TR>" if ($$rcfg{'options'}{'avgpeak'}{$router} and $InCo and $OutCo); 1398 1399 print HTML " 1400 </TABLE> 1401 <!-- End $sample{$peri} -->\n"; 1402 1403 } 1404 1405 if (!(defined $$rcfg{'options'}{'nolegend'}{$router})) { 1406 print HTML " 1407 <!-- Begin Legend --> 1408 <HR><BR> 1409 <TABLE WIDTH=500 BORDER=0 CELLPADDING=4 CELLSPACING=0>"; 1410 print HTML " 1411 <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb1'}{$router}\"> 1412 <B>$$rcfg{'col1'}{$router} ###</B></FONT></TD> 1413 <TD><FONT SIZE=-1>$leg1</FONT></TD></TR> " if $InCo; 1414 print HTML " 1415 <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb2'}{$router}\"> 1416 <B>$$rcfg{'col2'}{$router} ###</B></FONT></TD> 1417 <TD><FONT SIZE=-1>$leg2</FONT></TD></TR> " if $OutCo; 1418 1419 if ($$rcfg{'withpeak'}{$router}) { 1420 print HTML " 1421 <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb3'}{$router}\"> 1422 <B>$$rcfg{'col3'}{$router}###</B></FONT></TD> 1423 <TD><FONT SIZE=-1>$leg3</FONT></TD></TR> " if $InCo; 1424 print HTML " 1425 <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb4'}{$router}\"> 1426 <B>$$rcfg{'col4'}{$router}###</B></FONT></TD> 1427 <TD><FONT SIZE=-1>$leg4</FONT></TD></TR> "if $OutCo; 1428 } 1429 1430 if ($$rcfg{'options'}{'dorelpercent'}{$router}) { 1431 print HTML " 1432 <TR><TD ALIGN=RIGHT><FONT SIZE=-1 COLOR=\"$$rcfg{'rgb5'}{$router}\"> 1433 <B>$$rcfg{'col5'}{$router}###</B></FONT></TD> 1434 <TD><FONT SIZE=-1>$leg5</FONT></TD></TR> "; 1435 } 1436 1437 print HTML " 1438 </TABLE> 1439 <!-- End Legend -->"; 1440 } 1441 1442 # SE3 1443 # if (!(defined $$rcfg{'options'}{'nobanner'}{$router})) { 1444 # my $gifPath; 1445 1446 # if (defined $$cfg{icondir}) { 1447 # $gifPath = $$cfg{icondir}; 1448 #lets make sure there is a trailing path separator 1449 # $gifPath =~ s|/*$|/|; 1450 # } else { 1451 # $gifPath = "$dirrel$$cfg{imagehtml}"; 1452 # } 1453 1454 # print HTML<<TEXT; 1455 #<!-- Begin MRTG Block --> 1456 #<BR><HR><BR> 1457 #<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0> 1458 # <TR> 1459 # <TD WIDTH=63><A 1460 # HREF="http://people.ee.ethz.ch/~oetiker/webtools/mrtg/"><IMG 1461 # BORDER=0 SRC="${gifPath}mrtg-l.${main::GRAPHFMT}" WIDTH=63 HEIGHT=25 ALT="MRTG"></A></TD> 1462 # <TD WIDTH=25><A 1463 # HREF="http://people.ee.ethz.ch/~oetiker/webtools/mrtg/"><IMG 1464 # BORDER=0 SRC="${gifPath}mrtg-m.${main::GRAPHFMT}" WIDTH=25 HEIGHT=25 ALT=""></A></TD> 1465 # <TD WIDTH=388><A 1466 # HREF="http://people.ee.ethz.ch/~oetiker/webtools/mrtg/"><IMG 1467 # BORDER=0 SRC="${gifPath}mrtg-r.${main::GRAPHFMT}" WIDTH=388 HEIGHT=25 1468 # ALT="Multi Router Traffic Grapher"></A></TD> 1469 # </TR> 1470 #</TABLE> 1471 #<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0> 1472 # <TR VALIGN=top> 1473 # <TD WIDTH=88 ALIGN=RIGHT><FONT FACE="Arial,Helvetica" SIZE=2>$VERSION</FONT></TD> 1474 # <TD WIDTH=388 ALIGN=RIGHT><FONT FACE="Arial,Helvetica" SIZE=2> 1475 # <A HREF="http://people.ee.ethz.ch/~oetiker/">Tobias Oetiker</A> 1476 # <A HREF="mailto:oetiker\@ee.ethz.ch"><oetiker\@ee.ethz.ch></A> 1477 #TEXT 1478 1479 # print HTML &$LOC("and"); 1480 # print HTML ' <A HREF="http://www.bungi.com/">Dave Rand</A> <A HREF="mailto:dlr@bungi.com"><dlr@bungi.com></A></FONT>'; 1481 # print HTML<<TEXT; 1482 # </TD> 1483 #</TR> 1484 #</TABLE> 1485 #TEXT 1486 1487 # We don't need this any more. 1488 # undef $gifPath; 1489 1490 # if ($MRTG_lib::OS eq 'VMS') { 1491 # print HTML 1492 # "<div> 1493 #".&$LOC("Ported to OpenVMS Alpha by").". 1494 # <NOBR><A HREF=\"http://www.cerberus.ch/\">Werner Berger</A> 1495 # <A href=\"mailto:werner.berger\@cch.cerberus.ch\"> 1496 # <werner.berger\@cch.cerberus.ch></A></NOBR></div> 1497 #"; 1498 1499 } 1500 # There is not realy any significant portion of code from Studard left and 1501 # none of his addresses work anymore. -- Tobi 2001-06-04 1502 # if ($MRTG_lib::OS eq 'NT') { 1503 # print HTML 1504 # "<div> 1505 # ".&$LOC("Ported to WindowsNT by")." 1506 # <NOBR><small><A HREF=\"http://www.testlab.orst.edu/\">Stuart Schneider</A> 1507 # <A HREF=\"mailto:schneis\@testlab.orst.edu\"> 1508 # <schneis\@testlab.orst.edu></A></NOBR></div> 1509 # "; 1510 # } 1511 # if ( 1512 # $$cfg{'language'} and 1513 # defined($lang2tran::LOCALE{"\L$$cfg{'language'}\E"}) and 1514 # ($LOC != $lang2tran::LOCALE{"default"})) 1515 # { 1516 # if (defined($credits::LOCALE{"\L$$cfg{'language'}\E"})) { 1517 # print HTML "<div><small>".$credits::LOCALE{"\L$$cfg{'language'}\E"}."</small></div>"; 1518 # } else { 1519 # print HTML "<div><small>".$credits::LOCALE{'default'}."<small></div>"; 1520 # } 1521 # ; 1522 # } 1523 1524 # print HTML "<!-- End MRTG Block -->\n"; 1525 # } 1526 1527 1528 # print HTML $$rcfg{'pagefoot'}{$router} if defined $$rcfg{'pagefoot'}{$router}; 1529 # print HTML <<TEXT; 1530 #</BODY> 1531 #</HTML> 1532 1533 1534 #TEXT 1535 # close HTML; 1536 1537 # if (defined $$cfg{'writeexpires'} and $$cfg{'writeexpires'} =~ /^y/i) { 1538 # open(HTMLG, ">$$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router.". 1539 # "$$rcfg{'extension'}{$router}.meta") || 1540 # do { 1541 # warn "WARNING: Writing $$cfg{'htmldir'}$$rcfg{'directory'}{$router}$router.". 1542 # "$$rcfg{'extension'}{$router}.meta: $!\n"; 1543 # next 1544 # }; 1545 # print HTMLG "Expires: $expiration\n"; 1546 # close(HTMLG); 1547 # } 1548 #} 1549 1550 1551 sub printusage { 1552 print <<USAGEDESC; 1553 Usage: mrtg <config-file> 1554 1555 mrtg-2.10.13 is the Multi Router Traffic Grapher. 1556 1557 If you want to know more about this tool, you might want 1558 to read the docs. They came together with mrtg! 1559 1560 Home: http://people.ee.ethz.ch/~oetiker/webtools/mrtg/ 1561 1562 USAGEDESC 1563 exit(1); 1564 } 1565 1566 1567 sub lockit { 1568 my ($lockfile,$templock) = @_; 1569 if ($MRTG_lib::OS eq 'VMS' or $MRTG_lib::OS eq 'NT' or $MRTG_lib::OS eq 'OS2') { 1570 # too sad NT and VMS can't do links we'll do the diletants lock 1571 if (-e $lockfile and not unlink $lockfile) { 1572 my($lockage) = time()-(stat($lockfile))[9]; 1573 die "ERROR: I guess another mrtg is running. A lockfile ($lockfile)\n". 1574 " aged $lockage seconds is hanging around and I can't remove\n". 1575 " it because another process is still using it."; 1576 } 1577 1578 open (LOCK, ">$lockfile") or 1579 die "ERROR: Creating lockfile $lockfile: $!\n"; 1580 print LOCK "$$\n"; 1581 close LOCK; 1582 open (LOCK, "<$lockfile") or 1583 die "ERROR: Reading lockfile $lockfile for owner check: $!\n"; 1584 my($read)=<LOCK>; 1585 chomp($read); 1586 die "ERROR: Someone else just got the lockfile $lockfile\n" 1587 unless $$ == $read; 1588 } else { 1589 # now, lets do it the UNIX way ... Daves work ... 1590 open(LOCK,">$templock") or die "ERROR: Creating templock $templock: $!"; 1591 $main::Cleanfile = $templock; 1592 if (!link($templock,$lockfile)) { # Lock file exists - deal with it. 1593 my($nlink,$lockage) = (stat($lockfile))[3,9]; 1594 $lockage = time() - $lockage; 1595 if ($nlink < 2 or $lockage > 30*60) { #lockfile is alone and old 1596 unlink($lockfile) 1597 || do{ unlink $templock; 1598 die "ERROR: Can't unlink stale lockfile ($lockfile). Permissions?\n"}; 1599 link($templock,$lockfile) 1600 || do{ unlink $templock; 1601 die "ERROR: Can't create lockfile ($lockfile).\n". 1602 "Permission problem or another mrtg locking succesfully?\n"}; 1603 } else { 1604 unlink $templock; 1605 die "ERROR: It looks as if you are running two copies of mrtg in parallel on\n". 1606 " the same config file. There is a lockfile ($lockfile) and it is\n". 1607 " is only $lockage seconds old ... Check your crontab.\n". 1608 " (/etc/crontab and /var/spool/cron/root) \n" 1609 if $lockage < 4; 1610 1611 die "ERROR: I guess another mrtg is running. A lockfile ($lockfile) aged\n". 1612 "$lockage seconds is hanging around. If you are sure that no other mrtg\n". 1613 "is running you can remove the lockfile\n"; 1614 1615 } 1616 1617 } 1618 } 1619 } 1620 1621 sub threshcheck { 1622 # threshold checking by Tom Muggli 1623 # ... fsck'd up but fixed by Juha Laine 1624 my ($cfg,$rcfg,$cfgfile,$router,$cuin,$cuout) = @_; 1625 my $threshfile; 1626 my %threshval; 1627 1628 $threshval{i} = $$cuin{'d'}{$router}; 1629 $threshval{o} = $$cuout{'d'}{$router}; 1630 1631 # are we going to keep state ? 1632 if (defined $$cfg{'threshdir'}){ 1633 ensureSL(\$$cfg{'threshdir'}); 1634 $threshfile = $$cfg{'threshdir'}.(split /\Q$MRTG_lib::SL\E/, $cfgfile)[-1].".$router"; 1635 } 1636 1637 # setup environment for external scripts 1638 if (defined $$rcfg{'threshdesc'}{$router}) { 1639 $ENV{THRESH_DESC}=$$rcfg{'threshdesc'}{$router}; 1640 } else { 1641 delete $ENV{THRESH_DESC}; 1642 } 1643 1644 foreach my $dir (qw(i o)){ # in and out 1645 foreach my $bound (qw(min max)){ 1646 # skip unless a threshold is defined for this "$router" 1647 next unless defined $$rcfg{'thresh'.$bound.$dir}{$router}; 1648 # we can not deal with unknown data here 1649 warn "WARNING: can't do threshold checking for target $router($dir) -- No valid current data\n" 1650 unless defined $threshval{$dir}; 1651 my $value = $threshval{$dir}; 1652 next unless defined $value; 1653 my $boundval = $$rcfg{'thresh'.$bound.$dir}{$router}; 1654 next unless defined $boundval; 1655 if ($boundval =~ s/%$//) { # defined in % of maxbytes 1656 # 2 decimals in % 1657 $value = int($value / $$rcfg{maxbytes}{$router} * 10000.0) / 100; # the new code 1658 } 1659 1660 if (($bound eq 'min' and $boundval > $value) or 1661 ($bound eq 'max' and $boundval < $value)) { 1662 1663 # threshold was broken... 1664 my @exec = ( $$rcfg{'threshprog'.$dir}{$router}, $router, 1665 $$rcfg{'thresh'.$bound.$dir}{$router}, $threshval{$dir},($$rcfg{'threshdesc'}{$router} ||"No Description"), $value); 1666 1667 # Check if we use the status file or not... 1668 if ( defined $threshfile ) { 1669 if ( not -e $threshfile.".".$bound.uc($dir) ) { 1670 # Create a file to indicate a threshold problem for the time after the problem 1671 open THRESHTOUCH, ">".$threshfile.".".$bound.uc($dir) 1672 or warn "WARNING: Creating $threshfile.".$bound.uc($dir).": $!\n"; 1673 close THRESHTOUCH; 1674 debug('base',"run treshprog$dir: ".(join ",",@exec)); 1675 system @exec if defined $$rcfg{'threshprog'.$dir}{$router}; 1676 } 1677 } else { 1678 # no threshold dir so run on every 'break' 1679 system @exec if defined $$rcfg{'threshprog'.$dir}{$router}; 1680 } 1681 } else { 1682 1683 # no threshold broken ... 1684 my @exec = ( $$rcfg{'threshprogok'.$dir}{$router}, $router, 1685 $$rcfg{'thresh'.$bound.$dir}{$router}, $threshval{$dir}); 1686 1687 # Check if we use the status file or not... 1688 if ( defined $threshfile ) { 1689 if ( -e $threshfile.".".$bound.uc($dir) ){ 1690 unlink "$threshfile.".$bound.uc($dir); 1691 system @exec if defined $$rcfg{'threshprogok'.$dir}{$router}; 1692 } 1693 } 1694 } 1695 1696 } # foreach my $bound ... 1697 } # foreach my $dir 1698 } 1699 1700 sub getexternal ($) { 1701 my $command = shift; 1702 my $in=undef; 1703 my $out=undef; 1704 my $uptime="unknown"; 1705 my $name="unknown"; 1706 1707 open (EXTERNAL , $command."|") 1708 or warn "WARNING: Running '$command': $!\n"; 1709 1710 warn "WARNING: Could not get any data from external command ". 1711 "'".$command. 1712 "'\nMaybe the external command did not even start. ($!)\n\n" if eof EXTERNAL; 1713 1714 chomp( $in=<EXTERNAL>) unless eof EXTERNAL; 1715 chomp( $out=<EXTERNAL>) unless eof EXTERNAL; 1716 chomp( $uptime=<EXTERNAL>) unless eof EXTERNAL; 1717 chomp( $name=<EXTERNAL>) unless eof EXTERNAL; 1718 1719 close EXTERNAL; 1720 1721 # strip returned date 1722 $uptime =~ s/^\s*(.*?)\s*/$1/; 1723 $name =~ s/^\s*(.*?)\s*/$1/; 1724 1725 # do we have numbers in the external programs answer ? 1726 if ( not defined $in ) { 1727 warn "WARNING: Problem with External get '$command':\n". 1728 " Expected a Number for 'in' but nothing'\n\n"; 1729 } elsif ( $in eq 'UNKNOWN' ) { 1730 $in = undef; 1731 } elsif ( $in !~ /([-+]?\d+(.\d+)?)/ ) { 1732 warn "WARNING: Problem with External get '$command':\n". 1733 " Expected a Number for 'in' but got '$in'\n\n"; 1734 $in = undef; 1735 } else { 1736 $in = $1; 1737 } 1738 1739 if ( not defined $out ) { 1740 warn "WARNING: Problem with External get '$command':\n". 1741 " Expected a Number for 'out' but nothing'\n\n"; 1742 } elsif ( $out eq 'UNKNOWN' ) { 1743 $out = undef; 1744 } elsif ( $out !~ /([-+]?\d+(.\d+)?)/ ) { 1745 warn "WARNING: Problem with Externale get '$command':\n". 1746 " Expected a Number for 'out' but got '$out'\n\n"; 1747 $out = undef; 1748 } else { 1749 $out = $1; 1750 } 1751 debug('snpo',"External result:".($in||"undef")." out:".($out||"undef")." uptime:".($uptime||"undef")." name:".($name||"undef")); 1752 return ($in,$out,time,$uptime,$name); 1753 } 1754 1755 sub getsnmparg ($$$){ 1756 my $confcache = shift; 1757 my $target = shift; 1758 my $cfg = shift; 1759 my $retry = 0; 1760 1761 my $hostname = $$target{Host}; 1762 1763 if ($$target{ipv4only}) { 1764 if (not ( $hostname =~ /^\d+\.\d+\.\d+\.\d+$/ or gethostbyname $hostname) ){ 1765 warn "WARNING: Skipping host $hostname as it does not resolve to an IPv4 address\n"; 1766 return 'DEADHOST'; 1767 } 1768 } else { 1769 if($hostname =~ /^\[(.*)\]$/) { 1770 # Numeric IPv6 address. Check that it's valid 1771 $hostname = substr($hostname, 1); 1772 chop $hostname; 1773 if(! inet_pton(AF_INET6(), $hostname)) { 1774 warn "WARNING: Skipping host $hostname: invalid IPv6 address\n"; 1775 return 'DEADHOST'; 1776 } 1777 } else { 1778 # Hostname. Look it up 1779 my @res; 1780 my ($too,$port,$otheropts) = split(':', $$target{SnmpOpt}, 3); 1781 $port = 161 unless defined $port; 1782 @res = getaddrinfo($hostname, $port, AF_UNSPEC(), SOCK_DGRAM()); 1783 if (scalar (@res) < 5) { 1784 warn "WARNING: Skipping host $hostname as it does not resolve to an IPv4 or IPv6 address\n"; 1785 return 'DEADHOST'; 1786 } 1787 } 1788 } 1789 RETRY: 1790 my @ifnum = (); 1791 my @OID = (); 1792 # Find apropriate Interface to poll from 1793 for my $i (0..1) { 1794 if ($$target{IfSel}[$i] eq 'If') { 1795 $ifnum[$i] = ".".$$target{Key}[$i]; 1796 debug('snpo',"simple If: $ifnum[$i]"); 1797 } elsif($$target{IfSel}[$i] eq 'None') { 1798 $ifnum[$i] = ""; 1799 } else { 1800 $$target{Key}[$i] =~ s/\s+$//; # no trainling whitespace in keys ... 1801 if (not defined $$confcache{"$$target{Community}\@$$target{Host}$$target{SnmpOpt}"}{$$target{IfSel}[$i]}{$$target{Key}[$i]}) { 1802 debug('snpo',"($i) Populate ConfCache for $$target{Host}$$target{SnmpOpt}"); 1803 populateconfcache($confcache,"$$target{Community}\@$$target{Host}$$target{SnmpOpt}",$$target{ipv4only},1,$$cfg{snmpoptions}); 1804 } 1805 if (not defined $$confcache{"$$target{Community}\@$$target{Host}$$target{SnmpOpt}"}{$$target{IfSel}[$i]}{$$target{Key}[$i]}) { 1806 warn "WARNING: Could not match host:'$$target{Community}\@$$target{Host}$$target{SnmpOpt}' ref:'$$target{IfSel}[$i]' key:'$$target{Key}[$i]'\n"; 1807 return 'NOMATCH'; 1808 } else { 1809 $ifnum[$i] = ".".$$confcache{"$$target{Community}\@$$target{Host}$$target{SnmpOpt}"}{$$target{IfSel}[$i]}{$$target{Key}[$i]}; 1810 debug('snpo',"($i) Confcache Match $$target{Key}[$i] -> $ifnum[$i]"); 1811 } 1812 } 1813 if ($ifnum[$i] !~ /^$|^\.\d+$/) { 1814 warn "WARNING: Can not determine". 1815 " ifNumber for $$target{Community}\@$$target{Host}$$target{SnmpOpt} \tref: '$$target{IfSel}[$i]' \tkey: '$$target{Key}[$i]'\n"; 1816 return 'NOMATCH'; 1817 } 1818 } 1819 for my $i (0..1) { 1820 # add ifget methodes call for a cross check; 1821 for ($$target{IfSel}[$i]) { 1822 /^Eth$/ && do { 1823 push @OID, "ifPhysAddress".$ifnum[$i]; last 1824 }; 1825 /^Ip$/ && do { 1826 push @OID, "ipAdEntIfIndex".".".$$target{Key}[$i];last 1827 }; 1828 /^Descr$/ && do { 1829 push @OID, "ifDescr".$ifnum[$i]; last 1830 }; 1831 /^Type$/ && do { 1832 push @OID, "ifType".$ifnum[$i]; last 1833 }; 1834 /^Name$/ && do { 1835 push @OID, "ifName".$ifnum[$i]; last 1836 }; 1837 } 1838 push @OID ,$$target{OID}[$i].$ifnum[$i]; 1839 } 1840 # we also want to know uptime and system name unless we are 1841 if ( not defined $$cfg{nomib2} and $$cfg{logformat} ne 'rrdtool' ) { 1842 if ( $OID[0] !~ /^cache.+$/ and 1843 $OID[0] !~ /^\Q1.3.6.1.4.1.3495.1\E/ ) { 1844 push @OID, qw(sysUptime sysName); 1845 } else { 1846 push @OID, qw(cacheUptime cacheSoftware cacheVersionId) 1847 } 1848 } 1849 1850 # pull that data 1851 debug('snpo',"SNMPGet from $$target{Community}\@$$target{Host}$$target{SnmpOpt} -- ".(join ",", @OID)); 1852 my @ret; 1853 1854 # make sure we have no error messages hanging round. 1855 1856 $SNMP_Session::errmsg = ''; 1857 1858 my $targtemp = $$target{Community}.'@'.$$target{Host}.$$target{SnmpOpt}; 1859 $targtemp = v4onlyifnecessary($targtemp, $$target{ipv4only}); 1860 1861 my @snmpoids = grep !/^Pseudo/, @OID; 1862 if (defined $$cfg{singlerequest}){ 1863 local $BER::pretty_print_timeticks = 0; 1864 foreach my $oid (@snmpoids){ 1865 push @ret, snmpget($targtemp,$$cfg{snmpoptions},$oid); 1866 } 1867 } else { 1868 @ret = snmpget($targtemp,$$cfg{snmpoptions},@snmpoids); 1869 } 1870 my @newret; 1871 for (@OID) { 1872 /^PseudoZero$/ && do { push @newret, 0; next; }; 1873 /^PseudoOne$/ && do { push @newret, 1; next; }; 1874 push @newret, shift @ret; 1875 } 1876 @ret = @newret; 1877 debug('snpo',"SNMPfound -- ".(join ", ", map {"'".($_||"undef")."'"} @ret)); 1878 $ret[-2] = $ret[-2].' '.$ret[-1] if $OID[-1] and $OID[-1] eq 'cacheVersionId'; 1879 my $time = time; 1880 my @final; 1881 # lets do some reality check 1882 for my $i (0..1) { 1883 # some ifget methodes call for a cross check; 1884 for ($$target{IfSel}[$i]) { 1885 /^Eth$/ && do { 1886 my $bin = shift @ret || 0xff; 1887 my $eth = unpack 'H*', $bin; 1888 my @eth; 1889 while ($eth =~ s/^..//){ 1890 push @eth, $&; 1891 } 1892 my $phys=join '-', @eth; 1893 if ($phys ne $$target{Key}[$i]) { 1894 debug('snpo', "($i) eth if crosscheck got $phys expected $$target{Key}[$i]"); 1895 if (not $retry) { 1896 $retry=1; 1897 # remove broken entry 1898 $$confcache{$$target{Community}.'@'.$$target{Host}. 1899 $$target{SnmpOpt}}{$$target{IfSel}[$i]}{$$target{Key}[$i]} = undef; 1900 debug('repo',"($i) goto RETRY force if cache repopulation"); 1901 goto RETRY; 1902 } else { 1903 warn "WARNING: could not match&get". 1904 " $$target{Host}$$target{SnmpOpt}/$$target{OID}[$i] for Eth $$target{Key}[$i]\n"; 1905 return 'NOMATCH'; 1906 } 1907 }; 1908 debug ('snpo',"($i) Eth crosscheck OK"); 1909 }; 1910 /^Ip$/ && do { 1911 my $if = shift @ret || 'none'; 1912 if ($ifnum[$i] ne '.'.$if) { 1913 debug('repo', "($i) IP if crosscheck got .$if expected $ifnum[$i]"); 1914 if (not $retry) { 1915 $retry=1; 1916 # remove broken entry 1917 $$confcache{$$target{Community}.'@'.$$target{Host}. 1918 $$target{SnmpOpt}}{$$target{IfSel}[$i]}{$$target{Key}[$i]} = undef; 1919 debug('repo',"($i) goto RETRY force if cache repopulation"); 1920 goto RETRY; 1921 } else { 1922 warn "WARNING: could not match&get". 1923 " $$target{Host}$$target{SnmpOpt}/$$target{OID}[$i] for IP $$target{Key}[$i]\n"; 1924 return 'NOMATCH'; 1925 } 1926 } 1927 debug ('snpo',"($i) IP crosscheck OK"); 1928 }; 1929 /^(Descr|Name|Type)$/ && do { 1930 my $descr = shift @ret || 'Empty'; 1931 $descr =~ s/[\0- ]+$//; # remove excess spaces and stuff 1932 if ($descr ne $$target{Key}[$i]) { 1933 debug('repo', "($i) $_ if crosscheck got $descr expected $$target{Key}[$i]"); 1934 if (not $retry) { 1935 $retry=1; 1936 # remove broken entry 1937 $$confcache{$$target{Community}.'@'.$$target{Host}. 1938 $$target{SnmpOpt}}{$$target{IfSel}[$i]}{$$target{Key}[$i]} = undef; 1939 debug('repo',"($i) goto RETRY force if cache repopulation"); 1940 goto RETRY; 1941 } else { 1942 warn "WARNING: could not match&get". 1943 " $$target{Host}$$target{SnmpOpt}/$$target{OID}[$i] for $_ '$$target{Key}[$i]'\n"; 1944 return 'NOMATCH'; 1945 } 1946 } 1947 debug ('snpo',"($i) $_ crosscheck OK"); 1948 }; 1949 } 1950 # we no sense continuing here ... if there is no data ... 1951 if (defined $SNMP_Session::errmsg and $SNMP_Session::errmsg =~ /no response received/){ 1952 $SNMP_Session::errmsg = ''; 1953 warn "WARNING: skipping because at least the query for $OID[0] on $$target{Host} did not succeed\n"; 1954 return 'DEADHOST'; 1955 } 1956 if ($$target{OID}[$i] =~ /if(Admin|Oper)Hack/) { 1957 push @final, ((shift @ret) == 1) ? 1:0; 1958 } else { 1959 push @final, shift @ret; 1960 } 1961 } 1962 1963 my @res = ( @final,$time, @ret); 1964 1965 # have some cleanup first, it seems that some agents 1966 # are adding newlines to what they return 1967 map{ $_ =~ s/\n|\r//g if defined $_ } @res; 1968 map{ $_ =~ s/^\s+//g if defined $_ } @res; 1969 map{ $_ =~ s/\s+$//g if defined $_ } @res; 1970 1971 # Convert in and out values to integers with a user-defined subroutine 1972 # specified by the Conversion target key 1973 if( $target->{ Conversion } ) { 1974 foreach my $ri( 0..1 ) { 1975 next unless defined $res[ $ri ]; 1976 my $exp = "&MRTGConversion::$target->{ Conversion }( '$res[ $ri ]' )"; 1977 $res[ $ri ] = eval $exp; 1978 warn "WARNING: evaluation of \"$exp\" failed\n$@\n" if $@; 1979 } 1980 } 1981 1982 # in and out should be numbers only 1983 for my $ri (0..1){ 1984 # for folks using rrdtool I am allowing numbers 1985 # with decimals here 1986 if ( defined $res[$ri] and $res[$ri] !~ /^[-+]?\d+(.\d+)?$/ ) { 1987 warn "WARNING: Expected a number but got '$res[$ri]'\n"; 1988 $res[$ri] = undef; 1989 1990 } 1991 } 1992 return @res; 1993 } 1994 1995 1996 # read target function ... 1997 sub readtargets ($$$) { 1998 my ($confcache,$target,$cfg) = @_; 1999 my $forks = $$cfg{forks}; 2000 my $trgnum = $#{$target}+1; 2001 if (defined $forks and $forks > 1 and $trgnum > 1){ 2002 $forks = $trgnum if $forks > $trgnum; 2003 my $split = int($trgnum / $forks) + 1; 2004 my @hand; 2005 # get them forks to work ... 2006 for (my $i = 0; $i < $forks;$i++) { 2007 local *D; 2008 my $sleep_count=0; 2009 my $pid; 2010 do { 2011 $pid = open(D, "-|"); 2012 unless (defined $pid) { 2013 warn "WARNING cannot fork: $!\n"; 2014 die "ERROR bailing out after 6 faild forkattempts" 2015 if $sleep_count++ > 6; 2016 sleep 10; 2017 } 2018 } until defined $pid; 2019 if ($pid) { # parent 2020 $hand[$i] = *D; # funky file handle magic ... 2021 debug ('fork',"Parent $$ after fork of child $i"); 2022 } else { # child 2023 debug ('fork',"Child $i ($$) after fork"); 2024 my $res = ""; 2025 my %deadhost; 2026 for (my $ii = $i * $split; 2027 $ii < ($i+1) * $split and $ii < $trgnum; 2028 $ii++){ 2029 my $targ = $$target[$ii]; 2030 my @res; 2031 if ($$targ{Methode} eq 'EXEC') { 2032 @res = getexternal($$targ{Command}); 2033 } else { # parent 2034 if (not $deadhost{$$targ{Community}.$$targ{Host}}) { 2035 @res = getsnmparg($confcache,$targ,$cfg); 2036 if ( $res[0] and $res[0] eq 'DEADHOST') { 2037 # guess we got a blank here 2038 @res = ( undef,undef,time,undef,undef); 2039 $deadhost{$$targ{Community}.$$targ{Host}} = 1; 2040 warn "WARNING: no data for $$targ{OID}[0]&$$targ{OID}[1]:$$targ{Community}\@$$targ{Host}. Skipping further queries for Host $$targ{Host} in this round.\n" 2041 } elsif ($res[0] and $res[0] eq 'NOMATCH'){ 2042 @res = (undef,undef,time,undef,undef); 2043 } 2044 } else { 2045 @res = ( undef,undef,time,undef,undef); 2046 } 2047 } 2048 2049 for (my $iii=0;$iii<5;$iii++){ 2050 if (defined $res[$iii]){ 2051 $res .= "$res[$iii]\n"; 2052 } else { 2053 $res .= "##UNDEF##\n"; 2054 } 2055 } 2056 } 2057 debug ('fork',"Child $i ($$) waiting to deliver"); 2058 print $res; # we only talk after the work has been done to 2059 # otherwhise we might get blocked 2060 # return updated hosts from confcache 2061 writeconfcache($confcache,'&STDOUT') 2062 if defined $$confcache{___updated}; 2063 exit 0; 2064 } 2065 2066 } 2067 # happy reaping ... 2068 my $vin =''; # vector of pipe file-descriptors from children 2069 for (my $i = 0; $i < $forks;$i++) { 2070 vec($vin, fileno($hand[$i]), 1) = 1; 2071 } 2072 my $left = $forks; 2073 while ($left) { 2074 my $rout = $vin; # read vector 2075 my $eout = $vin; # exception vector 2076 my $nfound = select($rout, undef, $eout, undef); # no timeout 2077 if (1 > $nfound) { 2078 die sprintf("ERROR: select returned %d: $!\n", $nfound); 2079 } 2080 for (my $i = 0; $i < $forks; $i++) { 2081 next unless defined $hand[$i] and defined fileno($hand[$i]); 2082 # this does not seem to work reliably 2083 # if (vec($eout, fileno($hand[$i]), 1)) { 2084 # die "ERROR: fork $i has died ahead of time?\n"; 2085 # } 2086 next unless vec($rout, fileno($hand[$i]), 1); 2087 2088 vec($vin, fileno($hand[$i]), 1) = 0; # remove this child fd 2089 2090 debug ('fork',"Parent reading child $i"); 2091 my $h = $hand[$i]; 2092 for (my $ii = $i * $split; 2093 $ii < ($i+1) * $split and $ii < $trgnum; 2094 $ii++){ 2095 my $targ = $$target[$ii]; 2096 my @res; 2097 for (0..4){ 2098 my $line = <$h>; # must be a simple scalar here else it wont work 2099 die "ERROR: fork $i has died ahead of time ...\n" if not defined $line; 2100 chomp $line; 2101 # debug ('fork',"reading for $ii $line"); 2102 $line = undef if $line eq "##UNDEF##"; 2103 push @res,$line; 2104 }; 2105 2106 ($$targ{_IN_}, 2107 $$targ{_OUT_}, 2108 $$targ{_TIME_}, 2109 $$targ{_UPTIME_}, 2110 $$targ{_NAME_}) = @res; 2111 if ($] >= 5.0061){ 2112 $$targ{_IN_} = Math::BigFloat->new($$targ{_IN_}) if $$targ{_IN_}; 2113 $$targ{_OUT_} = Math::BigFloat->new($$targ{_OUT_}) if $$targ{_OUT_}; 2114 } 2115 } 2116 # feed confcache entries 2117 my $lasthost =""; 2118 while (<$h>){ 2119 chomp; 2120 my ($host,$method,$key,$value) = split (/\t/, $_); 2121 if ($host ne $lasthost){ 2122 debug ('fork',"start undef for $host"); 2123 $$confcache{$host} = undef; 2124 debug ('fork',"end undef for $host"); 2125 } 2126 $lasthost = $host; 2127 storeincache($confcache,$host,$method,$key,$value); 2128 } 2129 close $h; 2130 --$left; 2131 } 2132 } 2133 2134 } else { 2135 my %deadhost; 2136 foreach my $targ (@$target) { 2137 if ($$targ{Methode} eq 'EXEC') { 2138 debug('snpo', "run external $$targ{Command}"); 2139 ($$targ{_IN_}, 2140 $$targ{_OUT_}, 2141 $$targ{_TIME_}, 2142 $$targ{_UPTIME_}, 2143 $$targ{_NAME_}) = getexternal($$targ{Command}); 2144 } elsif ($$targ{Methode} eq 'SNMP' and not $deadhost{$$targ{Host}}) { 2145 debug('snpo', "run snmpget from $$targ{OID}[0]&$$targ{OID}[1]:$$targ{Community}\@$$targ{Host}"); 2146 ($$targ{_IN_}, 2147 $$targ{_OUT_}, 2148 $$targ{_TIME_}, 2149 $$targ{_UPTIME_}, 2150 $$targ{_NAME_}) = getsnmparg($confcache,$targ,$cfg); 2151 if ( $$targ{_IN_} and $$targ{_IN_} eq 'DEADHOST') { 2152 $$targ{_IN_} = undef; 2153 $$targ{_TIME_} =time; 2154 # guess we got a blank here 2155 $deadhost{$$targ{Host}} = 1; 2156 warn "WARNING: no data for $$targ{OID}[0]&$$targ{OID}[1]:$$targ{Community}\@$$targ{Host}. Skipping further queries for Host $$targ{Host} in this round.\n" 2157 } 2158 if ( $$targ{_IN_} and $$targ{_IN_} eq 'NOMATCH') { 2159 $$targ{_IN_} = undef; 2160 $$targ{_TIME_} =time; 2161 } 2162 2163 } else { 2164 $$targ{_IN_} = undef; 2165 $$targ{_OUT_} = undef; 2166 $$targ{_TIME_} = time; 2167 $$targ{_UPTIME_} = undef; 2168 $$targ{_NAME_} = undef; 2169 } 2170 if ($] >= 5.008 ){ 2171 $$targ{_IN_} = new Math::BigFloat "$$targ{_IN_}" if $$targ{_IN_}; 2172 $$targ{_OUT_} = new Math::BigFloat "$$targ{_OUT_}" if $$targ{_OUT_}; 2173 } 2174 2175 } 2176 } 2177 2178 } 2179 2180 sub imggen ($) { 2181 my $dir = shift; 2182 if ( ! -r "$dir$main::SL}mrtg-l.png" and open W, ">$dir$main::SL}mrtg-l.png" ){ 2183 binmode W; 2184 print W unpack ('u', <<'UUENC'); 2185 MB5!.1PT*&@H -24A$4@ #\ 9! , !TA.O' &%!,5$5]9GTT 2186 M79A?8HB(9WFR;6G_=DWM=%35<5R_M[A2 6)+1T0'%F&(ZP 1%)1$%4 2187 M>-JMDKUOPD ,Q:E4]CH?S0PMG8-.$6L1A*YMJ,D<T>Q%5?[_ON>$Y (2$R>= 2188 MY;-^OF=;GNCM\SFY#_#GW$IU0WMP/#O5HSGNW8"9R)/92$NQ\Z:GUDG/@.@! 2189 M)CP#4H\ >LT>)NB!A0]8,"]&0.(#WY92V<\$=FM4<P7$:Q,JN\^BGRV+WOX2 2190 MX.<2+4VH!U01B-LYX#V3B*U(1N 5[K,/?(G,)1!!9-%WX0.HYX7 :0!"]0&4 2191 MMV*/Z"/N@&8$P,N8!:FD[!4\ #7EN$G1 <M+"0*0B0&$!#:MQ@#P#?WIO@,^ 2192 M+KI@K$9V#B"P03V,!\5)T]1T#*A,8P"P.%JZ1USGL%%IPTC.#<ONMK2W@']' 2193 M6*MJXQ-D& $-T15AT4V]F='=A<F4 0"@C*4EM86=E36%G:6-K(#0N,BXY 2194 M(#DY+S Y+S Q(&-R:7-T>4!M>7-T:6,N97,N9'5P;VYT+F-O;>WHV? J 2195 M=$58=%-I9VYA='5R90!D,C(W8S<T.3AA-3 Q93=F830U,#@V8SEF9C0T8F(Y 2196 K8ULTB'X .=$58=%!A9V4 -C-X,C4K,"LP&!)XE !)14Y$KD)@@F(Y 2197 UUENC 2198 close W; 2199 } 2200 if ( ! -r "$dir$main::SL}mrtg-m.png" and open W, ">$dir$main::SL}mrtg-m.png" ){ 2201 binmode W; 2202 print W unpack ('u', <<'UUENC'); 2203 MB5!.1PT*&@H -24A$4@ !D 9! , VQYA0 &%!,5$5]9GTT 2204 M79A588QN9(*7:73_=DWL=%31<F'8YWD& 6)+1T0'%F&(ZP (!)1$%4 2205 M>-IC"$4"!0P$>"E&2B:I,%Z((!"(I$)X88H@GJ :A)<$Y@@*I8)YAA">("N( 2206 M%PYD"#L+"IJ#Y4!FN(86N4',# )J"4TO*R\O!_$"@::'@HTEQ /K _&$0+P 2207 M(.T:6@A2@62?H#B*6TRQN#,<Q0^AP<C^ _K=&,GO1(89 ,3!45'T;[0_ 2208 M0W1%6'13;V9T=V%R90! *",I26UA9V5-86=I8VL@-"XR+CD@.3DO,#DO,#$@ 2209 M8W)I<W1Y0&UY<W1I8RYE<RYD=7!O;G0N8V]M[>C9\ "IT15AT4VEG;F%T 2210 M=7)E #1E,S8X-S$P,38Q-S)A96%B.3,Y8SEA,F5D-31B86(U@DWZ,@ ET 2211 M15AT1&5L87D ,C4P(RC.$P YT15AT4&%G90 R-7@R-2LP*S"#D2 ? 2212 ) $E%3D2N0F"" 2213 UUENC 2214 close W; 2215 } 2216 if ( ! -r "$dir$main::SL}mrtg-r.png" and open W, ">$dir$main::SL}mrtg-r.png" ){ 2217 binmode W; 2218 print W unpack ('u', <<'UUENC'); 2219 MB5!.1PT*&@H -24A$4@ 80 9! , ##'$3) &%!,5$4T79@\ 2220 M8YQ5=JAPC;>:K\S\_?[5WNFZR-PB%CO! 6)+1T0'%F&(ZP !=5)1$%4 2221 M>-KM6$ESVE@0;BW 58: K_)"YDH(.%=YL/"511)7O""N3AS!WY_^NM^3Q)+, 2222 M4C55DZJ1*2&]U]O7Z\,4T"]__0_A;US.O\7$$#H*PR=R[_'@#? A9X3KLW,K 2223 MNRX_*L=MGK^#PQ)[$USW+J@'U)E,!JI<V>GS9"+RG0^B!(NDM,ZMB'G,M_?6 2224 MF@^[_#7D[U)*!V_N!#+4$)>M@+Z(.J/1)PNAI4]=5K# 0_,)'Z(4UXH*A<#/ 2225 M2SQ\3+?[=!F4Q&M?Z!8@2-?4X+O*L^Q\$PPQ;MA.R= 65RRWR/:[U&#PTVR_ 2226 MR4*JI#3?9#E-$U)#W)5*GE&3[Y&!T%P+?QR2)U;UUOB(0@A0"-Z*.AOVC)=^ 2227 MY=L&-T/L"$G !,KBW"V-3PU[.\8W@5N7J)W(?L'&WB5LP6_*X10OP+2L21G/ 2228 MH7OA=#:1&M)F-1FI\^A+8B&H %;A+\U>LP8A)HN^RZOC9^BZY#=#_&10NA8" 2229 M.5E !^R7H/2R=0G!6PH%1\%-!W@<"GU+PN4Q.Z2D6-K!2-;D]-=J"-2H?&C> 2230 M7"B$ABCW."HV-PX@%"6$YHS<3:@.K!$K2;N"4-0A\)X'.R[?%R4$MXQ"TT9, 2231 M7*Y:IP)!8N0L=Z0IVUJH(9!51H%B1)9A]$%,S3QB[_P0 EA;B\ W*KM/%?%Q 2232 M%*@8'$*0K?Y@54'0*+ !XZ@&P;C'2N$W?SU&\BX"Z"YKH08ATBB,^WCHW[U5 2233 MCK6U$!U'H3$WA9<<1\%+2I8R"H:]@ZT=Q8%9LK1%Z!1AA< XH902XAM@X#<; 2234 MA?;J) HL-F[!KJ*U%KC:D<XFTOAKZ35^+8FU7-S5\.8Z!(N;U7P)]B93.@G! 2235 M4XWWZ^$U)]+-]? "M9#5YI*_+%^LE''@S[5Q]&951\J&PYL0-FJ],-<4J>DD 2236 M_NQ\.9M$RD9?TE!AX\HJ8E,+IJE^'Q6+.H1X\K#A;V\FI.B6F=)&B$+E>'9T 2237 M51>-EPD:$VVE;#C>'CJ2:=.FJ?9>1_'20-CQ'_ESAN"5Y?Q4LT'=SFS?^.7* 2238 MYFU%;!(IFTP>!K!Q%=8AL.)7D@8/AL;K:#3A#LW#*>0H> <0(-"]YF!:*>X2 2239 MUG&GD;D08Z0] ,((4XWG0O;)0-@2UTPW8@V^G0NG46BO^FNB,@I.7A$?EO.W 2240 MK+1)V<4R&H<$E]MR-K7@GD!HB;DL!4G%N>VP;?YJCPE?\''#<:4C!?S7?-IH 2241 MXG%'2N"B.&2Y/^M(*ZE!6PM.]L..5#4997<P;JG(\SP]:JKLCZP&03+3&=[< 2242 M+B$% [N;Y?E&PQ<80[RJG)_Z(@Q;TERV&)DG48AJY>R@5W:5"SWE* JV([U5 2243 M*6W8H>EBM=_O>9B8CF2C0)M:.1L)@-*(!$_\^+C?S8TF.FJJO;6?& AP20*A 2244 MB6DR[*FS':G[7)5<<U$1VXYD6)RRO9L]:$)C@=3CT19'%00G53RMF96R55J+ 2245 M^! "2],!%$B88CAS9?S S>_,&2F1-N>:+LBJ2^+#Z1Q1?WV02(3PR2/<JV<D 2246 M8Q.O/]<@&#R<B4S6-\.SK+HS<Z&W4 @@Z!9<VSE0D)SWSI^1H"+^*H" Q!(? 2247 M3V<3W\H#'^=H&(1Z-F<D4PNA"F+#Y+TKRSC#,!DG/8=#*D;C73LC60B>'*IX 2248 M=,_1!P+ %2,A]5Q'TBSR49QN_$P5\?$9Z>2 P=;DXN8B..I(+ 2/'76SBU,P 2249 MC9=6BD28R\^O)=+1&2E2"#/C%CX7M++)J&#SFMP*GD^F,_SCC+.'42'H+;&) 2250 M0LH]YTU8>HM#"!3_GI@4.:R%*_3\U\EC:M+I8_I]-,T&9*3H0:4U/RYG:-+9 2251 M):7)9D,JX$_9*=,TW>)74"X0F@ Y50B83W?\'H!$"]80*XF;"P2P>%NUJ&2_ 2252 M?-51V7N3)7)?E!]B_$V:OMMJ^,+CZMYPMK??9;'SXBG"J;4C%PBPVX5^T]1" 2253 M6U-M/;K_[#>U>Q4<$?_I=?&SS>NP_(5\X=Z<<ITR.Y5YP7_B/QC_Z/\"?]4_ 2254 MO\3U!QLJ>FT="M4^ 0W1%6'13;V9T=V%R90! *",I26UA9V5-86=I8VL@ 2255 M-"XR+CD@.3DO,#DO,#$@8W)I<W1Y0&UY<W1I8RYE<RYD=7!O;G0N8V]M[>C9 2256 M\ "IT15AT4VEG;F%T=7)E #$R,3<U939B,S$X,S,S-V0S.#%F,#%C-C-C 2257 M9F,T,S9ELPXRP0 ]T15AT4&%G90 S.#AX,C4K,"LP4K-IB0 !)14Y$ 2258 $KD)@@C9E 2259 UUENC 2260 close W; 2261 } 2262 2263 } 2264 2265 # Local Variables: 2266 # mode: cperl 2267 # eval: (cperl-set-style "PerlStyle") 2268 # mode: flyspell 2269 # mode: flyspell-prog 2270 # End: 2271 # 2272 # vi: sw=4
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |