#! /usr/sepp/bin/perl
# -*- mode: Perl -*-
BEGIN{
$main::OS = 'UNIX';
#$main::OS = 'NT';
#$main::OS = 'VMS';
##################################################################
# MRTG 2.8.9  -- Config file creator
##################################################################
# Created by Tobias Oetiker <oetiker@ee.ethz.ch>
# this produces a config file for one router, by bulling info
# off the router via snmp
#################################################################
#
# Distributed under the GNU copyleft
   # The path separator is a slash, backslash or semicolon, depending
   # on the platform.
   $main::SL = {
     UNIX=>'/',
     WINDOWS=>'\\',
     NT=>'\\',
     VMS=>''
     }->{$main::OS};

   # The search path separator is a colon or semicolon depending on the
   # operating system.
   $main::PS = {
     UNIX=>':',
     WINDOWS=>';',
     NT=>';',
     VMS=>':'
     }->{$main::OS};

  # We need to find the place where cfgmaker is installed, and
  # then take the .pm and rateup programms from there.
  $main::binpath ="";
  if ($0 =~ /^(.+\Q${main::SL}\E)/) {
    $main::binpath="$1";
  } else {
    foreach $pathname ( split ${main::PS}, $ENV{'PATH'}) {
      if ((($main::OS eq 'NT') &&
           (-e "$pathname${main::SL}$0")) ||
           (-x "$pathname${main::SL}$0")) {
        $main::binpath=$pathname;
        last;
      }
    }
  }
  die "ERROR: Can\'t find location of cfgmaker executable\n" 
    unless $main::binpath; 
  unshift (@INC,$main::binpath);
}

use BER "0.57";
use SNMP_Session "0.59";
use SNMP_util "0.57";

use Socket;
use strict;
use vars '$DEBUG';

my ($session, %ipaddr, %iphost, %ipset);

my $DEBUG = 10;

my $codesc;
my $name;

my $argz = join($",@ARGV);

# Setup your defaults:
  my($vendor) = 0;
  my($codescr) = 0;
  my($withnodescr) = 0;
  my($ipindex) = 0;
  my($comments) = 0;
  my($Gsubdir) = 0;
  my($subdir) = 0;
  my($WorkDir) = "";
  my($Template) = "";
  my($invertreg) = "";
  my($noinvertreg) = "";
  my($withtables) = 1;
  my($match) = '.';
  my($nomatch) = '';

sub NormaliseDescr {
  $codesc =~ s/<BR>//g;
  $codesc =~ s/["|&\/><]//g;
  $codesc =~ s/\-[0-9]+[km]//i;
}

sub ParseOptions {
 while ($ARGV[0] =~ /^\-/) {
     if ($ARGV[0] eq '--vendor') {	$vendor = !$vendor; shift @ARGV}
  elsif ($ARGV[0] eq '-d') {	$codescr = !$codescr; shift @ARGV}
  elsif ($ARGV[0] eq '-i') {	$ipindex = !$ipindex; shift @ARGV}
  elsif ($ARGV[0] eq '-c') {	$comments = !$comments; shift @ARGV}
  elsif ($ARGV[0] eq '-s') {	$Gsubdir = $subdir ; $subdir = !$subdir; shift @ARGV}
  elsif ($ARGV[0] eq '-S') {	$subdir = $Gsubdir ; $Gsubdir = !$Gsubdir; shift @ARGV}
  elsif ($ARGV[0] eq '-n') {	$withnodescr = !$withnodescr; shift @ARGV}
  elsif ($ARGV[0] eq '-T') {	$withtables = !$withtables; shift @ARGV}
  elsif ($ARGV[0] eq '-w') {	shift @ARGV ; $WorkDir = $ARGV[0]; shift @ARGV}
  elsif ($ARGV[0] eq '-t') {	shift @ARGV ; $Template = $ARGV[0]; shift @ARGV}
  elsif ($ARGV[0] eq '-R') {	shift @ARGV ; $noinvertreg = ''; $invertreg = $ARGV[0]; shift @ARGV}
  elsif ($ARGV[0] eq '-r') {	shift @ARGV ; $invertreg = ''; $noinvertreg = $ARGV[0]; shift @ARGV}
  elsif ($ARGV[0] eq '-M') {	shift @ARGV ; $match = $ARGV[0]; shift @ARGV}
  elsif ($ARGV[0] eq '-m') {	shift @ARGV ; $nomatch = $ARGV[0]; shift @ARGV}

  else { Usage("Unknown option: $ARGV[0]\n") }
 }
}

sub Usage {
  my ($str) = @_;
  die <<USAGE;

USAGE: cfgmaker_ip [--vendor] [options] 'community'\@'router'

(This is an experimental version of cfgmaker for the new ip-get featrue of
 mrtg ... )

 Options:
 --vendor : use this option to try and wrestle some better information
   from willing livingston and cisco routers ... (may not work) (default: $vendor)

 -d : try to name Target[ifDescription] from --vendor interface description.
      If it fails, it falls back to regular naming. (default: $codescr)

 -i : to use interface IP aadress in place of its ifIndex. Useful for devices
      that may change ifIndex upon configuration changes. (default: $ipindex)
      (This depends on support of ipAdEntIfIndex snmp lookup)

 -c : toggle. Add inactive interfaces into config file as commented targets.
      (default: $comments)

 -s : add Directory[target]: router to the config file, so that each
      router gets its own subdirectory in mrtg structure. (default: $subdir)

 -S : add single global "Directory[^]: router". Useful if you use one
      config file per router. (default: $Gsubdir)

 -n : toggle. include/suppress interfaces without Description

 -w dir : specify relative or full mrtg WorkDir: (default: '$WorkDir')

 -t file : specify config file template, that is prepended to the generated conf

 -R regex : match final Titles that should be set as inverted counters
 -r regex : match final Titles that should NOT be set as inverted counters

 -M regex : include only interface whose final Title match given regex
 -m regex : from those that pass -M exclude those that match -m regex

 Note: -S and -s are exclusive. That is, using either resets the other.

EXAMPLE:  cfgmaker public\@ezwf7.ethz.ch >>mrtg.cfg

$str
USAGE
}

sub main {

    snmpmapOID('ipAdEntAddr' => '1.3.6.1.2.1.4.20.1.1',
	       'ipAdEntIfIndex' => '1.3.6.1.2.1.4.20.1.2',
	       'sysObjectID' => '1.3.6.1.2.1.1.2.0',
	       'CiscolocIfDescr' => '1.3.6.1.4.1.9.2.2.1.1.28',
	       'ifAlias' => '1.3.6.1.2.1.31.1.1.1.18');

  my(%ifType_d)=('1'=>'Other',
		 '2'=>'regular1822',
		 '3'=>'hdh1822',
		 '4'=>'ddnX25',
		 '5'=>'rfc877x25',
		 '6'=>'ethernetCsmacd',
		 '7'=>'iso88023Csmacd',
		 '8'=>'iso88024TokenBus',
		 '9'=>'iso88025TokenRing',
		 '10'=>'iso88026Man',
		 '11'=>'starLan',
		 '12'=>'proteon10Mbit',
		 '13'=>'proteon80Mbit',
		 '14'=>'hyperchannel',
		 '15'=>'fddi',
		 '16'=>'lapb',
		 '17'=>'sdlc',
		 '18'=>'ds1',
		 '19'=>'e1',
		 '20'=>'basicISDN',
		 '21'=>'primaryISDN',
		 '22'=>'propPointToPointSerial',
		 '23'=>'ppp',
		 '24'=>'softwareLoopback',
		 '25'=>'eon',
		 '26'=>'ethernet-3Mbit',
		 '27'=>'nsip',
		 '28'=>'slip',
		 '29'=>'ultra',
		 '30'=>'ds3',
		 '31'=>'sip',
		 '32'=>'frame-relay',
		 '33'=>'rs232',
		 '34'=>'para',
		 '35'=>'arcnet',
		 '36'=>'arcnetPlus',
		 '37'=>'atm',
		 '38'=>'miox25',
		 '39'=>'sonet',
		 '40'=>'x25ple',
		 '41'=>'iso88022llc',
		 '42'=>'localTalk',
		 '43'=>'smdsDxi',
		 '44'=>'frameRelayService',
		 '45'=>'v35',
		 '46'=>'hssi',
		 '47'=>'hippi',
		 '48'=>'modem',
		 '49'=>'aal5',
		 '50'=>'sonetPath',
		 '51'=>'sonetVT',
		 '52'=>'smdsIcip',
		 '53'=>'propVirtual',
		 '54'=>'propMultiplexor',
		 '55'=>'100BaseVG',
                 #### New IF Types added 9/24/98 by Russ Carleton (roccor@livenetworking.com)
                 #### based on the IANA file updated at ftp://ftp.isi.edu/mib/ianaiftype.mib
                 '56'=>'Fibre Channel',
                 '57'=>'HIPPI Interface',
                 '58'=>'Obsolete for FrameRelay',
                 '59'=>'ATM Emulation of 802.3 LAN',
                 '60'=>'ATM Emulation of 802.5 LAN',
                 '61'=>'ATM Emulation of a Circuit',
                 '62'=>'FastEthernet (100BaseT)',
                 '63'=>'ISDN & X.25',
                 '64'=>'CCITT V.11/X.21',
                 '65'=>'CCITT V.36',
                 '66'=>'CCITT G703 at 64Kbps',
                 '67'=>'Obsolete G702 see DS1-MIB',
                 '68'=>'SNA QLLC',
                 '69'=>'Full Duplex Fast Ethernet (100BaseFX)',
                 '70'=>'Channel',
                 '71'=>'Radio Spread Spectrum (802.11)',
                 '72'=>'IBM System 360/370 OEMI Channel',
                 '73'=>'IBM Enterprise Systems Connection',
                 '74'=>'Data Link Switching',
                 '75'=>'ISDN S/T Interface',
                 '76'=>'ISDN U Interface',
                 '77'=>'Link Access Protocol D (LAPD)',
                 '78'=>'IP Switching Opjects',
                 '79'=>'Remote Source Route Bridging',
                 '80'=>'ATM Logical Port',
                 '81'=>'AT&T DS0 Point (64 Kbps)',
                 '82'=>'AT&T Group of DS0 on a single DS1',
                 '83'=>'BiSync Protocol (BSC)',
                 '84'=>'Asynchronous Protocol',
                 '85'=>'Combat Net Radio',
                 '86'=>'ISO 802.5r DTR',
                 '87'=>'Ext Pos Loc Report Sys',
                 '88'=>'Apple Talk Remote Access Protocol',
                 '89'=>'Proprietary Connectionless Protocol',
                 '90'=>'CCITT-ITU X.29 PAD Protocol',
                 '91'=>'CCITT-ITU X.3 PAD Facility',
                 '92'=>'MultiProtocol Connection over Frame/Relay',
                 '93'=>'CCITT-ITU X213',
                 '94'=>'Asymetric Digitial Subscriber Loop (ADSL)',
                 '95'=>'Rate-Adapt Digital Subscriber Loop (RDSL)',
                 '96'=>'Symetric Digitial Subscriber Loop (SDSL)',
                 '97'=>'Very High Speed Digitial Subscriber Loop (HDSL)',
                 '98'=>'ISO 802.5 CRFP',
                 '99'=>'Myricom Myrinet',
                 '100'=>'Voice recEive and transMit (voiceEM)',
                 '101'=>'Voice Foreign eXchange Office (voiceFXO)',
                 '102'=>'Voice Foreign eXchange Station (voiceFXS)',
                 '103'=>'Voice Encapulation',
                 '104'=>'Voice Over IP Encapulation',
                 '105'=>'ATM DXI',
                 '106'=>'ATM FUNI',
                 '107'=>'ATM IMA',
                 '108'=>'PPP Multilink Bundle',
                 '109'=>'IBM IP over CDLC',
                 '110'=>'IBM Common Link Access to Workstation',
                 '111'=>'IBM Stack to Stack',
                 '112'=>'IBM Virtual IP Address (VIPA)',
                 '113'=>'IBM Multi-Protocol Channel Support',
                 '114'=>'IBM IP over ATM',
                 '115'=>'ISO 802.5j Fiber Token Ring',
                 '116'=>'IBM Twinaxial Data Link Control (TDLC)',
                 '117'=>'Gigabit Ethernet',
                 '118'=>'Higher Data Link Control (HDLC)',
                 '119'=>'Link Access Protocol F (LAPF)',
                 '120'=>'CCITT V.37',
                 '121'=>'CCITT X.25 Multi-Link Protocol',
                 '122'=>'CCITT X.25 Hunt Group',
                 '123'=>'Transp HDLC',
                 '124'=>'Interleave Channel',
                 '125'=>'Fast Channel',
                 '126'=>'IP (for APPN HPR in IP Networks)',
                 '127'=>'CATV MAC Layer',
                 '128'=>'CATV Downstream Interface',
                 '129'=>'CATV Upstream Interface',
                 '130'=>'Avalon Parallel Processor',
                 '131'=>'Encapsulation Interface',
                 '132'=>'Coffee Pot',
                 '133'=>'Circuit Emulation Service',
                 '134'=>'ATM Sub Interface',
                 '135'=>'Layer 2 Virtual LAN using 802.1Q',
                 '136'=>'Layer 3 Virtual LAN using IP',
                 '137'=>'Layer 3 Virtual LAN using IPX',
                 '138'=>'IP Over Power Lines',
                 '139'=>'Multi-Media Mail over IP',
                 '140'=>'Dynamic synchronous Transfer Mode (DTM)',
                 '141'=>'Data Communications Network',
                 '142'=>'IP Forwarding Interface'
                 );

  ParseOptions();
  my($community,$router) = ($1,$2) if $ARGV[0] =~ /(.*)\@(.*)/;

  Usage() unless $community && $router;

  if ($Template) {
     open(TEMPL,$Template) or die "Can't open template file: $Template: !$\n";
  }

  print "# cfgmaker was run with args: $argz\n";
  print "# Add a WorkDir: /some/path line to this file\n\n";
  print "WorkDir: $WorkDir\n\n" if ($WorkDir);

  if ($Template) {
     print "# included from $Template\n";
     while (<TEMPL>) {
	s/\t/ /g;  #replace tabs by spac
	next if /^\s+$/; #ignore white space
	next if /^\s*\#/; #ignore comments
	print ;
     }
     print "# /included from $Template\n";
     print "\n";
  }
  print "Directory[^]: $router\n\n" if ($Gsubdir);

    $session = SNMP_Session->open ($router, $community, 161)
	|| die "Error opening SNMP session to $router";
 
  my($sysDescr,$sysContact,$sysName,$sysLocation,$ifNumber,$sysObjectID) =
    snmpget("$community\@$router",
	    'sysDescr','sysContact','sysName',	'sysLocation', 'ifNumber', 'sysObjectID');

   my $coSysDescr = $sysDescr; 
   $sysDescr =~ s/[\r\n]+/<BR>/g;  # Change returns to <BR>
   $coSysDescr =~ s/[\r\n]+/\n#              /g;  # Change returns to commented
   my($cisco_router_sysid) = '1\.3\.6\.1\.4\.1\.9';
   my($livingston_router_sysid) = '1\.3\.6\.1\.4\.1\.307';
   my($ciscobox) = ($sysObjectID =~ /^$cisco_router_sysid/);
   my($portmaster) = ($sysObjectID =~ /^$livingston_router_sysid/);

    print <<ECHO if ($comments);

######################################################################
# Description: $coSysDescr
#     Contact: $sysContact
# System Name: $sysName
#    Location: $sysLocation
#.....................................................................
ECHO

  $session->map_table ([[1,3,6,1,2,1,4,20,1,1],	# ipAdEntAddr
			[1,3,6,1,2,1,4,20,1,2]], # ipAdEntIf
		       sub ($@) {
			   my ($index, $ipadentaddr, $ipadentif) = @_;
			   grep (defined $_ && ($_=pretty_print $_),
				 ($ipadentif, $ipadentaddr));
			   $ipaddr{$ipadentif} = $ipadentaddr if !$ipset{$ipadentif};
			   $iphost{$ipadentif} = 
			       gethostbyaddr(pack('C4',split(/\./,$ipaddr{$ipadentif})), AF_INET) if !$ipset{$ipadentif};
			   if (!defined $iphost{$ipadentif} || ($iphost{$ipadentif} eq '')){
			       $iphost{$ipadentif} = 'No name for IP';
			   }
			   $ipset{$ipadentif} = 1;
		       });

  print STDERR "Got Addresses\n" if $DEBUG;
  print STDERR "Got IfTable\n" if $DEBUG;

  my(%sifdesc,%siftype,%sifspeed,%sifadminstatus,%sifoperstatus,%sciscodescr);

  ### May need the cisco IOS version number so we know which oid to use
  ###   to get the cisco description.
  ###
  ### - mjd 2/5/98 (Mike Diehn) (mdiehn@mindspring.net)
  ###
  my ($cisco_ver, $cisco_descr_oid, @ciscodescr);
  if ( $ciscobox ) {
    ($cisco_ver) = ($sysDescr =~ m/Version\s+([\d\.]+)\(\d/o);
    $cisco_descr_oid = ($cisco_ver ge "11.2") ? "ifAlias" : "CiscolocIfDescr";
  }

$session->map_table ([[1,3,6,1,2,1,2,2,1,1], # ifIndex
		      [1,3,6,1,2,1,2,2,1,2], # ifDescr
		      [1,3,6,1,2,1,2,2,1,3], # ifType
		      [1,3,6,1,2,1,2,2,1,5], # ifSpeed
		      [1,3,6,1,2,1,2,2,1,7], # ifAdminStatus
		      [1,3,6,1,2,1,2,2,1,8]], # ifOperStatus
sub ($@) {
    my ($rowindex,$index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus) = @_;
    grep (defined $_ && ($_=pretty_print $_),
	  ($index,$ifdescr,$iftype,$ifspeed,$ifadminstatus,$ifoperstatus));
    $sifdesc{$index} = $ifdescr;
    $siftype{$index} = $iftype;
    $sifspeed{$index} = $ifspeed;
    $sifadminstatus{$index} = $ifadminstatus;
    $sifoperstatus{$index} = $ifoperstatus;
    if ($portmaster && $vendor) {
      
      # We can only approximate speeds
      # 
      # so we think that ppp can do 76800 bit/s, and slip 38400.
      # (actualy, slip is a bit faster, but usualy users with newer modems
      # use ppp). Alternatively, you can set async speed to 115200 or
      # 230400 (the maximum speed supported by portmaster).
      # 
      # But if the interface is ptpW (sync), max speed is 128000
      # change it to your needs. On various Portmasters there are
      # various numbers of sync interfaces, so modify it.
      # 
      #  The most commonly used PM-2ER has only one sync.
      # 
      #  Paul Makeev (mac@redline.ru)
      # 

      if ($siftype{$index} eq '23') {
              if ($sifdesc{$index} eq 'ptpW1') {
                      $sifspeed{$index} = 128000;
              } else {
                      $sifspeed{$index} = 76800;
              }
      } elsif ($siftype{$index} eq '28') {
              $sifspeed{$index} = 38400;
      } elsif ($siftype{$index} eq '6') {
              $sifspeed{$index} = 10000000;
      }
    }

    ### Move this section south so we know what type of
    ###  circuit we're looking at before we retrieve
    ###  the cisco interface alias.
    ###
    ### This whole cicso thing should be re-written, but since
    ###   this script doesn't need to run quickly...
    ###
    ###  - mjd 2/5/98
    ###
    # Get the user configurable interface description entered in the config 
    # if it's a cisco-box
    #
    if ($ciscobox && $vendor) {

	my ($enoid, @descr);

	$enoid = $cisco_descr_oid . "." . $index;

	if ( $cisco_ver ge "11.2" or $siftype{$index} != '32' ) {

	  ### This is either not a frame-relay sub-interface or
	  ###  this router is running IOS 11.2+ and interface
	  ###  type won't matter. In either of these cases, it's
	  ###  ok to try getting the ifAlias or ciscoLocIfDesc.
	  ###
	  @descr = snmpget("$community\@$router", $enoid);

	} else {

	  ### This is a frame-relay sub-interface *and* the router
	  ###  is running an IOS older than 11.2. Therefore, we can
	  ###  get neither ifAlias nor ciscoLocIfDesc. Do something
	  ###  useful.
	  ###
	  @descr = ("Cisco PVCs descriptions require IOS 11.2+.");

	} # end if else

	### Put whatever I got into the array we'll use later to append the result
	###   of this operation onto the results from the ifDescr fetch.
	###
	push @ciscodescr, shift @descr;

    } # end if ($cisco_box && $vendor)

    # especially since cisco does not return a if
    # descr for each interface it has ...
    ## JB 2/8/97 - sometimes IOS inserts E1 controllers in the standard-MIB
    ## interface table, but not in the local interface table. This puts the
    ## local interface description table out-of-sync. the following 
    ## modification skips over E1 cards as interfaces.
    #
    ### I suspect that the mod I made above, to use the ifAlias
    ###   oid if possible, may cause problems here. If it seems
    ###   that your descriptions are out of sync, try commenting
    ###   out the "if ( condition )" and it's closing right brace
    ###   so that the "shift @ciscodescr" get executed for *all*
    ###   iterations of this loop.
    ###
    ### - mjd 2/5/95
    ###
#    if ($ciscobox && $siftype{$index} != 18) {
          $sciscodescr{$index} = "<BR>" . (shift @ciscodescr) if @ciscodescr;
#    }
});
  my $index;
  print "#---------------------------------------------------------------\n";

INTERFACE:  foreach $index ( sort { $a <=> $b } keys %sifdesc) {
    my $c;
    my $speed = int($sifspeed{$index} / 8); # bits to byte
    my $speed_str=&fmi($speed);
    $name="$iphost{$index}";
    $name = "$router.$index" if not $name or $name =~ /\s/;


  if (($sifadminstatus{$index} != 1)
# this check added by Josh - don't query E1-stack controllers
      || ($siftype{$index} == 18)
	|| ($siftype{$index} == 24)
	|| ($speed == 0 ) 
	|| ($speed > 400 * 10**6)  #speeds of 400 MByte/s are not realistic
	|| ($sifoperstatus{$index} == 3)) {
    if(!$comments) { next INTERFACE ; }

    print <<ECHO;
########
######## This Interface is one of the following
######## - administratively not UP
######## - it is in test mode
######## - it is a softwareLoopback interface
######## - has a unrealistic speed setting
######## It is commented out for this reason.
########
ECHO
  $c="# ";
  }else {
    $c = '';
  }

 $codesc = $sciscodescr{$index};
my $coindex = $index;
my $coSubdir = "";
my $coTitle = "";

  if ($codescr) {
    $codesc =~ s/ /-/g;
    NormaliseDescr();
    $codesc =~ s/-+/-/g;
    $codesc =~ s/^-|-$//;
    $name = lc($codesc) if ($codesc =~ /.+/);
  }
  if ($ipindex) {
    $coindex = "/".$ipaddr{$index} if ($ipaddr{$index} =~ /.+/);
  }
  if ($subdir) {
    $coSubdir = "\n${c}Directory[$name]: $router";
  }

  $coTitle = $sciscodescr{$index};
  $coTitle =~ s/<BR>//;
  if (!$coTitle) {
    if (! $withnodescr) { next INTERFACE ; }
    $coTitle = "$sysName ($iphost{$index}): $sifdesc{$index}";
  }

  if ($invertreg) {
    $coindex = "-".$coindex if ($coTitle =~ /$invertreg/x ) }
  elsif ($noinvertreg) {
    $coindex = "-".$coindex if ($coTitle !~ /$noinvertreg/x ) }

  if ($match) {
     next INTERFACE if ($coTitle !~ /$match/);
  }
  if ($nomatch) {
     next INTERFACE if ($coTitle =~ /$nomatch/);
  }

  print <<ECHO;
${c}
${c}Target[$name]: $coindex:$community\@$router	# $index $coSubdir
${c}MaxBytes[$name]: $speed
${c}Title[$name]: $coTitle
${c}PageTop[$name]: <H1>Traffic Analysis for $sifdesc{$index}
${c} $sciscodescr{$index}</H1>
ECHO
  print <<TABLE if ($withtables);
${c} <TABLE>
${c}   <TR><TD>System:</TD><TD>$sysName in $sysLocation</TD></TR>
${c}   <TR><TD>Maintainer:</TD><TD>$sysContact</TD></TR>
${c}   <TR><TD>Interface:</TD><TD>$sifdesc{$index} ($index)</TD></TR>
${c}   <TR><TD>IP:</TD><TD>$iphost{$index} ($ipaddr{$index})</TD></TR>
${c}   <TR><TD>Max Speed:</TD>
${c}       <TD>$speed_str ($ifType_d{$siftype{$index}})</TD></TR>
${c}  </TABLE>
TABLE
  print <<SEPA;
${c}
#---------------------------------------------------------------
SEPA
  }
}
  
main;
exit(0);

sub fmi {
  my($number) = $_[0];
  my(@short);
  @short = ("Bytes/s","kBytes/s","MBytes/s","GBytes/s");
  my $digits=length("".$number);
  my $divm=0;
  while ($digits-$divm*3 > 4) { $divm++; }
  my $divnum = $number/10**($divm*3);
  return sprintf("%1.1f %s",$divnum,$short[$divm]);
}

