#!/bin/sh # the next line restarts using wish \ exec wish "$0" "$@" # User tunable parameters set default_FIFO "/etc/diald/diald.ctl" # Default globals set monfifo "" set monfd "" set fifofd "" # strip chart code proc stripchart {win x y label} { upvar #0 var$win type set type(scale) 1 set type(entry) 1 set type(height) $y set type(label) $label frame $win -bor 0 canvas $win.canv -width $x -height $y -bor 0 -highlightthickness 0 pack $win.canv -expand 1 -fill both -pady 0 } # add a new line to the strip chart, moving it left if needed proc addtick {w val} { set win $w.canv upvar #0 var$w type set e $type(entry) set s $type(scale) set o $type(height) set h [winfo height $win] set w [expr "[winfo width $win]"] $win delete ticks if {$val > $s} { # adjust the window for a larger value than currently displayed. # get the new scale set ns [expr "int($val)"] if {$val > $ns} { incr ns } set r [expr "($s+0.0)/$ns"] $win scale all 0 $o 1 $r set s $ns } else { # Also trim the window down for a smaller value if needed. # figure out how many ticks are currently spanned by the image set t [expr "$h-([lindex [$win bbox all] 1]+1)"] set fs [expr "($t*$s*1.0)/$h"] set ns [expr "int($fs)"] if {$fs > $ns} {incr ns} if {$ns != $s} { set r [expr "($s+0.0)/$ns"] $win scale all 0 $o 1 $r set s $ns } } set v [expr "($val*$h)/$s"] # rescale vertically if needed if {"$o"!="$h"} { set sc [expr "($h+0.0)/$o"] $win scale all 0 0 1 $sc set type(height) $h } # Create a new line $win create line $e $h $e [expr "$h-$v+1"] # Check if we can shrink or expand the tick count # scroll left if needed if {"$e">="$w"} { set diff [expr "$w-($e+1)"] $win move all $diff 0 set e $w } else { incr e } # kill window elements outside of the visible window and draw tick marks $win addtag extra all $win addtag ok enclosed 0 0 [expr "$w+1"] [expr "$h+1"] $win dtag ok extra $win delete extra $win dtag all ok set x 1 while {$x < $s} { set th [expr "($x*$h)/$s"] $win create line 1 $th $w $th -tag ticks -fill red incr x } $win create text 2 2 -anchor nw -fill blue -tags ticks -text $type(label) $win addtag deltag closest 0 [winfo height $win] set type(scale) $s set type(entry) $e } # If this is 1 the icon will be an active window. # If this is 2 then there will be a seperate top level window, # named dctrlIcon that can be swallowed by FVWM Goodstuff, # or the Bowman/Afterstep Wharf. # If this is 0 then there will be neither. set fancy_icon 0 set trans(DOWN) Down set trans(CONNECT) Connect set trans(CLOSE) Close set trans(START_LINK) Start set trans(UP) Up set trans(HALF_DEAD) HalfDead set trans(STOP_LINK) StopLink set trans(KILL_LINK) KillLink set trans(STOP_DIAL) StopDial set trans(KILL_DIAL) KillDial set trans(DISCONNECT) Disconnect set trans(RETRY) Retry set trans(ERROR) Error set trans(ZOMBIE) Zombie set colors(DOWN) {{} {} red} set colors(CONNECT) {{} yellow red} set colors(START_LINK) {{} yellow {}} set colors(STOP_DIAL) {{} red red} set colors(KILL_DIAL) {{} black red} set colors(UP) {green {} {}} set colors(HALF_DEAD) {yellow {} {}} set colors(DISCONNECT) {green yellow {}} set colors(STOP_LINK) {green red {}} set colors(KILL_LINK) {green black {}} set colors(CLOSE) {{} yellow yellow} set colors(RETRY) {yellow yellow yellow} set colors(ERROR) {red red red} set colors(ZOMBIE) {black black black} # Set up the basic data for the app wm title . "Diald Control" wm iconname . "Diald" wm minsize . 1 1 proc print_usage {} { puts {Usage dctrl [-i|-animated-icon] [-c|-control-window] [-iconic] [-fifo ] [-dstatus] [-tload] [-gload] [-pqueue] [-dlog]} exit } # Deal with command line options set previous "" foreach i $argv { if {"$previous"=="-fifo"} { set default_FIFO $i set previous "" } elseif {"$i"=="-i"} { set fancy_icon 1 } \ elseif {"$i"=="-animated-icon"} { set fancy_icon 1 } \ elseif {"$i"=="-c"} { set fancy_icon 2 } \ elseif {"$i"=="-control-window"} { set fancy_icon 2 } \ elseif {"$i"=="-fifo"} { set previous $i } \ elseif {"$i"=="-iconic"} {wm iconify .} \ elseif {"$i"=="-dstatus"} { set dstatus 1 } \ elseif {"$i"=="-tload"} { set tload 1 } \ elseif {"$i"=="-gload"} { set gload 1 } \ elseif {"$i"=="-pqueue"} { set pqueue 1 } \ elseif {"$i"=="-dlog"} { set dlog 1 } \ else { print_usage } } if {"$previous"!=""} { print_usage } proc make_icon {} { toplevel .dctrlIcon -class DctrlIcon -width 50 -height 50 canvas .dctrlIcon.canv -width 50 -height 32 .dctrlIcon.canv create text 2 2 \ -font -adobe-times-medium-r-*-*-12-*-*-*-*-*-*-* \ -text "Diald" -anchor nw .dctrlIcon.canv create text 2 15 \ -font -adobe-times-medium-r-*-*-12-*-*-*-*-*-*-* \ -text "Status" -anchor nw .dctrlIcon.canv create rectangle 35 2 45 32 -fill grey75 .dctrlIcon.canv create oval 37 4 43 10 -tag top .dctrlIcon.canv create oval 37 14 43 20 -tag mid .dctrlIcon.canv create oval 37 24 43 30 -tag bot label .dctrlIcon.message -textvar status(fsm_trans) -border 0 -width 50 \ -font -adobe-times-bold-r-*-*-12-*-*-*-*-*-*-* pack propagate .dctrlIcon 0 pack .dctrlIcon.canv -padx 0 -pady 0 -fill x -expand 1 pack .dctrlIcon.message -padx 0 -pady 0 -fill x -expand 1 bind .dctrlIcon { if {$fancy_icon=="1"} { if {"%W"==".dctrlIcon"} {after idle make_icon} } else { dctrlQuit } } bind .dctrlIcon {wm deiconify .} } if {"$fancy_icon" != 0} { make_icon } if {"$fancy_icon"==1} { wm iconwindow . .dctrlIcon } # # MONITOR_STATE 0x0001 # MONITOR_INTERFACE 0x0002 # MONITOR_STATUS 0x0004 # MONITOR_LOAD 0x0008 # MONITOR_MESSAGE 0x0010 # MONITOR_QUEUE 0x0020 # proc openFifo {} { global fifofd monfifo monfd default_FIFO # Turn off any previous monitoring if {$monfd!=""} {close $monfd} if {$monfifo!=""} {catch {exec rm -f $monfifo}} # get new monitoring fifo set fifofd [open $default_FIFO w] set monfifo /tmp/dctrl.[pid] catch {exec mkfifo -m 0600 $monfifo} fifoCmd "monitor $monfifo" set monfd [open $monfifo r] fileevent $monfd readable {stateChange} } proc fifoCmd {cmd} { global fifofd if {$fifofd!=""} { puts $fifofd $cmd catch {flush $fifofd} } } proc cmp {a b} { if {[lindex $a 3]<[lindex $b 3]} { return 1; } if {[lindex $a 3]>[lindex $b 3]} { return -1; } return 0; } proc updateIcon {} { global colors status trans fancy_icon set status(fsm_trans) [set trans($status(fsm))] set clist [set colors($status(fsm))] set tcol [lindex $clist 0] set mcol [lindex $clist 1] set bcol [lindex $clist 2] if {"$fancy_icon" != 0} { .dctrlIcon.canv itemconfig top -fill $tcol .dctrlIcon.canv itemconfig mid -fill $mcol .dctrlIcon.canv itemconfig bot -fill $bcol } } proc stateChange {} { global monfd status trans colors gload tload set foo [gets $monfd] if {$foo=="STATE"} { set status(fsm) [gets $monfd] if {$status(fsm)=="CONNECT"} {.message.vis.text delete 0.0 end} if {$status(fsm)=="UP"} { load_init } updateIcon } if {$foo=="STATUS"} { set status(up) [gets $monfd] set status(force) [gets $monfd] set status(impmode) [gets $monfd] set status(imp_itime) [gets $monfd] set status(imp_time) [gets $monfd] set status(imp_fuzz) [gets $monfd] set status(imp_timeout) [gets $monfd] set status(force_timeout) [gets $monfd] set status(timeout) [gets $monfd] } if {$foo=="QUEUE"} { set foo [gets $monfd] set lst [list] .queue.vis.text delete 0.0 end while {$foo!="END QUEUE"} { lappend lst $foo set foo [gets $monfd] } foreach i $lst { .queue.vis.text insert end $i .queue.vis.text insert end "\n" } } if {$foo=="MESSAGE"} { set message [gets $monfd] .message.vis.text insert end $message .message.vis.text insert end "\n" } if {$foo=="INTERFACE"} { set status(iface) [gets $monfd] set status(lip) [gets $monfd] set status(rip) [gets $monfd] } if {$foo=="LOAD"} { if {$status(fsm)=="UP"} { set txtotal [gets $monfd] set rxtotal [gets $monfd] set e5 ".81873075307798185867" set e150 ".99335550625503441537" set fp "1" set status(rx_load5) [expr {$status(rx_load5)*$e5+$rxtotal*($fp-$e5)}] set status(tx_load5) [expr {$status(tx_load5)*$e5+$txtotal*($fp-$e5)}] if {$tload} { set status(rx_load150) [expr {$status(rx_load150)*$e150+$rxtotal*($fp-$e150)}] set status(tx_load150) [expr {$status(tx_load150)*$e150+$txtotal*($fp-$e150)}] set status(rx_load) [format "%.3f %.3f" [expr {$status(rx_load5)/1000}] [expr {$status(rx_load150)/1000}]] set status(tx_load) [format "%.3f %.3f" [expr {$status(tx_load5)/1000}] [expr {$status(tx_load150)/1000}]] } if {$gload} { update addtick .lm.tx [expr {$status(tx_load5)/1000}] addtick .lm.rx [expr {$status(rx_load5)/1000}] } set status(tx_total) [expr {$status(tx_total)+$txtotal}] set status(rx_total) [expr {$status(rx_total)+$rxtotal}] } } update } proc dctrlQuit {} { global fifofd monfifo fancy_icon if {$fifofd!=""} { if {$monfifo!=""} {catch {exec rm -f $monfifo}} catch {flush $fifofd} } if {"$fancy_icon" != 0} { bind .dctrlIcon {} } exit # destroy . } # Create menu bar. frame .menu -relief raised -bd 2 pack .menu -side top -fill x -expand 0 frame .spacer -width 480 -height 0 pack .spacer -side top menubutton .menu.file -text "File" -menu .menu.file.m -underline 0 menu .menu.file.m .menu.file.m add command -label "Restart monitoring" \ -command openFifo -underline 0 .menu.file.m add command -label "Quit" -command dctrlQuit -underline 0 pack .menu.file -side left menubutton .menu.control -text "Control" -menu .menu.control.m -underline 0 menu .menu.control.m .menu.control.m add check -label "Block connection" -underline 0 \ -variable blocked -command { if {$blocked} {fifoCmd "block"} {fifoCmd "unblock"} } .menu.control.m add check -label "Forced up" -underline 0 \ -variable forced -command { if {$forced} {fifoCmd "force"} {fifoCmd "unforce"} } .menu.control.m add sep .menu.control.m add command -label "Up request" -underline 0 \ -command "fifoCmd up" .menu.control.m add command -label "Down request" -underline 0 \ -command "fifoCmd down" .menu.control.m add command -label "Terminate on idle" -underline 0 \ -command "fifoCmd delayed-quit" .menu.control.m add command -label "Quit diald" -underline 0 \ -command "fifoCmd quit" pack .menu.control -side left menubutton .menu.options -text "Options" -menu .menu.options.m -underline 0 menu .menu.options.m .menu.options.m add check -label "Detailed Status" -underline 0 \ -variable dstatus -command { repack } .menu.options.m add check -label "Numeric Load Monitor" -underline 0 \ -variable tload -command { repack } .menu.options.m add check -label "Graphical Load Monitor" -underline 0 \ -variable gload -command { repack} .menu.options.m add check -label "Packet Queue" -underline 0 \ -variable pqueue -command { repack } .menu.options.m add check -label "Dialing Log" -underline 8 \ -variable dlog -command { repack } pack .menu.options -side left # Basic status display frame .basic label .basic.p1 -text "Interface " label .basic.p2 -textvar status(iface) label .basic.p3 -text " from " label .basic.p4 -textvar status(lip) label .basic.p5 -text " to " label .basic.p6 -textvar status(rip) label .basic.p7 -text " in state " label .basic.p8 -textvar status(fsm) pack .basic.p1 -side left pack .basic.p2 -side left pack .basic.p3 -side left pack .basic.p4 -side left pack .basic.p5 -side left pack .basic.p6 -side left pack .basic.p7 -side left pack .basic.p8 -side left frame .bar1 -bor 1 -rel sunken -height 2 # Link status display frame .status -bor 0 set col1 {"Link Status" "Next Alarm" "Forcing Rule"} set col2 {status(up) status(timeout) status(force)} set col3 {"Forcing Timeout" "Impulse State" "Initial Impulse"} set col4 {status(force_timeout) status(impmode) status(imp_itime)} set col5 {"Impulse Length" "Impulse Fuzz" "Impulse Timeout"} set col6 {status(imp_time) status(imp_fuzz) status(imp_timeout)} frame .status.col1 frame .status.col2 frame .status.col3 frame .status.col4 frame .status.col5 frame .status.col6 pack .status.col1 -side left -anchor nw pack .status.col2 -side left -expand 0 -fill x -anchor nw pack .status.col3 -side left -anchor nw pack .status.col4 -side left -expand 0 -fill x -anchor nw pack .status.col5 -side left -anchor nw pack .status.col6 -side left -expand 0 -fill x -anchor nw set i0 0 foreach i $col1 { label .status.col1.$i0 -text $i pack .status.col1.$i0 -side top -anchor nw incr i0 } set i0 0 foreach i $col2 { message .status.col2.$i0 -textvar $i -rel sunken -bor 1 -width 100 -anchor nw pack .status.col2.$i0 -side top -fill x -expand 1 -anchor nw incr i0 } set i0 0 foreach i $col3 { label .status.col3.$i0 -text $i pack .status.col3.$i0 -side top -anchor nw incr i0 } set i0 0 foreach i $col4 { message .status.col4.$i0 -textvar $i -rel sunken -bor 1 -width 100 -anchor nw pack .status.col4.$i0 -side top -fill x -expand 1 -anchor nw incr i0 } set i0 0 foreach i $col5 { label .status.col5.$i0 -text $i pack .status.col5.$i0 -side top -anchor nw incr i0 } set i0 0 foreach i $col6 { message .status.col6.$i0 -textvar $i -rel sunken -bor 1 -width 100 -anchor nw pack .status.col6.$i0 -side top -fill x -expand 1 -anchor nw incr i0 } frame .bar2 -bor 1 -rel sunken -height 2 # Textual load monitor... frame .tlm -bor 0 label .tlm.l1 -text "RX Load/Total" message .tlm.l2l -textvar status(rx_load) -width 100 -bor 1 -rel sunken message .tlm.l2t -textvar status(rx_total) -width 100 -bor 1 -rel sunken label .tlm.l3 -text "TX Load/Total" message .tlm.l4l -textvar status(tx_load) -width 100 -bor 1 -rel sunken message .tlm.l4t -textvar status(tx_total) -width 100 -bor 1 -rel sunken pack .tlm.l1 -side left -expand 0 -fill x pack .tlm.l2l -side left -expand 1 -fill x pack .tlm.l2t -side left -expand 1 -fill x pack .tlm.l3 -side left -expand 0 -fill x pack .tlm.l4l -side left -expand 1 -fill x pack .tlm.l4t -side left -expand 1 -fill x frame .bar3 -bor 1 -rel sunken -height 2 # Graphical load monitor... frame .lm -bor 0 # 60 is a good height. Divisible by 1 through 6 evenly, but high enough to see. stripchart .lm.tx 100 60 "TX" frame .lm.sep -width 2 -bor 2 -rel sunken stripchart .lm.rx 100 60 "RX" pack .lm.rx -side left -expand 1 -fill both -pady 0 pack .lm.sep -side left -fill y -pady 0 pack .lm.tx -side left -expand 1 -fill both -pady 0 frame .bar4 -bor 1 -rel sunken -height 2 # Connection queue frame .queue -bor 0 label .queue.label -text "Connection Queue" frame .queue.bar -height 2 -bor 1 -rel sunken frame .queue.vis -bor 0 text .queue.vis.text -bor 0 -yscrollcommand ".queue.vis.scroll set" -height 6 -width 60 -highlightthickness 0 scrollbar .queue.vis.scroll -relief sunken -command ".queue.vis.text yview" -highlightthickness 0 pack .queue.vis.text -side left -fill both -expand 1 -pady 0 pack .queue.vis.scroll -side right -fill y -pady 0 pack .queue.label -side top -anchor nw -pady 0 pack .queue.bar -side top -fill x -pady 0 pack .queue.vis -side top -fill both -expand 1 -pady 0 frame .bar5 -bor 1 -rel sunken -height 2 #Dialing log frame .message -bor 0 label .message.label -text "Dialing Log" frame .message.bar -height 2 -bor 1 -rel sunken frame .message.vis text .message.vis.text -bor 0 -yscrollcommand ".message.vis.scroll set" -height 8 -width 60 -highlightthickness 0 scrollbar .message.vis.scroll -relief sunken -command ".message.vis.text yview" -highlightthickness 0 pack .message.vis.text -side left -fill both -padx 2 -pady 2 -expand 1 pack .message.vis.scroll -side right -fill y pack .message.label -side top -anchor nw -pady 0 pack .message.bar -side top -fill x -pady 0 pack .message.vis -side top -fill both -expand 1 -pady 0 proc repack {} { global dstatus tload gload pqueue dlog pack forget .basic pack forget .bar1 pack forget .status pack forget .bar2 pack forget .tlm pack forget .bar3 pack forget .lm pack forget .bar4 pack forget .queue pack forget .bar5 pack forget .message pack .basic -anchor nw -expand 0 -fill x -side top if {$dstatus} { pack .bar1 -fill x -side top pack .status -side top -fill both -expand 0 -pady 0 } if {$tload} { pack .bar2 -fill x -side top pack .tlm -side top -fill both -expand 0 -pady 0 } if {$gload} { pack .bar3 -fill x -side top pack .lm -side top -fill both -expand 0 -pady 0 } if {$pqueue} { pack .bar4 -fill x -side top pack .queue -side top -fill both -expand 1 -pady 0 } if {$dlog} { pack .bar5 -fill x -side top pack .message -side top -fill both -expand 1 -pady 0 } } repack proc load_init {} { global status set status(rx_load5) "0.0" set status(tx_load5) "0.0" set status(rx_load30) "0.0" set status(tx_load30) "0.0" set status(rx_load150) "0.0" set status(tx_load150) "0.0" set status(tx_total) 0 set status(rx_total) 0 } load_init update openFifo