Blame lib/mrtg2/MRTG_lib.pm

Packit 667938
# -*- mode: Perl -*-
Packit 667938
package MRTG_lib;
Packit 667938
###################################################################
Packit 667938
# MRTG 2.17.7  Support library MRTG_lib.pm
Packit 667938
###################################################################
Packit 667938
# Created by Tobias Oetiker <tobi@oetiker.ch>
Packit 667938
#            and Dave Rand <dlr@bungi.com>
Packit 667938
#
Packit 667938
# For individual Contributers check the CHANGES file
Packit 667938
#
Packit 667938
###################################################################
Packit 667938
#
Packit 667938
# Distributed under the GNU General Public License
Packit 667938
#
Packit 667938
###################################################################
Packit 667938
Packit 667938
require 5.005;
Packit 667938
use strict;
Packit 667938
use vars qw($OS $SL $PS @EXPORT @ISA $VERSION %timestrpospattern);
Packit 667938
Packit 667938
Packit 667938
my %mrtgrules;
Packit 667938
Packit 667938
BEGIN {
Packit 667938
    # Automatic OS detection ... do NOT touch
Packit 667938
    if ( $^O =~ /^(?:(ms)?(dos|win(32|nt)?))/i ) {
Packit 667938
        $OS = 'NT';
Packit 667938
        $SL = '\\';
Packit 667938
        $PS = ';';
Packit 667938
    } elsif ( $^O =~ /^NetWare$/i ) {
Packit 667938
	$OS = 'NW';
Packit 667938
	$SL = '/';
Packit 667938
	$PS = ';';
Packit 667938
    } elsif ( $^O =~ /^VMS$/i ) {
Packit 667938
        $OS = 'VMS';
Packit 667938
        $SL = '.';
Packit 667938
        $PS = ':';
Packit 667938
    } elsif ( $^O =~ /^os2$/i ) {
Packit 667938
	$OS = 'OS2';
Packit 667938
	$SL = '/';
Packit 667938
	$PS = ';';
Packit 667938
    }  else {
Packit 667938
        $OS = 'UNIX';
Packit 667938
        $SL = '/';
Packit 667938
        $PS = ':';
Packit 667938
    }
Packit 667938
}
Packit 667938
Packit 667938
require Exporter;
Packit 667938
@ISA = qw(Exporter);
Packit 667938
@EXPORT = qw(readcfg cfgcheck setup_loghandlers 
Packit 667938
	     datestr expistr ensureSL timestamp
Packit 667938
             create_pid demonize_me debug log2rrd storeincache readfromcache clearfromcache cleanhostkey
Packit 667938
	     populateconfcache readconfcache writeconfcache
Packit 667938
	     v4onlyifnecessary);
Packit 667938
Packit 667938
$VERSION = 2.100016;
Packit 667938
Packit 667938
%timestrpospattern =
Packit 667938
      (
Packit 667938
       'NO' => 0,
Packit 667938
       'LU' => 1,
Packit 667938
       'RU' => 2,
Packit 667938
       'LL' => 3,
Packit 667938
       'RL' => 4
Packit 667938
      );
Packit 667938
Packit 667938
%mrtgrules =
Packit 667938
      (                         # General CFG
Packit 667938
       'workdir' => 
Packit 667938
       [sub{$_[0] && (-d $_[0])}, sub{"Working directory $_[0] does not exist"}],
Packit 667938
Packit 667938
       'htmldir' =>
Packit 667938
       [sub{$_[0] && (-d $_[0])}, sub{"Html directory $_[0] does not exist"}],
Packit 667938
Packit 667938
       'imagedir' =>
Packit 667938
       [sub{$_[0] && (-d $_[0])}, sub{"Image directory $_[0] does not exist"}],
Packit 667938
Packit 667938
       'logdir' =>
Packit 667938
       [sub{$_[0] && (-d $_[0] )}, sub{"Log directory $_[0] does not exist"}],
Packit 667938
Packit 667938
       'forks' =>
Packit 667938
       [sub{$_[0] && (int($_[0]) > 0 and $MRTG_lib::OS eq 'UNIX')},
Packit 667938
        sub{"Less than 1 fork or not running on Unix/Linux"}],
Packit 667938
Packit 667938
       'refresh' => 
Packit 667938
       [sub{int($_[0]) >= 300}, sub{"$_[0] should be 300 seconds or more"}],
Packit 667938
Packit 667938
       'enablesnmpv3' =>
Packit 667938
       [sub{((lc($_[0])) eq 'yes' or (lc($_[0])) eq 'no')}, sub{"$_[0] must be yes or no"}],
Packit 667938
Packit 667938
       'enableipv6' =>
Packit 667938
       [sub{((lc($_[0])) eq 'yes' or (lc($_[0])) eq 'no')}, sub{"$_[0] must be yes or no"}],
Packit 667938
Packit 667938
       'interval' => 
Packit 667938
       [sub{$_[0] =~ /(\d+)(?::(\d+))?/ ; 
Packit 667938
            my $int = $1*60; $int += $2 if $2;
Packit 667938
            $int >= 1 and $int <= 60*60}, sub{"$_[0] should be at least 1 Second (0:01) and no more than 60 Minutes (60)"}], 
Packit 667938
Packit 667938
       'writeexpires' =>  
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'nomib2' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'singlerequest' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'icondir' =>
Packit 667938
       [sub{$_[0]}, sub{"Directory argument missing"}],
Packit 667938
Packit 667938
       'language' =>
Packit 667938
       [sub{1}, sub{"Mrtg not localized for $_[0] - defaulting to english"}],
Packit 667938
Packit 667938
       'loadmibs' =>
Packit 667938
       [sub{$_[0]}, sub{"No MIB Files specified"}],
Packit 667938
Packit 667938
       'userrdtool' =>
Packit 667938
       [sub{0}, sub{"UseRRDtool is not valid any more. Use LogFormat, PathAdd and LibAdd instead"}],
Packit 667938
Packit 667938
       'userrdtool[]' =>
Packit 667938
       [sub{0}, sub{"UseRRDtool[] is not valid any more. Check the new xyz*bla[] syntax for passing parameters to tool xyz who reads the mrtg.cfg"}],
Packit 667938
       
Packit 667938
       'logformat' =>
Packit 667938
       [sub{$_[0] =~ /^(rateup|rrdtool)$/}, sub{"Invalid Logformat '$_[0]'"}],
Packit 667938
Packit 667938
       'pathadd' =>
Packit 667938
       [sub{-d $_[0]}, sub{"$_[0] is not the name of a directory"}],
Packit 667938
Packit 667938
       'libadd' =>
Packit 667938
       [sub{-d $_[0]}, sub{"$_[0] is not the name of a directory"}],
Packit 667938
       
Packit 667938
       'runasdaemon' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'nodetach' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'maxage' =>
Packit 667938
       [sub{(($_[0] =~ /^[0-9]+$/) and ($_[0] > 0)) },
Packit 667938
        sub{"$_[0] must be a Number bigger than 0"}],
Packit 667938
Packit 667938
       'nospacechar' =>
Packit 667938
       [sub{length($_[0]) == 1}, sub{"$_[0] must be one character long"}],
Packit 667938
Packit 667938
       'snmpoptions' =>
Packit 667938
       [sub{ debug('eval',"snmpotions $_[0]");local $SIG{__DIE__}; eval( '{'.$_[0].'}' ); return not $@},
Packit 667938
        sub{"Must have the format \"OptA => Number, OptB => 'String', ... \""}],
Packit 667938
Packit 667938
       'conversioncode' =>
Packit 667938
       [sub{-r $_[0]}, sub{"Cannot read conversion code file $_[0]"}],
Packit 667938
Packit 667938
       # Check for an environment setting for RRDCACHED_ADDRESS
Packit 667938
       # Steve Shipway, Sep 2010
Packit 667938
       'rrdcached' =>
Packit 667938
#       [sub{(($_[0] =~ /^unix:(\S+)/)and(-w $1))}, sub{"Currently, only UNIX domain sockets are supported for RRDCached, and must exist and be writeable."}],
Packit 667938
       [sub{1},sub{"Internal Error"}],
Packit 667938
Packit 667938
       # Get graphite server name/ip and port
Packit 667938
       'sendtographite' =>
Packit 667938
       [sub{$_[0] =~ /^.*,\d+$/}, sub{"Invalid Graphite Destination '$_[0]'"}],
Packit 667938
Packit 667938
       # Per Router CFG
Packit 667938
       'target[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #will test this later
Packit 667938
Packit 667938
       'snmpoptions[]' =>
Packit 667938
       [sub{ debug('eval',"snmpotions[] $_[0]");local  $SIG{__DIE__}; eval('{'.$_[0].'}' ); return not $@},
Packit 667938
        sub{"Must have the format \"OptA => Number, OptB => 'String', ... \""}],
Packit 667938
Packit 667938
       'routeruptime[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #will test this later
Packit 667938
Packit 667938
       'routername[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #will test this later
Packit 667938
Packit 667938
       'nohc[]' =>
Packit 667938
       [sub{((lc($_[0])) eq 'yes' or (lc($_[0])) eq 'no')}, sub{"$_[0] must be yes or no"}],
Packit 667938
Packit 667938
       'maxbytes[]' => 
Packit 667938
       [sub{(($_[0] =~ /^[0-9]+$/) && ($_[0] > 0)) },
Packit 667938
        sub{"$_[0] must be a Number bigger than 0"}],
Packit 667938
Packit 667938
       'maxbytes1[]' =>
Packit 667938
       [sub{(($_[0] =~ /^[0-9]+$/) && ($_[0] > 0))},
Packit 667938
        sub{"$_[0] must be numerical and larger than 0"}],
Packit 667938
Packit 667938
       'maxbytes2[]' =>
Packit 667938
       [sub{(($_[0] =~ /^[0-9]+$/) && ($_[0] > 0))},
Packit 667938
        sub{"$_[0] must a number bigger than 0"}],
Packit 667938
Packit 667938
       'ipv4only[]' =>
Packit 667938
       [sub{((lc($_[0])) eq 'yes' or (lc($_[0])) eq 'no')}, sub{"$_[0] must be yes or no"}],
Packit 667938
Packit 667938
       'absmax[]' => 
Packit 667938
       [sub{($_[0] =~ /^[0-9]+$/)}, sub{"$_[0] must be a Number"}],
Packit 667938
Packit 667938
       'title[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'directory[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'clonedirectory[]' =>
Packit 667938
       [sub{($_[0] =~ /[^,]\s*$/)}, sub{"$_[0] with comma must have the second parameter"}], 
Packit 667938
Packit 667938
       'pagetop[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'bodytag[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'pagefoot[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'addhead[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'rrdrowcount[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'rrdrowcount30m[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'rrdrowcount2h[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'rrdrowcount1d[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'rrdhwrras[]' =>
Packit 667938
       [sub{$_[0] =~ /^RRA:(HWPREDICT|SEASONAL|DEVPREDICT|DEVSEASONAL|FAILURES):\S+(\s+RRA:(HWPREDICT|SEASONAL|DEVPREDICT|DEVSEASONAL|FAILURES):\S+)*$/},
Packit 667938
        sub{"This does not look like rrdtool HW RRAs. Check the rrdcreate manual page for inspiration. ($_[0])"}],
Packit 667938
Packit 667938
       'extension[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}], #what ever the user chooses.
Packit 667938
Packit 667938
       'unscaled[]' => 
Packit 667938
       [sub{$_[0] =~ /[ndwmy]+/i}, sub{"Must be a string of [n]one, [d]ay, [w]eek, [m]onth, [y]ear"}],
Packit 667938
Packit 667938
       'weekformat[]' => 
Packit 667938
       [sub{$_[0] =~ /[UVW]/}, sub{"Must be either W, V, or U"}],
Packit 667938
Packit 667938
       'withpeak[]' =>
Packit 667938
       [sub{$_[0] =~ /[ndwmy]+/i}, sub{"Must be a string of [n]one, [d]ay, [w]eek, [m]onth, [y]ear"}],
Packit 667938
Packit 667938
       'suppress[]' =>
Packit 667938
       [sub{$_[0] =~ /[ndwmy]+/i}, sub{"Must be a string of [n]one, [d]ay, [w]eek, [m]onth, [y]ear"}],
Packit 667938
Packit 667938
       'xsize[]' =>
Packit 667938
       [sub{((int($_[0]) >= 30) && (int($_[0]) <= 600))}, sub{"$_[0] must be between 30 and 600 pixels"}],
Packit 667938
Packit 667938
       'ysize[]' =>
Packit 667938
       [sub{(int($_[0]) >= 30)}, sub{"Must be >= 30 pixels"}],
Packit 667938
Packit 667938
       'ytics[]' =>
Packit 667938
       [sub{(int($_[0]) >= 1) }, sub{"Must be >= 1"}],
Packit 667938
Packit 667938
       'yticsfactor[]' =>
Packit 667938
       [sub{$_[0] =~ /[-+0-9.efg]+/}, sub{"Should be a numerical value"}],
Packit 667938
Packit 667938
       'factor[]' =>
Packit 667938
       [sub{$_[0] =~ /[-+0-9.efg]+/}, sub{"Should be a numerical value"}],
Packit 667938
Packit 667938
       'step[]'  =>
Packit 667938
       [sub{(int($_[0]) >= 0)}, sub{"$_[0] must be > 0"}],
Packit 667938
Packit 667938
       'timezone[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'options[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'colours[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'background[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'kilo[]' => 
Packit 667938
       [sub{($_[0] =~ /^[0-9]+$/)}, sub{"$_[0] must be a Integer Number"}],
Packit 667938
       #define whatever k should be (1000, 1024, ???)
Packit 667938
Packit 667938
       'kmg[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'pngtitle[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'ylegend[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'shortlegend[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legend1[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legend2[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legend3[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legend4[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legend5[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legendi[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'legendo[]' =>
Packit 667938
       [sub{1}, sub{"Internal Error"}],
Packit 667938
Packit 667938
       'setenv[]' => 
Packit 667938
       [sub{$_[0] =~ /^(?:[-\w]+=\"[^"]*"(?:\s+|$))+$/},
Packit 667938
        sub{"$_[0] must be XY=\"dddd\" AASD=\"kjlkj\" ... "}],
Packit 667938
Packit 667938
Packit 667938
       'xzoom[]' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'yzoom[]' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'xscale[]' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'yscale[]' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'threshdir' =>
Packit 667938
       [sub{$_[0] && (-d $_[0])}, sub{"Threshold directory $_[0] does not exist"}],
Packit 667938
 
Packit 667938
       'threshhyst' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'hwthreshhyst' =>
Packit 667938
       [sub{($_[0] =~ /^[0-9]+(?:\.[0-9]+)?$/)},
Packit 667938
        sub{"$_[0] must be a Number xxx.xxx"}],
Packit 667938
Packit 667938
       'threshmailserver' =>
Packit 667938
       [sub{$_[0] && gethostbyname($_[0])}, sub{"Unknown mailserver hostname $_[0]"}],
Packit 667938
Packit 667938
       'threshmailsender' =>
Packit 667938
       [sub{$_[0] && ($_[0] =~ /\S+\@\S+/)}, sub{"ThreshMailAddress $_[0] does not look like an email address at all"}],
Packit 667938
Packit 667938
       'threshmini[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'threshmino[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'threshmaxi[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'threshmaxo[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'threshdesc[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'threshprogi[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'threshprogo[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'threshprogoki[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'threshprogoko[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'threshmailaddress[]' =>
Packit 667938
       [sub{$_[0] && ($_[0] =~ /\S+\@\S+/)}, sub{"ThreshMailAddress $_[0] does not look like an email address at all"}],
Packit 667938
Packit 667938
       'hwthreshmini[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'hwthreshmino[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'hwthreshmaxi[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'hwthreshmaxo[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'hwthreshdesc[]' =>
Packit 667938
       [sub{1}, sub{"Internal Threshold Config Error"}],
Packit 667938
Packit 667938
       'hwthreshprogi[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'hwthreshprogo[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'hwthreshprogoki[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'hwthreshprogoko[]' =>
Packit 667938
       [sub{$_[0] && (-e $_[0])}, sub{"Threshold program $_[0] cannot be executed"}],
Packit 667938
Packit 667938
       'hwthreshmailaddress[]' =>
Packit 667938
       [sub{$_[0] && ($_[0] =~ /\S+\@\S+/)}, sub{"ThreshMailAddress $_[0] does not look like an email address at all"}],
Packit 667938
Packit 667938
       'timestrpos[]' => 
Packit 667938
       [sub{$_[0] =~ /^(no|[lr][ul])$/i}, sub{"Must be a string of NO, LU, RU, LL, RL"}],
Packit 667938
Packit 667938
       'timestrfmt[]' => 
Packit 667938
       [sub{1}, sub{"Internal Error"}] #what ever the user chooses.
Packit 667938
);
Packit 667938
Packit 667938
Packit 667938
# config file reading
Packit 667938
Packit 667938
sub readcfg ($$$$;$$) {
Packit 667938
    my $cfgfile = shift;
Packit 667938
    my $routers = shift;
Packit 667938
    my $cfg = shift;
Packit 667938
    my $rcfg = shift;
Packit 667938
    my $extprefix = shift || '';
Packit 667938
    my $extrules = shift;
Packit 667938
    my ($first,$second,$key,$userules);
Packit 667938
    my (%seen);
Packit 667938
    my (%pre,%post,%deflt,%defaulted);
Packit 667938
    unless ($cfgfile) {
Packit 667938
        die "ERROR: readfg: no configfile specified\n";
Packit 667938
    }
Packit 667938
    unless (ref($routers) eq 'ARRAY' and ref($cfg) eq 'HASH'
Packit 667938
            and ref($rcfg) eq 'HASH') {
Packit 667938
        die "ERROR: readcfg called with wrong arguments\n";
Packit 667938
    }
Packit 667938
    if ($extprefix and ref($extrules) ne 'HASH') {
Packit 667938
        die "ERROR: readcfg called with wrong args for mrtg extension\n";
Packit 667938
    }
Packit 667938
    my $hand;
Packit 667938
    my $file;
Packit 667938
    my @filestack;
Packit 667938
    local *CFG;
Packit 667938
    if ($cfgfile eq '-'){$cfgfile = '<&STDIN'};
Packit 667938
    open (CFG, $cfgfile) || die "ERROR: unable to open config file: $cfgfile\n";
Packit 667938
    $hand = *CFG;
Packit 667938
    my @handstack;
Packit 667938
    my $nextfile = $cfgfile;
Packit 667938
    my %routerhash;
Packit 667938
    while (1) {        
Packit 667938
        if (eof $hand || not defined ($_ = <$hand>) ) {
Packit 667938
                close $hand;
Packit 667938
                if (scalar @handstack){
Packit 667938
                        $hand = pop @handstack;
Packit 667938
                        $nextfile = pop @filestack;
Packit 667938
                        next;
Packit 667938
                } else {
Packit 667938
                        last;
Packit 667938
                }
Packit 667938
        }
Packit 667938
        $file=$nextfile;
Packit 667938
        chomp;
Packit 667938
        my $line = $.;
Packit 667938
        if (/^include:\s*(.*?\S)\s*$/i){
Packit 667938
                my $newhandle;
Packit 667938
                my @nextfiles;
Packit 667938
                $nextfile = $1;
Packit 667938
                if( $nextfile =~ /\*/ ) {
Packit 667938
                    @nextfiles = glob( $nextfile );
Packit 667938
                    @nextfiles = glob( ($cfgfile =~ m#(.+)${MRTG_lib::SL}[^${MRTG_lib::SL}]+$#)[0] . ${MRTG_lib::SL} . $nextfile )
Packit 667938
                        if(!@nextfiles);	
Packit 667938
                } else { 
Packit 667938
                    $nextfile =  ($cfgfile =~ m#(.+)${MRTG_lib::SL}[^${MRTG_lib::SL}]+$#)[0] . ${MRTG_lib::SL} . $nextfile 
Packit 667938
                        if(!-r $nextfile);
Packit 667938
                    @nextfiles = ( $nextfile ); 
Packit 667938
                }
Packit 667938
                foreach $nextfile ( @nextfiles ) {
Packit 667938
                    open my $newhandle, '<', $nextfile or die "ERROR: unable to open include file: $nextfile\n";
Packit 667938
                    push @handstack, $hand;
Packit 667938
                    push @filestack, $file;
Packit 667938
                    $hand = $newhandle;
Packit 667938
                    $file = $nextfile;
Packit 667938
                }
Packit 667938
                next;
Packit 667938
        }
Packit 667938
Packit 667938
        debug('cfg',"$file\[$.\]: $_");
Packit 667938
                
Packit 667938
        s/\t/ /g;               #replace tab by space
Packit 667938
        s/\r$//;                # kill dos newlines ...
Packit 667938
        s/ +$//g;               #remove space at the end of the line
Packit 667938
        next if /^ *\#/;       #ignore comment lines
Packit 667938
        next if /^ *$/;        #ignore empty lines
Packit 667938
        # oops spelling error
Packit 667938
        s/^supress/suppress/gi;
Packit 667938
Packit 667938
                
Packit 667938
        # the line we got starts with white space so it is to be appended to what ever
Packit 667938
        # was on the previous line.
Packit 667938
Packit 667938
        if (defined $first && /^\s+(.*\S)\s*$/) {
Packit 667938
            if (defined $second) {
Packit 667938
               $second eq '^' && do { $pre{$first} .= "\n".$1; next};
Packit 667938
               $second eq '$' && do { $post{$first} .= "\n".$1; next};
Packit 667938
               $second eq '_' && do { $deflt{$first} .= "\n".$1; next};
Packit 667938
               $$rcfg{$first}{$second} .= " ".$1;
Packit 667938
            } else {
Packit 667938
               $$cfg{$first} .= "\n".$1;
Packit 667938
            }
Packit 667938
            next;
Packit 667938
        }
Packit 667938
    
Packit 667938
        if (defined $first && defined $second && defined $post{$first} && ($second !~ /^[\$^_]$/)) {
Packit 667938
            if (defined $defaulted{$first}{$second}) {
Packit 667938
                $$rcfg{$first}{$second} = $post{$first};
Packit 667938
                delete $defaulted{$first}{$second};
Packit 667938
            } else {
Packit 667938
                $$rcfg{$first}{$second} .= ( defined $$cfg{nospacechar} and $post{$first} =~ /(.*)\Q$$cfg{nospacechar}\E$/) ? $1 : " ".$post{$first} ;
Packit 667938
            }
Packit 667938
        }
Packit 667938
Packit 667938
        if (defined $first and $first =~ m/^([^*]+)\*(.+)$/) {
Packit 667938
            $userules = ($1 eq $extprefix ? $extrules : '');
Packit 667938
        } else {
Packit 667938
            $userules = \%mrtgrules;
Packit 667938
        }
Packit 667938
Packit 667938
        if ($first && defined $deflt{$first} && ($second eq '_')) {
Packit 667938
            quickcheck($first,$second,$deflt{$first},$file,$line,$userules)
Packit 667938
        } elsif ($first && $second && ($second !~ /^[\$^_]$/)) {
Packit 667938
            quickcheck($first,$second,$$rcfg{$first}{$second},$file,$line,$userules)
Packit 667938
        } elsif ($first && not $second) {
Packit 667938
            quickcheck($first,0,$$cfg{$first},$file, $line,$userules)
Packit 667938
        }
Packit 667938
Packit 667938
        if (/^([A-Za-z0-9*]+)\[(\S+)\]\s*:\s*(.*\S?)\s*$/) {
Packit 667938
            $first = lc($1);
Packit 667938
            $second = lc($2);
Packit 667938
            # For us spelling-handicapped Americans. ;)
Packit 667938
            # James Overbeck, grendel@gmo.jp, 2003/01/19
Packit 667938
            if ($first eq 'colors') { $first = 'colours' };
Packit 667938
            if ($second eq '^') {
Packit 667938
                if ($3 ne '') {
Packit 667938
                    $pre{$first}=$3;
Packit 667938
                } else {
Packit 667938
                    delete $pre{$first};
Packit 667938
                }
Packit 667938
                next;
Packit 667938
            }
Packit 667938
            if ($second eq '$') {
Packit 667938
                if ($3 ne '') {
Packit 667938
                    $post{$first}=$3;
Packit 667938
                } else {
Packit 667938
                    delete $post{$first};
Packit 667938
                }
Packit 667938
                next;
Packit 667938
            }
Packit 667938
            if ($second eq '_') {
Packit 667938
                if ($3 ne '') {
Packit 667938
                    $deflt{$first}=$3;
Packit 667938
                } else {
Packit 667938
                    delete $deflt{$first};
Packit 667938
                }
Packit 667938
                next;
Packit 667938
            }
Packit 667938
Packit 667938
            if (not defined $routerhash{$second}) {
Packit 667938
                    push (@{$routers}, $second);
Packit 667938
                    $routerhash{$second} = 1;
Packit 667938
            }
Packit 667938
      
Packit 667938
            # make sure that default tags spring into existance upon first 
Packit 667938
            # call of a router
Packit 667938
Packit 667938
            foreach $key (keys %deflt) {
Packit 667938
                if (! defined $$rcfg{$key}{$second}) {
Packit 667938
                    $$rcfg{$key}{$second} = $deflt{$key};
Packit 667938
                    $defaulted{$key}{$second} = 1;
Packit 667938
                }
Packit 667938
            }
Packit 667938
Packit 667938
            # make sure that prefix-only tags spring into existance upon first 
Packit 667938
            # call of a router
Packit 667938
Packit 667938
            foreach $key (keys %pre) {
Packit 667938
                if (! defined $$rcfg{$key}{$second}) {
Packit 667938
                    delete $defaulted{$key}{$second} if $defaulted{$key}{$second};
Packit 667938
                    $$rcfg{$key}{$second} = ( defined $$cfg{nospacechar} && $pre{$key} =~ m/(.*)\Q$$cfg{nospacechar}\E$/ ) ? $1 : $pre{$key}." ";
Packit 667938
                }
Packit 667938
            }
Packit 667938
Packit 667938
            if ($seen{$first}{$second}) {
Packit 667938
                die ("ERROR: Line $line ($_) in CFG file ($file)\n".
Packit 667938
                     "contains a duplicate definition for $first\[$second].\n".
Packit 667938
                     "First definition is on line $seen{$first}{$second}\n")
Packit 667938
            } else {
Packit 667938
                $seen{$first}{$second} = $line;
Packit 667938
            }
Packit 667938
Packit 667938
            if ($defaulted{$first}{$second}) {
Packit 667938
                $$rcfg{$first}{$second} = '';
Packit 667938
                delete $defaulted{$first}{$second};
Packit 667938
            }
Packit 667938
            $$rcfg{$first}{$second} .= $3;
Packit 667938
Packit 667938
            next;
Packit 667938
Packit 667938
        }
Packit 667938
        if (/^(\S+):\s*(.*\S)\s*$/) {
Packit 667938
            $first = lc($1);    
Packit 667938
            $$cfg{$first} = $2;
Packit 667938
            $second = '';
Packit 667938
            next;
Packit 667938
        }
Packit 667938
        die "ERROR: Line $line ($_) in CFG file ($file)  does not make sense\n";
Packit 667938
    }
Packit 667938
Packit 667938
    # append $ stuff to the very last tag in cfg file if necessary 
Packit 667938
    if (defined $first && defined $second && defined $post{$first} && ($second !~ /^[\$^_]$/)) {
Packit 667938
        if ($defaulted{$first}{$second}) {
Packit 667938
            $$rcfg{$first}{$second} = $post{$first};
Packit 667938
            delete $defaulted{$first}{$second};
Packit 667938
        } else {
Packit 667938
            $$rcfg{$first}{$second} .= 
Packit 667938
	      ( defined $$cfg{'nospacechar'} && $post{$first} =~ /(.*)\Q$$cfg{nospacechar}\E$/ ) ? $1 : " ".$post{$first} ;      
Packit 667938
        }
Packit 667938
    }
Packit 667938
  
Packit 667938
    #check the last input line
Packit 667938
    if ($first =~ m/^([^*]+)\*(.+)$/) {
Packit 667938
        $userules = ($1 eq $extprefix ? $extrules : '');
Packit 667938
    } else {
Packit 667938
        $userules = \%mrtgrules;
Packit 667938
    }
Packit 667938
    if ($first && defined $deflt{$first} && ($second eq '_')) {
Packit 667938
        quickcheck($first,$second,$deflt{$first},$file,$.,$userules)
Packit 667938
    } elsif ($first && $second && ($second !~ /^[\$^_]$/)) {
Packit 667938
        quickcheck($first,$second,$$rcfg{$first}{$second},$file,$.,$userules)
Packit 667938
    } elsif ($first && not $second) {
Packit 667938
        quickcheck($first,0,$$cfg{$first},$file,$.,$userules)
Packit 667938
    }
Packit 667938
Packit 667938
    close (CFG);
Packit 667938
Packit 667938
	# Check for an environment setting for RRDCACHED_ADDRESS
Packit 667938
	# Steve Shipway, Sep 2010
Packit 667938
	if( $ENV{RRDCACHED_ADDRESS} and not exists $cfg->{ rrdcached } ) {
Packit 667938
		warn("WARNING: Using environment variable RRDCACHED_ADDRESS\n");
Packit 667938
		$cfg->{ rrdcached } = $ENV{RRDCACHED_ADDRESS};
Packit 667938
        quickcheck('rrdcached',0,$ENV{RRDCACHED_ADDRESS},'Environment variable RRDCACHED_ADDRESS','n/a',\%mrtgrules);
Packit 667938
	}
Packit 667938
	if( exists $cfg->{ rrdcached } ) {
Packit 667938
        warn ("WARNING: You are running with RRDCached enabled (".$cfg->{ rrdcached }.").  This will disable all Threshold checking, since RRDCached does not support updatev and an update/fetch will cancel out the caching benefits.\n");
Packit 667938
        if( $cfg->{ rrdcached } !~ /^unix:/ ) {
Packit 667938
            warn("WARNING: You are running RRDCached in TCP mode.  This means that it will use its own Base Directory instead of WorkDir for storing the RRD files.  Also, changes to MaxBytes and DS Type will not be actioned after the RRD file has been created.\n");
Packit 667938
        }
Packit 667938
	}
Packit 667938
    if ($cfg->{enablesnmpv3} and $cfg->{enablesnmpv3} eq 'yes' and eval {local $SIG{__DIE__}; require Net_SNMP_util} ) {
Packit 667938
        import Net_SNMP_util;
Packit 667938
    } else {
Packit 667938
        require SNMP_util;
Packit 667938
        import SNMP_util;
Packit 667938
    }
Packit 667938
}
Packit 667938
Packit 667938
# quick checks
Packit 667938
Packit 667938
sub quickcheck ($$$$$$) {
Packit 667938
    my ($first,$second,$arg,$file,$line,$rules) = @_;
Packit 667938
    return unless ref($rules) eq 'HASH';
Packit 667938
    my $braces = $second ? '[]':'';
Packit 667938
    if (exists $rules->{$first.$braces}) {
Packit 667938
        if (&{$rules->{$first.$braces}[0]}($arg)) {
Packit 667938
            return 1;
Packit 667938
        } else {
Packit 667938
            if ($second) {
Packit 667938
                die "ERROR: CFG Error in \"$first\[$second\]\", file $file line $line: ".
Packit 667938
                  &{$rules->{$first.$braces}[1]}($arg)."\n\n"; 
Packit 667938
            } else {
Packit 667938
                die "ERROR: CFG Error in \"$first\", file $file line $line: ".
Packit 667938
                  &{$rules->{$first.$braces}[1]}($arg)."\n\n"; 
Packit 667938
            } 
Packit 667938
        }
Packit 667938
    }
Packit 667938
    die "ERROR: CFG Error Unknown Option \"$first\" in file $file on line $line or above.\n".
Packit 667938
      "           Check /usr/share/doc/mrtg/mrtg-reference.txt.gz for Help\n\n";
Packit 667938
}
Packit 667938
Packit 667938
# complex config checks
Packit 667938
Packit 667938
sub mkdirhier ($){
Packit 667938
    my @dirs = split /\Q${MRTG_lib::SL}\E+/, shift;
Packit 667938
    my $path = "";
Packit 667938
    while (@dirs){
Packit 667938
	$path .= shift @dirs;
Packit 667938
	$path .= ${MRTG_lib::SL};
Packit 667938
	if (! -d $path){
Packit 667938
                warn ("WARNING: $path did not exist I will create it now\n");
Packit 667938
		mkdir $path, 0777  or die ("ERROR: mkdir $path: $!\n");
Packit 667938
	}
Packit 667938
    }
Packit 667938
}
Packit 667938
Packit 667938
sub cfgcheck ($$$$;$) {
Packit 667938
    my $routers = shift;
Packit 667938
    my $cfg = shift;
Packit 667938
    my $rcfg = shift;
Packit 667938
    my $target = shift;
Packit 667938
    my $opts = shift || {};
Packit 667938
    my ($rou, $confname, $one_option);
Packit 667938
    # Target index hash. Keys are "int:community@router" target definition
Packit 667938
    # strings and values are indices of the @$target array. Used to avoid
Packit 667938
    # duplicate entries in @$target.
Packit 667938
    my $targIndex = { };
Packit 667938
    my $error="no";
Packit 667938
    my(@known_options) = qw(growright bits noinfo absolute gauge nopercent avgpeak derive
Packit 667938
			    integer perhour perminute transparent dorelpercent 
Packit 667938
			    unknaszero withzeroes noborder noarrow noi noo
Packit 667938
			    nobanner nolegend logscale secondmean pngdate printrouter expscale);
Packit 667938
Packit 667938
    snmpmapOID('hrSystemUptime' => '1.3.6.1.2.1.25.1.1');
Packit 667938
Packit 667938
    if (defined $$cfg{workdir}) {
Packit 667938
        die ("ERROR: WorkDir must not contain spaces when running on Windows. (Yeat another reason to get Linux)\n")
Packit 667938
                if ($OS eq 'NT' or $OS eq 'OS2') and $$cfg{workdir} =~ /\s/;
Packit 667938
        ensureSL(\$$cfg{workdir});
Packit 667938
        $$cfg{logdir}=$$cfg{htmldir}=$$cfg{imagedir}=$$cfg{workdir};
Packit 667938
        mkdirhier "$$cfg{workdir}"  unless $opts->{check};
Packit 667938
        
Packit 667938
    } elsif ( not (defined $$cfg{logdir} or defined $$cfg{htmldir} or defined $$cfg{imagedir})) {
Packit 667938
          die ("ERROR: \"WorkDir\" not specified in mrtg config file\n");
Packit 667938
	  $error = "yes";
Packit 667938
    } else {
Packit 667938
        if (! defined $$cfg{logdir}) {
Packit 667938
            warn ("WARNING: \"LogDir\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        } else {
Packit 667938
          ensureSL(\$$cfg{logdir});
Packit 667938
          mkdirhier $$cfg{logdir} unless $opts->{check};
Packit 667938
        }
Packit 667938
        if (! defined $$cfg{htmldir}) {
Packit 667938
            warn ("WARNING: \"HtmlDir\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        } else {
Packit 667938
          ensureSL(\$$cfg{htmldir});
Packit 667938
          mkdirhier $$cfg{htmldir}  unless $opts->{check};
Packit 667938
        }
Packit 667938
        if (! defined $$cfg{imagedir}) {
Packit 667938
            warn ("WARNING: \"ImageDir\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        } else {
Packit 667938
          ensureSL(\$$cfg{imagedir});
Packit 667938
          mkdirhier $$cfg{imagedir}  unless $opts->{check};
Packit 667938
        }
Packit 667938
    }
Packit 667938
    if ($cfg->{threshmailserver} and not $cfg->{threshmailsender}){
Packit 667938
	warn ("WARNING: If \"ThreshMailServer\" is defined, then \"ThreshMailSender\" must be defined too.\n");
Packit 667938
        $error = "yes";
Packit 667938
    }
Packit 667938
    if ($cfg->{threshmailsender} and not $cfg->{threshmailserver}){
Packit 667938
	warn ("WARNING: If \"ThreshMailSender\" is defined, then \"ThreshMailServer\" must be defined too.\n");
Packit 667938
        $error = "yes";
Packit 667938
    }
Packit 667938
    # default ThreshHyst to 0.1 if ThreshDir is defined
Packit 667938
    if ($cfg->{threshdir}){
Packit 667938
        $cfg->{threshhyst} = 0.1 unless $cfg->{threshhyst};
Packit 667938
    }
Packit 667938
    # build relativ path from htmldir to image dir.
Packit 667938
    my @htmldir = split /\Q${MRTG_lib::SL}\E+/, $$cfg{htmldir};
Packit 667938
    my @imagedir =  split /\Q${MRTG_lib::SL}\E+/, $$cfg{imagedir};
Packit 667938
    while (scalar @htmldir > 0 and $htmldir[0] eq $imagedir[0]) {
Packit 667938
    	shift @htmldir; shift @imagedir;
Packit 667938
    }
Packit 667938
    # this is for the webpages so we use / path separator always
Packit 667938
    $$cfg{imagehtml} = "";
Packit 667938
    foreach my $dir ( @htmldir ) {
Packit 667938
        $$cfg{imagehtml} .= "../" if $dir;
Packit 667938
    }
Packit 667938
    map {$$cfg{imagehtml} .= "$_/" } @imagedir;
Packit 667938
    # relative path is built
Packit 667938
    debug('dir', "imagehtml = $$cfg{imagehtml}");
Packit 667938
Packit 667938
    $SNMP_util::CacheFile = "$$cfg{'logdir'}oid-mib-cache.txt";
Packit 667938
    $Net_SNMP_util::CacheFile = "$$cfg{'logdir'}oid-mib-cache.txt";
Packit 667938
Packit 667938
    if (defined $$cfg{loadmibs}) {
Packit 667938
        my($mibFile);
Packit 667938
        foreach $mibFile (split /[,\s]+/, $$cfg{loadmibs}) {
Packit 667938
            snmpQueue_MIB_File($mibFile);
Packit 667938
        }
Packit 667938
    }
Packit 667938
    if(defined $$cfg{pathadd}){
Packit 667938
        ensureSL(\$$cfg{pathadd});        
Packit 667938
        $ENV{PATH} = "$$cfg{pathadd}${MRTG_lib::PS}$ENV{PATH}";
Packit 667938
    }
Packit 667938
    if(defined $$cfg{libadd}){
Packit 667938
        ensureSL(\$$cfg{libadd});
Packit 667938
        debug('eval',"libadd $$cfg{libadd}\n");
Packit 667938
    	local $SIG{__DIE__};
Packit 667938
        eval "use lib qw( $$cfg{libadd} )";
Packit 667938
    	my @match;
Packit 667938
	    foreach my $dir (@INC){
Packit 667938
		    push @match, $dir if -f "$dir/RRDs.pm";
Packit 667938
    	}
Packit 667938
	    warn "WARN: found several copies of RRDs.pm in your path: ".
Packit 667938
            (join ", ", @match)." I will be using $match[0]. This could ".
Packit 667938
        	"be a problem if this is an old copy and you think I would be using a newer one!\n"
Packit 667938
		    if $#match > 0;
Packit 667938
    }
Packit 667938
    $$cfg{logformat} = 'rateup' unless defined $$cfg{logformat};
Packit 667938
Packit 667938
    if($$cfg{logformat} eq 'rrdtool') {
Packit 667938
        my ($name);
Packit 667938
        if ($MRTG_lib::OS eq 'NT' or $MRTG_lib::OS eq 'OS2'){
Packit 667938
            $name = "rrdtool.exe";
Packit 667938
        } elsif ($MRTG_lib::OS eq 'NW'){
Packit 667938
            $name = "rrdtool.nlm";
Packit 667938
        } else {
Packit 667938
            $name = "rrdtool";
Packit 667938
        }
Packit 667938
        foreach my $path (split /\Q${MRTG_lib::PS}\E/, $ENV{PATH}) {
Packit 667938
            ensureSL(\$path);
Packit 667938
            -f "$path$name" && do { 
Packit 667938
                $$cfg{'rrdtool'} = "$path$name";
Packit 667938
                last;}
Packit 667938
        };
Packit 667938
        die "ERROR: could not find $name. Use PathAdd: in mrtg.cfg to help mrtg find rrdtool\n" 
Packit 667938
                unless defined $$cfg{rrdtool};
Packit 667938
        debug ('rrd',"found rrdtool in $$cfg{rrdtool}");
Packit 667938
        my $found;
Packit 667938
        foreach my $path (@INC) {
Packit 667938
            ensureSL(\$path);
Packit 667938
            -f "${path}RRDs.pm" && do { 
Packit 667938
                $found=1;
Packit 667938
                last;}
Packit 667938
        };
Packit 667938
        die "ERROR: could not find RRDs.pm. Use LibAdd: in mrtg.cfg to help mrtg find RRDs.pm\n" 
Packit 667938
                unless defined $found;
Packit 667938
    }
Packit 667938
    if (defined $$cfg{snmpoptions}) {
Packit 667938
	   debug('eval',"redef snmpotions $cfg->{snmpoptions}");
Packit 667938
	   local $SIG{__DIE__};
Packit 667938
           $cfg->{snmpoptions} = eval('{'.$cfg->{snmpoptions}.'}');
Packit 667938
    }
Packit 667938
Packit 667938
    # default interval is 5 minutes
Packit 667938
    if ($cfg->{interval} and $cfg->{interval} =~ /(\d+)(?::(\d+))?/){
Packit 667938
	$cfg->{interval} = $1;
Packit 667938
	$cfg->{interval} += $2/60.0 if $2;
Packit 667938
    } else {
Packit 667938
        $cfg->{interval} = 5;
Packit 667938
    }
Packit 667938
    unless ($$cfg{logformat} eq 'rrdtool') {
Packit 667938
        # interval has to be 5 minutes at least without userrdtool
Packit 667938
        if ($$cfg{interval} < 5.0) {
Packit 667938
            die "ERROR: CFG Error in \"Interval\": should be at least 5 Minutes (unless you use rrdtool)";
Packit 667938
        }
Packit 667938
    }
Packit 667938
Packit 667938
    # Check for a Conversion Code file and evaluate its contents, which
Packit 667938
    # should consist of one or more subroutine definitions. The code goes
Packit 667938
    # into the MRTGConversion name space.
Packit 667938
    if( exists $cfg->{ conversioncode } ) {
Packit 667938
        open CONV, $cfg->{ conversioncode }
Packit 667938
            or die "ERROR: Can't open file $cfg->{ conversioncode }\n";
Packit 667938
        my $code = "local \$SIG{__DIE__};package MRTGConversion;\n". join( '', <CONV> ) . "1;\n";
Packit 667938
        close CONV;
Packit 667938
        debug('eval',"covnversioncode  $cfg->{ conversioncode }");
Packit 667938
        die "ERROR: File $cfg->{ conversioncode } conversion code evaluation failed\n$@\n"
Packit 667938
            unless eval $code;
Packit 667938
    }
Packit 667938
Packit 667938
    my $thresh_error;
Packit 667938
Packit 667938
    # sendtographite directive parsing
Packit 667938
    # sanity check for <ip>,<port> or <dnsname>,<port>
Packit 667938
    if ($cfg->{sendtographite}){
Packit 667938
      my @a = split ",",$cfg->{sendtographite};
Packit 667938
Packit 667938
      # is this an IP address?
Packit 667938
      unless($a[0] =~ /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/) { 
Packit 667938
        # maybe we were passed a DNS name?
Packit 667938
        unless(gethostbyname($a[0])) { die "ERROR: cannot find graphite server name $a[0] in DNS\n"; }
Packit 667938
      }
Packit 667938
      
Packit 667938
      # if we got this far, now check the port number range
Packit 667938
      unless($a[1] > 0 and $a[1] < 65536) {
Packit 667938
        die "ERROR: invalid port number $a[1] in sendtographite directive\n";
Packit 667938
      }
Packit 667938
    }
Packit 667938
Packit 667938
    foreach $rou (@$routers) {
Packit 667938
        # and now for the testing
Packit 667938
	if (defined $rcfg->{threshmailaddress}{$rou}){
Packit 667938
	    if (not defined  $cfg->{threshmailserver} and not $thresh_error){
Packit 667938
		warn (qq{ERROR: ThreshMailAddress[$rou]: specified without "ThreshMailServer:"});
Packit 667938
		$error = "yes";
Packit 667938
		$thresh_error = "yes";
Packit 667938
            }
Packit 667938
	    # the dependency between sender and server is taken care of already
Packit 667938
	}	
Packit 667938
	if (! defined $rcfg->{snmpoptions}{$rou}) {
Packit 667938
		$rcfg->{snmpoptions}{$rou} = {%{$cfg->{snmpoptions}}}
Packit 667938
		  if defined $cfg->{snmpoptions};
Packit 667938
    	} else {
Packit 667938
                debug('eval',"redef snmpoptions[$rou] $rcfg->{snmpoptions}{$rou}");
Packit 667938
 		local $SIG{__DIE__};
Packit 667938
    	        $rcfg->{snmpoptions}{$rou} = eval('{'.$rcfg->{snmpoptions}{$rou}.'}');
Packit 667938
        }
Packit 667938
        $rcfg->{snmpoptions}{$rou}{avoid_negative_request_ids} = 1;
Packit 667938
        # $rcfg->{snmpoptions}{$rou}{domain} = 'udp';
Packit 667938
        
Packit 667938
        if (! defined $$rcfg{"title"}{$rou}) {
Packit 667938
            warn ("WARNING: \"Title[$rou]\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        }
Packit 667938
        if (defined $$rcfg{'directory'}{$rou} and $$rcfg{'directory'}{$rou} ne "") {
Packit 667938
            # They specified a directory for this router.  Append the
Packit 667938
            # pathname seperator to it (so that it can either be present or
Packit 667938
            # absent, and the rules for including it are the same).
Packit 667938
	    ensureSL(\$$rcfg{'directory'}{$rou});
Packit 667938
            for my $x (qw(imagedir logdir htmldir)) {
Packit 667938
                mkdirhier $$cfg{$x}.$$rcfg{directory}{$rou}  unless $opts->{check};
Packit 667938
            }                   
Packit 667938
            $$rcfg{'directory_web'}{$rou} = $$rcfg{'directory'}{$rou};
Packit 667938
	    $$rcfg{'directory_web'}{$rou} =~ s/\Q${MRTG_lib::SL}\E+/\//g;
Packit 667938
            debug('dir', "directory for $rou '$$rcfg{'directory_web'}{$rou}'");
Packit 667938
        } else {
Packit 667938
                $$rcfg{'directory'}{$rou}="";
Packit 667938
                $$rcfg{'directory_web'}{$rou}="";
Packit 667938
        }
Packit 667938
Packit 667938
     	if (defined $$rcfg{"pagetop"}{$rou}) {
Packit 667938
            $$rcfg{"pagetop"}{$rou} =~ s/\\n/\n/g;
Packit 667938
        }
Packit 667938
Packit 667938
Packit 667938
        if (defined $$rcfg{"pagefoot"}{$rou}) {
Packit 667938
            # allow for linebreaks
Packit 667938
            $$rcfg{"pagefoot"}{$rou} =~ s/\\n/\n/g;
Packit 667938
        }
Packit 667938
 
Packit 667938
        $$rcfg{"maxbytes1"}{$rou} = $$rcfg{"maxbytes"}{$rou} unless defined $$rcfg{"maxbytes1"}{$rou};
Packit 667938
        $$rcfg{"maxbytes2"}{$rou} = $$rcfg{"maxbytes"}{$rou} unless defined $$rcfg{"maxbytes2"}{$rou};
Packit 667938
Packit 667938
        if (    not defined $$rcfg{"maxbytes"}{$rou} 
Packit 667938
            and not defined $$rcfg{"maxbytes1"}{$rou} 
Packit 667938
            and not defined $$rcfg{"maxbytes2"}{$rou}) {
Packit 667938
            warn ("WARNING: \"MaxBytes[$rou]\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        } else {
Packit 667938
Packit 667938
        if (not defined $$rcfg{"maxbytes1"}{$rou}) {
Packit 667938
            warn ("WARNING: \"MaxBytes1[$rou]\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        }
Packit 667938
        if (not defined $$rcfg{"maxbytes2"}{$rou}) {
Packit 667938
            warn ("WARNING: \"MaxBytes2[$rou]\" not specified\n");
Packit 667938
            $error = "yes";
Packit 667938
        }
Packit 667938
        }
Packit 667938
        # set default extension
Packit 667938
        if (! defined $$rcfg{"extension"}{$rou}) {
Packit 667938
            $$rcfg{"extension"}{$rou}="html";
Packit 667938
        }
Packit 667938
Packit 667938
        # set default size 
Packit 667938
        if (! defined $$rcfg{"xsize"}{$rou}) {
Packit 667938
            $$rcfg{"xsize"}{$rou}=400;
Packit 667938
        } 
Packit 667938
        if (! defined $$rcfg{"ysize"}{$rou}) {
Packit 667938
            $$rcfg{"ysize"}{$rou}=100;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{"ytics"}{$rou}) {
Packit 667938
            $$rcfg{"ytics"}{$rou}=4;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{"yticsfactor"}{$rou}) {
Packit 667938
            $$rcfg{"yticsfactor"}{$rou}=1;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{"factor"}{$rou}) {
Packit 667938
            $$rcfg{"factor"}{$rou}=1;
Packit 667938
        }
Packit 667938
    
Packit 667938
        if (defined $$rcfg{"options"}{$rou}) {      
Packit 667938
            my $opttemp = lc($$rcfg{"options"}{$rou});          
Packit 667938
            delete $$rcfg{"options"}{$rou};
Packit 667938
            foreach $one_option (split /[,\s]+/, $opttemp) {
Packit 667938
                if (grep {$one_option eq $_} @known_options) {
Packit 667938
                    $$rcfg{'options'}{$one_option}{$rou} = 1;
Packit 667938
                } else {
Packit 667938
                    warn ("WARNING: Option[$rou]: \"$one_option\" is unknown\n");
Packit 667938
                    $error="yes";
Packit 667938
                }
Packit 667938
            }
Packit 667938
	    if ($rcfg->{'options'}{derive}{$rou} and not $cfg->{logformat} eq 'rrdtool'){
Packit 667938
		    warn ("WARNING: Option[$rou]: \"derive\" works only with rrdtool logformat\n");
Packit 667938
		    $error="yes";
Packit 667938
	    }
Packit 667938
        }
Packit 667938
        #
Packit 667938
        # Check out routeruptime definition
Packit 667938
        #
Packit 667938
        if (defined $$rcfg{"routeruptime"}{$rou}) {
Packit 667938
            ($$rcfg{"community"}{$rou},$$rcfg{"router"}{$rou}) =
Packit 667938
              split(/@/,$$rcfg{"routeruptime"}{$rou});
Packit 667938
        }
Packit 667938
        #
Packit 667938
        # Check out target definition
Packit 667938
        #
Packit 667938
        if (defined $$rcfg{"target"}{$rou}) {
Packit 667938
            $$rcfg{targorig}{$rou} = $$rcfg{target}{$rou};
Packit 667938
	    debug ('tarp',"Starting $rou -> $$rcfg{target}{$rou}");
Packit 667938
            # Decide whether to turn on IPv6 support for this target.
Packit 667938
            # IPv6 support is turned on only if the EnableIPv6 global
Packit 667938
            # setting is yes and the IPv4Only per-target setting is no.
Packit 667938
            # If IPv6 is disabled, we set IPv4Only to true for all
Packit 667938
            # targets, thus disabling all IPv6-related code.
Packit 667938
            my $ipv4only = 1;
Packit 667938
            if ($$cfg{enableipv6} and $$cfg{enableipv6} eq 'yes') {
Packit 667938
                # IPv4Only is off by default
Packit 667938
                $ipv4only = 0
Packit 667938
                  unless (defined $$rcfg{ipv4only}{$rou}) && (lc($$rcfg{ipv4only}{$rou}) eq 'yes');
Packit 667938
            }
Packit 667938
	    # Check if nohc has been set, designating a low-speed interface
Packit 667938
	    # without working HC counters.  Default is that high-speed
Packit 667938
	    # counters exist.
Packit 667938
	    my $nohc = 0;
Packit 667938
	    $nohc = 1 if (defined $$rcfg{nohc}{$rou}) && (lc($$rcfg{nohc}{$rou}) eq 'yes');
Packit 667938
	    
Packit 667938
	    ( $$rcfg{target}{$rou}, $$rcfg{uniqueTarget}{$rou} ) =
Packit 667938
		targparser( $$rcfg{target}{$rou}, $target, $targIndex, $ipv4only, $rcfg->{snmpoptions}{$rou}, $nohc );
Packit 667938
        } else {
Packit 667938
            warn ("WARNING: I can't find a \"target[$rou]\" definition\n");
Packit 667938
            $error = "yes";
Packit 667938
        }
Packit 667938
Packit 667938
        # colors format: name#hexcol,
Packit 667938
        if (defined $$rcfg{"colours"}{$rou}) {
Packit 667938
            if ($$rcfg{'options'}{'dorelpercent'}{$rou}) {
Packit 667938
                if ($$rcfg{"colours"}{$rou} =~  
Packit 667938
                    /^([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})/ix) {
Packit 667938
                    ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
Packit 667938
                     $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
Packit 667938
                     $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
Packit 667938
                     $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou},
Packit 667938
                     $$rcfg{'col5'}{$rou}, $$rcfg{'rgb5'}{$rou}) = 
Packit 667938
                       ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
Packit 667938
                } else {
Packit 667938
                    warn ("WARNING: \"colours[$rou]\" for colour definition\n".
Packit 667938
                          "       use the format: Name#hexcolour, Name#Hexcolour,...\n",
Packit 667938
                          "       note, that dorelpercent requires 5 colours");
Packit 667938
                    $error="yes";
Packit 667938
                }
Packit 667938
            } else {            
Packit 667938
                if ($$rcfg{"colours"}{$rou} =~  
Packit 667938
                    /^([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})\s*,\s*
Packit 667938
                     ([^\#]+)(\#[0-9a-f]{6})/ix) {
Packit 667938
                    ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
Packit 667938
                     $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
Packit 667938
                     $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
Packit 667938
                     $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou}) =
Packit 667938
                       ($1, $2, $3, $4, $5, $6, $7, $8);
Packit 667938
                } else {
Packit 667938
                    warn "WARNING: \"colours[$rou]\" for colour definition\n".
Packit 667938
                          "       use the format: Name#hexcolour, Name#Hexcolour,...\n";
Packit 667938
                    $error="yes";
Packit 667938
                }
Packit 667938
            }
Packit 667938
        } else {            
Packit 667938
            if (defined $$rcfg{'options'}{'dorelpercent'}{$rou}) {
Packit 667938
                ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
Packit 667938
                 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
Packit 667938
                 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
Packit 667938
                 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou},
Packit 667938
                 $$rcfg{'col5'}{$rou}, $$rcfg{'rgb5'}{$rou}) = 
Packit 667938
                   ("GREEN","#00cc00",
Packit 667938
                    "BLUE","#0000ff",
Packit 667938
                    "DARK GREEN","#006600",
Packit 667938
                    "MAGENTA","#ff00ff",
Packit 667938
                    "AMBER","#ef9f4f");
Packit 667938
            } else {            
Packit 667938
                ($$rcfg{'col1'}{$rou}, $$rcfg{'rgb1'}{$rou},
Packit 667938
                 $$rcfg{'col2'}{$rou}, $$rcfg{'rgb2'}{$rou},
Packit 667938
                 $$rcfg{'col3'}{$rou}, $$rcfg{'rgb3'}{$rou},
Packit 667938
                 $$rcfg{'col4'}{$rou}, $$rcfg{'rgb4'}{$rou}) =
Packit 667938
                   ("GREEN","#00cc00",
Packit 667938
                    "BLUE","#0000ff",
Packit 667938
                    "DARK GREEN","#006600",
Packit 667938
                    "MAGENTA","#ff00ff");
Packit 667938
            }
Packit 667938
        }
Packit 667938
        # Background color, format: #rrggbb
Packit 667938
        if (! defined $$rcfg{'background'}{$rou}) {
Packit 667938
            $$rcfg{'background'}{$rou} = "#ffffff";
Packit 667938
        }
Packit 667938
        if ($$rcfg{'background'}{$rou} =~ /^(\#[0-9a-f]{6})/i) {
Packit 667938
            $$rcfg{'backgc'}{$rou} = "$1";
Packit 667938
        } else {
Packit 667938
            warn "WARNING: \"background[$rou]: ".
Packit 667938
                  "$$rcfg{'background'}{$rou}\" for colour definition\n".
Packit 667938
                  "       use the format: #rrggbb\n";
Packit 667938
            $error="yes";
Packit 667938
        }
Packit 667938
Packit 667938
        if (! defined  $$rcfg{'kilo'}{$rou}) {
Packit 667938
            $$rcfg{'kilo'}{$rou} = 1000;
Packit 667938
        }
Packit 667938
        if (defined $$rcfg{'kmg'}{$rou}) {
Packit 667938
            $$rcfg{'kmg'}{$rou} =~ s/\s+//g;
Packit 667938
        }
Packit 667938
Packit 667938
        if (! defined $$rcfg{'xzoom'}{$rou}) {
Packit 667938
            $$rcfg{'xzoom'}{$rou} = 1.0;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{'yzoom'}{$rou}) {
Packit 667938
            $$rcfg{'yzoom'}{$rou} = 1.0;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{'xscale'}{$rou}) {
Packit 667938
            $$rcfg{'xscale'}{$rou} = 1.0;
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{'yscale'}{$rou}) {
Packit 667938
            $$rcfg{'yscale'}{$rou} = 1.0;
Packit 667938
        }
Packit 667938
        if (defined $$rcfg{'options'}{'pngdate'}{$rou}) {
Packit 667938
            $$rcfg{'timestrpos'}{$rou} = 'RU';
Packit 667938
            $$rcfg{'timestrfmt'}{$rou} = $$rcfg{'timezone'}{$rou} ? "%Y-%m-%d %H:%M %Z" : "%Y-%m-%d %H:%M";
Packit 667938
            delete $$rcfg{'options'}{'pntdate'}{$rou}
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{'timestrpos'}{$rou}) {
Packit 667938
            $$rcfg{'timestrpos'}{$rou} = 'NO';
Packit 667938
        }
Packit 667938
        if (! defined $$rcfg{'timestrfmt'}{$rou}) {
Packit 667938
            $$rcfg{'timestrfmt'}{$rou} = "%Y-%m-%d %H:%M";
Packit 667938
        }
Packit 667938
        if ($error eq "yes") {        
Packit 667938
            die "ERROR: Please fix the error(s) in your config file\n";
Packit 667938
        }
Packit 667938
    }
Packit 667938
}
Packit 667938
Packit 667938
# make sure string ends with a slash.
Packit 667938
sub ensureSL($) {
Packit 667938
#  return;
Packit 667938
  my $ref = shift;
Packit 667938
  return if not $$ref;
Packit 667938
  debug('dir',"ensure path IN:  '$$ref'");
Packit 667938
  if (${MRTG_lib::SL} eq '\\'){
Packit 667938
     # two slashes at the start of the string are OK
Packit 667938
     $$ref =~ s/(.)\Q${MRTG_lib::SL}\E+/$1${MRTG_lib::SL}/g;
Packit 667938
  } else {
Packit 667938
     $$ref =~ s/\Q${MRTG_lib::SL}\E+/${MRTG_lib::SL}/g;
Packit 667938
  }
Packit 667938
  $$ref =~ s/\Q${MRTG_lib::SL}\E*$/${MRTG_lib::SL}/;
Packit 667938
  debug('dir',"ensure path OUT: '$$ref'");
Packit 667938
}
Packit 667938
Packit 667938
# convert current supplied time into a nice date string
Packit 667938
Packit 667938
sub datestr ($) {
Packit 667938
    my ($time) = shift || return 0;
Packit 667938
    my ($wday) = ('Sunday','Monday','Tuesday','Wednesday',
Packit 667938
                  'Thursday','Friday','Saturday')[(localtime($time))[6]];
Packit 667938
    my ($month) = ('January','February' ,'March' ,'April' ,
Packit 667938
                   'May' , 'June' , 'July' , 'August' , 'September' , 
Packit 667938
                   'October' ,
Packit 667938
                   'November' , 'December' )[(localtime($time))[4]];
Packit 667938
    my ($mday,$year,$hour,$min) = (localtime($time))[3,5,2,1];
Packit 667938
    if ($min<10) {
Packit 667938
        $min = "0$min";
Packit 667938
    }
Packit 667938
    return "$wday, $mday $month ".($year+1900)." at $hour:$min";
Packit 667938
}
Packit 667938
Packit 667938
Packit 667938
# create expire date for expiery in ARG Minutes
Packit 667938
Packit 667938
sub expistr ($) {
Packit 667938
    my ($time) = time+int($_[0]*60)+5;
Packit 667938
    my ($wday) = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[(gmtime($time))[6]];
Packit 667938
    my ($month) = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep', 
Packit 667938
                   'Oct','Nov','Dec')[(gmtime($time))[4]];
Packit 667938
    my ($mday,$year,$hour,$min,$sec) = (gmtime($time))[3,5,2,1,0];
Packit 667938
    if ($mday<10) {
Packit 667938
        $mday = "0$mday";
Packit 667938
    }
Packit 667938
    ;
Packit 667938
    if ($hour<10) {
Packit 667938
        $hour = "0$hour";
Packit 667938
    }
Packit 667938
    ;
Packit 667938
    if ($min<10) {
Packit 667938
        $min = "0$min";
Packit 667938
    }
Packit 667938
    if ($sec<10) {
Packit 667938
        $sec = "0$sec";
Packit 667938
    }
Packit 667938
    return "$wday, $mday $month ".($year+1900)." $hour:$min:$sec GMT";
Packit 667938
}
Packit 667938
Packit 667938
sub create_pid ($) {
Packit 667938
    my $pidfile = shift;
Packit 667938
    return if ($OS eq 'NT' );
Packit 667938
    return if -e $pidfile;
Packit 667938
    if ( open(PIDFILE,">$pidfile")) {
Packit 667938
         close PIDFILE;
Packit 667938
    } else {
Packit 667938
         warn "cannot write to $pidfile: $!\n";
Packit 667938
    }
Packit 667938
}
Packit 667938
Packit 667938
sub demonize_me ($) {
Packit 667938
    my $pidfile = shift;
Packit 667938
    my $cfgfile = shift;
Packit 667938
    print "Daemonizing MRTG ...\n";
Packit 667938
    if ( $OS eq 'NT' ) {
Packit 667938
        print "Do Not close this window. Or MRTG will die\n";
Packit 667938
#            require Win32::Console;
Packit 667938
#            my $CONSOLE = new Win32::Console;
Packit 667938
        #    detach process from Console
Packit 667938
#            $CONSOLE->Flush();
Packit 667938
#            $CONSOLE->Free();
Packit 667938
#            $CONSOLE->Alloc();
Packit 667938
#            $CONSOLE->Mode()
Packit 667938
    }
Packit 667938
    elsif( $OS eq 'OS2')
Packit 667938
    {
Packit 667938
     require OS2::Process;
Packit 667938
     if (my_type() eq 'VIO'){
Packit 667938
        $main::Cleanfile3 = $pidfile;
Packit 667938
Packit 667938
        print "MRTG detached. PID=".system(P_DETACH(),$^X." ".$0." ".$cfgfile);
Packit 667938
        exit;
Packit 667938
     }
Packit 667938
    } else {
Packit 667938
           # Check out if there is another mrtg running before forking
Packit 667938
           if (defined $pidfile && open(READPID, "<$pidfile")){
Packit 667938
               if (not eof READPID) {
Packit 667938
                   chomp(my $input = <READPID>);    # read process id in pidfile
Packit 667938
                   my ($pid) = $input =~ /^(\d+)$/; # to improve taint-safe code
Packit 667938
                   if ($pid && kill 0 => $pid) {# oops - the pid actually exists
Packit 667938
                        die "ERROR: I Quit! Another copy of mrtg seems to be running. Check $pidfile\n";
Packit 667938
                   }
Packit 667938
               }
Packit 667938
               close READPID;
Packit 667938
           }
Packit 667938
Packit 667938
           defined (my $pid = fork) or die "Can't fork: $!";
Packit 667938
           if ($pid) {
Packit 667938
              exit;
Packit 667938
            } else {
Packit 667938
                if (defined $pidfile){
Packit 667938
                   $main::Cleanfile3 = $pidfile;
Packit 667938
                   if (open(PIDFILE,">$pidfile")) {
Packit 667938
                        print PIDFILE "$$\n";
Packit 667938
                        close PIDFILE;
Packit 667938
                   } else {
Packit 667938
                        warn "cannot write to $pidfile: $!\n";
Packit 667938
                   }
Packit 667938
              }
Packit 667938
              require 'POSIX.pm';
Packit 667938
              POSIX::setsid() or die "Can't start a new session: $!";
Packit 667938
              open STDOUT,'>/dev/null' or die "ERROR: Redirecting STDOUT to /dev/null: $!";
Packit 667938
              open STDERR,'>/dev/null' or die "ERROR: Redirecting STDERR to /dev/null: $!";
Packit 667938
              open STDIN, '
Packit 667938
      }
Packit 667938
   }
Packit 667938
}
Packit 667938
Packit 667938
# Create a new SNMP target entry for the @$target array and return a
Packit 667938
# reference to it
Packit 667938
sub newSnmpTarg( $$ ) {
Packit 667938
	my $t = shift;		# target string
Packit 667938
	my $if = shift;		# interface match strings
Packit 667938
	my $targ = { };		# New target closure
Packit 667938
	$targ->{ Methode }		= 'SNMP';
Packit 667938
	$targ->{ Community }	= $if->{ComStr};
Packit 667938
	$targ->{ Host }			= ( defined $if->{HostIPv6} ) ? $if->{HostIPv6} : $if->{HostName};
Packit 667938
	$targ->{ SnmpOpt }		= $if->{SnmpInfo};
Packit 667938
	$targ->{ snmpoptions} 		= $if->{snmpoptions};
Packit 667938
	$targ->{ Conversion }	= ( defined $if->{ConvSub} ) ? $if->{ConvSub} : '';
Packit 667938
	for my $i( 0..1 ) {
Packit 667938
		die 'ERROR: Malformed ', $i ? 'output ' : 'input ', "ifSpec in '$t'\n"
Packit 667938
			if not defined $if->{OID}[$i] and not defined $if->{Alt}[$i];
Packit 667938
		$targ->{OID}[$i]				= $if->{OID}[$i];
Packit 667938
		if( defined $if->{Alt}[$i] ) {
Packit 667938
			if( defined $if->{Num}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'If';
Packit 667938
				$targ->{Key}[$i]		= $if->{Num}[$i];
Packit 667938
			} elsif( defined $if->{IP}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'Ip';
Packit 667938
				$targ->{Key}[$i]		= $if->{IP}[$i];
Packit 667938
			} elsif( defined $if->{Desc}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'Descr';
Packit 667938
				$targ->{Key}[$i]		= $if->{Desc}[$i];
Packit 667938
			} elsif( defined $if->{Name}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'Name';
Packit 667938
				$targ->{Key}[$i]		= $if->{Name}[$i];
Packit 667938
			} elsif( defined $if->{Eth}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'Eth';
Packit 667938
				$targ->{Key}[$i]		= join( '-', map( { sprintf '%02x', hex $_ } split( /-/, $if->{Eth}[$i] ) ) );
Packit 667938
			} elsif( defined $if->{Type}[$i] ) {
Packit 667938
				$targ->{IfSel}[$i]		= 'Type';
Packit 667938
				$targ->{Key}[$i]		= $if->{Type}[$i];
Packit 667938
			} else {
Packit 667938
				die "ERROR: Internal error parsing ifSpec in '$t'\n";
Packit 667938
			}
Packit 667938
		} else {
Packit 667938
			$targ->{IfSel}[$i]			= 'None';
Packit 667938
			$targ->{Key}[$i]			= '';
Packit 667938
		}
Packit 667938
		# Remove escaped characters and trailing space from Descr or Name Key
Packit 667938
		$targ->{Key}[$i] =~ s/\\([\s:&@])/$1/g
Packit 667938
			if $targ->{IfSel}[$i] eq 'Descr' or $targ->{IfSel}[$i] eq 'Name';
Packit 667938
		$targ->{Key}[$i] =~ s/[\0- ]+$//;
Packit 667938
	}
Packit 667938
	# Remove escaped characters from community
Packit 667938
	$targ->{ Community } =~ s/\\([ @])/$1/g;
Packit 667938
	return $targ;	# Return new target closure
Packit 667938
}
Packit 667938
Packit 667938
# ( $string, $unique ) = targparser( $string, $target, $targIndex, $ipv4only )
Packit 667938
# Walk amd analyze the target string $string. $target is a reference to the
Packit 667938
# array of targets being built. $targIndex is a reference to a hash of targets
Packit 667938
# previously encountered indexed by target string. When $ipv4only is nonzero,
Packit 667938
# only IPv4 is in use. Returns the modifed target string and the index of the
Packit 667938
# @$target array to which the target refers if that index is unique. If the
Packit 667938
# index is not unique, i.e. the target definition is a calculation involving
Packit 667938
# two or more different targets, then the value -1 is returned for $unique.
Packit 667938
# Targparser updates the target array avoiding duplicate targets. The goal is
Packit 667938
# to substitute all target definitions with strings of the form
Packit 667938
# "$t1$thisTarg$t2", where $thisTarg is the target index, and $t1 and $t2 are
Packit 667938
# as defined below. The intended result is a target string that can be eval'ed
Packit 667938
# in its entirety later on when monitoring data has been collected. This
Packit 667938
# evaluation occurs in sub getcurrent in the main mrtg script.
Packit 667938
Packit 667938
# Note: In the regular expressions in &targparser, we have avoided m/.../i
Packit 667938
# and the variables &`, $&, and $'. Use of these makes regex processing less
Packit 667938
# efficient. See Friedl, J.E.F. Mastering Regular Expressions. O'Reilly.
Packit 667938
# p. 273
Packit 667938
Packit 667938
sub targparser( $$$$$$ ) {
Packit 667938
	# Target string (int:community@router, etc.)
Packit 667938
	my $string = shift;
Packit 667938
	# Reference to target array
Packit 667938
	my $target = shift;
Packit 667938
	# Reference to target index hash
Packit 667938
	my $targIndex = shift;
Packit 667938
	# Nonzero if only IPv4 is in use
Packit 667938
	my $ipv4only = shift;
Packit 667938
	# options passed per target.
Packit 667938
	my $snmpoptions = shift;
Packit 667938
	# Highspeed Counter test
Packit 667938
	my $nohc = shift;
Packit 667938
	
Packit 667938
	# Next available index in the @$target array
Packit 667938
	my $idx = @$target;
Packit 667938
	# Common match strings: pre-target, target, post-target
Packit 667938
	my( $pre, $t, $post );
Packit 667938
	# Portion of string already parsed
Packit 667938
	my $parsed = '';
Packit 667938
	# Initialize $unique to undefined. It will take on the $targIndex value
Packit 667938
	# of the first target encountered. $otherTargCount will count the
Packit 667938
	# number of other targets (targets with different values of $targIndex)
Packit 667938
	# encountered during the parse. $unique will be returned as undef
Packit 667938
	# unless $otherTargCount remains 0.
Packit 667938
	my $unique = -1;
Packit 667938
	my $otherTargCount = 0;
Packit 667938
Packit 667938
	# Components of the target expression that are substituted into the
Packit 667938
	# target string each time a target is identified. The substitution
Packit 667938
	# string is the interpolated value of "$t1$targIndex$t2". At present
Packit 667938
	# $t1 and $t2 are set to create a new BigFloat object.
Packit 667938
#	my $t1 = ' Math::BigFloat->new($target->[';
Packit 667938
#	my $t2 = ']{$mode}) ';
Packit 667938
        # this gives problems with perl 5.005 so bigfloat is introduces in mrtg itself
Packit 667938
	my $t1 = ' $target->[';
Packit 667938
	my $t2 = ']{$mode} ';
Packit 667938
Packit 667938
	# Find and substitute all external program targets
Packit 667938
	while( ( $pre, $t, $post ) = $string =~ m<
Packit 667938
		^(.*?)					# capture pre-target string
Packit 667938
		`						# beginning of program target
Packit 667938
		((?:\\`|[^`])+)			# capture target contents (\` allowed)
Packit 667938
		`						# end of program target
Packit 667938
		(.*)$					# capture post-target string
Packit 667938
	>x ) {						# Total of 3 captures
Packit 667938
		my $thisTarg;
Packit 667938
		if( exists $targIndex->{ $t } ) {
Packit 667938
			# This program target has been encountered previously
Packit 667938
			$thisTarg = $targIndex->{ $t };
Packit 667938
			debug( 'tarp', "Existing program target [$thisTarg]" );
Packit 667938
		} else {
Packit 667938
			# A new program target is needed
Packit 667938
			my $targ = { };
Packit 667938
			$targ->{ Methode } = 'EXEC';
Packit 667938
			$targ->{ Command } = $t;
Packit 667938
			# Remove escaped backticks
Packit 667938
			$targ->{ Command } =~ s/\\\`/\`/g;
Packit 667938
			$target->[ $idx ] = $targ;
Packit 667938
			$thisTarg = $idx++;
Packit 667938
			$targIndex->{ $t } = $thisTarg;
Packit 667938
			debug( 'tarp', "New program target [$thisTarg] '$t'" );
Packit 667938
		}
Packit 667938
		$parsed .= "$pre$t1$thisTarg$t2";
Packit 667938
		$string = $post;
Packit 667938
		if( $unique < 0 ) {
Packit 667938
			$unique = $thisTarg;
Packit 667938
		} else {
Packit 667938
			$otherTargCount++ unless $thisTarg == $unique;
Packit 667938
		}
Packit 667938
	};
Packit 667938
	# Reset $string for new target type search
Packit 667938
	$string = $parsed . $string;
Packit 667938
	$parsed = '';
Packit 667938
	debug( 'tarp', "&targparser external done: '$string'" );
Packit 667938
Packit 667938
	# Common interface specification regex components
Packit 667938
Packit 667938
	# Simple interface specification regex component. Matches interface
Packit 667938
	# specification by IPv4 address, description, name, Ethernet address, or
Packit 667938
	# type.
Packit 667938
	my $ifSimple =
Packit 667938
		'       (\d+)|' .				# by number ($if->{Num})
Packit 667938
		'  /    (\d+(?:\.\d+)+)|' .		# by IPv4 address ($if->{IP})
Packit 667938
		'  \\\\ ((?:\\\\[\s:&@]|[^\s:&@])+)|' . # by description (allow \  \: \& \@) ($if->{Desc})
Packit 667938
		'  \#   ((?:\\\\[\s:&@]|[^\s:&@])+)|' . # by name (allow \  \: \& \@) ($if->{Name})
Packit 667938
		'  !    ([a-fA-F0-9]+(?:-[a-fA-F0-9]+)+)|' . # by Ethernet address ($if->{Eth})
Packit 667938
		'  %    (\d+)'; 				# by type ($if->{Type})
Packit 667938
Packit 667938
	# Complex interface specification regex component. Note that a null string
Packit 667938
	# will match. Therefore the match must be postprocessed to check that
Packit 667938
	# $ifOID and $ifAlt are not both null.
Packit 667938
	my $ifComplex =
Packit 667938
		'((?:\.\d+)*?\.?[-a-zA-Z0-9]*(?:\.\d+)*?)' .	# OID possibly starting with a MIB name ($if->{OID})
Packit 667938
		'(' .							# Interface specification alternatives: ($if->{Alt})
Packit 667938
			'\.' .						#  separator
Packit 667938
			$ifSimple .					#  simple alternatives (6 variables)
Packit 667938
		')?';							#  maybe none of the above
Packit 667938
Packit 667938
	# Community-host interface specification regex component.
Packit 667938
	my $ifComHost =
Packit 667938
		'((?:\\\\[@ ]|[^\s@])+)' .		# community string ('\@' and '\ ' allowed) ($if->{ComStr})
Packit 667938
			'@' .						# separator
Packit 667938
		'(?:(\[[a-fA-F0-9:]*\])|' .		# hostname as IPv6 address ($if->{HostIPv6})
Packit 667938
		'([-\w]+(?:\.[-\w]+)*))' .		# or DNS name ($if->{HostName})
Packit 667938
		'((?::[\d.!]*)*)' .				# SNMP session configuration ($if->{SnmpInfo})
Packit 667938
		'(?:\|([a-zA-Z_][\w]*))?';		# numeric conversion subroutine ($if->{ConvSub})
Packit 667938
Packit 667938
	# Match strings for simple and complex interface specifications. Entries
Packit 667938
	# are of the form $if->{k1}[i], where k1 is OID, Alt, Num, IP, Desc,
Packit 667938
	# Name, Eth, or Type, and i is 0 or 1 (input or output). Entries may also
Packit 667938
	# have the form $if->{k1}, where k1 is Rev, ComStr, HostIPv6, HostName,
Packit 667938
	# SnmpInfo, or ConvSub, with no [i] in these cases.
Packit 667938
	my $if;
Packit 667938
Packit 667938
	# Find and substitute all complex OID targets
Packit 667938
Packit 667938
	while( ( $pre, $t, $if->{OID}[0], $if->{Alt}[0], $if->{Num}[0],
Packit 667938
	$if->{IP}[0], $if->{Desc}[0], $if->{Name}[0], $if->{Eth}[0],
Packit 667938
	$if->{Type}[0], $if->{OID}[1], $if->{Alt}[1], $if->{Num}[1],
Packit 667938
	$if->{IP}[1], $if->{Desc}[1], $if->{Name}[1], $if->{Eth}[1],
Packit 667938
	$if->{Type}[1], $if->{ComStr}, $if->{HostIPv6}, $if->{HostName},
Packit 667938
	$if->{SnmpInfo}, $if->{ConvSub}, $post ) = $string =~ m<
Packit 667938
		^(.*?)					# capture pre-target string
Packit 667938
		(						# capture entire target
Packit 667938
			${ifComplex}		# input interface specification (8 captures)
Packit 667938
				&				# separator
Packit 667938
			${ifComplex}		# output interface specification (8 captures)
Packit 667938
				:				# separator
Packit 667938
			${ifComHost}		# community-host specification (5 captures)
Packit 667938
		)						# end of entire target capture
Packit 667938
		(.*)$					# capture post-target string
Packit 667938
	>x ) {						# Total of 24 captures
Packit 667938
		my $thisTarg;
Packit 667938
		# Exception: skip and try to parse later as a simple target if
Packit 667938
		# $if->{Desc}[0], $if->{Name}[0], $if->{Desc}[1], or $if->{Name}[1]
Packit 667938
		# ends with a backslash character
Packit 667938
		if( ( defined $if->{Desc}[0] and $if->{Desc}[0] =~ m<\\$> ) or
Packit 667938
			( defined $if->{Name}[0] and $if->{Name}[0] =~ m<\\$> ) or
Packit 667938
			( defined $if->{Desc}[1] and $if->{Desc}[1] =~ m<\\$> ) or
Packit 667938
			( defined $if->{Name}[1] and $if->{Name}[1] =~ m<\\$> ) ) {
Packit 667938
			$parsed .= "$pre$t";
Packit 667938
			$string = $post;
Packit 667938
			next;
Packit 667938
		}
Packit 667938
		if( exists $targIndex->{ $t } ) {
Packit 667938
			# This complex target has been encountered previously
Packit 667938
			$thisTarg = $targIndex->{ $t };
Packit 667938
			debug( 'tarp', "Existing complex target [$thisTarg]" );
Packit 667938
		} else {
Packit 667938
			# A new complex target is needed
Packit 667938
			my $targ = newSnmpTarg( $t, $if );
Packit 667938
			$targ->{ ipv4only } = $ipv4only;
Packit 667938
			$targ->{ snmpoptions } = $snmpoptions;
Packit 667938
			$target->[ $idx ] = $targ;
Packit 667938
			$thisTarg = $idx++;
Packit 667938
			$targIndex->{ $t } = $thisTarg;
Packit 667938
			debug( 'tarp', "New complex target [$thisTarg] '$t':\n" .
Packit 667938
				"  Comu:  $targ->{Community}, Host: $targ->{Host}\n" .
Packit 667938
				"  Opt:   $targ->{SnmpOpt}, IPv4: $targ->{ipv4only}\n" .
Packit 667938
				"  Conv:  $targ->{Conversion}\n" .
Packit 667938
				"  OID:   $targ->{OID}[0], $targ->{OID}[1]\n" .
Packit 667938
				"  IfSel: $targ->{IfSel}[0], $targ->{IfSel}[1]\n" .
Packit 667938
				"  Key:   $targ->{Key}[0], $targ->{Key}[1]" );
Packit 667938
		}
Packit 667938
		$parsed .= "$pre$t1$thisTarg$t2";
Packit 667938
		$string = $post;
Packit 667938
		if( $unique < 0 ) {
Packit 667938
			$unique = $thisTarg;
Packit 667938
		} else {
Packit 667938
			$otherTargCount++ unless $thisTarg == $unique;
Packit 667938
		}
Packit 667938
	}
Packit 667938
	# Reset $string and $parsedfor new target type search
Packit 667938
	$string = $parsed . $string;
Packit 667938
	$parsed = '';
Packit 667938
	debug( 'tarp', "&targparser complex done: '$string'" );
Packit 667938
Packit 667938
	# Find and substitute all simple targets
Packit 667938
Packit 667938
	while( ( $pre, $t, $if->{Rev}, $if->{Num}[0], $if->{IP}[0],
Packit 667938
	$if->{Desc}[0], $if->{Name}[0], $if->{Eth}[0], $if->{Type}[0],
Packit 667938
	$if->{ComStr}, $if->{HostIPv6}, $if->{HostName}, $if->{SnmpInfo},
Packit 667938
	$if->{ConvSub}, $post ) = $string =~ m<
Packit 667938
		^(.*?)					# capture pre-target string
Packit 667938
		(						# capture entire target
Packit 667938
			(-)?				# capture direction reversal
Packit 667938
			(?: ${ifSimple} )	# simple interface specification (6 captures)
Packit 667938
				:				# separator
Packit 667938
			${ifComHost}		# community-host specification (5 captures)
Packit 667938
		)						# end of entire target capture
Packit 667938
		(.*)$					# capture post-target string
Packit 667938
	>x ) {						# Total of 15 captures
Packit 667938
		my $thisTarg;
Packit 667938
		if( exists $targIndex->{ $t } ) {
Packit 667938
			# This simple target has been encountered previously
Packit 667938
			$thisTarg = $targIndex->{ $t };
Packit 667938
			debug( 'tarp', "Existing simple target [$thisTarg]" );
Packit 667938
		} else {
Packit 667938
			# A new simple target is needed
Packit 667938
			# Reverse interface directions if indicated by $if->{Rev}.
Packit 667938
			# The sense of $d1 and $d2 is 0 for input and 1 for output
Packit 667938
			my $d1 = ( defined $if->{Rev} and $if->{Rev} eq '-' ) ? 1 : 0;
Packit 667938
			my $d2 = 1 - $d1;
Packit 667938
			# Set the OIDs depending on whether SNMPv2 has been specified
Packit 667938
			# and on the direction
Packit 667938
			if( $if->{SnmpInfo} =~ m/(?::[^:]*){4}:[32][Cc]?/ and $nohc == 0 ) {
Packit 667938
				$if->{OID}[$d1] = 'ifHCInOctets';
Packit 667938
				$if->{OID}[$d2] = 'ifHCOutOctets';
Packit 667938
			} else {
Packit 667938
				$if->{OID}[$d1] = 'ifInOctets';
Packit 667938
				$if->{OID}[$d2] = 'ifOutOctets';
Packit 667938
			}
Packit 667938
			# Give $if->{Alt}[i] an arbitrary defined value so that
Packit 667938
			# &newSnmpTarg works correctly
Packit 667938
			$if->{Alt}[0]	= 1;
Packit 667938
			$if->{Alt}[1]	= 1;
Packit 667938
			# Copy input specification to output
Packit 667938
			$if->{Num}[1]	= $if->{Num}[0];
Packit 667938
			$if->{IP}[1]	= $if->{IP}[0];
Packit 667938
			$if->{Desc}[1]	= $if->{Desc}[0];
Packit 667938
			$if->{Name}[1]	= $if->{Name}[0];
Packit 667938
			$if->{Eth}[1]	= $if->{Eth}[0];
Packit 667938
			$if->{Type}[1]	= $if->{Type}[0];
Packit 667938
			my $targ = newSnmpTarg( $t, $if );
Packit 667938
			$targ->{ snmpoptions} = $snmpoptions;
Packit 667938
			$targ->{ ipv4only } = $ipv4only;
Packit 667938
			$target->[ $idx ] = $targ;
Packit 667938
			$thisTarg = $idx++;
Packit 667938
			$targIndex->{ $t } = $thisTarg;
Packit 667938
			debug( 'tarp', "New simple target [$thisTarg] '$t':\n" .
Packit 667938
				"  Comu:  $targ->{Community}, Host: $targ->{Host}\n" .
Packit 667938
				"  Opt:   $targ->{SnmpOpt}, IPv4: $targ->{ipv4only}\n" .
Packit 667938
				"  Conv:  $targ->{Conversion}\n" .
Packit 667938
				"  OID:   $targ->{OID}[0], $targ->{OID}[1]\n" .
Packit 667938
				"  IfSel: $targ->{IfSel}[0], $targ->{IfSel}[1]\n" .
Packit 667938
				"  Key:   $targ->{Key}[0], $targ->{Key}[1]" );
Packit 667938
		}
Packit 667938
		$parsed .= "$pre$t1$thisTarg$t2";
Packit 667938
		$string = $post;
Packit 667938
		if( $unique < 0 ) {
Packit 667938
			$unique = $thisTarg;
Packit 667938
		} else {
Packit 667938
			$otherTargCount++ unless $thisTarg == $unique;
Packit 667938
		}
Packit 667938
	}
Packit 667938
	# Assemble string to be returned
Packit 667938
	$string = $parsed . $string;
Packit 667938
	# Set $unique undefined if more than one target is referred to in the
Packit 667938
	# target string
Packit 667938
	$unique = -1 if $otherTargCount;
Packit 667938
	debug( 'tarp', "&targparser simple done: '$string'" );
Packit 667938
	debug( 'tarp', "&targparser returning: unique = $unique" );
Packit 667938
	return ( $string, $unique );
Packit 667938
}
Packit 667938
Packit 667938
# Display of &targparser intermediate values for debugging purposes. Call as
Packit 667938
# showMatch( $string, $pre, $t, $post, $if ) from within &targparser.
Packit 667938
sub showMatch( $$$$$ ) {
Packit 667938
	my( $string, $pre, $t, $post, $if ) = @_;
Packit 667938
	warn "# Matching on string '$string'\n";
Packit 667938
	warn "# Prematch:  '$pre'\n";
Packit 667938
	warn "# Target:    '$t'\n";
Packit 667938
	warn "# Postmatch: '$post'\n";
Packit 667938
	warn "# Captured:\n";
Packit 667938
	foreach my $k( keys %$if ) {
Packit 667938
		if( ref( $if->{$k} ) eq 'ARRAY' ) {
Packit 667938
			warn "#  \$if->{$k}[0,1]: '",
Packit 667938
				( defined $if->{$k}[0] ) ? $if->{$k}[0] : 'undef', "', '",
Packit 667938
				( defined $if->{$k}[1] ) ? $if->{$k}[1] : 'undef', "'\n";
Packit 667938
		} else {
Packit 667938
			warn "#  \$if->{$k}:      '",
Packit 667938
				( defined $if->{$k} ) ? $if->{$k} : 'undef', "'\n";
Packit 667938
		}
Packit 667938
	}
Packit 667938
}
Packit 667938
Packit 667938
sub readconfcache ($) {
Packit 667938
    my $cfgfile = shift;
Packit 667938
    my %confcache;
Packit 667938
    if (open (CFGOK,"<$cfgfile")) {
Packit 667938
        while (<CFGOK>) {
Packit 667938
            chomp;
Packit 667938
            next unless /\t/; #ignore odd lines
Packit 667938
	    next if /^\S+:/; #ignore legacy lines
Packit 667938
            my ($host,$method,$key,$if) = split (/\t/, $_);
Packit 667938
            $key =~ s/[\0- ]+$//; # no trailing whitespace in keys realy !
Packit 667938
            $key =~ s/[\0- ]/ /g; # all else becomes a normal space ... get a life
Packit 667938
            $confcache{$host}{$method}{$key} = $if;
Packit 667938
        }
Packit 667938
        close CFGOK;
Packit 667938
    }
Packit 667938
    return \%confcache;
Packit 667938
}
Packit 667938
Packit 667938
sub writeconfcache ($$) {
Packit 667938
    my $confcache = shift;
Packit 667938
    my $cfgfile = shift;
Packit 667938
    if ($cfgfile ne '&STDOUT'){
Packit 667938
      open (CFGOK,">$cfgfile") or die "ERROR: writing $cfgfile.ok: $!";
Packit 667938
    }
Packit 667938
    my @hosts;
Packit 667938
    if (defined $$confcache{___updated}) {
Packit 667938
        @hosts = @{$$confcache{___updated}} ;
Packit 667938
        delete $$confcache{___updated};
Packit 667938
    } else {
Packit 667938
        @hosts = grep !/^___/, keys %{$confcache}
Packit 667938
    }
Packit 667938
    foreach my $host (sort @hosts) {	
Packit 667938
        foreach my $method (sort keys %{$$confcache{$host}}) {
Packit 667938
            foreach my $key (sort keys %{$$confcache{$host}{$method}}) {
Packit 667938
                if ($cfgfile ne '&STDOUT'){
Packit 667938
                        print CFGOK "$host\t$method\t$key\t".
Packit 667938
                            $$confcache{$host}{$method}{$key},"\n";
Packit 667938
                } else {
Packit 667938
                         print "$host\t$method\t$key\t".
Packit 667938
                            $$confcache{$host}{$method}{$key},"\n";
Packit 667938
                }
Packit 667938
            }
Packit 667938
        }
Packit 667938
    }
Packit 667938
    close CFGOK;
Packit 667938
}
Packit 667938
Packit 667938
sub cleanhostkey ($){
Packit 667938
    my $host = shift;
Packit 667938
    return undef unless defined $host;
Packit 667938
    $host =~ s/(:\d*)(?:(:\d*)(?:(:\d*)(?:(:\d*)(?:(:\d*)))))$/$1$5/
Packit 667938
        or
Packit 667938
    $host =~ s/(:\d*)(?:(:\d*)(?:(:\d*)(?:(:\d*)?)?)?)$/$1/;
Packit 667938
    $host =~ s/:/_/g; # make sure that double invocations do not kill us
Packit 667938
    return $host;
Packit 667938
}
Packit 667938
Packit 667938
sub storeincache ($$$$$){
Packit 667938
    my($confcache,$host,$method,$key,$value) = @_;
Packit 667938
    $host = cleanhostkey $host;
Packit 667938
    if (not defined $value ){
Packit 667938
	 $$confcache{$host}{$method}{$key} = undef;
Packit 667938
	 return;
Packit 667938
    }
Packit 667938
    $value =~ s/[\0- ]/ /g; # all else becomes a normal space ... get a life
Packit 667938
    $value =~ s/ +$//; # no trailing spaces
Packit 667938
    if (defined $$confcache{$host}{$method}{$key} and 
Packit 667938
	$$confcache{$host}{$method}{$key} ne $value) {
Packit 667938
        $$confcache{$host}{$method}{$key} = "Dup";
Packit 667938
	debug('coca',"store in confcache $host $method $key --> $value (duplicate)");
Packit 667938
    } else {
Packit 667938
        $$confcache{$host}{$method}{$key} = $value;
Packit 667938
	debug('coca',"store in confcache $host $method $key --> $value");
Packit 667938
    }
Packit 667938
Packit 667938
}
Packit 667938
Packit 667938
sub readfromcache ($$$$){
Packit 667938
    my($confcache,$host,$method,$key) = @_;
Packit 667938
    $host = cleanhostkey $host;
Packit 667938
    return $$confcache{$host}{$method}{$key};
Packit 667938
}
Packit 667938
Packit 667938
Packit 667938
sub clearfromcache ($$){
Packit 667938
    my($confcache,$host) = @_;
Packit 667938
    $host = cleanhostkey $host;
Packit 667938
    delete $$confcache{$host};
Packit 667938
    debug('coca',"clear confcache $host");
Packit 667938
}
Packit 667938
Packit 667938
Packit 667938
sub populateconfcache ($$$$$) {
Packit 667938
    my $confcache = shift;
Packit 667938
    my $host = shift;
Packit 667938
    my $ipv4only = shift;
Packit 667938
    my $reread = shift;
Packit 667938
    my $snmpoptions = shift || {};
Packit 667938
    my $hostkey = cleanhostkey $host;    
Packit 667938
    return if defined $$confcache{$hostkey} and not $reread;
Packit 667938
    my $snmp_errlevel = $SNMP_Session::suppress_warnings;
Packit 667938
    my $net_snmp_errlevel = $Net_SNMP_util::suppress_warnings;
Packit 667938
    $SNMP_Session::suppress_warnings = 3;   
Packit 667938
    $Net_SNMP_util::suppress_warnings = 3;   
Packit 667938
    debug('coca',"populate confcache $host");
Packit 667938
Packit 667938
    # clear confcache for host;
Packit 667938
    delete $$confcache{$hostkey};
Packit 667938
Packit 667938
    my @ret;
Packit 667938
    my %tables = ( ifDescr => 'Descr',
Packit 667938
		   ifName  => 'Name',
Packit 667938
		   ifType  => 'Type',
Packit 667938
		   ipAdEntIfIndex => 'Ip' );
Packit 667938
    my @nodes = qw (ifName ifDescr ifType ipAdEntIfIndex);
Packit 667938
    # it seems that some devices only give back sensible data if their tables
Packit 667938
    # are walked in the right ordere ....
Packit 667938
    foreach my $node (@nodes) {
Packit 667938
	next if $confcache->{___deadhosts}{$hostkey} and time - $confcache->{___deadhosts}{$hostkey} < 300;
Packit 667938
	$SNMP_Session::errmsg = undef;
Packit 667938
	$Net_SNMP_util::ErrorMessage = undef;
Packit 667938
	@ret = &main::snmpwalk(v4onlyifnecessary($host, $ipv4only), $snmpoptions, $node);
Packit 667938
	unless ( $SNMP_Session::errmsg or $Net_SNMP_util::ErrorMessage){
Packit 667938
	    foreach my $ret (@ret)
Packit 667938
	      {
Packit 667938
		  my ($oid, $desc) = split(':', $ret, 2);
Packit 667938
		  if ($tables{$node} eq 'Ip') {
Packit 667938
		      storeincache($confcache,$host,$tables{$node},$oid,$desc);
Packit 667938
		  } else {
Packit 667938
                      $desc =~ s/[\0- ]+$//; #trailing whitespace is too sick for us
Packit 667938
                      $desc =~ s/[\0- ]/ /g; #whitespace is just whitespace
Packit 667938
		      storeincache($confcache,$host,$tables{$node},$desc,$oid);
Packit 667938
		  }
Packit 667938
	      };
Packit 667938
	} else {
Packit 667938
  	    $confcache->{___deadhosts}{$hostkey} = time
Packit 667938
		if defined($SNMP_Session::errmsg) and $SNMP_Session::errmsg =~ /no response received/;
Packit 667938
  	    $confcache->{___deadhosts}{$hostkey} = time
Packit 667938
		if defined($Net_SNMP_util::ErrorMessage) and $Net_SNMP_util::ErrorMessage =~ /No response from remote/;
Packit 667938
	    debug('coca',"Skipping $node scanning because $host does not seem to support it");
Packit 667938
	}
Packit 667938
    }
Packit 667938
    if ($confcache->{___deadhosts}{$hostkey} and time - $confcache->{___deadhosts}{$hostkey} < 300){
Packit 667938
	$SNMP_Session::suppress_warnings = $snmp_errlevel;
Packit 667938
	$Net_SNMP_util::suppress_warnings = $snmp_errlevel;
Packit 667938
	return;
Packit 667938
    }
Packit 667938
    $SNMP_Session::errmsg = undef;
Packit 667938
    $Net_SNMP_util::ErrorMessage = undef;
Packit 667938
    @ret = &main::snmpwalk(v4onlyifnecessary($host, $ipv4only), $snmpoptions, "ifPhysAddress");
Packit 667938
    unless ( $SNMP_Session::errmsg or $Net_SNMP_util::ErrorMessage){
Packit 667938
	foreach my $ret (@ret)
Packit 667938
	  {
Packit 667938
	      my ($oid, $bin) = split(':', $ret, 2);
Packit 667938
	      my $eth = unpack 'H*', $bin; 
Packit 667938
 	      my @eth;
Packit 667938
	      while ($eth =~ s/^..//){
Packit 667938
	        push @eth, $&;
Packit 667938
	      }
Packit 667938
	      my $phys=join '-', @eth;
Packit 667938
	      storeincache($confcache,$host,"Eth",$phys,$oid);
Packit 667938
           }
Packit 667938
     } else {
Packit 667938
            debug('coca',"Skipping ifPhysAddress scanning because $host does not seem to support it");
Packit 667938
     }
Packit 667938
Packit 667938
     if (ref $$confcache{___updated} ne 'ARRAY') {
Packit 667938
        $$confcache{___updated} = []; #init to empty array
Packit 667938
     }
Packit 667938
     push @{$$confcache{___updated}}, $hostkey;
Packit 667938
Packit 667938
    $SNMP_Session::suppress_warnings = $snmp_errlevel;    
Packit 667938
    $Net_SNMP_util::supress_warnings = $net_snmp_errlevel;
Packit 667938
}
Packit 667938
Packit 667938
sub log2rrd ($$$) {
Packit 667938
    my $router = shift;
Packit 667938
    my $cfg = shift;
Packit 667938
    my $rcfg = shift;
Packit 667938
    my %mark;
Packit 667938
    my %incomp;
Packit 667938
    my %elapsed_time;
Packit 667938
    my %rate;
Packit 667938
    my %store;
Packit 667938
    my %first_step;
Packit 667938
    my %cur;
Packit 667938
    my %next;
Packit 667938
    my $rrd;    
Packit 667938
    my @steps = qw(300 1800 7200 86400);
Packit 667938
    my %sizes = ( 300 => 600, 1800 => 700, 7200 => 775, 86400 => 797);
Packit 667938
Packit 667938
    open R, "<$$cfg{logdir}$$rcfg{'directory'}{$router}$router.log" or 
Packit 667938
	die "ERROR: opening $$cfg{logdir}$$rcfg{'directory'}{$router}$router.log: $!";
Packit 667938
    debug('rrd',"converting $$cfg{logdir}$$rcfg{'directory'}{$router}$router.log");
Packit 667938
    my $latest_timestamp;
Packit 667938
    my %latest_counter;
Packit 667938
    chomp($_ = <R>);
Packit 667938
    my $time;
Packit 667938
    my $next_time;
Packit 667938
    ($latest_timestamp,$latest_counter{in},$latest_counter{out}) = split /\s+/;
Packit 667938
    chomp($_ = <R>);	 
Packit 667938
    ($time,$cur{in},$cur{out},$cur{maxin},$cur{maxout}) = split /\s+/;
Packit 667938
Packit 667938
    foreach my $s (@steps) {
Packit 667938
	$mark{$s} = $latest_timestamp - ($latest_timestamp % $s) + $s;
Packit 667938
	$first_step{$s} = $latest_timestamp - ($mark{$s} - $s);
Packit 667938
	$elapsed_time{$s} = $s - $first_step{$s};
Packit 667938
	$rate{in}{$s}=$cur{in};
Packit 667938
	$rate{out}{$s}=$cur{out};
Packit 667938
	$rate{maxin}{$s}=$cur{maxin};
Packit 667938
	$rate{maxout}{$s}=$cur{maxout};
Packit 667938
    }
Packit 667938
Packit 667938
    while(<R>){
Packit 667938
	chomp;
Packit 667938
	($next_time,$next{in},$next{out},$next{maxin},$next{maxout}) =
Packit 667938
	    split /\s+/;
Packit 667938
        foreach my $s (@steps) {
Packit 667938
	    # bail if we have enough entries
Packit 667938
	    next if ref $store{in}{$s} and
Packit 667938
		scalar @{$store{in}{$s}} > $sizes{$s};
Packit 667938
	   
Packit 667938
	    # ok we are still here. If next mark is before the next time
Packit 667938
            # we take a short step, else we gobble up
Packit 667938
	    my $next_stop;
Packit 667938
	    do {
Packit 667938
		if ($elapsed_time{$s} + $time - $next_time > $s) {
Packit 667938
		    $next_stop = $mark{$s}-$s;
Packit 667938
		} else {
Packit 667938
		    $next_stop = $next_time;
Packit 667938
		}
Packit 667938
		my $time_diff = $time-$next_stop;
Packit 667938
		foreach my $d (qw(in out)) {		    
Packit 667938
		    $rate{$d}{$s} = ($rate{$d}{$s} * $elapsed_time{$s}
Packit 667938
				     + $cur{$d} * $time_diff) /
Packit 667938
			       ($elapsed_time{$s} + $time_diff);
Packit 667938
		}
Packit 667938
		foreach my $d (qw(maxin maxout)){
Packit 667938
		    $rate{$d}{$s} = $cur{$d} if $rate{$d}{$s} < $cur{$d};
Packit 667938
		}
Packit 667938
		$elapsed_time{$s} += $time_diff;
Packit 667938
#		print "$time $next_stop\n" if $s == 300;
Packit 667938
		if ($next_stop == $mark{$s}-$s) {
Packit 667938
		    foreach my $t (qw(in out maxin maxout)){
Packit 667938
                       $rate{$t}{$s}/=3600
Packit 667938
                           if (defined $$rcfg{'options'}{'perhour'}{$router});    
Packit 667938
                       $rate{$t}{$s}/=60
Packit 667938
                           if (defined $$rcfg{'options'}{'perminute'}{$router});
Packit 667938
 	  	       push @{$store{$t}{$s}}, $rate{$t}{$s};
Packit 667938
		    }
Packit 667938
		    $mark{$s} -= $s;
Packit 667938
		    $rate{maxin}{$s} = 0;
Packit 667938
		    $rate{maxout}{$s} = 0;
Packit 667938
		    $elapsed_time{$s} = 0;
Packit 667938
		}
Packit 667938
            } while ($next_stop > $next_time );
Packit 667938
	}
Packit 667938
        ($time,$cur{in},$cur{out},$cur{maxin},$cur{maxout}) = 
Packit 667938
	    ($next_time,$next{in},$next{out},$next{maxin},$next{maxout});
Packit 667938
    }
Packit 667938
    close R;
Packit 667938
    # lets see if we have rrdtool 1.2 at our hands
Packit 667938
    my $VERSION = '0001';
Packit 667938
    if ($RRDs::VERSION >= 1.2){
Packit 667938
	$VERSION = '0003';
Packit 667938
    }
Packit 667938
    my $DST;
Packit 667938
    my $pdprepin = (shift @{$store{in}{300}})*($first_step{300});
Packit 667938
    my $pdprepout = (shift @{$store{out}{300}})*($first_step{300});
Packit 667938
Packit 667938
    if (defined $$rcfg{'options'}{'absolute'}{$router}) {
Packit 667938
	$DST = 'ABSOLUTE'
Packit 667938
    } elsif (defined $$rcfg{'options'}{'gauge'}{$router}) {
Packit 667938
	$DST = 'GAUGE'
Packit 667938
    } else {
Packit 667938
	$DST = 'COUNTER'
Packit 667938
    }
Packit 667938
Packit 667938
    my $MHB = int($$cfg{interval} * 60 * 2);
Packit 667938
Packit 667938
    my $MAX1 =
Packit 667938
      $$rcfg{'absmax'}{$router}
Packit 667938
	|| $$rcfg{'maxbytes1'}{$router} 
Packit 667938
	  || 'U';
Packit 667938
Packit 667938
    my $MAX2 =
Packit 667938
      $$rcfg{'absmax'}{$router}
Packit 667938
	|| $$rcfg{'maxbytes2'}{$router} 
Packit 667938
	  || 'U';
Packit 667938
    
Packit 667938
    $rrd = <
Packit 667938
Packit 667938
<rrd>
Packit 667938
	<version> $VERSION </version>
Packit 667938
	<step> 300 </step>
Packit 667938
	<lastupdate> $latest_timestamp </lastupdate>
Packit 667938
Packit 667938
	<ds>
Packit 667938
		<name> ds0 </name>
Packit 667938
		<type> $DST </type>
Packit 667938
		<minimal_heartbeat> $MHB </minimal_heartbeat>
Packit 667938
		<min> 0 </min>
Packit 667938
		<max> $MAX1 </max>
Packit 667938
Packit 667938
		
Packit 667938
		<last_ds> $latest_counter{in} </last_ds>
Packit 667938
		<value> $pdprepin </value>
Packit 667938
		<unknown_sec> 0 </unknown_sec>
Packit 667938
	</ds>
Packit 667938
Packit 667938
	<ds>
Packit 667938
		<name> ds1 </name>
Packit 667938
		<type> $DST </type>
Packit 667938
		<minimal_heartbeat> $MHB </minimal_heartbeat>
Packit 667938
		<min> 0 </min>
Packit 667938
		<max> $MAX2 </max>
Packit 667938
Packit 667938
		
Packit 667938
		<last_ds> $latest_counter{out} </last_ds>
Packit 667938
		<value> $pdprepout </value>
Packit 667938
		<unknown_sec> 0 </unknown_sec>
Packit 667938
	</ds>
Packit 667938
RRD
Packit 667938
    $first_step{300} = 0; # invalidate
Packit 667938
    addarch(1,'AVERAGE','in','out',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(6,'AVERAGE','in','out',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(24,'AVERAGE','in','out',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(288,'AVERAGE','in','out',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(1,'MAX','maxin','maxout',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(6,'MAX','maxin','maxout',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(24,'MAX','maxin','maxout',\%store,\%first_step,\$rrd);
Packit 667938
    addarch(288,'MAX','maxin','maxout',\%store,\%first_step,\$rrd);
Packit 667938
    $rrd .= <
Packit 667938
</rrd>
Packit 667938
RRD
Packit 667938
        
Packit 667938
    if ( $OS eq 'NT'  or $OS eq 'OS2') {
Packit 667938
       open (R, "|$$cfg{rrdtool} restore - $$cfg{logdir}$$rcfg{'directory'}{$router}$router.rrd");
Packit 667938
    } else {
Packit 667938
       open (R, "|-") or exec "$$cfg{rrdtool}","restore","-","$$cfg{logdir}$$rcfg{'directory'}{$router}$router.rrd";
Packit 667938
    }
Packit 667938
    print R $rrd;
Packit 667938
    close R;
Packit 667938
}
Packit 667938
Packit 667938
Packit 667938
sub addarch($$$$$$$){
Packit 667938
    my $steps = shift;
Packit 667938
    my $cons = shift;
Packit 667938
    my $in = shift;
Packit 667938
    my $out = shift;
Packit 667938
    my $store = shift;
Packit 667938
    my $first_step = shift;
Packit 667938
    my $rrd = shift;
Packit 667938
    my $cdpin = 'NaN';
Packit 667938
    my $cdpout = 'NaN';
Packit 667938
Packit 667938
    my $param_start = '';
Packit 667938
    my $param_end = '';
Packit 667938
    my $extra_ds = '';
Packit 667938
    if ($RRDs::VERSION >= 1.2){
Packit 667938
        $param_start = '<params>';
Packit 667938
        $param_end = '</params>';
Packit 667938
        $extra_ds = '<primary_value> 0.0000000000e+00 </primary_value> <secondary_value> 0.0000000000e+00 </secondary_value>';
Packit 667938
    }
Packit 667938
Packit 667938
    if ($steps != 300) {
Packit 667938
	$cdpin = shift @{$$store{$in}{300*$steps}};
Packit 667938
	$cdpout = shift @{$$store{$out}{300*$steps}};
Packit 667938
    };
Packit 667938
    $$rrd .= <
Packit 667938
Packit 667938
	<rra>
Packit 667938
		<cf> $cons </cf>
Packit 667938
		<pdp_per_row> $steps </pdp_per_row>
Packit 667938
		$param_start <xff> 0.5 </xff> $param_end
Packit 667938
		<cdp_prep>
Packit 667938
			<ds>$extra_ds <value> $cdpin </value>  <unknown_datapoints> 0 </unknown_datapoints></ds>
Packit 667938
			<ds>$extra_ds <value> $cdpout </value>  <unknown_datapoints> 0 </unknown_datapoints></ds>
Packit 667938
		</cdp_prep>
Packit 667938
Packit 667938
		<database>
Packit 667938
RRD
Packit 667938
    while (@{$$store{$in}{$steps*300}}){
Packit 667938
        # we take zero as UNKNOWN
Packit 667938
	my $inr = pop @{$$store{$in}{$steps*300}} || 'NaN';
Packit 667938
	my $outr = pop @{$$store{$out}{$steps*300}} || 'NaN';
Packit 667938
	$$rrd .= <
Packit 667938
	             <row><v> $inr </v><v> $outr </v></row>
Packit 667938
RRD
Packit 667938
    }
Packit 667938
    $$rrd .= <
Packit 667938
		</database>
Packit 667938
	</rra>
Packit 667938
RRD
Packit 667938
}
Packit 667938
Packit 667938
Packit 667938
Packit 667938
Packit 667938
# debug if the relevant debug tag is active print the debug message
Packit 667938
sub debug ($$) {
Packit 667938
    return unless scalar @main::DEBUG;
Packit 667938
    my $tag = shift;
Packit 667938
    my $msg = shift;
Packit 667938
    return unless grep {$_ eq $tag} @main::DEBUG;
Packit 667938
    warn "--".$tag.": ".$msg."\n";
Packit 667938
    return;
Packit 667938
}
Packit 667938
Packit 667938
# timestamp
Packit 667938
sub timestamp () {
Packit 667938
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
Packit 667938
                                                localtime(time);
Packit 667938
    $year += 1900;
Packit 667938
    $mon += 1;
Packit 667938
    return sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year,$mon,$mday,$hour,$min,$sec;
Packit 667938
}
Packit 667938
Packit 667938
# configure __DIE__ and __WARN__
Packit 667938
       
Packit 667938
sub setup_loghandlers ($){
Packit 667938
    $::global_logfile = $_[0];
Packit 667938
    for($_[0]){
Packit 667938
	/^eventlog$/i && do {
Packit 667938
	    require Win32::EventLog;
Packit 667938
	    $SIG{__WARN__} = sub {
Packit 667938
		my $EventLog = Win32::EventLog->new('MRTG');
Packit 667938
		my $Type = ($_[0] =~ /warning/) ? 
Packit 667938
		  &Win32::EventLog::EVENTLOG_WARNING_TYPE : 
Packit 667938
		  &Win32::EventLog::EVENTLOG_INFORMATION_TYPE;
Packit 667938
		my $Msg = $_[0];
Packit 667938
		$Msg =~ s/\n/\r\n/g;
Packit 667938
                $Msg =~ s/[\n\r]$//g;
Packit 667938
		$EventLog->Report({
Packit 667938
 		      EventID => 1000,
Packit 667938
                      Category => "WARN",
Packit 667938
		      EventType => $Type,
Packit 667938
                      Data => '',                       
Packit 667938
		      Strings => $Msg });
Packit 667938
		$EventLog->Close;
Packit 667938
	    };
Packit 667938
	    $SIG{__DIE__} = sub {
Packit 667938
                return if $^S ; # no handler in eval
Packit 667938
		my $EventLog = Win32::EventLog->new('MRTG');
Packit 667938
		my $Msg = $_[0];
Packit 667938
		$Msg =~ s/\n/\r\n/g;
Packit 667938
                $Msg =~ s/[\n\r]$//g;
Packit 667938
		$EventLog->Report({
Packit 667938
		      EventID => 1000,
Packit 667938
                      Category => "ERROR",
Packit 667938
		      EventType => &Win32::EventLog::EVENTLOG_ERROR_TYPE,
Packit 667938
                      Data => '',
Packit 667938
		      Strings => $Msg });
Packit 667938
		$EventLog->Close;
Packit 667938
		exit 1;
Packit 667938
	    };
Packit 667938
	    last;
Packit 667938
	};
Packit 667938
	$SIG{__WARN__} = sub {
Packit 667938
	    if (open DEB, ">>$::global_logfile") {
Packit 667938
		print DEB timestamp." -- $_[0]";
Packit 667938
		close DEB;
Packit 667938
	    } else {
Packit 667938
		print STDERR timestamp." -- $_[0]" 
Packit 667938
	    }
Packit 667938
	};
Packit 667938
	
Packit 667938
	
Packit 667938
	$SIG{__DIE__} = sub {
Packit 667938
            return if $^S ; # no handler in eval	    	    
Packit 667938
	    if ( open DEB, ">>$::global_logfile") {
Packit 667938
		print DEB timestamp." -- $_[0]";
Packit 667938
		close DEB;
Packit 667938
	    } else {
Packit 667938
		print STDERR timestamp." -- $_[0]" 
Packit 667938
	    }
Packit 667938
	    exit 1
Packit 667938
	};
Packit 667938
	
Packit 667938
    }
Packit 667938
}    
Packit 667938
Packit 667938
# Adds the v4only attribute to a target if the caller requests it.
Packit 667938
# (this includes targets specified using numeric IPv6 addresses...)
Packit 667938
sub v4onlyifnecessary ($$) {
Packit 667938
    my $target = shift;
Packit 667938
    my $add = shift;
Packit 667938
    my ($v6addr, $temptarget);
Packit 667938
Packit 667938
    if($add) {
Packit 667938
	# Catch numeric IPv6 addresses
Packit 667938
	if ( $target =~ /(\[[\w:]*\])(.*)/) {
Packit 667938
	    ($v6addr, $temptarget) = ($1,$2);
Packit 667938
	} else {
Packit 667938
	    $temptarget = $target;
Packit 667938
	}
Packit 667938
	return $target.(":" x (5 - ($temptarget =~ tr/://))).":v4only";
Packit 667938
    } else {
Packit 667938
	return $target;
Packit 667938
    }
Packit 667938
}
Packit 667938
__END__
Packit 667938
Packit 667938
=pod
Packit 667938
Packit 667938
=head1 NAME
Packit 667938
Packit 667938
MRTG_lib.pm - Library for MRTG and support scripts
Packit 667938
Packit 667938
=head1 SYNOPSIS
Packit 667938
Packit 667938
 use MRTG_lib;
Packit 667938
 my ($configfile, @target_names, %globalcfg, %targetcfg);
Packit 667938
 readcfg($configfile, \@target_names, \%globalcfg, \%targetcfg);
Packit 667938
 my (@parsed_targets);
Packit 667938
 cfgcheck(\@target_names, \%globalcfg, \%targetcfg, \@parsed_targets);
Packit 667938
Packit 667938
=head1 DESCRIPTION
Packit 667938
Packit 667938
MRTG_lib is part of MRTG, the Multi Router Traffic Grapher. It was separated
Packit 667938
from MRTG to allow other programs to easily use the same config files. The
Packit 667938
main part of MRTG_lib is the config file parser but some other funcions are
Packit 667938
there too.
Packit 667938
Packit 667938
=over 4
Packit 667938
Packit 667938
=item C<$MRTG_lib::OS>
Packit 667938
Packit 667938
Type of OS: WIN, UNIX, VMS
Packit 667938
Packit 667938
=item C<$MRTG_lib::SL>
Packit 667938
Packit 667938
I<Slash> in the current OS.
Packit 667938
Packit 667938
=item C<$MRTG_lib::PS>
Packit 667938
Packit 667938
Path separator in PATH variable
Packit 667938
Packit 667938
=item C<readcfg>
Packit 667938
Packit 667938
C<readcfg($file, \@targets, \%globalcfg, \%targetcfg [, $prefix, \%extrules])>
Packit 667938
Packit 667938
Reads a config file, parses it and fills some arrays and hashes. The
Packit 667938
mandatory arguments are: the name of the config file, a ref to an array which
Packit 667938
will be filled with a list of the target names, a hashref for the global
Packit 667938
configuration, a hashref for the target configuration.
Packit 667938
Packit 667938
The configuration file syntax is:
Packit 667938
Packit 667938
 globaloption: value
Packit 667938
 targetoption[targetname]: value
Packit 667938
 aprefix*extglobal: value
Packit 667938
 aprefix*exttarget[target2]: value
Packit 667938
Packit 667938
E.g.
Packit 667938
Packit 667938
 workdir: /var/stat/mrtg
Packit 667938
 target[router1]: 2:public@router1.local.net
Packit 667938
 14all*columns: 2
Packit 667938
Packit 667938
The global config hash has the structure
Packit 667938
Packit 667938
 $globalcfg{configoption} = 'value'
Packit 667938
Packit 667938
The target config hash has the structure
Packit 667938
Packit 667938
 $targetcfg{configoption}{targetname} = 'value'
Packit 667938
Packit 667938
See L<mrtg-reference> for more information about the MRTG configuration syntax.
Packit 667938
Packit 667938
C<readcfg> can take two additional arguments to extend the config file
Packit 667938
syntax. This allows programs to put their configuration into the mrtg config
Packit 667938
file. The fifth argument is the prefix of the extension, the sixth argument
Packit 667938
is a hash with the checkrules for these extension settings. E.g. if the
Packit 667938
prefix is "14all" C<readcfg> will check config lines that begin with
Packit 667938
"14all*", i.e. all lines like
Packit 667938
Packit 667938
 14all*columns: 2
Packit 667938
 14all*graphsize[target3]: 500 200
Packit 667938
Packit 667938
against the rules in %extrules. The format of this hash is:
Packit 667938
Packit 667938
 $extrules{option} = [sub{$_[0] =~ m/^\d+$/}, sub{"Error message for $_[0]"}]
Packit 667938
     i.e.
Packit 667938
 $extrules{option}[0] -> a test expression
Packit 667938
 $extrules{option}[1] -> error message if test fails
Packit 667938
Packit 667938
The first part of the array is a perl expression to test the value of the
Packit 667938
option. The test can access this value in the variable "$arg". The second
Packit 667938
part of the array is an error message to display when the test fails. The
Packit 667938
failed value can be integrated by using the variable "$arg".
Packit 667938
Packit 667938
Config settings with an different prefix than the one given in the C<readcfg>
Packit 667938
call are not checked but inserted into I<%globalcfg> and I<%targetcfg>.
Packit 667938
Prefixed settings keep their prefix in the config hashes:
Packit 667938
Packit 667938
 $targetcfg{'14all*graphsize'}{'target3'} = '500 200'
Packit 667938
Packit 667938
=item C<cfgcheck>
Packit 667938
Packit 667938
C<cfgcheck(\@target_names, \%globalcfg, \%targetcfg, \@parsed_targets)>
Packit 667938
Packit 667938
Checks the configuration read by C<readcfg>. Checks the values in the config
Packit 667938
for syntactical and/or semantical errors. Sets defaults for some options.
Packit 667938
Parses the "target[...]" options and filles the array @parsed_targets ready
Packit 667938
for mrtg functions.
Packit 667938
Packit 667938
The first three arguments are the same as for C<readcfg>. The fourth argument
Packit 667938
is an arrayref which will be filled with the parsed target defs.
Packit 667938
Packit 667938
C<cfgcheck> converts the values of target settings I<options>, e.g.
Packit 667938
Packit 667938
 options[router1]: bits, growright
Packit 667938
Packit 667938
to a hash:
Packit 667938
Packit 667938
 $targetcfg{'option'}{'bits'}{'router1'} = 1
Packit 667938
 $targetcfg{'option'}{'growright'}{'router1'} = 1
Packit 667938
Packit 667938
This is not done by C<readcfg> so if you don't use C<cfgcheck> you have to
Packit 667938
check the scalar variable I<$targetcfg{'option'}{'router1'}> (MRTG allows
Packit 667938
options to be separated by space or ',').
Packit 667938
Packit 667938
=item C<ensureSL>
Packit 667938
Packit 667938
C<ensureSL(\$pathname)>
Packit 667938
Packit 667938
Checks that the I<pathname> does not contain double path separators and ends
Packit 667938
with a path separator. It uses $MRTG_lib::SL as path separator which will be /
Packit 667938
or \ depending on the OS.
Packit 667938
Packit 667938
=item C<log2rrd>
Packit 667938
Packit 667938
C<log2rrd ($router,\%globalcfg,\%targetcfg)>
Packit 667938
Packit 667938
Convert log file to rrd format. Needs rrdtool.
Packit 667938
Packit 667938
=item C<datestr>
Packit 667938
Packit 667938
C<datestr(time)>
Packit 667938
Packit 667938
Returns the time given in the argument as a nicely formated date string.
Packit 667938
The argument has to be in UNIX time format (seconds since 1970-1-1).
Packit 667938
Packit 667938
=item C<timestamp>
Packit 667938
Packit 667938
C<timestamp()>
Packit 667938
Packit 667938
Return a string representing the current time.
Packit 667938
Packit 667938
=item C<setup_loghandlers>
Packit 667938
Packit 667938
C<setup_loghandlers(filename)>
Packit 667938
Packit 667938
Install signalhandlers for __DIE__ and __WARN__ making the errors
Packit 667938
go the the specified destination. If filename is 'eventlog'
Packit 667938
mrtg will log to the windows event logger.
Packit 667938
Packit 667938
=item C<expistr>
Packit 667938
Packit 667938
C<expistr(time)>
Packit 667938
Packit 667938
Returns the time given in the argument formatted suitable for HTTP
Packit 667938
Expire-Headers.
Packit 667938
Packit 667938
=item C<create_pid> 
Packit 667938
Packit 667938
C<create_pid()> 
Packit 667938
Packit 667938
Creates a pid file for the mrtg daemon       
Packit 667938
Packit 667938
=item C<demonize_me>
Packit 667938
Packit 667938
C<demonize_me()>
Packit 667938
Packit 667938
Puts the running program into background, detaching it from the terminal.
Packit 667938
Packit 667938
=item C<populatecache>
Packit 667938
Packit 667938
C<populatecache(\%confcache, $host, $reread, $snmpoptshash)>
Packit 667938
Packit 667938
Reads the SNMP variables I<ifDescr>, I<ipAdEntIfIndex>, I<ifPhysAddress>, I<ifName> from
Packit 667938
the I<host> and stores the values in I<%confcache> as follows:
Packit 667938
Packit 667938
 $confcache{$host}{'Descr'}{ifDescr}{oid} = (ifDescr or 'Dup')
Packit 667938
 $confcache{$host}{'IP'}{ipAdEntIfIndex}{oid} = (ipAdEntIfIndex or 'Dup')
Packit 667938
 $confcache{$host}{'Eth'}{ifPhysAddress}{oid} = (ifPhysAddress or 'Dup')
Packit 667938
 $confcache{$host}{'Name'}{ifName}{oid} = (ifName or 'Dup')
Packit 667938
 $confcache{$host}{'Type'}{ifType}{oid} = (ifType or 'Dup')
Packit 667938
Packit 667938
The value (at the right side of =) is 'Dup' if a value was retrieved
Packit 667938
muliple times, the retrieved value else.
Packit 667938
Packit 667938
=item C<readconfcache>
Packit 667938
Packit 667938
C<my $confcache = readconfcache($file)>
Packit 667938
Packit 667938
Preload the confcache from a file.
Packit 667938
Packit 667938
=item C<readfromconfcache>
Packit 667938
Packit 667938
C<writeconfcache($confcache,$file)>
Packit 667938
Packit 667938
Store the current confcache into a file.
Packit 667938
Packit 667938
=item C<writeconfcache>
Packit 667938
Packit 667938
C<writeconfcache($confcache,$file)>
Packit 667938
Packit 667938
Store the current confcache into a file.
Packit 667938
Packit 667938
=item C<storeincache>
Packit 667938
Packit 667938
C<storeincache($confcache,$host,$method,$key,$value)>
Packit 667938
Packit 667938
=item C<readfromcache>
Packit 667938
Packit 667938
C<readfromcache($confcache,$host,$method,$key)>
Packit 667938
Packit 667938
=item C<clearfromcache>
Packit 667938
Packit 667938
C<clearfromcache($confcache,$host)>
Packit 667938
Packit 667938
=item C<debug>
Packit 667938
Packit 667938
C<debug($type, $message)>
Packit 667938
Packit 667938
Prints the I<message> on STDERR if debugging is enabled for type I<type>.
Packit 667938
A debug type is enabled if I<type> is in array @main::DEBUG.
Packit 667938
Packit 667938
=back
Packit 667938
Packit 667938
=head1 AUTHORS
Packit 667938
Packit 667938
Rainer Bawidamann E<lt>Rainer.Bawidamann@rz.uni-ulm.deE<gt>
Packit 667938
Packit 667938
(This Manpage)
Packit 667938
Packit 667938
=cut