#!/usr/pkg/bin/perl

#           ########  hostmon-client.osf1 #######
#
## $Header: /home/vikas/src/nocol/perlnocol/hostmon-osclients/RCS/hostmon-client.osf1,v 1.0 1999/01/05 06:47:23 vikas Exp $
#
# This file is appended by 'hostmon-client'
#
###
# All the following functions must print out the following:
#   		VARIABLE VALUE UNITS COMMENT
# For variables that are part of a varying maximum, normalize it and give
# the percentage instead (e.g. free memory, etc.)
###
###

### csh% uptime
###  12:09pm  up 16 days, 19:58,  5 users,  load average: 0.32, 0.21, 0.01
###
sub uptime {
    local ($cmd) = "uptime";
    local ($value) = -1 ;
    local ($uptime) = 0;    
    open (CMD, "$cmd |");
    while (<CMD>) {
	$debug &&  print STDERR "(debug)uptime: $_" ;
	chop; tr/\r\n//d;

	if ( /^.*up\s+(\d+)\s+day.*,\s*(\d+):(\d+),.*load\s*average\S*:\s+(\S+),\s+(\S+),\s+(\S+).*$/ ) {
	    $uptime = ($1 * 1440) + ($2 * 60) + $3;
	    printf "Uptime %d mins\n", $uptime;
	    printf "Load5 %d load-5min\n", int($5) ;
	    last ;
	}
	elsif ( /^.*up\s+(\d+):(\d+),.*load\s*average\S*:\s+(\S+),\s+(\S+),\s+(\S+).*$/ ) {
	    $uptime = ($1 * 60) + $2;
	    printf "Uptime %d mins\n", $uptime;
	    printf "Load5 %d load-5min\n", int($4) ;
	    last ;
	}
	elsif ( /^.*load\s*average\S*:\s+(\S+),\s+(\S+),\s+(\S+).*$/ ) {
	    printf "Load5 %d load-5min\n", int($2) ;
	    last ;
	}
	else { print STDERR "(debug)uptime() : command format not understood.\n"; }
    }	
    close (CMD);

#    print "Load 9999 load UnParseableInput\n";
}

### sunos4% pstat -T
#	367/1017 files
#	298/693 inodes
#	97/266 processes
#	53924/154220 swap
#
# osf1% swapon -s
#	Total swap allocation:
#	    Allocated space:        32768 pages (256MB)
#	    Reserved space:          6738 pages ( 20%)
#	    Available space:        26030 pages ( 79%)

sub pstat {

    local ($tmb, $total);
    open (CMD, "swapon -s |");
    while (<CMD>) {
      $total++ if (/^Total/);
      next unless $total;
      if ( /\s*Allocated\s+space.*?(\d+)MB/ ) { $tmb = $1 ; next; }
      if ( /\s*Available\s+space.*?(\d+)%/ )  {
	printf "SwapSpace %d MBytes\n", int($tmb * $1 / 100);
	break ;		# no more processing needed
      }
    }
    close (CMD);

}  # end &pstat()

### nfsstat
# Have to calculate deltas in each pass since the nfsstat command does not
# give us 'rate' over a time period.  
# STORE THE OLD VALUES IN EACH PASS AND CALC DELTA EACH TIME.
#
# Timeouts are not the same as retries!  Timeouts to reflect problems 
# communicating to the server (nfs server not responding), which in turn
# is indicated by successive retries on a NFS request.  The cause for the
# retry may be local socket blockage, network loss, or a busy server.
#
# sunos4> nfsstat -rc
#
# Client rpc:
# calls    badcalls retrans  badxid   timeout  wait     newcred  timers
# 7915078  52102    0        345      52073    0        0        7164
#
# osf1> nfsstat -rc
# Client rpc:
# tcp: calls      badxids    badverfs   timeouts   newcreds
#      0          0          0          0          0          
#      creates    connects   badconns   inputs     avails     interrupts
#      0          0          0          0          0          0          
# udp: calls      badxids    badverfs   timeouts   newcreds   retrans
#      2266289    28         0          138        0          0          
#      badcalls   timers     waits
#      139        1982       0          
#
sub nfsstat {
    local ($cmd) = "nfsstat";
    local ($dcalls, $dtimeo, $dretries, $tvalue, $rvalue);
    if ($OS_BSDI) { open (CMD, "$cmd |");}
    else { open (CMD, "$cmd -rc |");}	# '-rc' for client related data only
    while (<CMD>) {
	chop; tr/\r\n//d;
				# rate =  timeout/calls
	if (/^\s*(\d+)\s+\d+\s+\d+\s+\d+\s+(\d+).*$/ )  {
	    $debug && print STDERR "(debug)nfsstat: $_\n" ;
	    
	    $dcalls = $1 - $onfscalls ; $onfscalls = $1 ;
	    $dtimeo = $2 - $otimeo ; $otimeo = $2 ;
	    last ;		# no more lines
	}
    }				# end (while)
    close (CMD);

    if ($dcalls == 0) { $tvalue = 0 ; $rvalue = 0;}
    else {
	$tvalue = int($dtimeo * 100 / $dcalls);   # calc timeout rate
	$rvalue = int($dretries * 100 / $dcalls); # calc retry rate
    }

    if ($debug) { print STDERR "(debug)nfsstat: $dtimeo/$dcalls\n" ;}
    print "NFStimeouts $tvalue %timeouts\n";

}	# end &nfsstat()

## df
# Extract space availability stats. Printing out available MBytes and
# percent full (together they make sense).
# Note that this command prints out a number of lines with same variable
# name (one for each disk). The hostmon server picks out the worst of
# these lines.
#
# sun41-vikas> df -t 4.2
#   Filesystem            kbytes    used   avail capacity  Mounted on
#   /dev/sd0a              24239   12492    9324    57%    /
#   /dev/sd0g             191919  149692   23036    87%    /usr
#   /dev/sd3c            1230152 1062490   44647    96%    /usr/local
#
# osf1> df -t ufs -k -i
# Filesystem  1024-blocks   Used   Available Capacity     Iused       Ifree  %Iused  Mounted on
# /dev/rz3a         63231  51991     4916    92%    1816    15078    11%   /

sub df {

    open (CMD, "df -t ufs -k -i |");
    while (<CMD>) {
	chop; tr/\r\n//d;
	if (/^\s*Filesystem/)  { next; }    # ignore header line
	if (/^\s*\S+:\/\S*/)   { next; }    # ignore NFS mounts

	if (/^\s*(\/dev\/.*|mfs:\d+)\s+\d+\s+\d+\s+(\d+)\s+(\d+)%\s+(\d+)\s+(\d+)\s+(\d+)%\s+(\/\S*)\s*$/)
	{
	    $debug && print STDERR "(debug)df: $_\n" ;
	    
	    printf "DFspace_avail %d MB $7\n", int($2/1000);
	    print "DFspace_\%used $3 \%full $7\n";
	    print "DFinodes_avail $5 inodes $7\n";
	    print "DFinodes_\%used $6 \%inodes $7\n";
	}
    }
    close (CMD);
    return ;
}	# end &df()

##
#  For each disk, the number of transfers per second, bytes transferred
#  per second (in kilobytes), and the milliseconds per average seek.  Not
#  all disk drives report seek times.
#
# osf1>  iostat 5 2
#      tty     rz1      rz2      rz3      dk3     cpu
# tin tout bps tps  bps tps  bps tps  bps tps  us ni sy id
#   0    6   1   0    1   0    6   1    0   0   6  0  7 87
#   0   12   0   0    0   0    0   0    0   0   2  0  1 97
##
sub iostat {
    local ($cmd) = "iostat";
    local ($str, $diskno, $numdisks, $ttydone);
    local (@IOname);

    open (CMD, "$cmd 5 3 |");

    while (<CMD>) {
	chop; tr/\r\n//d;
	$str = $_ ;
	if (/^\s*bps\s+tps\s+/) { next; } # ignore header line
	if (/^\s+[A-z]+/) {	# header line containing disk names...
	    if ($debug)  { print STDERR "(debug)iostat: $_\n"; }
	    $numdisks = 0;
	    while ( $str =~ /\s*(\w+)\s+/ ) {
		if ( $1 eq 'tty' ) { $str = $'; next; }   # BSDI lists 'tty'
		if ( $1 eq 'cpu' ) { $str = $'; last; }   # 'cpu' is not a disk 
		$str = $' ; 		   # remaining string
		$IOname[++$numdisks] = $1; # extract the name of disk
	    }			# end while()
	}

    }		# end: while(<CMD>)
    close (CMD);

    # Here we have the last line from the command above
    if ($debug)  { print STDERR "(debug)iostat: $str\n"; }
    $diskno = 0;
    $ttydone = 0;
    while ($str =~ /\s*(\d+)\s+(\d+)\s/)  # extract bps & tps
    {
	if ($diskno == $numdisks) { last ;}
	$str = $' ;  # remaining string
	if ($ttydone == 0) {++$ttydone ; next ;}   # skip tty counts
	++$diskno ;
	printf "IObps %d kbps $IOname[$diskno]\n", int($1 / 2);
    }
}	# end &iostat()


##        vmstat
# Extract paging, real-memory, cache hits, CPU load, Context switches.
# Note: Seems like the fields are fixed length, and sometimes there are
#       no spaces between the output fields.
# osf1% vmstat 5 2
# Virtual Memory Statistics: (pagesize = 8192)
#   procs    memory         pages                          intr        cpu     
#   r w u    act  free wire fault cow zero react pin pout  in  sy  cs  us sy id
#   2 60 26  4774 4810 1781  20M   5M   8M  22K   5M  14K  72 -152 145  2  7 91
#   2 60 26  4777 4807 1781  120   14   77    0    9    0  69  69  70   0  1 99
## 
sub vmstat {
    local ($i) = 0;
    local($dline);
    local ($cmd) = "vmstat";

    open (CMD, "$cmd 5 2 |");
    while (<CMD>) { $dline = $_; next; }

    # Here we have the last data line from the command above.
    if ($debug)  { print STDERR "(debug)vmstat: $dline"; }
    $_ = $dline ;
    chop; tr/\r\n//d;
	
    # if any CPU time is 100, vmstat doesnt have any spaces in it.
    s/100(\s+\d+){0,2}\s*$/ 100\1/;
    
    # I have also found vmstat to mess up the 'cs' field (no space if
    # it or the sorrounding fields are too long). Hence taking only
    # 3 digits of the context switches.
    ##  procs  #  avm  #  fre  #  si   #  so   #   pi  #  po   # disks  #      #    cs     #  us   #  sy   #  id   ######
    if (/^(\s+\d+){3}\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)(\s+\d+)+\s+\d*((\s|\d)\d\d)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/)
    {
	printf "MemFree %d MB\n", int($3 / 1000); # convert KB to MB
	print "PageFlt $5 pgflts\n";
	print "CtxtSw $9 rate\n";
	print "CPUus $11 %user\n";
	print "CPUsy $12 %system\n";
	print "CPUidle $13 %idle\n";
    }
    close (CMD);
}	# end &vmstat()


##       netstat
# Extract collision and error rates. Luckily, on SunOS there is an option
# for printing out the delta values. Since there is no easy way to 
# terminate the command after displaying 5 lines, forcibly close the
# command stream.
# Ignore the first few lines, look at the 5th and then forcibly close.
# Since the command only displays one interface's data, we look at the
# 'totals' field (anchor regexp on the right)
#
#   input    (ln0)     output            input   (Total)    output
# packets  errs  packets  errs colls   packets  errs  packets  errs colls
#   <first line with total values, ignore>
#     147     0       83     0     1       147     0       83     0     1
#     218     0      129     0     0       218     0      129     0     0
#
# 
sub netstat {
    local ($i) = 0;
    local ($cmd) = "netstat";

    local($pid) = open (CMD, "$cmd 10 |");	# 10 second sampling
    while (<CMD>) {
	if (/^\s+[A-z]+/) { next; }	# ignore header lines if any
	if (++$i < 3)  { next ;} # ignore first 3 lines
	chop; tr/\r\n//d;
	$debug && print STDERR "(debug)netstat: $_\n" ;

	if (/^\s*\d+(\s+\d+)*\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*$/)
	{
	    local ($ipkts, $opkts) = ($2, $4);

	    if ($ipkts == 0) { $ipkts = 1; } # avoid division by zero
	    if ($opkts == 0) { $opkts = 1; }
	    printf "NetIErr %d PktRate\n", int ($3 * 100 / $ipkts);
	    printf "NetOErr %d PktRate\n", int ($5 * 100 / $opkts);
	    printf "NetColl %d PktRate\n", int ($6 * 100 / $opkts);
	}
	kill ('TERM', $pid) ; last ;		# no more lines
    }	
    close (CMD);
}	# end &netstat()

# require this otherwise require &xxxx will issue an error saying true not
# returned by xxxxx module.
1;

###############      END OF hostmon-client.osf1  ###################
