Blame perl/AnyData_SNMP/netsh

Packit fcad23
#!/usr/bin/perl
Packit fcad23
Packit fcad23
use Getopt::Std;
Packit fcad23
Packit fcad23
use DBI;
Packit fcad23
use Term::ReadLine;
Packit fcad23
use SNMP;
Packit fcad23
use AutoLoader;
Packit fcad23
use IO::File;
Packit fcad23
Packit fcad23
BEGIN {
Packit fcad23
    $opts{'t'} = ! eval { require Text::FormatTable; };
Packit fcad23
    $ansicolor = eval { require Term::ANSIColor; };
Packit fcad23
}
Packit fcad23
Packit fcad23
# override some of the functions to force our colorized semantics.
Packit fcad23
# This is really ugly, but if you pass colorized strings directly to
Packit fcad23
# Text::FormatTable then it calculates the string lengths incorrectly.
Packit fcad23
# Children: don't try this at home.  We're trained professionals.
Packit fcad23
if ($colorize) {
Packit fcad23
   eval {
Packit fcad23
        #
Packit fcad23
	# colorized strings.
Packit fcad23
	#
Packit fcad23
	package color_string;
Packit fcad23
Packit fcad23
	require Term::ANSIColor;
Packit fcad23
Packit fcad23
	use overload
Packit fcad23
	    '""' => \&string_it
Packit fcad23
	;
Packit fcad23
Packit fcad23
	sub string_it {
Packit fcad23
	    if ($_[0][3]) {
Packit fcad23
		if ($_[0][3] == 1) {
Packit fcad23
		    return color_it();
Packit fcad23
		} else {
Packit fcad23
		    $_[0][3] -= 1;
Packit fcad23
		    return $_[0][1];
Packit fcad23
		}
Packit fcad23
	    }
Packit fcad23
	    return $_[0][1];
Packit fcad23
	}
Packit fcad23
Packit fcad23
        sub colorize_next {
Packit fcad23
	    $_[0][3] = 2;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	sub color_it {
Packit fcad23
	    my $str = $_[1] || $_[0][1];
Packit fcad23
	    return $_[0][0] . $str . $_[0][2];
Packit fcad23
	}
Packit fcad23
Packit fcad23
	sub new {
Packit fcad23
	    my $this = [Term::ANSIColor::color($_[2]), $_[1],
Packit fcad23
		      Term::ANSIColor::color('reset')];
Packit fcad23
	    return bless($this, $_[0]);
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
if ($opts{'t'} == 0 && $colorize) {
Packit fcad23
    eval {
Packit fcad23
	package Text::FormatTable;
Packit fcad23
Packit fcad23
	sub _l_box($$)
Packit fcad23
	{
Packit fcad23
	    my ($width, $text) = @_;
Packit fcad23
	    my $lines = _wrap($width, $text);
Packit fcad23
	    map { 
Packit fcad23
		if (ref($text) eq "color_string") {
Packit fcad23
		    $_ .= $text->color_it($_) . ' 'x($width-length($_));
Packit fcad23
		} else {
Packit fcad23
		    $_ .= ' 'x($width-length($_));
Packit fcad23
		} 
Packit fcad23
	    } @$lines;
Packit fcad23
	    return $lines;
Packit fcad23
	}
Packit fcad23
Packit fcad23
	sub _r_box($$)
Packit fcad23
	{
Packit fcad23
	    my ($width, $text) = @_;
Packit fcad23
	    my $lines = _wrap($width, $text);
Packit fcad23
	    map { 
Packit fcad23
		if (ref($text) eq "color_string") {
Packit fcad23
		    $_ = ' 'x($width-length($_)) . $text->color_it($_);
Packit fcad23
		} else {
Packit fcad23
		    $_ = ' 'x($width-length($_)) . $_;
Packit fcad23
		} 
Packit fcad23
	    } @$lines;
Packit fcad23
	    return $lines;
Packit fcad23
	}
Packit fcad23
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
if (!$ansicolor) {
Packit fcad23
    $begin = $end = "*";
Packit fcad23
}
Packit fcad23
Packit fcad23
$SNMP::use_enums=1;
Packit fcad23
Packit fcad23
Packit fcad23
#defaults
Packit fcad23
$opts{'d'} = "\t";
Packit fcad23
$opts{'v'} = 1;
Packit fcad23
$opts{'l'} = 'authNoPriv';
Packit fcad23
$params = "";
Packit fcad23
Packit fcad23
getopts('hd:tR:u:l:v:a:A:x:X:p:c:t:r:',\%opts);
Packit fcad23
Packit fcad23
usage() if ($#ARGV == -1 || $opts{'h'});
Packit fcad23
Packit fcad23
my %parammap = {
Packit fcad23
    'v' => 'Version',
Packit fcad23
    'u' => 'SecName',
Packit fcad23
    'a' => 'AuthProto',
Packit fcad23
    'A' => 'AuthPass',
Packit fcad23
    'x' => 'PrivProto',
Packit fcad23
    'X' => 'PrivPass',
Packit fcad23
    'p' => 'RemotePort',
Packit fcad23
    't' => 'Timeout',
Packit fcad23
    'r' => 'Retries',
Packit fcad23
    'c' => 'Community',
Packit fcad23
    'l' => 'SecLevel'
Packit fcad23
    };
Packit fcad23
Packit fcad23
foreach my $x (keys(%opts)) {
Packit fcad23
    if ($parammap{$x}) {
Packit fcad23
	$params .= ";ad_SNMP_$parammap{$x}=$x";
Packit fcad23
    }
Packit fcad23
    push @sessparams,$parammap{$x},$x;
Packit fcad23
}
Packit fcad23
Packit fcad23
my $host = shift @ARGV;
Packit fcad23
$params .= ";ad_SNMP_DestHost=" . $host;
Packit fcad23
push @sessparms,'DestHost', $host;
Packit fcad23
Packit fcad23
# connect to the DBI interface
Packit fcad23
$AnyData::Storage::SNMP::debugre = $opts{'R'} if ($opts{'R'});
Packit fcad23
($dbh = DBI->connect("dbi:AnyData:ad_default=SNMP$params"))
Packit fcad23
    || die "\tConnection problem: $DBI::errstr\n";
Packit fcad23
$AnyData::Storage::SNMP::debugre = $opts{'R'} if ($opts{'R'});
Packit fcad23
Packit fcad23
$prompt = "netsh> ";
Packit fcad23
Packit fcad23
load_rcs();
Packit fcad23
Packit fcad23
# setup terminal prompter
Packit fcad23
$ENV{'PERL_RL'}='o=0' if (!exists($ENV{'PERL_RL'}));
Packit fcad23
# the ornaments are too ugly
Packit fcad23
$term = new Term::ReadLine 'netsh';
Packit fcad23
Packit fcad23
if ($#ARGV >= 0) {
Packit fcad23
    # command line command
Packit fcad23
    netsh(join(" ",@ARGV));
Packit fcad23
} else {
Packit fcad23
    # interactive shell
Packit fcad23
    while($cmd = $term->readline($prompt)) {
Packit fcad23
	last if ($cmd eq "exit" || $cmd eq "quit" || $cmd eq "q");
Packit fcad23
	netsh($cmd, \%conf);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
# load all configuration files we can find.
Packit fcad23
sub load_rcs {
Packit fcad23
    if (-f "$ENV{'HOME'}/.snmp/netshrc") {
Packit fcad23
	source_file("$ENV{'HOME'}/.snmp/netshrc");
Packit fcad23
    }
Packit fcad23
    if (-d "$ENV{'HOME'}/.snmp/netsh") {
Packit fcad23
	foreach my $i (glob("$ENV{'HOME'}/.snmp/netsh/*")) {
Packit fcad23
	    if (-f "$i" && "$i" !~ /.*(~|.bak)$/) {
Packit fcad23
		source_file("$i");
Packit fcad23
	    }
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
# command definition for sourcing a particular file
Packit fcad23
sub source_file {
Packit fcad23
    my $fh = new IO::File;
Packit fcad23
    if ($fh->open("<$_[0]")) {
Packit fcad23
	while(<$fh>) {
Packit fcad23
	    if (s/<<\s*(\w+)$//) {
Packit fcad23
		my $stopat = $1;
Packit fcad23
		my $lines = $_;
Packit fcad23
		while(<$fh>) {
Packit fcad23
		    last if (/$stopat/);
Packit fcad23
		    $lines .= $_;
Packit fcad23
		}
Packit fcad23
		$_ = $lines;
Packit fcad23
	    }
Packit fcad23
	    netsh($_);
Packit fcad23
	}
Packit fcad23
    } else {
Packit fcad23
	print STDERR "no such file: $_[0]\n";
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
# export data into an external file
Packit fcad23
sub my_export {
Packit fcad23
    shift;
Packit fcad23
    if (!$insh) {
Packit fcad23
	my $cmd = "create table exporttable (" . join (" varchar(255), ",@{$sth->{NAME}}) . " varchar(255))";
Packit fcad23
	$exporth->do($cmd);
Packit fcad23
	$cmd = "insert into exporttable values(" . ('?, ' x ($#_)) . "?)";
Packit fcad23
	$insh = $exporth->prepare($cmd);
Packit fcad23
    }
Packit fcad23
    $insh->execute(@_);
Packit fcad23
}
Packit fcad23
Packit fcad23
# the main processing function.
Packit fcad23
sub netsh {
Packit fcad23
    my $stmt = shift;
Packit fcad23
    chomp($stmt);      # remove trailing white space
Packit fcad23
    $stmt =~ s/^\s+//; # remove leading white space
Packit fcad23
    $stmt =~ s/;*$//;  # get rid of trailing semicolons
Packit fcad23
    return if ($stmt =~ /^\s*$/);
Packit fcad23
    return if ($stmt =~ /^\s*\#/);
Packit fcad23
    my ($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
Packit fcad23
Packit fcad23
    #define alias
Packit fcad23
#    print "doing [$multi_alias]: $stmt\n";
Packit fcad23
    if ($name eq "alias" || $multi_alias) {
Packit fcad23
	if ($multi_alias) {
Packit fcad23
	    if ($stmt =~ /^prompt\s+(\d+)\s+[\"\'](.+)[\"\']/) {
Packit fcad23
		$aliases{$current_alias}{'prompts'}[$1] = $2;
Packit fcad23
		return;
Packit fcad23
	    } elsif ($stmt =~ /^prompt\s+(\d+)\s+(.+)/) {
Packit fcad23
		my $x = $2;
Packit fcad23
		my $spot = $1;
Packit fcad23
		$x =~ s/\s+$//;
Packit fcad23
		$aliases{$current_alias}{'prompts'}[$spot] = "$x ";
Packit fcad23
		return;
Packit fcad23
	    } elsif ($stmt =~ /^\s*\}\s*$/) {
Packit fcad23
		$prompt = $oprompt;
Packit fcad23
		$multi_alias = 0;
Packit fcad23
		return;
Packit fcad23
	    }
Packit fcad23
	    push @{$aliases{$current_alias}{'definition'}},$stmt;
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
	$stmt =~ s/^alias\s+//;
Packit fcad23
	if ($args eq "") {
Packit fcad23
	    foreach $i (sort keys(%aliases)) {
Packit fcad23
		display_alias($i);
Packit fcad23
	    }
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
	($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
Packit fcad23
	if ($args eq "") {
Packit fcad23
	    display_alias($name);
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
#	print "alias: $name $args\n";
Packit fcad23
	if ($args eq "{") {
Packit fcad23
	    $oprompt = $prompt;
Packit fcad23
	    $prompt = "define $name> ";
Packit fcad23
	    $current_alias = $name;
Packit fcad23
	    $multi_alias = 1;
Packit fcad23
	    $aliases{$name}{'definition'} = [];
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
	$aliases{$name}{'definition'} = $args;
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    #eval
Packit fcad23
    if ($name eq "eval") {
Packit fcad23
	eval $args;
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    #eval just vars
Packit fcad23
    if ($name eq "evalvars") {
Packit fcad23
#	print "args1:",$args,"\n";
Packit fcad23
	$args =~ s/\$(\w+)/$$1/eg;
Packit fcad23
#	print "args2:",$args,"\n";
Packit fcad23
	netsh($args);
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    #eval aliases
Packit fcad23
    while (exists $aliases{$name}) {
Packit fcad23
#	print "modified: $stmt -> ";
Packit fcad23
	my @ARGS = split(/\s+/,$args);
Packit fcad23
	my $statements;
Packit fcad23
	if (ref($aliases{$name}{'definition'}) eq "ARRAY") {
Packit fcad23
	    $statements = $aliases{$name}{'definition'};
Packit fcad23
Packit fcad23
	    # maybe prompt for values
Packit fcad23
	    if ($#{$aliases{$name}{'prompts'}} > -1) {
Packit fcad23
		my $i;
Packit fcad23
		for($i = 1; $i <= $#{$aliases{$name}{'prompts'}}; $i++) {
Packit fcad23
		    if (!$ARGS[$i-1] && $term) {
Packit fcad23
			$ARGS[$i-1] = 
Packit fcad23
			    $term->readline($aliases{$name}{'prompts'}[$i]);
Packit fcad23
		    }
Packit fcad23
		}
Packit fcad23
	    }
Packit fcad23
	} else {
Packit fcad23
	    $statements = [$aliases{$name}{'definition'}];
Packit fcad23
	}
Packit fcad23
	foreach my $stmt (@$statements) {
Packit fcad23
	    #print "$stmt -> ";
Packit fcad23
	    $stmt =~ s/\\(\d+)/$ARGS[$1-1]/g;
Packit fcad23
#	    print "running $stmt\n";
Packit fcad23
	    ($name, $args) = ($stmt =~ /^(\w+)\s*(.*)$/);
Packit fcad23
	    netsh($stmt);
Packit fcad23
	}
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ /^rehash$/) {
Packit fcad23
	load_rcs();
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    my $subfn;
Packit fcad23
Packit fcad23
    if ($stmt =~ /^eval (.*)/) {
Packit fcad23
	eval $1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ s/^printf\s+(\".*\")\s*(.*)/$2/) {
Packit fcad23
	if ($2 eq "") {
Packit fcad23
	    print eval $1;
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
	$subfn = \&my_printf;
Packit fcad23
	$stmt = $2;
Packit fcad23
	$printfmt = $1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    # special show columns statement
Packit fcad23
    if ($stmt =~ /^show columns from (\w+)$/) {
Packit fcad23
	my $mibnode = $SNMP::MIB{$1};
Packit fcad23
	my $entrynode = $mibnode->{children}[0];
Packit fcad23
	if (!defined($mibnode) || !defined($entrynode)) {
Packit fcad23
	    print STDERR "no such table: $1\n";
Packit fcad23
	    return;
Packit fcad23
	}
Packit fcad23
	if ($opts{'t'}) {
Packit fcad23
	    map { print $_->{label},"\n"; } sort { $a->{subID} <=> $b->{subID}} @{$entrynode->{children}};
Packit fcad23
	} else {
Packit fcad23
	    $table = Text::FormatTable->new('|r|');
Packit fcad23
	    $table->rule('-');
Packit fcad23
	    $table->head('Column');
Packit fcad23
	    $table->rule('-');
Packit fcad23
	    map { $table->row($_->{label}); } sort { $a->{subID} <=> $b->{subID}} @{$entrynode->{children}};
Packit fcad23
	    $table->rule('-');
Packit fcad23
	    print $table->render();
Packit fcad23
	}
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ /^source\s+(.*)/) {
Packit fcad23
	source_file($1);
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ s/^export\s+(\S+)\s+(.*)/$2/) {
Packit fcad23
	$insh = undef;
Packit fcad23
	unlink($1);
Packit fcad23
	$exporth = DBI->connect('dbi:AnyData:');
Packit fcad23
	$exporth->func('exporttable','CSV',$1,'ad_catalog');
Packit fcad23
	$subfn = \&my_export;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ /^import\s+(\S+)/) {
Packit fcad23
	my $exporth = DBI->connect('dbi:AnyData:');
Packit fcad23
	$exporth->func('exporttable','CSV',$1,'ad_catalog');
Packit fcad23
	my $selh = $exporth->prepare("select * from exporttable");
Packit fcad23
	$selh->execute();
Packit fcad23
	$old_data = [];
Packit fcad23
	while(my $row = $selh->fetchrow_arrayref) {
Packit fcad23
	    push @$old_data, @$row;
Packit fcad23
	}
Packit fcad23
	$selh->finish();
Packit fcad23
	$exporth->disconnect();
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
    
Packit fcad23
    if ($stmt =~ /^diff\s+(.*)/) {
Packit fcad23
	$running_watch = 2;
Packit fcad23
	netsh($1);
Packit fcad23
	$running_watch = 0;
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if ($stmt =~ /^watch\s+(.*)/) {
Packit fcad23
	$running_watch = 1;
Packit fcad23
	my $cmd = $1;
Packit fcad23
	my $delay = 1;
Packit fcad23
	my $clear = `clear`;
Packit fcad23
	if ($cmd =~ s/^(\d+)\s+(.*)/$2/) {
Packit fcad23
	    $delay = $1;
Packit fcad23
	    $cmd = $2;
Packit fcad23
	}
Packit fcad23
	$SIG{'TERM'} = sub { $running_watch = 0; };
Packit fcad23
	$SIG{'INT'} = sub { $running_watch = 0; };
Packit fcad23
	while($running_watch) {
Packit fcad23
	    print $clear;
Packit fcad23
	    netsh($cmd);
Packit fcad23
	    sleep($delay);
Packit fcad23
	}
Packit fcad23
	$SIG{'TERM'} = \&exit;
Packit fcad23
	$SIG{'INT'} = \&exit;
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    # we have an SQL statement.  process it.
Packit fcad23
    if ($stmt =~ /^(select|insert|update|delete)/) {
Packit fcad23
	$sth = $dbh->prepare($stmt);
Packit fcad23
	$sth->execute();
Packit fcad23
	if ($stmt =~ /^select/) {
Packit fcad23
	    my $table;
Packit fcad23
	    my $older_data = $old_data;
Packit fcad23
	    if ($running_watch == 1) {
Packit fcad23
		$old_data = [];
Packit fcad23
	    }
Packit fcad23
	    my $oldcount = 0;
Packit fcad23
	    while($row = $sth->fetchrow_arrayref) {
Packit fcad23
		
Packit fcad23
		if ($running_watch) {
Packit fcad23
		    $newrow=[];
Packit fcad23
		    my $count;
Packit fcad23
		    for($count = 0; $count <= $#$row; $count++) {
Packit fcad23
			if ($older_data &&
Packit fcad23
			    $row->[$count] ne
Packit fcad23
			    $older_data->[$oldcount][$count]) {
Packit fcad23
			    if ($ansicolor) {
Packit fcad23
				push @$newrow, new color_string($row->[$count],'red');
Packit fcad23
			    } else {
Packit fcad23
				push @$newrow,"$begin$row->[$count]$end";
Packit fcad23
			    }
Packit fcad23
			} else {
Packit fcad23
			    push @$newrow,$row->[$count];
Packit fcad23
			}
Packit fcad23
			if ($running_watch == 1) {
Packit fcad23
			    $old_data->[$oldcount][$count] = $row->[$count];
Packit fcad23
			}
Packit fcad23
		    }
Packit fcad23
		    $oldcount++;
Packit fcad23
		    $row = $newrow;
Packit fcad23
 		}
Packit fcad23
Packit fcad23
		# self printing;
Packit fcad23
		if (ref($subfn) eq "CODE") {
Packit fcad23
		    &$subfn($printfmt,@$row);
Packit fcad23
		    next;
Packit fcad23
		}
Packit fcad23
Packit fcad23
		if ($opts{'t'}) {
Packit fcad23
		    if ($opts{'d'} eq 'xml') {
Packit fcad23
			print "  <row>\n";
Packit fcad23
			for(my $xx = 0; $xx < $#{$sth->{NAME}}; $xx++) {
Packit fcad23
			    print "    <$sth->{NAME}[$xx]>$row->[$xx]</$sth->{NAME}[$xx]>\n";
Packit fcad23
			}
Packit fcad23
			print "  </row>\n";
Packit fcad23
		    } elsif ($opts{'d'} eq 'xmlshort') {
Packit fcad23
			print "  
Packit fcad23
			for(my $xx = 0; $xx < $#{$sth->{NAME}}; $xx++) {
Packit fcad23
			    print " $sth->{NAME}[$xx]=\"$row->[$xx]\"";
Packit fcad23
			}
Packit fcad23
			print "/>\n";
Packit fcad23
		    } else {
Packit fcad23
			print join($opts{'d'},@$row),"\n";
Packit fcad23
		    }
Packit fcad23
		} elsif (!$table) {
Packit fcad23
		    $table = Text::FormatTable->new('|r' x ($#$row+1) . "|");
Packit fcad23
		    $table->rule('-');
Packit fcad23
		    $table->head(@{$sth->{NAME}});
Packit fcad23
		    $table->rule('-');
Packit fcad23
		    $table->row(@$row);
Packit fcad23
		} else {
Packit fcad23
		    $table->row(@$row);
Packit fcad23
		}
Packit fcad23
	    }
Packit fcad23
	    if ($table) {
Packit fcad23
		$table->rule('-');
Packit fcad23
		print $table->render();
Packit fcad23
	    }
Packit fcad23
	}
Packit fcad23
	$sth->finish();
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    # retrieve just one variable and display it
Packit fcad23
    if ($stmt =~ /^(get|)\s*([^\s]+)\s*[^=]/) {
Packit fcad23
	my $sess = make_session();
Packit fcad23
	if ($sess) {
Packit fcad23
	    my @results = split(/[,\s]+/,$stmt);
Packit fcad23
	    my $resultsv = new SNMP::VarList();
Packit fcad23
	    # expression stolen from the main perl SNMP module
Packit fcad23
	    map {  my ($tag, $iid) = 
Packit fcad23
		       (/^((?:\.\d+)+|(?:\w+(?:\-*\w+)+))\.?(.*)$/);
Packit fcad23
		   push @$resultsv, [$tag, $iid] } @results;
Packit fcad23
	    $sess->get($resultsv)  || 
Packit fcad23
		print STDERR "Error: $sess->{ErrorNum} $sess->{ErrString}\n";
Packit fcad23
  	    @results = ();
Packit fcad23
	    map { push @results, $_->[2] } @$resultsv;
Packit fcad23
	    if (ref($subfn) eq "CODE") {
Packit fcad23
		&$subfn($printfmt,@results);
Packit fcad23
	    } else {
Packit fcad23
		print join(" ", @results),"\n";
Packit fcad23
	    }
Packit fcad23
	} else {
Packit fcad23
	    print STDERR "could not establish a SNMP session to $host\n";
Packit fcad23
	}
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    # set something
Packit fcad23
    if ($stmt =~ /^(set|)\s*([^\s]+)\s=\s(.*)$/) {
Packit fcad23
	my $sess = make_session();
Packit fcad23
	if ($sess) {
Packit fcad23
	    $sess->set([$2,undef,$1]) || 
Packit fcad23
		print STDERR "opps: $sess->{ErrorNum} $sess->{ErrString}\n";
Packit fcad23
	} else {
Packit fcad23
	    print STDERR "could not establish a SNMP session to $host\n";
Packit fcad23
	}
Packit fcad23
	return;
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
sub auto_snmp {
Packit fcad23
    my $node = $SNMP::MIB{$_[0]};
Packit fcad23
#    print STDERR "netsh::fetch_snmp $_[0] $node->{label}\n";
Packit fcad23
    my $indexes = $node->{parent}{indexes};
Packit fcad23
    if ($#$indexes > -1) {
Packit fcad23
#	print STDERR "column\n";
Packit fcad23
	# table 
Packit fcad23
    } else {
Packit fcad23
	# scalar
Packit fcad23
	if (exists($_[1])) {
Packit fcad23
	    my $sess = make_session();
Packit fcad23
	    my $val = $sess->set([$_[0],0,$_[1]]) || return;
Packit fcad23
#	    print STDERR "scalar set: $val\n";
Packit fcad23
	    return $val;
Packit fcad23
	} else {
Packit fcad23
	    my $sess = make_session();
Packit fcad23
	    my $val = $sess->get([$_[0],0]);
Packit fcad23
#	    print STDERR "scalar get: $val\n";
Packit fcad23
	    return $val;
Packit fcad23
	}
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
sub AUTOLOAD {
Packit fcad23
    my $nodename = $AUTOLOAD;
Packit fcad23
    $nodename =~ s/.*:://;
Packit fcad23
    print STDERR "netsh::AUTOLOAD $AUTOLOAD $nodename\n";
Packit fcad23
    if ($SNMP::MIB{$nodename}) {
Packit fcad23
	eval << "END";
Packit fcad23
        sub $AUTOLOAD {
Packit fcad23
	    auto_snmp($nodename, \@_);
Packit fcad23
	}
Packit fcad23
END
Packit fcad23
	goto &$AUTOLOAD;
Packit fcad23
    }
Packit fcad23
    print STDERR join(",",@_),"\n";
Packit fcad23
}
Packit fcad23
Packit fcad23
sub my_printf {
Packit fcad23
    # drop quotes
Packit fcad23
    my $fmt = shift;
Packit fcad23
    $fmt = eval $fmt;
Packit fcad23
    map { if (ref($_) eq "color_string") { $_->colorize_next(); } } @_;
Packit fcad23
    printf($fmt, @_);
Packit fcad23
}
Packit fcad23
Packit fcad23
sub display_alias {
Packit fcad23
    my $name = shift;
Packit fcad23
    if (exists $aliases{$name}{'definition'}) {
Packit fcad23
	if (ref($aliases{$name}{'definition'}) eq "ARRAY") {
Packit fcad23
	    print "alias $name {\n";
Packit fcad23
	    map { print "  $_\n"; } @{$aliases{$name}{'definition'}};
Packit fcad23
	    print "}\n";
Packit fcad23
	} else {
Packit fcad23
	    print "alias $name $aliases{$name}{'definition'}\n";
Packit fcad23
	}
Packit fcad23
    } else {
Packit fcad23
	print "no alias defined for \"$name\"\n";
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
sub make_session {
Packit fcad23
    if (!$sess) {
Packit fcad23
	$sess = new SNMP::Session(@sessparms);
Packit fcad23
    }
Packit fcad23
    return $sess;
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
sub usage {
Packit fcad23
    print STDERR "
Packit fcad23
$0 [ARGUMENTS] HOSTNAME [SQL_COMMAND] 
Packit fcad23
Packit fcad23
  $0 implements a simple SQL shell which maps onto SNMP.  All
Packit fcad23
  statements issued within the shell are converted to SNMP requests and
Packit fcad23
  sent to HOSTNAME and the results displayed in a nice table output
Packit fcad23
  format if the Text::FormatTable module is available.  If SQL_COMMAND
Packit fcad23
  is given on the command line, then it's interpreted and control is
Packit fcad23
  returned to the caller.  If not, an interactive prompt is given where
Packit fcad23
  multiple commands can be issued.
Packit fcad23
Packit fcad23
ARGUMENTS may include:
Packit fcad23
Packit fcad23
  -t         delimiter separated output, don't print pretty tables.
Packit fcad23
  -d DELIM   use DELIM as the delimiter.  A tab is the default delimiter.
Packit fcad23
             'xml' is a special delimiter to produce xml output.
Packit fcad23
Packit fcad23
ARGUMENTS also may include the following.  See the net-snmp snmpcmd
Packit fcad23
manual page for details on what they mean:
Packit fcad23
Packit fcad23
  -v VERSION        (default: 1)
Packit fcad23
  -t TIMEOUT
Packit fcad23
  -r RETRIES
Packit fcad23
  -p PORT
Packit fcad23
  -c COMMUNITY
Packit fcad23
  -a AUTHPROTOCOL   (default: MD5)
Packit fcad23
  -x PRIVPROTOCOL   (default: DES)
Packit fcad23
  -A AUTHPASS
Packit fcad23
  -X PRIVPASS
Packit fcad23
  -l SECURITY_LEVEL (default: authNoPriv)
Packit fcad23
  
Packit fcad23
";
Packit fcad23
    exit;
Packit fcad23
}
Packit fcad23
Packit fcad23
__END__
Packit fcad23
Packit fcad23
=head1 NAME
Packit fcad23
Packit fcad23
netsh - A shell environment for interacting with networking devices
Packit fcad23
Packit fcad23
=head1 SYNOPSIS
Packit fcad23
Packit fcad23
netsh [(subset of) snmpcmd arguments] hostname[,hostname...] [command]
Packit fcad23
Packit fcad23
=head1 OPTIONAL PERL MODULES
Packit fcad23
Packit fcad23
There are some optional perl modules which make using the shell nicer
Packit fcad23
in general.  These modules are:
Packit fcad23
Packit fcad23
  Text::FormatTable
Packit fcad23
  Term::ReadLine::Gnu or Term::ReadLine::Perl
Packit fcad23
  Term::ANSIColor
Packit fcad23
Packit fcad23
You can install these by running [as root]:
Packit fcad23
Packit fcad23
  perl -MCPAN -e shell
Packit fcad23
  cpan> install Text::FormatTable
Packit fcad23
  ...
Packit fcad23
Packit fcad23
It is B<strongly> recommend you at least install the Text::FormatTable
Packit fcad23
module, and if you like command line editing one of the two extra
Packit fcad23
Term::ReadLine modules (Gnu being the better of the two).
Packit fcad23
Packit fcad23
=head1 DESCRIPTION
Packit fcad23
Packit fcad23
The netsh script provides an interactive, console-like environment
Packit fcad23
suitable for monitoring and manipulating data within networking
Packit fcad23
devices.  The environment is highly extensible through command
Packit fcad23
aliases and easy-to-use SQL-like queries.
Packit fcad23
Packit fcad23
It is implemented on top of the SNMP protocol using the net-snmp
Packit fcad23
package and perl.  See the snmpcmd and snmp.conf manual pages for
Packit fcad23
details on configuring net-snmp for authentication information for
Packit fcad23
the networking devices you wish to access.
Packit fcad23
Packit fcad23
=head1 ABOUT THE EXAMLPES IN THIS DOCUMENT
Packit fcad23
Packit fcad23
All the examples in this document are exact cut-n-pastes from the
Packit fcad23
inside of the netsh shell.  This includes the "netsh> " prompt and
Packit fcad23
possibly other prompts as well.
Packit fcad23
Packit fcad23
=head1 COMMANDS
Packit fcad23
Packit fcad23
The following is a list of the basic core commands supported by
Packit fcad23
netsh.  Many default aliases are also supplied, some of which are
Packit fcad23
listed in the next section.  At the command prompt type "alias" for
Packit fcad23
a full list of all the aliases and their definitions.
Packit fcad23
Packit fcad23
=over
Packit fcad23
Packit fcad23
=item show columns from TABLE
Packit fcad23
Packit fcad23
=item select ... 
Packit fcad23
Packit fcad23
=item update ...
Packit fcad23
Packit fcad23
=item insert ...
Packit fcad23
Packit fcad23
=item delete ...
Packit fcad23
Packit fcad23
netsh supports the standard sql-like language queries of snmp tables.
Packit fcad23
These are implemented via the SQL::Statement parser, so any form of
Packit fcad23
expression it accepts netsh will accept as well.
Packit fcad23
Packit fcad23
Examples:
Packit fcad23
Packit fcad23
  netsh> show columns from ifTable
Packit fcad23
  +-----------------+
Packit fcad23
  |           Column|
Packit fcad23
  +-----------------+
Packit fcad23
  |          ifIndex|
Packit fcad23
  ...
Packit fcad23
  netsh> select * from ifTable
Packit fcad23
  ... [output not shown]
Packit fcad23
  netsh> select tcpConnState, tcpConnRemotelAddress from tcpConnTable where tcpConnState = established
Packit fcad23
  ... [output not shown]
Packit fcad23
  netsh> update ifTable set ifAdminStatus = up where ifOperStatus = down
Packit fcad23
  ... [output not shown]
Packit fcad23
Packit fcad23
=item SNMPOBJECT
Packit fcad23
Packit fcad23
Simple lists of objects may be given which will directly request or
Packit fcad23
operate on those objects.  See printf below for controlling the
Packit fcad23
formatting of results
Packit fcad23
Packit fcad23
Examples:
Packit fcad23
Packit fcad23
  netsh> sysContact.0, sysLocation.0
Packit fcad23
  hardaker@somewhere.net my location
Packit fcad23
  netsh> sysContact.0 = my new contact information
Packit fcad23
Packit fcad23
=item alias my_command some other command
Packit fcad23
Packit fcad23
or
Packit fcad23
Packit fcad23
=back
Packit fcad23
Packit fcad23
alias my_many_commands {
Packit fcad23
  command1
Packit fcad23
  command2
Packit fcad23
  prompt NUMBER question
Packit fcad23
Packit fcad23
}
Packit fcad23
Packit fcad23
=over
Packit fcad23
Packit fcad23
=item
Packit fcad23
Packit fcad23
You can create aliases of your frequently used commands by aliasing
Packit fcad23
them to an easy to remember name.  \N parameters in the defined
Packit fcad23
command will be replaced by the positional argument of options passed
Packit fcad23
to the alias name.
Packit fcad23
Packit fcad23
For multi-line defined aliases, optional prompts may be given to
Packit fcad23
request information from the user when the NUMBERth argument is not
Packit fcad23
given to the alias.  If it is not given, the prompt will be printed
Packit fcad23
and the user will be asked to input a value for it.  This allows the
Packit fcad23
easy definition of interactive commands.  The value will be inserted
Packit fcad23
in alias parts containing \N substitution requests.
Packit fcad23
Packit fcad23
  netsh> alias interfaces select ifDescr from ifTable
Packit fcad23
  netsh> interfaces
Packit fcad23
  +-------+
Packit fcad23
  |ifDescr|
Packit fcad23
  +-------+
Packit fcad23
  |     lo|
Packit fcad23
  |   eth0|
Packit fcad23
  +-------+
Packit fcad23
  netsh> alias interface select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
Packit fcad23
  netsh> interface eth0
Packit fcad23
  +-------+--------+
Packit fcad23
  |ifDescr| ifSpeed|
Packit fcad23
  +-------+--------+
Packit fcad23
  |   eth0|10000000|
Packit fcad23
  +-------+--------+
Packit fcad23
Packit fcad23
=item printf FORMATSTRING COMMAND
Packit fcad23
Packit fcad23
Allows B<careful> formatting of results returned by the commands.
Packit fcad23
Packit fcad23
Example:
Packit fcad23
Packit fcad23
  netsh> alias interface {
Packit fcad23
  define interface> printf "interface %s is running at %d Mb/s\n" select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
Packit fcad23
  define interface> prompt 1 Enter the interface to describe:
Packit fcad23
  define interface> }
Packit fcad23
  netsh> interface
Packit fcad23
  Enter the interface to describe: eth0
Packit fcad23
  interface eth0 is running at 10000000 Mb/s
Packit fcad23
Packit fcad23
To list the definition of an already defined command, simply exclude
Packit fcad23
the definition and netsh will report the definition to you:
Packit fcad23
Packit fcad23
  netsh> alias interface
Packit fcad23
  alias interface {
Packit fcad23
    printf "interface %s is running at %d Mb/s\n" select ifDescr, ifSpeed from ifTable where ifDescr = '\1'
Packit fcad23
    prompt 1 Enter the interface to describe:
Packit fcad23
  }
Packit fcad23
Packit fcad23
To list all the aliases defined in the system, just type "alias" by itself.
Packit fcad23
Packit fcad23
=item watch [TIME] COMMAND
Packit fcad23
Packit fcad23
Continually watches the results of the COMMAND being run, which is run
Packit fcad23
every TIME seconds.  For select statements, it will attempt to mark
Packit fcad23
the changing values from one screen to the next by surrounding them
Packit fcad23
with "*"s or color (assuming you have the Term::ANSIColor perl module
Packit fcad23
installed) for easy picking out on the screen.
Packit fcad23
Packit fcad23
=item rehash
Packit fcad23
Packit fcad23
Re-load the alias definitions files in the common directory, as
Packit fcad23
well as those files found in $HOME/.snmp/netsh.
Packit fcad23
Packit fcad23
=item source FILE
Packit fcad23
Packit fcad23
loads definitons and commands from FILE into the running environment.
Packit fcad23
Packit fcad23
=back
Packit fcad23
Packit fcad23
=head1 FILES
Packit fcad23
Packit fcad23
By default, netsh will source all the definition files it can find.
Packit fcad23
It does this by first reading everything in
Packit fcad23
/usr/local/share/snmp/netsh/* and then reading everything in
Packit fcad23
$HOME/.snmp/netsh/*.  Everything contained in these files are
Packit fcad23
commands, but most frequently they entirely consist of aliases
Packit fcad23
definitions.
Packit fcad23
Packit fcad23
=head1 AUTHOR
Packit fcad23
Packit fcad23
bugs, comments, questions to net-snmp-users@lists.sourceforge.net
Packit fcad23
Packit fcad23
=head1 Copyright
Packit fcad23
Packit fcad23
     Copyright (c) 2002 Networks Associates Technology, Inc. All
Packit fcad23
     rights reserved.  This program is free software; you can
Packit fcad23
     redistribute it and/or modify it under the same terms as Perl
Packit fcad23
     itself.
Packit fcad23
Packit fcad23
=cut