##
## Simple and first SNMP Agent. Provides some TUBS extensions. See the
## MIB definition tubs.mib for more details.
##
## Copyright (c) 1994
##
## J. Schoenwaelder
## TU Braunschweig, Germany
## Institute for Operating Systems and Computer Networks
##
## Permission to use, copy, modify, and distribute this
## software and its documentation for any purpose and without
## fee is hereby granted, provided that this copyright
## notice appears in all copies.  The University of Braunschweig
## makes no representations about the suitability of this
## software for any purpose.  It is provided "as is" without
## express or implied warranty.

mib load $scotty_lib/mibs/tubs.mib

##
## Return the actual date and time in the textual convention format.
##

proc DateAndTime {} {
    set months "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"
    set date [getdate]
    set y [lindex $date 4]
    set m [lsearch $months [lindex $date 1]]; incr m
    set d [lindex $date 2]
    return "$y-$m-$d-[lindex $date 3]"
}

snmp instance scottyDate.0 scottyDate [DateAndTime]
snmp instance scottyTrapDst.0 scottyTrapDst localhost
snmp instance scottyTrapMsg.0 scottyTrapMsg ""

##
## Create the scalars in the tcl group.
##

snmp instance tclVersion.0 tclVersion [info tclversion]

snmp instance tclCmdCount.0 tclCmdCount
trace variable tclCmdCount r tclCmdCount::get
proc tclCmdCount::get { vname idx operation } {
    upvar #0 $vname tclCmdCount
    set tclCmdCount [info cmdcount]
}

##
## Create the scalars in the nfsstat group. A get request to
## the variables nfsstatScalls or nfsstatCcalls will refresh
## all values by calling nfsstat and parsing the output.
##

foreach s [mib successor nfsServer] {
    snmp instance nfsServer.$s.0 nfsstatS$s 0
}
foreach s [mib successor nfsClient] {
    snmp instance nfsClient.$s.0 nfsstatC$s 0
}

trace variable nfsstatScalls r nfsstatScalls::get
proc nfsstatScalls::get { vname idx operation } {

    global nfsstatScalls nfsstatSbad \
	nfsstatSnull nfsstatSgetattr nfsstatSsetattr nfsstatSroot \
	nfsstatSlookup nfsstatSreadlink nfsstatSread \
	nfsstatSwrcache nfsstatSwrite nfsstatScreate \
	nfsstatSremove nfsstatSrename nfsstatSlink nfsstatSsymlink \
	nfsstatSmkdir nfsstatSrmdir nfsstatSreaddir nfsstatSfsstat

    set f [open "|/usr/etc/nfsstat -sn"]
    gets $f line; gets $f line; gets $f line; gets $f line
    scan $line "%d %d" nfsstatScalls nfsstatSbad
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s %d %*s %d %*s %d %*s" \
        nfsstatSnull nfsstatSgetattr nfsstatSsetattr nfsstatSroot \
	nfsstatSlookup nfsstatSreadlink nfsstatSread
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s %d %*s %d %*s %d %*s" \
        nfsstatSwrcache nfsstatSwrite nfsstatScreate \
	nfsstatSremove nfsstatSrename nfsstatSlink nfsstatSsymlink
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s" \
	nfsstatSmkdir nfsstatSrmdir nfsstatSreaddir nfsstatSfsstat
    close $f
}

trace variable nfsstatCcalls r nfsstatCcalls::get
proc nfsstatCcalls::get { vname idx operation } {

    global nfsstatCcalls nfsstatCbad \
	nfsstatCnull nfsstatCgetattr nfsstatCsetattr nfsstatCroot \
	nfsstatClookup nfsstatCreadlink nfsstatCread \
	nfsstatCwrcache nfsstatCwrite nfsstatCcreate \
	nfsstatCremove nfsstatCrename nfsstatClink nfsstatCsymlink \
	nfsstatCmkdir nfsstatCrmdir nfsstatCreaddir nfsstatCfsstat

    set f [open "|/usr/etc/nfsstat -cn"]
    gets $f line; gets $f line; gets $f line; gets $f line
    scan $line "%d %d" nfsstatCcalls nfsstatCbad
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s %d %*s %d %*s %d %*s" \
        nfsstatCnull nfsstatCgetattr nfsstatCsetattr nfsstatCroot \
	nfsstatClookup nfsstatCreadlink nfsstatCread
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s %d %*s %d %*s %d %*s" \
        nfsstatCwrcache nfsstatCwrite nfsstatCcreate \
	nfsstatCremove nfsstatCrename nfsstatClink nfsstatCsymlink
    gets $f line; gets $f line
    scan $line "%d %*s %d %*s %d %*s %d %*s" \
	nfsstatCmkdir nfsstatCrmdir nfsstatCreaddir nfsstatCfsstat
    close $f
}

##
## The tclEval group contains a table of variables that can store
## tcl code for evaluation. This is only useful if you use security
## mechanisms in the protocol exchange.
##

snmp instance tclEvalSlot.0 tclEvalSlot 1

trace variable tclEvalSlot r tclEvalSlot::get
proc tclEvalSlot::get { vname idx operation } {
    upvar #0 $vname tclEvalSlot
    incr tclEvalSlot
}

set tclEvalValue(foo) ""
trace variable tclEvalValue r tclEvalValue::get
unset tclEvalValue(foo)
proc tclEvalValue::get { vname idx operation } {
    upvar #0 $vname tclEvalValue
    global tclEvalStatus tclEvalString
    if {$tclEvalStatus($idx) == "active"} {
	if [catch {eval $tclEvalString($idx)} res] {
	    puts stderr "** TclEvaluation of $tclEvalString($idx) failed"
	}
	set tclEvalValue($idx) $res
    }
}

set tclEvalStatus(foo) ""
trace variable tclEvalStatus w tclEvalStatus::set
unset tclEvalStatus(foo)
proc tclEvalStatus::set { vname idx operation } {
    upvar #0 $vname tclEvalStatus
    global tclEvalSlot
    switch $tclEvalStatus($idx) {
	active {
	}
	notInService {
	}
	notReady {
	}
	createAndGo {
	    snmp instance tclEvalIndex.$idx  tclEvalIndex($idx) $idx
	    snmp instance tclEvalString.$idx tclEvalString($idx)
	    snmp instance tclEvalValue.$idx  tclEvalValue($idx)
	    snmp instance tclEvalStatus.$idx tclEvalStatus($idx) active
	    set tclEvalStatus($idx) active
	}
	createAndWait {
	    snmp instance tclEvalIndex.$idx  tclEvalIndex($idx) $idx
	    snmp instance tclEvalString.$idx tclEvalString($idx)
	    snmp instance tclEvalValue.$idx  tclEvalValue($idx)
	    set tclEvalStatus($idx) notReady
	}
	destroy {
	    after 5 "unset tclEvalIndex($idx)"
	    after 5 "unset tclEvalString($idx)"
	    after 5 "unset tclEvalValue($idx)"
	    after 5 "unset tclEvalStatus($idx)"
	}
    }
}

##
## The proc group contains a table of actually running processes.
## This is much the same as the running software group of the Host
## Resources MIB, but it was here much earlier and it has a mechanism
## to explicitly reload the proc table.
##

snmp instance procReload.0 procReload

trace variable procReload w procReload::set
proc procReload::set { vname idx operation } {

    global procReload procID procCmd

    # destroy all existing entries
    if {[info exists procID]} {
	foreach id [array names procID] { unset procID($id) }
    }
    if {[info exists procCmd]} {
	foreach id [array names procCmd] { unset procCmd($id) }
    }

    # get the process inforamtion
    if {[catch read_ps_ax]} {
        if {[catch read_ps_e]} {
            puts stderr "** Fatal error: unable to get process list"
        }
    }

    set procReload [DateAndTime]
}

##
## Implementation. Proc read_ps read the global arrays procID and
## procCmd. There are two version for BSD and SYSV machines.
##

proc read_ps_ax {} {

    global procID procCmd

    set ps [open "| ps -axc"]
    gets $ps line
    while {![eof $ps]} {
        set pid [lindex $line 0]
        if {[scan $pid "%d" foo] == 1} {
            regsub {^[^:]*:[0-9][0-9]} $line "" cmd
            snmp instance procID.$pid procID($pid) $pid
            snmp instance procCmd.$pid procCmd($pid) [string trim $cmd]
        }
        gets $ps line
    }
    close $ps
}

proc read_ps_e {} {

    global procID procCmd

    set ps [open "| ps -e"]
    gets $ps line
    while {![eof $ps]} {
        set pid [lindex $line 0]
        if {[scan $pid "%d" foo] == 1} {
            regsub {^[^:]*:[0-9][0-9]} $line "" cmd
            snmp instance procID.$pid procID($pid) $pid
            snmp instance procCmd.$pid procCmd($pid) [string trim $cmd]
        }
        gets $ps line
    }
    close $ps
}
