and added files
[bcm963xx.git] / userapps / opensource / net-snmp / local / snmpcheck.def
1 #!/usr/local/bin/perl -w
2
3 use strict 'refs';
4 require Net::Ping;
5 require Term::ReadKey;
6
7 #defaults
8 $mibident=".ERRORNAME";
9 $miberrflag=".ERRORFLAG";
10 $miberrmsg=".ERRORMSG";
11 $mibfix=".ERRORFIX";
12 $mibheadall=".EXTENSIBLEDOTMIB";
13 $mibclearcache="$mibheadall.VERSIONMIBNUM.VERCLEARCACHE";
14 $mibrestartagent="$mibheadall.VERSIONMIBNUM.VERRESTARTAGENT";
15 $mibupdateconfig="$mibheadall.VERSIONMIBNUM.VERUPDATECONFIG";
16 %miblist=(    '.PROCMIBNUM.1' => 'processes',
17               '.SHELLMIBNUM.1' => 'scripts',
18               '.MEMMIBNUM' => 'swap space',
19               '.DISKMIBNUM.1' => 'disks',
20               '.LOADAVEMIBNUM.1' => 'load-average',
21               '.ERRORMIBNUM' => 'snmp-agent-errors');
22 @fixitlist=('.PROCMIBNUM.1','.SHELLMIBNUM.1');
23 %mibchecklist = ('.PROCMIBNUM.1' => 1,
24                  '.SHELLMIBNUM.1' => 1,
25                  '.MEMMIBNUM' => 1,
26                  '.DISKMIBNUM.1' => 1,
27                  '.LOADAVEMIBNUM.1' => 1,
28                  '.ERRORMIBNUM' => 1);
29 $errlog="/net/tyfon/1/OV/log/ece-log";
30 $default_get_args = "-v 1 %s private";
31 $default_set_args = "-v 1 %s private";
32 $andlog=0;
33 $snmppath="BINDIR";
34 $eraseline="                                                                           \r";
35 $fixit=0;  # this should be 0 not -1, but is necissary till getc(STDIN) works
36 $rescanWhen = 300;
37 $display = $ENV{'DISPLAY'};
38 $hidden = 0;
39 $pinghost = 0;
40 $loglevel = 1;
41 $logwindowatstart = 0;
42 $numloglevels = 5;
43 $dontstart = 0;
44 $raiseonnew = 1;
45
46 #
47 #  Mib Package:  Each mib has a mib number attached and can check/fix itself;
48 #
49
50 package Mib;
51
52 # @ISA = qw( Host );
53
54 sub new {
55     my $tmp = shift;
56     my $self = {};
57     $self->{'HostId'} = shift;
58     $self->{'Host'} = $self->{'HostId'}->{'Name'};
59     $_ = shift;
60     $self->{'Mib'} = $_;
61     print "test: $_\n";
62     ($self->{'MibSuffix'}) = /(\.[0-9]+)$/;
63     if (!defined($mibchecklist{$self->{'MibSuffix'}})) {
64         ($self->{'MibSuffix'}) = /(\.[0-9]+\.1)$/;
65     }
66     print "suff: $self->{'MibSuffix'}\n";
67     $self->{'MibDesc'} = shift;
68     $self->{'Frame'} = shift;
69     bless $self;
70 }
71
72 sub getmibnum {
73     my $self = shift;
74     return ($self->{'Mib'});
75 }
76
77 sub snmp_walk {
78     my $self = shift;
79     $self->{'Frame'}->toplevel->Busy() if ($::display);
80     my $mib = shift;
81     my $cmd = "$::snmppath/snmpwalk " . sprintf($::default_get_args, $self->{'Host'}) . " $mib|";
82     ::addToLog("running:  $cmd",5);
83     open(OUT,"$cmd");
84     my $outcount = 0;
85     my @result = [];
86     while (<OUT>) {
87         $result[$outcount] = $_;
88         chop;
89         ::addToLog("snmpwalk:  $_",5);
90         if ($::display) {
91             $self->{'Frame'}->toplevel->update;
92         }
93         $outcount++;
94     }
95     close(OUT);
96     for($i=0; $i <= $#result; $i++) {
97         $result[$i] =~ s/ Hex:.*$//g;
98         $result[$i] =~ s/\"//g;
99     }
100     $self->{'Frame'}->toplevel->Unbusy() if ($::display);
101     if ($result[0] =~ /No Response/) {
102         $self->{'HostId'}->hostdown;
103         splice(@result,0);
104     }
105     return @result;
106 }
107
108 sub check {
109     my $self = shift;
110     my $tmp = [];
111     if ($::mibchecklist{$self->{'MibSuffix'}} != 1) {
112         return @{$tmp};
113     }
114     if (! $::display) {
115         printf "%sChecking %s: %s\r", $::eraseline,$self->{'Host'},
116         $self->{'MibDesc'};
117     }
118     my @walkout = $self->snmp_walk("$self->{'Mib'}$::miberrflag");
119     while ($#walkout > -1) {
120         $_ = shift @walkout;
121         ($result) = /= ([0-9]+)/;
122         if (defined($result) && $result > 0)
123         {
124             ($mibloc) = /\.([0-9]+) /;
125             push(@{$tmp},FixProblem::new("",$self->{'HostId'}, $self->{'Mib'},
126                                          $self->{'MibDesc'},
127                                          $mibloc,$self->{'Frame'}));
128             if (! $::display) {
129                 printf("%s%-8.8s  %-12.12s  %2d -- %-37.37s",$::eraseline,
130                        $self->{'Host'},$tmp->[0]->{'ErrName'},
131                        $result,$tmp->[0]->{'ErrMsg'});
132                 if ($tmp->[0]->canfix() && $::fixit == 0) {
133                     printf(" / Fix? ");
134                     $ans = Term::ReadKey::ReadKey(0);
135                     if ("$ans" eq "y" || "$ans" eq "Y") {
136                         printf("\b\b\b\b\b\b\b\b");
137                         $tmp->[0]->fix($mibloc);     # fix now if curses
138                     } else {
139                         print $ans;
140                         printf("\nChecking %s: %s\r",$self->{'Host'}, 
141                                $self->{'MibDesc'});
142                     }
143                 } elsif ($::fixit > 0) {
144                     $tmp->[0]->fix($mibloc);     # fix now if curses
145                 }
146                 shift @{$tmp};
147             }
148         }
149     }
150     return(@{$tmp});
151 }
152
153 #
154 #  Problem Package: A problem comes into existence when found.  It may
155 #  or may not know how to fix itself (Problem/FixProblem).
156 #
157
158 package Problem;
159
160 @ISA = qw( Mib );
161
162 sub snmp_get {
163     my $self = shift;
164     $self->{'Frame'}->toplevel->Busy() if ($::display);
165     my $mib = shift;
166     my $args = sprintf($::default_get_args, $self->{'Host'});
167     $_ = `$::snmppath/snmpget $args $mib`;
168     my ($result) = /= (.*)$/;
169     if (!defined($result) || $result =~ /No Response/) {
170         $self->{'HostId'}->hostdown;
171         $result = "";
172     }
173     $result =~ s/\"//g;
174     $result =~ s/ Hex:.*$//g;
175     ::addToLog("snmpget:  $_",5);
176     $self->{'Frame'}->toplevel->Unbusy() if ($::display);
177     return $result;
178 }
179
180 sub snmp_set {
181     my $self = shift;
182     $self->{'Frame'}->toplevel->Busy() if ($::display);
183     my $mib = shift;
184     my $args = sprint($::default_set_args, $self->{'Host'});
185     $_ = `$::snmppath/snmpset $args $mib`;
186     my ($result) = /= (.*)$/;
187     $result = "" if (!defined($result));
188     $result =~ s/\"//g;
189     ::addToLog("snmpset:  $_",5);
190     $self->{'Frame'}->toplevel->Unbusy() if ($::display);
191     return $result;
192 }
193
194 sub new{
195     my $tmp = shift;
196     my $hostId = shift;
197     my $mib = shift;
198     my $mibname = shift;
199     my $self = new Mib ($hostId,$mib,$mibname);
200     $self->{'MibLocation'} = shift;
201     $tmp = shift;
202     if ($::display) {
203         $self->{'Frame'} = $tmp->Frame();
204     }
205     bless $self;
206     $self->{'ErrName'} = 
207         $self->snmp_get("$self->{'Mib'}$::mibident.$self->{'MibLocation'}");
208     $self->{'ErrMsg'} = 
209         $self->snmp_get("$self->{'Mib'}$::miberrmsg.$self->{'MibLocation'}");
210     if (exists $self->{'HostId'}->{'Down'}) {
211         return $self;
212     }
213     if ($::display) {
214         $self->{'Frame'}->pack();
215         $self->{'Desc'} = 
216             $self->{'Frame'}->Button(-text => sprintf("%-12.12s %-42.42s",
217                                                      $self->{'ErrName'},
218                                                      $self->{'ErrMsg'}),
219                                      -font => "6x13",
220                                      -highlightcolor => "#ffffff",
221                                      -borderwidth => 0,
222                                      -relief => "flat",
223                                      -bd => 0, -padx => 0, -pady => 0,
224                                      -activeforeground => 'red',
225                                      -activebackground => '#C9C9C9',
226                                      -background => '#E0C9C9',
227                                      -command => [\&selectme,$self]);
228         $self->{'Desc'}->pack(-fill => "x",-expand => 1,-side=>"left"); # 
229         if ($::raiseonnew) {
230             $tmp->toplevel->deiconify();
231             $tmp->toplevel->raise();
232         }
233         ::addToLog("problem found:  $self->{'Host'}\t$self->{'ErrName'}\t$self->{'ErrMsg'}",2);
234     }
235     bless $self;
236     return $self;
237 }
238
239 sub haveseen {
240     my $self = shift;
241     $self->{'Desc'}->configure(-background => '#C9C9C9');
242 }
243
244 sub selectme {
245     my $self = shift;
246     if ($main::hidden) {
247       main::makeappear();
248         return;
249     }
250     if (exists $self->{'Selected'}) {
251       main::deselectitem($self);
252         delete $self->{'Selected'};
253     } else {
254       main::selectitem($self);
255         $self->{'Desc'}->configure(-foreground => "red");
256         $self->{'Selected'} = 1;
257     }
258     $self->haveseen();
259 }
260
261 sub deselectme {
262     my $self = shift;
263     $self->{'Desc'}->configure(-foreground => "black");
264     delete $self->{'Selected'};
265 }
266
267 sub check {
268     my $self = shift;
269     if ($::display) {
270       main::setstatus("Checking $self->{'Host'} -- $self->{'ErrName'}");
271     }
272     else {
273         printf("Checking \b\b\b\b\b\b\b\b\b");
274     }
275     $result = $self->snmp_get("$self->{'Mib'}$::miberrflag.$self->{'MibLocation'}");
276     if (exists $self->{'HostId'}->{'Down'}) {
277         return 0;
278     }
279     if ($result == 0) {
280         $self->deleteme();
281     }
282   main::setstatus("idle");
283     return $result;
284 }
285
286 sub fix {
287 # Don't fix and/or unable to
288     my $self = shift;
289   main::setmsg("Don't know how to fix $self->{'ErrName'}");
290 }
291
292 sub rsh {
293     my $self = shift;
294     if ($::display) {
295         system "xterm -e rsh $self->{'HostId'}->{'Name'} -l root &";
296     }
297 }
298
299 sub deleteme {
300     my $self = shift;
301     my $host = $self->{'HostId'};
302     $host->deleteProb($self);
303 }
304
305 sub deleteself {
306     my $self = shift;
307     if ($::display) {
308         if ($self->{'Selected'}) {
309           main::deselectitem($self);
310         }
311         $self->{'Desc'}->destroy();
312         $self->{'Frame'}->destroy();
313     }
314 }
315
316 sub canfix {
317     return 0;
318 }
319
320 package FixProblem;
321
322 @ISA = qw( Problem );
323
324 sub new {
325     my $tmp = shift;
326     my $hostId = shift;
327     my $mib = shift;
328     my $mibdesc = shift;
329     my $mibloc = shift;
330     my $frame = shift;
331     my $self = new Problem ($hostId,$mib,$mibdesc,$mibloc,$frame);
332     $_ = $mib;
333     ($mymib) = /(\.[0-9]+)$/;
334     if (grep(/$mymib/,@::fixitlist) && ($::fixit >= 0)) {
335         bless $self;            # Make it a FixProblem if fixable
336     }
337     return $self;               # else just return a Problem
338 }
339
340 sub canfix {
341     return 1;
342 }
343
344 sub fix {
345     my $self = shift;
346     my $mibloc = shift;
347     if ($::display) {
348       main::setstatus(sprintf("Fixing %s:  %s",
349                               $self->{'Host'}, $self->{'ErrName'}));
350     } 
351     else {
352         printf(" / Fixing...\b\b\b\b\b\b\b\b\b");
353     }
354     $self->snmp_set("$self->{'Mib'}$::mibfix.$self->{'MibLocation'} integer 1");
355     $self->snmp_set("$::mibclearcache integer 1");
356     if (exists $self->{'HostId'}->{'Down'}) {
357         return;
358     }
359     if ($::display) {
360         main::setstatus("Sleeping");
361     }
362     else {
363         printf("Sleeping \b\b\b\b\b\b\b\b\b");
364     }
365     sleep(2);
366     if ($::display) {
367         main::setstatus("Checking");
368     }
369     else {
370         printf("Checking\b\b\b\b\b\b\b\b");
371     }
372     if ($self->check() != 0) {
373         if (! $::display) {
374             printf("*failed*  \n");
375         } else {
376             main::setmsg("Failed to fix $self->{'ErrName'} on $self->{'Host'}");
377         }
378     }
379     else {
380         if ($::display) {
381 #           $self->{'HostId'}->deleteProb($self);
382             main::setmsg("Fixed $self->{'ErrName'} on $self->{'Host'}");
383         } 
384         else {
385             printf("Fixed     \n");
386         }
387     }
388   main::setstatus("Idle");
389 }
390
391 #
392 #  Host Package:  Each object is a host which can check itself and display
393 #                 the results
394 #
395 package Host;
396
397 sub mibsort {
398     $_ = $a;
399     ($av) = /\.([0-9]+)/;
400     $_ = $b;
401     ($bv) = /\.([0-9]+)/;
402     return $av <=> $bv;
403 }
404
405 sub new {
406     my $self = {};
407     my $tmp = shift;
408     $self->{'Name'} = shift;
409     $self->{'Host'} = $self->{'Name'};
410     $self->{'Mibs'} = [];
411     $self->{'Problems'} = [];
412     bless $self;
413     if ($::display) {
414         $self->{'MainFrame'} = $::HostFrame->Frame();
415         if (!$::hidden) {
416             $self->{'MainFrame'}->configure(-relief =>"sunken",-borderwidth=>2);
417         }
418         $self->{'ProbFrame'} = $self->{'MainFrame'}->Frame();
419         $self->{'hostlabel'} = 
420             $self->{'MainFrame'}->Button(-text => sprintf("%-9.9s",
421                                                             $self->{'Name'}),
422                                          -bd => 0, -padx => 0, -pady => 0,
423                                          -command =>[\&selectme,$self],
424                                          -activeforeground => 'red',
425                                          -activebackground => '#C9C9C9',
426                                          -width => 9,
427                                          -anchor => "w",
428                                          -relief => "flat");
429         $self->{'hostlabel'}->pack(-side=>"left",-ipadx=>1,
430                                    -padx=> 1,-pady =>1);
431         $self->{'ProbFrame'}->pack(-side=>"left",-ipadx=>1,
432                                    -padx=> 1,-pady =>1);
433         $self->{'MainFrame'}->pack( #-padx => 2,-pady =>2, 
434                                    -fill => "x", -expand => 1);
435     } 
436     foreach $mibx ( sort mibsort keys(%::miblist) ) {
437         push(@{$self->{'Mibs'}},
438              new Mib ($self,"$::mibheadall$mibx",$::miblist{$mibx},
439                       $self->{'ProbFrame'}));
440     }
441     return $self;
442 }
443
444 sub rsh {
445     my $self = shift;
446     if ($::display) {
447         system "xterm -e rsh $self->{'Name'} -l root &";
448     }
449 }
450
451 sub selectme {
452     my $self = shift;
453     if ($main::hidden) {
454       main::makeappear();
455         return;
456     }
457     if (exists $self->{'Selected'}) {
458       main::deselectitem($self);
459         delete $self->{'Selected'};
460     } else {
461       main::selectitem($self);
462         $self->{'hostlabel'}->configure(-foreground => "red");
463         $self->{'Selected'} = 1;
464     }
465 }
466
467 sub deselectme {
468     my $self = shift;
469     $self->{'hostlabel'}->configure(-foreground => "black");
470     delete $self->{'Selected'};
471 }
472
473 sub fix {
474     my $self = shift;
475     if (! exists $self->{'Down'}) {
476         foreach $i (@{$self->{'Problems'}}) {
477             if ($i->canfix() && ref($i) ne Host) {
478                 $i->fix();
479             }
480         }
481     }
482 }
483
484 sub seenall {
485     my $self = shift;
486     foreach $i (@{$self->{'Problems'}}) {
487         if (ref($i) ne Host) {
488             $i->haveseen();
489         }
490     }
491 }
492
493 sub canfix {
494     return 1;
495 }
496
497 sub hostdown {
498     my $self = shift;
499     $self->deleteProbs();
500     push(@{$self->{'Problems'}},$self);
501     $self->{'Down'} = 1;
502     if ($::display) {
503         if (!exists $self->{'hostlabel'}) {
504             $self->{'hostlabel'} = 
505                 $self->{'MainFrame'}->Button(-text => sprintf("%-9.9s",
506                                                               $self->{'Name'}),
507                                              -bd => 0, -padx => 0, -pady => 0,
508                                              -command =>[\&selectme,$self],
509                                              -activeforeground => 'red',
510                                              -activebackground => '#C9C9C9',
511                                              -width => 9,
512                                              -anchor => "w",
513                                              -relief => "flat");
514         }
515         ::addToLog("$self->{'Name'} is down",2);
516         $self->{'hostlabel'}->configure(-text => 
517                                         sprintf("%-9.9s down",$self->{'Name'}),
518                                         -width => 14);
519     }
520 }
521
522 sub check {
523     my $self = shift;
524     $self->{'noDelete'} = 1;
525     $self->deleteProbs();
526     delete $self->{'noDelete'};
527     if ($::display) {
528         $self->{'hostlabel'}->configure(-text => $self->{'Name'},-width=>9);
529     }
530     delete $self->{'Down'};
531   main::setstatus("pinging $self->{'Name'}");
532     if (!($::pinghost) || Net::Ping::pingecho($self->{'Name'},2)) {
533         foreach $i (@{$self->{'Mibs'}}) {
534             if (ref($i) ne Mib) {
535                 print "$i is a ref($i) not a Mib\n";
536             } else {
537               main::setstatus("Checking $self->{'Name'}:  " . $i->{'MibDesc'});
538                 push(@{$self->{'Problems'}},$i->check());
539             }
540             if (exists $self->{'Down'}) {
541                 last;
542             }
543         }
544     } else {
545         $self->hostdown();
546     }
547   main::setstatus("Idle");
548     if ($#{$self->{'Problems'}} == -1) {
549         $self->deleteme();
550     }
551 }
552
553 sub deleteme {
554     my $self = shift;
555     if ($self->{'Selected'}) {
556       main::deselectitem($self);
557     }
558     $self->deleteProbs();
559     if ($::display) {
560         $self->{'hostlabel'}->destroy();
561         $self->{'ProbFrame'}->destroy();
562         my $top = $self->{'MainFrame'}->toplevel;
563         $self->{'MainFrame'}->destroy();
564         $top->update;
565     }
566   main::deletehost($self->{'Name'});
567 }
568
569 sub deleteProbs {
570     my $self = shift;
571     foreach $i (@{$self->{'Problems'}}) {
572         if (ref($i) eq Host) {
573             delete $self->{'Problems'};
574             return;
575         }
576         if (ref($i) ne Problem && ref($i) ne FixProblem) {
577             print "i:  $i is a ", ref($i), "\n";
578             next;
579         }
580         $self->deleteProb($i);
581     }
582 }
583
584 sub deleteProb {
585     my $self = shift;
586     my $child = shift;
587     for ($k = 0; $k <= $#{$self->{'Problems'}}; $k++) {
588         if (ref($self->{'Problems'}->[$k]) eq Problem ||
589             ref($self->{'Problems'}->[$k]) eq FixProblem ) {
590             if ($self->{'Problems'}->[$k]->{'Mib'} eq $child->{'Mib'} && 
591             $self->{'Problems'}->[$k]->{'MibLocation'} eq
592             $child->{'MibLocation'}) {
593                 splice(@{$self->{'Problems'}},$k,1);
594                 $child->deleteself();
595                 if ($#{$self->{'Problems'}} == -1 && 
596                     !exists $self->{'noDelete'}) {
597                     $self->deleteme();
598                 }
599                 last;
600             }
601         } else {
602             print "    not: ",$self->{'Problems'}->[$k],"/",
603             ref($self->{'Problems'}->[$k]),"\n";
604         }
605     }
606 }
607
608 package main;
609
610 #
611 # Read arguments
612 #
613
614 if ($#ARGV != -1) {
615     while ($#ARGV >= 0 && $ARGV[0] =~ /^-/) {
616         $_ = shift;
617         $andlog = 1 if (/^-a/);
618         $dontstart = 1 if (/^-d/);
619         $fixit = -1 if (/^-n/);
620         $fixit = 1 if (/^-y/);
621         $display = 0 if (/^-x/);
622         $pinghost = 1 if (/^-p/);
623         $hidden = 1 if (/^-H/);
624         $loglevel = shift if (/^-V/);
625         $logwindowatstart = 1 if (/^-L/);
626         &display_help() if (/^-h/);
627         &setmibchecklist(@fixitlist) if (/^-f/);
628     }
629 }
630
631 #
632 # If necessary check the ece-log file for problems
633 #
634
635 if (($andlog || $#ARGV == -1) && !$dontstart) {
636     open(LOG,$errlog);
637     while (<LOG>) {
638         @fields = split;
639         @tmp = grep(/$fields[0]/,@ARGV);
640         if ($#tmp == -1) { #  && $fields[1] ne "down") {
641             $ARGV[$#ARGV + 1] = $fields[0];
642         }
643     }
644     close(LOG);
645 }
646
647 #
648 # Check all the found hosts 
649 #
650
651 if ($display) {
652     use Tk;
653 #    $tk_strictMotif = 1;
654     $top = MainWindow->new();
655     $top->bind('all',"<Control-q>",[\&quit]);
656     $top->bind('all',"<Control-h>",[\&makehidden]);
657     $top->bind('all',"<Control-s>",[\&seenall]);
658     $top->bind('all',"<Control-f>",[\&fixall]);
659      $top->option('add','*highlightThickness','0');        #wish this worked
660 #     $top->option('add','*highlightbackground','#C9C9C9');
661      $top->option('add','*background','#C9C9C9');
662      $top->option('add','*font','6x13');
663     $HostFrame = $top->Frame();
664     $MenuFrame = $top->Frame(-relief => "raised",-borderwidth => 2);
665     $MenuFrame->pack(-fill => "x",-expand => 1);
666     $statusBar = $top->Frame(-relief => "raised",-borderwidth => 2);
667     $status = $statusBar->Label(-text => "initializing",-anchor =>"e");
668     $statusl = $statusBar->Label(-text => "Status:  ", -anchor => "w");
669     $msgBar = $top->Frame(-relief => "raised",-borderwidth => 2);
670     $msg = $msgBar->Label(-text => "",-anchor =>"e");
671     $msgl = $msgBar->Label(-text => "Note:  ", -anchor => "w");
672     
673     $botFrame = $top->Frame();
674     $butFrame = $top->Frame();
675     $entryhost = "";
676     $NewHost = $botFrame->Entry(-textvariable => \$entryhost,-width=>20,
677                                 -relief => "sunken");
678     $NewHost->bind("<Return>",sub {newHost("$entryhost");
679                                $NewHost->delete(0,length($entryhost));});
680     $BotLabel = $botFrame->Label(-text => "Check New Host:  ",
681                             -anchor => "w");
682     $CmdsMenuBut = $MenuFrame->Menubutton(-text => "Cmds");
683     $CmdsMenu = $CmdsMenuBut->Menu(-tearoff => 1);
684     $CmdsMenuBut->configure(-menu => $CmdsMenu);
685     $CmdsMenuBut->pack(-side => "left");
686     $CmdsMenuBut->command(-label => "Check Hosts", -command => [\&rescanhosts]);
687     $CmdsMenuBut->command(-label => "Check Log", -command => [\&scanlog]);
688     $CmdsMenuBut->command(-label => "Fix All", -command => [\&fixall],
689                           -accelerator => "Ctrl-f");
690     $CmdsMenuBut->command(-label => "Seen All", -command => [\&seenall],
691                           -accelerator => "Ctrl-s");
692     $CmdsMenuBut->separator();
693     $CmdsMenuBut->command(-label => "Hide", -command => [\&makehidden],
694                           -accelerator => "Ctrl-h");
695     $CmdsMenuBut->command(-label => "Quit", -command => [\&quit],
696                           -accelerator => "Ctrl-q");
697     $PrefsMenuBut = $MenuFrame->Menubutton(-text => "Prefs");
698     $PrefsMenu = $PrefsMenuBut->Menu(-tearoff => 1);
699     $PrefsMenuBut->configure(-menu => $PrefsMenu);
700     $PrefsMenuBut->pack(-side => "left");
701     $PrefsMenuBut->cascade(-label => "Rescan");
702     $RescanPrefsBut = $PrefsMenu->Menu();
703     $PrefsMenuBut->entryconfigure("Rescan",-menu => $RescanPrefsBut);
704     $AutoRescan = 1;
705     if ($AutoRescan) {
706       $afterId = Tk::after($rescanWhen*1000,[\&autorescan]);
707     }
708     $RescanPrefsBut->checkbutton(-label =>"Auto Rescan",
709                                -variable =>\$AutoRescan,
710                                -command => sub {if ($AutoRescan) {
711                                    $afterId = 
712                                      Tk::after($rescanWhen*1000,[\&autorescan])
713                                    } else {
714                                      Tk::after("cancel",$afterId);
715                                    }});
716     $AutoCheckLog = 1;
717     $RescanPrefsBut->checkbutton(-label =>"Checks Log",
718                                -variable =>\$AutoCheckLog);
719     $AutoCheckHosts = 0;
720     $RescanPrefsBut->checkbutton(-label =>"Checks Hosts",
721                                -variable =>\$AutoCheckHosts);
722     $RescanWhenHidden = 1;
723     $RescanPrefsBut->checkbutton(-label =>"Only When Hidden",
724                                -variable =>\$RescanWhenHidden);
725
726     $RescanPrefsBut->checkbutton(-label =>"Pop forward with new",
727                                -variable =>\$raiseonnew);
728
729     $PrefsMenuBut->cascade(-label => "Log Verbosity");
730     $LogVerbBut = $PrefsMenu->Menu();
731     $PrefsMenuBut->entryconfigure("Log Verbosity",
732                                   -menu => $LogVerbBut);
733     for ($i=1; $i <= $numloglevels; $i++) {
734         $LogVerbBut->radiobutton(-label => "$i", -variable => \$loglevel, 
735                                  -value => $i);
736     }
737
738     $PrefsMenuBut->cascade(-label => "Check For");
739     $CheckForBut = $PrefsMenu->Menu();
740     $PrefsMenuBut->entryconfigure("Check For",
741                                   -menu => $CheckForBut);
742     $CheckForBut->command(-label => "Fixable Problems", 
743                           -command => [\&setmibchecklist,@fixitlist]);
744     $CheckForBut->command(-label => "Everything", 
745                           -command => [\&setmibchecklist,keys(%miblist)]);
746     $CheckForBut->separator();
747     foreach $i ( sort mibsort keys(%::mibchecklist) ) {
748         $CheckForBut->checkbutton(-label => $miblist{$i}, 
749                                   -variable => \$mibchecklist{$i});
750     }
751
752     $PrefsMenuBut->checkbutton(-label => "Ping Host First", 
753                                -variable => \$pinghost);
754
755     # Agent control
756
757     $agentMenuBut = $MenuFrame->Menubutton(-text => "Agent-Control");
758     $agentMenu = $agentMenuBut->Menu(-tearoff => 1);
759     $agentMenuBut->configure(-menu => $agentMenu);
760     $agentMenuBut->pack(-side => "left");
761     $agentMenuBut->command(-label => "Re-read Configuration", 
762                            -command => [sub {if ($selected) { $top->Busy(); 
763                                                               my $args = sprint($::default_get_args, $selected->{'Host'});
764 $_ = `$::snmppath/snmpset $args $mibupdateconfig i 1`; $top->Unbusy();}}]);
765     $agentMenuBut->command(-label => "Clear Exec Cache", 
766                            -command => [sub {if ($selected) { $top->Busy();
767                                                               my $args = sprint($::default_get_args, $selected->{'Host'});
768 $_ = `$::snmppath/snmpset $args $mibclearcache i 1`; $top->Unbusy();}}]);
769     $agentMenuBut->separator();
770     $agentMenuBut->command(-label => "Re-start Agent", 
771                            -command => [sub {if ($selected) { $top->Busy(); 
772                                                               my $args = sprint($::default_get_args, $selected->{'Host'});
773 $_ = `$::snmppath/snmpset $args $mibrestartagent i 1`; $top->Unbusy();} }]);
774
775     # set up remote commands
776
777     $remoteMenuBut = $MenuFrame->Menubutton(-text => "Remote-Info");
778     $remoteMenu = $remoteMenuBut->Menu(-tearoff => 1);
779     $remoteMenuBut->configure(-menu => $remoteMenu);
780     $remoteMenuBut->pack(-side => "left");
781     $remoteMenuBut->command(-label => "Load-Av", -command => [\&remote_load]);
782     $remoteMenuBut->separator();
783     $remoteMenuBut->command(-label => "top", -command => [\&remote_cmd,"top"]);
784     $remoteMenuBut->command(-label => "mailq", -command => [\&remote_cmd,"mailq"]);
785     $remoteMenuBut->command(-label => "ps", -command => [\&remote_cmd,"ps"]);
786     $remoteMenuBut->command(-label => "conf", -command => [\&remote_cmd,"conf"]);
787
788     # set up log file menu
789     $logFileMenuBut = $MenuFrame->Menubutton(-text => "Log");
790     $logFileMenu = $logFileMenuBut->Menu(-tearoff => 1);
791     $logFileMenuBut->configure(-menu => $logFileMenu);
792     $logFileMenuBut->pack(-side => "left");
793     $logFileMenuBut->command(-label => "show log", -command => [\&displayLog]);
794     $logFileMenuBut->command(-label => "clear log", -command => [\&clearLog]);
795     $logFileMenuBut->separator();
796     $logFileMenuBut->command(-label => "show Tyfon's log", -command => [\&displayTyfon]);
797
798
799     # set up status bar
800
801     $statusl->pack(-fill => "x", -expand => 1, -side =>"left");
802     $status->pack(-fill => "x", -expand => 1, -side =>"left");
803     $msgl->pack(-fill => "x", -expand => 1, -side => "left");
804     $msg->pack(-fill => "x", -expand => 1, -side => "left");
805     $statusBar->pack(-fill => "x", -expand => 1);
806     $msgBar->pack(-fill => "x", -expand => 1);
807     $HostFrame->pack(-fill => "x",-expand => 1);
808     $butFrame->pack(-fill => "x",-expand => 1);
809     $botFrame->pack(-fill => "x",-expand => 1);
810     $FixBut = $butFrame->Button(-text => "Fix",-command=>[sub{print "hi\n"}],
811                                 -state => "disabled");
812     $FixBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2,
813                    -ipady => 2);
814     $RshBut = $butFrame->Button(-text => "Rsh",-command=>[sub{print "hi\n"}],
815                                 -state => "disabled");
816     $RshBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2,
817                    -ipady => 2);
818     $DelBut = $butFrame->Button(-text => "Del",
819                                  -state => "disabled");
820     $DelBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2,
821                    -ipady => 2);
822     $ChkBut = $butFrame->Button(-text => "Chk",
823                                  -state => "disabled");
824     $ChkBut->pack(-side => "left",-padx => 4,-pady => 2,-ipadx => 2,
825                    -ipady => 2);
826     $BotLabel->pack(-fill => "x",-expand => 1,-side=>"left");
827     $NewHost->pack(-side=>"left");
828     &makehidden() if ($hidden);
829     $top->update();
830
831     # generate log window, but tell it not to create display 
832     $logwindow = MainWindow->new;
833     $logwindow->option('add','*highlightThickness','0');        #wish this worked
834 #     $logwindow->option('add','*highlightbackground','#C9C9C9');
835     $logwindow->option('add','*background','#C9C9C9');
836     $logwindow->option('add','*font','6x13');
837
838     $logbuttons = $logwindow->Frame;
839     $logbuttons->pack(-side => 'bottom', -expand => 1, -fill => 'x');
840     $logclose = $logbuttons->Button(-text => 'Close', 
841                                  -command => ['withdraw',$logwindow]);
842     $logclose->pack(-side => 'left', -expand => 1);
843
844     $logtext = $logwindow->Text(-height => 40, -setgrid => 1);
845     $logtext->pack(-side => 'left', -fill => 'both', -expand => 1);
846     $logscroll = $logwindow->Scrollbar(-command => ['yview',$logtext]);
847     $logscroll->pack(-side => 'right', -fill => 'y');
848     $logtext->configure(-yscrollcommand => ['set', $logscroll]);
849     $logwindow->title("snmpcheck Action Log file");
850     $logwindow->iconname("snmpcheck-log");
851     $logtext->delete('1.0','end');
852     $logclear = $logbuttons->Button(-text => 'Clear Log', 
853                                  -command => [\&deleteLog]);
854     $logclear->pack(-side => 'right', -expand => 1);
855     if (! $logwindowatstart) {
856         $logwindow->withdraw;
857     }
858
859     $status->configure(-text => "Idle");
860     $selected = 0;
861     # fill table with hosts
862     if (!$dontstart) {
863         loadAllHosts(@ARGV);
864     }
865     MainLoop;
866 }
867 else {
868     select(STDOUT);
869     $| = 1;
870     if ($::fixit == 0) {
871         Term::ReadKey::ReadMode(3);
872     }
873     loadAllHosts(@ARGV);
874     printf("$eraseline");
875 }
876
877 sub loadAllHosts {
878     my @hostlist = @_;
879     foreach $host ( @hostlist ) {
880         newHost($host);
881     }
882 }    
883
884 sub newHost {
885     my $name = shift;
886     if (!exists $chost{"$name"}) {
887         $chost{"$name"} = new Host ($name);
888         if ($::display) { $top->update(); }
889         $chost{"$name"}->check;
890     } else {
891         setmsg("$name all ready exists");
892     }
893 }
894
895 sub deletehost {
896     my $name = shift;
897     delete $chost{"$name"};
898 }
899
900 sub setstatus {
901     my $arg = shift;
902     if ($display) {
903         $status->configure(-text => $arg);
904         $top->update();
905         addToLog($arg,4);
906     }
907 }
908
909 sub setmsg {
910     my $arg = shift;
911     if ($display) {
912         $msg->configure(-text => $arg);
913         $top->update();
914         addToLog($arg);
915     }
916 }
917
918 sub addToLog {
919     if ($display) {
920         my $logmsg = shift;
921         my $logaddlevel = shift;
922         if (! defined($logaddlevel)) {
923             $logaddlevel = 1;
924         }
925         if ($logaddlevel <= $loglevel) {
926             $logtext->insert('end'," " x ($logaddlevel-1) . "$logmsg\n");
927         }
928     }
929 }
930
931 sub displayTyfon {
932     remote_cmd_generic("cat /net/tyfon/1/OV/log/ece-log","Tyfon -- ece-log"); 
933 }
934
935 sub displayLog {
936     $logwindow->deiconify;
937     $logwindow->raise;
938 }
939
940 sub deleteLog {
941     $logtext->delete('1.0','end');
942 }
943
944 sub deselectitem {
945     $obj = shift;
946     $obj->deselectme();
947     $FixBut->configure(-state => "disabled");
948     $RshBut->configure(-state => "disabled");
949     $DelBut->configure(-state => "disabled");
950     $ChkBut->configure(-state => "disabled");
951     $selected = 0;
952 }
953
954 sub selectitem {
955     if ($selected) {
956         $selected->deselectme();
957     }
958     $selected = shift;
959     if (ref($selected) ne Host || !(exists $selected->{'Down'})) {
960         $RshBut->configure(-state => "normal", -command => ['rsh',$selected]);
961     } else {
962         $RshBut->configure(-state => "disabled");
963     }
964     $DelBut->configure(-state => "normal", -command => ['deleteme',$selected]);
965     $ChkBut->configure(-state => "normal", -command => ['check',$selected]);
966     if ($selected->canfix() && !(exists $selected->{'Down'})) {
967         $FixBut->configure(-state => "normal", 
968                            -command => ['fix',$selected]);
969     } else {
970         $FixBut->configure(-state => "disabled");
971     }
972     if ($hidden == 1) {
973         makeappear();
974     }
975 }
976
977 sub makehidden {
978     $MenuFrame->pack("forget");
979     $statusBar->pack("forget");
980     $msgBar->pack("forget");
981     $butFrame->pack("forget");
982     $botFrame->pack("forget");
983     flatten();
984     $hidden=1;
985 }
986
987 sub makeappear {
988     $HostFrame->pack("forget");
989     $MenuFrame->pack(-expand => 1, -fill => "x");
990     $statusBar->pack(-expand => 1, -fill => "x");
991     $msgBar->pack(-expand => 1, -fill => "x");
992     $HostFrame->pack(-expand => 1, -fill => "x");
993     $butFrame->pack(-expand => 1, -fill => "x"); 
994     $botFrame->pack(-expand => 1, -fill => "x");
995     reliefen();
996     $hidden=0;
997 }
998
999 sub quit {
1000     $top->destroy();
1001     exit();
1002 }
1003
1004 sub scanlog {
1005     my (@fields, @tmp);
1006     open(LOG,$::errlog);
1007     while (<LOG>) {
1008         @fields = split;
1009         @tmp = grep(/$fields[0]/,@ARGV);
1010         if ($#tmp == -1 && !exists $::chost->{$fields[0]}) {
1011             newHost($fields[0]);
1012         }
1013     }
1014     close(LOG);
1015 }
1016
1017 sub rescanhosts {
1018     foreach $i (keys(%chost)) {
1019         $chost{$i}->check();
1020     }
1021 }
1022
1023 sub autorescan {
1024     $afterId = Tk::after($rescanWhen*1000,[\&autorescan]);
1025     if ($RescanWhenHidden && !$hidden) {return;}
1026     if ($AutoCheckHosts) {
1027         rescanhosts();
1028     }
1029     if ($AutoCheckLog) {
1030         scanlog();
1031     }
1032 }
1033
1034 sub flatten {
1035     foreach $i (keys(%chost)) {
1036         $chost{$i}->{'MainFrame'}->configure(-relief => "flat",-borderwidth=>0);
1037     }
1038 }
1039
1040 sub reliefen {
1041     foreach $i (keys(%chost)) {
1042         $chost{$i}->{'MainFrame'}->configure(-relief =>"sunken",-borderwidth=>2);
1043     }
1044 }
1045
1046 sub fixall {
1047     foreach $i (keys(%chost)) {
1048         $chost{$i}->fix();
1049     }
1050 }
1051
1052 sub seenall {
1053     foreach $i (keys(%chost)) {
1054         $chost{$i}->seenall();
1055     }
1056 }
1057
1058 sub remote_cmd {
1059     my $type = shift;
1060     if ($selected) {
1061         remote_cmd_generic("$::snmppath/rsnmp -p $type $selected->{'Host'}",
1062                            "$selected->{'Host'} -- $type",1);
1063     } else {
1064         setmsg("Error:  Nothing selected");
1065     }
1066 }
1067
1068 sub remote_load {
1069     if ($selected) {
1070         remote_cmd_generic("$::snmppath/snmpwalk " . sprintf($::default_get_args,$selected->{'Host'}) . " .EXTENSIBLEDOTMIB.LOADAVEMIBNUM.LOADAVE",
1071                            "$selected->{'Host'} -- LoadAve");
1072     } else {
1073         setmsg("Error:  Nothing selected");
1074     }
1075 }
1076
1077 sub remote_cmd_generic {
1078     my $cmd = shift;
1079     my $title = shift;
1080     my $insert = shift;
1081     addToLog("running:  $cmd ... ");
1082     my $newwin = MainWindow->new;
1083     $newwin->Busy();
1084
1085     $newwin->option('add','*highlightThickness','0');        #wish this worked
1086 #     $newwin->option('add','*highlightbackground','#C9C9C9');
1087     $newwin->option('add','*background','#C9C9C9');
1088     $newwin->option('add','*font','6x13');
1089
1090     my $buttons = $newwin->Frame;
1091     $buttons->pack(-side => 'bottom', -expand => 1, -fill => 'x');
1092     my $entries = $newwin->Frame;
1093     $entries->pack(-side => 'bottom', -expand => 1, -fill => 'x');
1094
1095     my $text = $newwin->Text(-height => 40, -setgrid => 1);
1096     $text->pack(-side => 'left', -fill => 'both', -expand => 1);
1097     my $scroll = $newwin->Scrollbar(-command => ['yview',$text]);
1098     $scroll->pack(-side => 'left', -fill => 'y');
1099     $text->configure(-yscrollcommand => ['set', $scroll]);
1100
1101     my $close = $buttons->Button(-text => 'Close', 
1102                                  -command => ['destroy',$newwin]);
1103     $close->pack(-side => 'left', -expand => 1);
1104     my $rerun = $buttons->Button(-text => 'Re-Run', 
1105                                  -command=>[\&fill_text,'',$text,
1106                                             \$cmd,$insert]);
1107     $rerun->pack(-side => 'left', -expand => 1);
1108
1109     my $cmdlabel = $entries->Label(-text => "Command:  ");
1110     my $cmdtexte = $entries->Entry(-textvariable => \$cmd, 
1111                                       -relief => "sunken");
1112     $cmdtexte->bind('<Return>' => [\&fill_text,$text, \$cmd,$insert]);
1113     $cmdlabel->pack(-side => 'left');
1114     $cmdtexte->pack(-side => 'left');
1115     
1116     my $searchtext = '';
1117     my $searchlabel = $entries->Label(-text => "Search for:  ");
1118     my $searchtexte = $entries->Entry(-textvariable => \$searchtext, 
1119                                       -relief => "sunken");
1120
1121     $searchtexte->pack(-side => 'right');
1122     $searchlabel->pack(-side => 'right');
1123     $searchtexte->bind('<Return>' => [sub { $text->tag('remove','search','0.0','end');
1124                                             my($current, $length) = ('1.0', 0);
1125                                             while (1) {
1126                                                 $current = $text->search(-count => \$length, $searchtext, $current, 'end');
1127                                                 last if not $current;
1128                                                 $text->tag('add', 'search', $current, "$current + $length char");
1129                                                 $current = $text->index("$current + $length char");
1130                                                 $text->tag('configure','search',
1131                                                            -background => 
1132                                                            'lightBlue');}}]);
1133
1134     if (defined($title)) {
1135         $newwin->title($title);
1136         $newwin->iconname($title);
1137     }
1138     fill_text('',$text,\$cmd,$insert);
1139 }
1140
1141 sub fill_text {
1142     my $dump = shift;
1143     my $textw = shift;
1144     my $cmd = shift;
1145     my $insert = shift;
1146     $textw->delete('1.0','end');
1147     if (defined($insert) && $insert) {
1148         $textw->insert('end',"running:  $$cmd\n\n");
1149     }
1150     $textw->toplevel->update();
1151     $textw->toplevel->Busy();
1152     open(OUT,"$$cmd|");
1153     while (<OUT>) {
1154         $textw->insert('end',$_);
1155         $textw->toplevel->update();
1156         $textw->toplevel->Busy();
1157     }
1158     close(OUT);
1159     if (defined ($insert) && $insert) {
1160         $textw->insert('end',"\ndone.\n");
1161     }
1162     $textw->toplevel->Unbusy();
1163     $textw->Unbusy();
1164     addToLog("done:  $$cmd");
1165 }
1166
1167 sub display_help {
1168     print "
1169 Usage:  snmpcheck [-x] [-n|y] [-h] [-H] [-V NUM] [-L] [-f] [[-a] HOSTS] 
1170
1171   -h\tDisplay this message.
1172   -a\tcheck error log file AND hosts specified on command line.
1173   -p\tDon't try and ping-echo the host first
1174   -f\tOnly check for things I can fix
1175   HOSTS\tcheck these hosts for problems.
1176
1177 X Options:
1178   -x\tforces ascii base if \$DISPLAY set (instead of tk).
1179   -H\tstart in hidden mode.  (hides user interface)
1180   -V NUM\tsets the initial verbosity level of the command log (def: 1)
1181   -L\tShow the log window at startup
1182   -d\tDon't start by checking anything.  Just bring up the interface.
1183
1184 Ascii Options:
1185   -n\tDon't ever try and fix the problems found.  Just list.
1186   -y\tAlways fix problems found.
1187
1188 ";
1189     exit(0);
1190
1191 }
1192
1193 sub option_get {
1194     my $resource = shift;
1195     return $top->option('get',$resource);
1196 }
1197
1198 sub option_set {
1199     my $resource = shift;
1200     my $value = shift;
1201     $top->option('add',"*$resource",$value);
1202 }
1203
1204 sub option_save {
1205
1206 }
1207
1208 sub mibsort {
1209     $_ = $a;
1210     ($av) = /\.([0-9]+)/;
1211     $_ = $b;
1212     ($bv) = /\.([0-9]+)/;
1213     return $av <=> $bv;
1214 }
1215
1216 sub setmibchecklist {
1217     my $i;
1218     foreach $i (keys(%mibchecklist)) {
1219         $mibchecklist{$i} = 0;
1220     }
1221     foreach $i (@_) {
1222         $mibchecklist{$i} = 1;
1223     }
1224 }