#! /usr/bin/perl
##
## $Id: alurancid.in 3505 2016-11-20 04:45:26Z heas $
##
## rancid 3.6.2
## Copyright (c) 1997-2016 by Henry Kilmer and John Heasley
## All rights reserved.
##
## This code is derived from software contributed to and maintained by
## Henry Kilmer, John Heasley, Andrew Partan,
## Pete Whiting, Austin Schutz, and Andrew Fort.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted provided that the following conditions
## are met:
## 1. Redistributions of source code must retain the above copyright
## notice, this list of conditions and the following disclaimer.
## 2. Redistributions in binary form must reproduce the above copyright
## notice, this list of conditions and the following disclaimer in the
## documentation and/or other materials provided with the distribution.
## 3. All advertising materials mentioning features or use of this software
## must display the following acknowledgement:
## This product includes software developed by Henry Kilmer and John
## Heasley and its contributors for RANCID.
## 4. Neither the name of RANCID nor the names of its
## contributors may be used to endorse or promote products derived from
## this software without specific prior written permission.
## 5. It is requested that non-binding fixes and modifications be contributed
## back to RANCID.
##
## THIS SOFTWARE IS PROVIDED BY Henry Kilmer, John Heasley AND CONTRIBUTORS
## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
## POSSIBILITY OF SUCH DAMAGE.
##
## It is the request of the authors, but not a condition of license, that
## parties packaging or redistributing RANCID NOT distribute altered versions
## of the etc/rancid.types.base file nor alter how this file is processed nor
## when in relation to etc/rancid.types.conf. The goal of this is to help
## suppress our support costs. If it becomes a problem, this could become a
## condition of license.
#
# The expect login scripts were based on Erik Sherk's gwtn, by permission.
#
# The original looking glass software was written by Ed Kern, provided by
# permission and modified beyond recognition.
#
# Amazingly hacked version of Hank's rancid - this one tries to
# deal with HP procurves.
#
# RANCID - Really Awesome New Cisco confIg Differ
#
# usage: alurancid [-dltCV] [-f filename | hostname]
#
use 5.010;
use strict 'vars';
use warnings;
no warnings 'uninitialized';
use Exporter;
use Getopt::Std;
our($opt_d, $opt_f, $opt_h, $opt_l, $opt_t, $opt_C, $opt_V);
getopts('dflt:CV');
BEGIN {
push(@INC, "/usr/local/rancid/lib/rancid");
}
use rancid;
our @ISA = qw(Exporter rancid);
if ($opt_V) {
print "rancid 3.6.2\n";
exit(0);
}
$log = $opt_l;
$debug = $opt_d;
$file = $opt_f;
$host = $ARGV[0];
$clean_run = 0;
$found_end = 0;
$timeo = 90;
my(@commandtable, %commands, @commands);# command lists
my($aclsort) = ("ipsort"); # ACL sorting mode
my($filter_commstr); # SNMP community string filtering
my($filter_osc); # oscillating data filtering mode
my($filter_pwds); # password filtering mode
my($systeminfo) = 0; # show system-information
our $cmd;
our @EXPORT = qw($cmd);
# This routine parses "show chassis"
sub ShowChassis {
print STDERR " In ShowChassis: $_" if ($debug);
my $chassis_id = 0;
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
return(1) if (/ERROR: Invalid entry:/i);
# /([^,]+)/ && ProcessHistory("COMMENTS","keysort","A1","!$1\n");
if (/^Chassis (\d+)/) {
$chassis_id=($chassis_id + 1);
if ($chassis_id == 1) {ProcessHistory("COMMENTS","keysort","A$1","!Chassis: $1\n");next;}
elsif ($chassis_id == 2) {ProcessHistory("COMMENTS","keysort","B$1","!Chassis: $1\n");next;}
};
if (/Model Name:\s*([A-Za-z0-9_-]*)/) {
my $row = ($chassis_id + 1);
if ($chassis_id == 1) {ProcessHistory("COMMENTS","keysort","A$row","! Model: $1\n") && next;}
elsif ($chassis_id == 2) {ProcessHistory("COMMENTS","keysort","B$row","! Model: $1\n") && next;}
};
if (/Description:\s*([^,]*)/) {
my $row = ($chassis_id + 2);
if ($chassis_id == 1) {ProcessHistory("COMMENTS","keysort","A$row","! Description: $1\n") && next;}
elsif ($chassis_id == 2) {ProcessHistory("COMMENTS","keysort","B$row","! Description: $1\n") && next;}
};
if (/Hardware Revision:\s*(\d+)/) {
my $row = ($chassis_id + 3);
if ($chassis_id == 1) {ProcessHistory("COMMENTS","keysort","A$row","! Hardware Revision: $1\n") && next;}
elsif ($chassis_id == 2) {ProcessHistory("COMMENTS","keysort","B$row","! Hardware Revision: $1\n") && next;}
};
if (/Serial Number:\s*([A-Za-z0-9]*)/) {
my $row = ($chassis_id + 4);
if ($chassis_id == 1) {ProcessHistory("COMMENTS","keysort","A$row","! Serial Number: $1\n") && next;}
elsif ($chassis_id == 2) {ProcessHistory("COMMENTS","keysort","B$row","! Serial Number: $1\n") && next;}
};
}
return(0);
}
# This routine parses "show system" to take OS Version
sub ShowSystem {
print STDERR " In ShowSystem: $_" if ($debug);
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
/Description:\s*([A-Za-z0-9_\-.\s]*)/ && ProcessHistory("COMMENTS","keysort","D1","!OS Version: $1\n") && next;
}
return(0);
}
# This routine parses "show stack topology"
sub ShowStackTopolgy {
print STDERR " In ShowStackTopolgy: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","F1","!STACK TOPOLOGY:\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
return(1) if (/ERROR: Invalid entry:/i);
ProcessHistory("COMMENTS","keysort","F2","!$_") && next;
}
return(0);
}
# This routine parses "show module"
sub ShowModule {
print STDERR " In ShowModule: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","E1","!MODULES INSTALLED:\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
return(1) if (/Line has invalid autocommand /);
ProcessHistory("COMMENTS","keysort","E2","!$_") && next;
}
return(0);
}
# This routine parses PoE interfaces statistics
sub ShowLanPower {
print STDERR " In ShowLanPower: $_" if ($debug);
if ($cmd =~ m/1/) {ProcessHistory("COMMENTS","keysort","G1","!POE STATISTICS:\n!\n")}
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
if ($cmd =~ m/1/) {ProcessHistory("COMMENTS","keysort","G2","!$_") && next;}
elsif ($cmd =~ m/2/) {ProcessHistory("COMMENTS","keysort","H1","!$_") && next;}
}
return(0);
}
# This routine parses show user
sub ShowUser {
print STDERR " In ShowUser: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","I1","!USERS CONFIGURED:\n!\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
ProcessHistory("COMMENTS","keysort","I2","!$_") && next;
}
return(0);
}
# This routine parses generic output
sub GenericParse {
print STDERR " In GenericParse: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","L1","!\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
ProcessHistory("COMMENTS","keysort","L1","!$_") && next;
}
return(0);
}
# This routine parses "show vlan"
sub ShowVLAN {
print STDERR " In ShowVLAN: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","M1","!VLAN DEFINED:\n!\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
/^((?!Vlan type:).)*$/ && ProcessHistory("COMMENTS","keysort","M2","!$_") && next;
}
return(0);
}
# This routine parses "show interfaces port" and track the port alias
sub ShowInterfaces {
print STDERR " In ShowInterfaces: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","N1","!PORT NAMES:\n!\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
if (/^(Slot\/)([A-Za-z\s]+)(Alias)$/) {ProcessHistory("COMMENTS","keysort","N2","!$1\t$3\n");next;}
elsif (/^(Port)/) {ProcessHistory("COMMENTS","keysort","N3","!$1\n");next;}
elsif (/^((\s)+\d\/(\d)+)([a-z\d\s]*)("")$/) {next;}
elsif (/^((\s)+\d\/(\d)+)([a-z\d\s]*)("(([A-Za-z\d\s\-\_\\])*)")$/) {
ProcessHistory("COMMENTS","keysort","N4","!$1 $6\n");
next;}
}
return(0);
}
# This routine parses "show configuration snapshot"
sub ShowConf {
print STDERR " In ShowConf: $_" if ($debug);
ProcessHistory("COMMENTS","keysort","O1","CONFIGURATION:\n!\n");
while () {
tr/\015//d;
last if (/^$prompt/);
next if (/^(\s*|\s*$cmd\s*)$/);
ProcessHistory("COMMENTS","keysort","O2","$_") && next;
}
return(0);
}
# Main
rancidinit();
@commandtable = (
{'show chassis' => 'ShowChassis'},
{'show system' => 'ShowSystem'},
{'show module' => 'ShowModule'},
{'show stack topology' => 'ShowStackTopolgy'},
{'show lanpower 1' => 'ShowLanPower'},
{'show lanpower 2' => 'ShowLanPower'},
{'show user' => 'ShowUser'},
{'ls' => 'GenericParse'},
{'ls certified/' => 'GenericParse'},
{'ls working/' => 'GenericParse'},
{'ls switch/' => 'GenericParse'},
{'ls network/' => 'GenericParse'},
{'show vlan' => 'ShowVLAN'},
{'show interfaces port' => 'ShowInterfaces'},
{'show configuration snapshot' => 'ShowConf'},
);
# Use an array to preserve the order of the commands and a hash for mapping
# commands to the subroutine and track commands that have been completed.
@commands = map(keys(%$_), @commandtable);
%commands = map(%$_, @commandtable);
$commandcnt = scalar(keys %commands);
$commandstr=join(";",@commands);
$cmds_regexp = join("|", map quotemeta($_), @commands);
if (length($host) == 0) {
if ($file) {
print(STDERR "Too few arguments: file name required\n");
exit(1);
} else {
print(STDERR "Too few arguments: host name required\n");
exit(1);
}
}
if ($opt_C) {
print "alulogin -t $timeo -c\'$commandstr\' $host\n";
exit(0);
}
open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n";
select(OUTPUT);
# make OUTPUT unbuffered if debugging
if ($debug) { $| = 1; }
if ($file) {
print(STDERR "opening file $host\n") if ($debug || $log);
open(INPUT,"<$host") || die "open failed for $host: $!\n";
} else {
print(STDERR "executing alulogin -t $timeo -c\"$commandstr\" $host\n") if ($debug || $log);
if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
system "/usr/local/rancid/bin/alulogin -t $timeo -c \"$commandstr\" $host $host.raw 2>&1" || die "alulogin failed for $host: $!\n";
open(INPUT, "< $host.raw") || die "alulogin failed for $host: $!\n";
} else {
open(INPUT,"/usr/local/rancid/bin/alulogin -t $timeo -c \"$commandstr\" $host ) {
tr/\015//d;
# if (/[#>]\s*(exit|logout)\s*$/i) {
# if (/$prompt\s*(exit|logout)\s*$/i) {
if (/$prompt\s*exit/i) {
$clean_run=1;
last;
}
if (/^Error:/) {
print STDOUT ("$host clogin error: $_");
print STDERR ("$host clogin error: $_") if ($debug);
$clean_run=0;
last;
}
while (/[>#]\s*($cmds_regexp)\s*$/) {
$cmd = $1;
if (!defined($prompt)) {
print STDERR "Prompt before is: $_\n" if ($debug);
# $prompt = ($_ =~ /^([^#]+)/)[0];
$prompt = ($_ =~ /^([\w\-]+)/)[0];
# $prompt =~ s/([][}{)(\\])/\\$1/g;
$prompt .= " ->";
print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
}
print STDERR ("HIT COMMAND:$_") if ($debug);
if (! defined($commands{$cmd})) {
print STDERR "$host: found unexpected command - \"$cmd\"\n";
$clean_run = 0;
last TOP;
}
my($rval) = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd);
delete($commands{$cmd});
if ($rval == -1) {
$clean_run = 0;
last TOP;
}
}
}
print STDOUT "Done $lscript: $_\n" if ($log);
# Flush History
ProcessHistory("","","","");
# Cleanup
close(INPUT);
close(OUTPUT);
if (defined($ENV{NOPIPE}) && $ENV{NOPIPE} =~ /^YES/i) {
unlink("$host.raw") if (! $debug);
}
# check for completeness
if (scalar(%commands) || !$clean_run) {
if (scalar(keys %commands) eq $commandcnt) {
printf(STDERR "$host: missed cmd(s): all commands\n");
} elsif (scalar(%commands)) {
my($count, $i) = 0;
for ($i = 0; $i < $#commands; $i++) {
if ($commands{$commands[$i]}) {
if (!$count) {
printf(STDERR "$host: missed cmd(s): %s", $commands[$i]);
} else {
printf(STDERR ", %s", $commands[$i]);
}
$count++;
}
}
if ($count) {
printf(STDERR "\n");
}
}
print STDERR "$clean_run\n" if ($debug);
if (!$clean_run) {
print(STDERR "$host: End of run not found\n");
system("/usr/bin/tail -1 $host.new");
}
unlink "$host.new" if (! $debug);
}