[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3master/usr/share/se3/sbin/ -> mrtg-se3 (source)

   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}&nbsp;</FONT>";
1296          }
1297      } else {
1298          $InCo="<FONT COLOR=\"$$rcfg{'rgb1'}{$router}\">".
1299            &$LOC("&nbsp;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}&nbsp;</FONT>";
1309          }
1310      } else {
1311          $OutCo="<FONT COLOR=\"$$rcfg{'rgb2'}{$router}\">".
1312            &$LOC("&nbsp;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&nbsp;</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):&nbsp;&nbsp;"),
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">&lt;oetiker\@ee.ethz.ch&gt;</A> 
1477  #TEXT
1478  
1479  #    print HTML &$LOC("and");
1480  #    print HTML '&nbsp;<A HREF="http://www.bungi.com/">Dave&nbsp;Rand</A>&nbsp;<A HREF="mailto:dlr@bungi.com">&lt;dlr@bungi.com&gt;</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  #  &lt;werner.berger\@cch.cerberus.ch&gt;</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  #  &lt;schneis\@testlab.orst.edu&gt;</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


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1