diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/cat5rancid | 996 | ||||
-rwxr-xr-x | bin/clogin | 118 | ||||
-rwxr-xr-x | bin/control_rancid | 29 | ||||
-rwxr-xr-x | bin/do-diffs | 19 | ||||
-rw-r--r-- | bin/env | 5 | ||||
-rwxr-xr-x | bin/flogin | 4 | ||||
-rwxr-xr-x | bin/francid | 9 | ||||
-rwxr-xr-x | bin/jlogin | 192 | ||||
-rwxr-xr-x | bin/jrancid | 104 | ||||
-rwxr-xr-x | bin/rancid | 116 | ||||
-rwxr-xr-x | bin/rancid-fe | 2 |
11 files changed, 1433 insertions, 161 deletions
diff --git a/bin/cat5rancid b/bin/cat5rancid new file mode 100755 index 0000000..0055cc8 --- /dev/null +++ b/bin/cat5rancid @@ -0,0 +1,996 @@ +#!/usr/local/bin/perl +## +## +## Copyright (C) 1997 by Henry Kilmer. +## All rights reserved. +## +## This software may be freely copied, modified and redistributed without +## fee for non-commerical purposes provided that this copyright notice is +## preserved intact on all copies and modified copies. +## +## There is no warranty or other guarantee of fitness of this software. +## It is provided solely "as is". The author(s) disclaim(s) all +## responsibility and liability with respect to this software's usage +## or its effect upon hardware, computer systems, other software, or +## anything else. +## +## +# +# RANCID - Really Awesome New Cisco confIg Differ +# +# usage: rancid [-d] [-l] [-f filename | $host] +# +use Getopt::Std; +getopts('dflm'); +$log = $opt_l; +$debug = $opt_d; +$file = $opt_f; +$host = $ARGV[0]; +$clean_run = 0; +$found_end = 0; +$timeo = 90; # clogin timeout in seconds + +# This routine is used to print out the router configuration +sub ProcessHistory { + my($new_hist_tag,$new_command,$command_string,@string)=(@_); + if((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) + && defined %history) { + print eval "$command \%history"; + undef %history; + } + if (($new_hist_tag) && ($new_command) && ($command_string)) { + if ($history{$command_string}) { + $history{$command_string} = "$history{$command_string}@string"; + } else { + $history{$command_string} = "@string"; + } + } elsif (($new_hist_tag) && ($new_command)) { + $history{++$#history} = "@string"; + } else { + print "@string"; + } + $hist_tag = $new_hist_tag; + $command = $new_command; + 1; +} + +sub numerically { $a <=> $b; } + +# This is a sort routing that will sort numerically on the +# keys of a hash as if it were a normal array. +sub keynsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort numerically keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# keys of a hash as if it were a normal array. +sub keysort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort keys(%lines)) { + $sorted_lines[$i] = $lines{$key}; + $i++; + } + @sorted_lines; +} + +# This is a sort routing that will sort on the +# values of a hash as if it were a normal array. +sub valsort{ + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $key (sort values %lines) { + $sorted_lines[$i] = $key; + $i++; + } + @sorted_lines; +} + +# This is a numerical sort routing (ascending). +sub numsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $num (sort {$a <=> $b} keys %lines) { + $sorted_lines[$i] = $lines{$num}; + $i++; + } + @sorted_lines; +} + +# This is a sort routine that will sort on the +# ip address when the ip address is anywhere in +# the strings. +sub ipsort { + local(%lines)=@_; + local($i) = 0; + local(@sorted_lines); + foreach $addr (sort sortbyipaddr keys %lines) { + $sorted_lines[$i] = $lines{$addr}; + $i++; + } + @sorted_lines; +} + +# These two routines will sort based upon IP addresses +sub ipaddrval { + my(@a) = ($_[0] =~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#); + $a[3]+256*($a[2]+256*($a[1]+256*$a[0])); +} +sub sortbyipaddr { + &ipaddrval($a) <=> &ipaddrval($b); +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if(/^$prompt/); + next if(/^(\s*|\s*$cmd\s*)$/); + if (/^Slave in slot (\d+) is running/) { + $slave = " Slave:"; + next; + } + /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && + ProcessHistory("COMMENTS","keysort","F1", + "!Image:$slave Software: $1, $2\n") && next; + /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ && + ProcessHistory("COMMENTS","keysort","F2", + "!Image:$slave $1 Synced to mainline version: $2\n") && next; + /^Compiled (.*)$/ && + ProcessHistory("COMMENTS","keysort","F3", + "!Image:$slave Compiled: $1\n") && next; + /^ROM: (System )?Bootstrap.*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G1", + "!ROM Bootstrap: $2\n") && next; + /^ROM: \d+ Bootstrap .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G2", + "!ROM Image: Bootstrap $1\n!\n") && next; + /^ROM: .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G3","!ROM Image: $1\n") && next; + /^BOOTFLASH: .*(Version.*)$/ && + ProcessHistory("COMMENTS","keysort","G4","!BOOTFLASH: $1\n") && next; + /^System image file is "([^\"]*)", booted via (\S*)/ && +# removed the booted source due to +# CSCdk28131: cycling info in 'sh ver' +# ProcessHistory("COMMENTS","keysort","F4","!Image: booted via $2, $1\n") && + ProcessHistory("COMMENTS","keysort","F4","!Image: booted $1\n") && + next; + /^System image file is "([^\"]*)"$/ && + ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && next; + if (/(\S+)\s+\((\S+)\)\s+processor.*with (\S+K) bytes/) { + my($proc) = $1; + my($cpu) = $2; + my($mem) = $3; + if ( $1 eq "CSC") { + $type = "AGS"; + } elsif ( $1 eq "CSC4") { + $type = "AGS+"; + } elsif ( $1 eq "2511" || $1 eq "2524" || $1 eq "AS2511-RJ") { + $type = "2500"; + } elsif ( $1 eq "3620" || $1 eq "3640") { + $type = "3600"; + } elsif ( $1 eq "RSP7000") { + $type = "7500"; + } elsif ( $1 =~ /RSP\d/) { + $type = "7500"; + } elsif ( $1 eq "RP1") { + $type = "7000"; + } elsif ( $1 eq "RP") { + $type = "7000"; + } elsif ( $1 =~ /720[246]/) { + $type = "7200"; + } elsif ($1 =~ /1200[48]\/GRP/ || $1 =~ /1201[26]\/GRP/) { + $type = "12000"; + } else { + $type = $1; + } + print STDERR "TYPE = $type\n" if ($debug); + ProcessHistory("COMMENTS","keysort","A1", + "!Chassis type:$slave $proc - a $type router\n"); + ProcessHistory("COMMENTS","keysort","B1", + "!Memory:$slave main $mem\n"); + ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $cpu\n"); + next; + } + if (/(\S+) Silicon\s*Switch Processor/) { + if (!defined($C0)) { + $C0=1; ProcessHistory("COMMENTS","keysort","C0","!\n"); + } + ProcessHistory("COMMENTS","keysort","C2","!SSP: $1\n"); + $ssp = 1; + $sspmem = $1; + next; + } + /^(\d+K) bytes of multibus/ && + ProcessHistory("COMMENTS","keysort","B2", + "!Memory: multibus $1\n") && next; + /^(\d+K) bytes of non-volatile/ && + ProcessHistory("COMMENTS","keysort","B3", + "!Memory: nvram $1\n") && next; + /^(\d+K) bytes of flash memory/ && + ProcessHistory("COMMENTS","keysort","B5","!Memory: flash $1\n") && + next; + /^(\d+K) bytes of .*flash partition/ && + ProcessHistory("COMMENTS","keysort","B6", + "!Memory: flash partition $1\n") && next; + /^(\d+K) bytes of Flash internal/ && + ProcessHistory("COMMENTS","keysort","B4", + "!Memory: bootflash $1\n") && next; + if(/^(\d+K) bytes of (Flash|ATA)?.*PCMCIA .*slot ?(\d)/i) { + ProcessHistory("COMMENTS","keysort","B7", + "!Memory: pcmcia $2 slot$3 $1\n"); + next; + } + if(/^WARNING/) { + if (!defined($I0)) { + $I0=1; + ProcessHistory("COMMENTS","keysort","I0","!\n"); + } + ProcessHistory("COMMENTS","keysort","I1","! $_"); + # The line after the WARNING is what to do about it. + $_ = <INPUT>; tr/\015//d; + ProcessHistory("COMMENTS","keysort","I1","! $_"); + } + if (/^Configuration register is (.*)$/) { + $config_register=$1; + next; + } + } + return(0); +} + +# This routine parses "show install active" +sub ShowInstallActive { + print STDERR " In ShowInstallActive: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + return(1) if /Unknown command/; + ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next; + } + return(0); +} + +# This routine parses "show env all" +sub ShowEnv { + # Skip if this is not a 7500, 7200, or 7000. + print STDERR " In ShowEnv: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^7/); + if (!defined($E0)) { + $E0=1; + ProcessHistory("COMMENTS","keysort","E0","!\n"); + } + if (/^Arbiter type (\d), backplane type (\S+)/) { + if (!defined($C0)) { + $C0=1; ProcessHistory("COMMENTS","keysort","C0","!\n"); + } + ProcessHistory("COMMENTS","keysort","C1", + "!Enviromental Arbiter Type: $1\n"); + ProcessHistory("COMMENTS","keysort","A2", + "!Chassis type: $2 backplane\n"); + next; + } + /^\s*(Power .*)/ && + ProcessHistory("COMMENTS","keysort","E1","!Power: $1\n") && next; + /^\s*(Lower Power .*)/i && + ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && next; + } + ProcessHistory("COMMENTS","","","!\n"); + return(0); +} + +# This routine parses "show gsr chassis-info" for the gsr +# This will create arrarys for hw info. +sub ShowGSR { + # Skip if this is not a 1200n. + print STDERR " In ShowGSR: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^120/); + /^$/ && next; + /^\s+Chassis: type (\S+) Fab Ver: (\S+)/ && + ProcessHistory("COMMENTS","keysort","D0","!\n") && + ProcessHistory("COMMENTS","keysort","D1", + "!GSR Chassis type: $1 Fab Ver: $2\n") && + next; + /^\s+Chassis S\/N: (.*)$/ && + ProcessHistory("COMMENTS","keysort","D2", + "!GSR Chassis S/N: $1\n") && + next; + /^\s+PCA: (\S+)\s*rev: (\S+)\s*dev: \S+\s*HW ver: (\S+)$/ && + ProcessHistory("COMMENTS","keysort","D3", + "!GSR Backplane PCA: $1, rev $2, ver $3\n") && + next; + /^\s+Backplane S\/N: (\S+)$/ && + ProcessHistory("COMMENTS","keysort","D4", + "!GSR Backplane S/N: $1\n") && + next; + } + ProcessHistory("COMMENTS","","","!\n"); + return(0); +} + +# This routine parses "show boot" +sub ShowBoot { + # Pick up boot variables if 7000/7200/7500/12000; + # otherwise pick up bootflash. + print STDERR " In ShowBoot: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Ambiguous command/i; + return(1) if /Invalid input detected/; + return(1) if /Unknown command/; + return(1) if /(Open device \S+ failed|Error opening \S+:)/; + next if /CONFGEN variable/; + if (!defined($H0)) { + $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); + } + if ($type !~ /^(120|7)/) { + ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); + } elsif (/variable/) { + ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + } + } + ProcessHistory("COMMENTS","","","!\n"); + return(0); +} + +# This routine parses "show flash" +sub ShowFlash { + # skip if this is 7000, 7200, 7500, or 12000. + print STDERR " In ShowFlash: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type =~ /^(120|7)/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + ProcessHistory("FLASH","","","!Flash: $_"); + } + ProcessHistory("","","","!\n"); + return; +} + +# This routine parses "dir /all ((disk|slot)N|bootflash):" +sub DirSlotN { + # Skip if this is not a 3600, 7000, 7200, 7500, or 12000. + print STDERR " In DirSlotN: $_" if ($debug); + + my($dev) = (/\s([^\s]+):/); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^(120|7|36)/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + return(1) if /\%Error: No such file or directory/; + return(1) if /No space information available/; + return(-1) if /\%Error calling/; + return(-1) if /: device being squeezed/; # Flash is busy + return(1) if /(Open device \S+ failed|Error opening \S+:)/; + ProcessHistory("FLASH","","","!Flash: $dev: $_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine parses "show controllers" +sub ShowContAll { + # Skip if this is a 70[01]0, 7500, or 12000. + print STDERR " In ShowContAll: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type =~ /^(120|7[05])/); + if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; } + /^(BRI unit \d)/ && + ProcessHistory("INT","","","!Interface: $1\n") && next; + /^LANCE unit \d, NIM/ && + ProcessHistory("INT","","","!Interface: $_") && next; + /^(LANCE unit \d)/ && + ProcessHistory("INT","","","!Interface: $1\n") && next; + /(Media Type is \S+),/ && + ProcessHistory("INT","","","!\t$1\n"); + if (/(M\dT:) show controller:$/) { + my($ctlr) = $1; + $_ = <INPUT>; tr/\015//d; s/ subunit \d,//; + ProcessHistory("INT","","","!Interface: $ctlr $_"); + } + if (/^(\S+) : show controller:$/) { + my($ctlr) = $1; + $_ = <INPUT>; tr/\015//d; s/ subunit \d,//; + ProcessHistory("INT","","","!Interface: $ctlr: $_"); + } + /^(HD unit \d), idb/ && + ProcessHistory("INT","","","!Interface: $1\n") && next; + /^HD unit \d, NIM/ && + ProcessHistory("INT","","","!Interface: $_") && next; + /^buffer size \d+ HD unit \d, (.*)/ && + ProcessHistory("INT","","","!\t$1\n") && next; + /^AM79970 / && ProcessHistory("INT","","","!Interface: $_") && next; + /^buffer size \d+ (Universal Serial: .*)/ && + ProcessHistory("INT","","","!\t$1\n") && next; + /^Hardware is (.*)/ && + ProcessHistory("INT","","","!Interface: $INT$1\n") && next; + /^(QUICC Serial unit \d),/ && + ProcessHistory("INT","","","!$1\n") && next; + /^QUICC Ethernet .*/ && + ProcessHistory("INT","","","!$_") && next; + /^DTE .*\.$/ && + ProcessHistory("INT","","","!\t$_") && next; + /^(cable type :.*),/ && + ProcessHistory("INT","","","!\t$1\n") && next; + /^(.* cable.*), received clockrate \d+$/ && + ProcessHistory("INT","","","!\t$1\n") && next; + /^.* cable.*$/ && + ProcessHistory("INT","","","!\t$_") && next; + } + return(0); +} + +# This routine parses "show controllers cbus" +# Some of this is printed out in ShowDiagbus. +sub ShowContCbus { + # Skip if this is not a 7000 or 7500. + print STDERR " In ShowContCbus: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^7[05]0/); + if (/^\s*slot(\d+): ([^,]+), hw (\S+), sw (\S+), ccb/) { + $slot = $1; + $board{$slot} = $2; + $hwver{$slot} = $3; + $hwucode{$slot} = $4; + } elsif (/^\s*(\S+) (\d+), hardware version (\S+), microcode version (\S+)/) { + $slot = $2; + $board{$slot} = $1; + $hwver{$slot} = $3; + $hwucode{$slot} = $4; + } elsif (/(Microcode .*)/) { + $ucode{$slot} = $1; + } elsif (/(software loaded .*)/) { + $ucode{$slot} = $1; + } elsif (/(\d+) Kbytes of main memory, (\d+) Kbytes cache memory/) { + $hwmemd{$slot} = $1; + $hwmemc{$slot} = $2; + } elsif (/byte buffers/) { + chop; + s/^\s*//; + $hwbuf{$slot} = $_; + } elsif (/Interface (\d+) - (\S+ \S+),/) { + $interface = $1; + ProcessHistory("HW","","", + "!\n!Int $interface: in slot $slot, named $2\n"); next; + } elsif (/(\d+) buffer RX queue threshold, (\d+) buffer TX queue limit, buffer size (\d+)/) { + ProcessHistory("HW","","","!Int $interface: rxq $1, txq $2, bufsize $3\n"); + next; + } + } + return(0); +} + +# This routine parses "show diagbus" +# This will create arrarys for hw info. +sub ShowDiagbus { + # Skip if this is not a 7000, 70[01]0, or 7500. + print STDERR " In ShowDiagbus: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^7[05]/); + if (/^\s*Slot (\d+):/i) { + $slot = $1; + next; + } elsif (/^\s*Slot (\d+) \(virtual\):/i) { + $slot = $1; + next; + } elsif (/^\s*(.*Processor.*|.*controller|.*Chassis Interface), HW rev (\S+), board revision (\S+)/i) { + $board = $1; + $hwver = $2; + $boardrev = $3; + if ($board =~ /Processor/) { + if ($board =~ /7000 Route\/Switch/) { + $board = "RSP7000"; + } elsif ($board =~ /Route\/Switch Processor (\d)/) { + $board = "RSP$1"; + } elsif ($board =~ /Route/) { + $board = "RP"; + } elsif ($board =~ /Silicon Switch/) { + $board = "SSP"; + } elsif ($board =~ /Switch/) { + $board = "SP"; + $board = "SSP $sspmem" if $ssp; + } elsif ($board =~ /ATM/) { + $board = "AIP"; + } + } elsif ($board =~ /(.*) controller/i) { + $board = $1; + } + # hwucode{$slot} defined in ShowContCbus + if (defined $hwucode{$slot}) { + ProcessHistory("SLOT","","","!\n!Slot $slot/$board: hvers $hwver rev $boardrev ucode $hwucode{$slot}\n"); + } else { + ProcessHistory("SLOT","","","!\n!Slot $slot/$board: hvers $hwver rev $boardrev\n"); + } + # These are also from the ShowContCbus + ProcessHistory("SLOT","","","!Slot $slot/$board: $ucode{$slot}\n") if (defined $ucode{$slot}); + ProcessHistory("SLOT","","","!Slot $slot/$board: memd $hwmemd{$slot}, cache $hwmemc{$slot}\n") + if ((defined $hwmemd{$slot}) && (defined $hwmemc{$slot})); + ProcessHistory("SLOT","","","!Slot $slot/$board: $hwbuf{$slot}\n") if (defined $hwbuf{$slot}); + next; + } + /Serial number: (\S+)\s*Part number: (\S+)/ && + ProcessHistory("SLOT","","", + "!Slot $slot/$board: part $2, serial $1\n") && + next; + /^\s*Controller Memory Size: (.*)$/ && + ProcessHistory("SLOT","","","!Slot $slot/$board: $1\n") && + next; + if (/PA Bay (\d) Information/) { + $pano = $1; + if ("PA" =~ /$board/) { + ($s,$c) = split(/\//,$board); + $board = "$s/$c/PA $pano"; + } else { + $board =~ s/\/PA \d//; + $board = "$board/PA $pano"; + } + next; + } + /\s+(.*) PA, (\d) ports?, (\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot/$board: type $3, $2 ports\n") && + next; + /\s+(.*) PA( \(\S+\))?, (\d) ports?/ && + ProcessHistory("SLOT","","","!Slot $slot/$board: type $1$2, $3 ports\n") && + next; + /^\s*HW rev (\S+), Board revision (\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot/$board: hvers $1 rev $2\n") && + next; + /Serial number: (\S+)\s*Part number: (\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot/$board: part $2, serial $1\n") && next; + } + return(0); +} + +# This routine parses "show diag" for the gsr, 7200, 3600, 2600. +# This will create arrarys for hw info. +sub ShowDiag { + # Skip if this is not a 12000. + print STDERR " In ShowDiag: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^(120|720|36|26)/); + /^$/ && next; + if (!defined($showdiags)) {$showdiags=1; ProcessHistory("SLOT","","","!\n");} + s/Port Packet Over SONET/POS/; + if (/^\s*SLOT (\d+)\s+\(.*\): (.*)/) { + $slot = $1; + ProcessHistory("SLOT","","","!Slot $slot: $2\n"); + $board = "RP" if (/Route Processor/); + $board = "CLK" if (/Clock Scheduler Card/); + next; + } + if (/^\s+PCA:\s+(.*)/){ + local($part) = $1; + $_ = <INPUT>; + /^\s+HW version (\S+)\s+S\/N (\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot/PCA: part $part, serial $2\n") && + ProcessHistory("SLOT","","","!Slot $slot/PCA: hvers $1\n"); + next; + } + + if (/^\s+MBUS: .*\)\s+(.*)/) { + local($tmp) = "!Slot $slot/MBUS: part $1"; + $_ = <INPUT>; + /^\s+HW version (\S+)\s+S\/N (\S+)/ && + ProcessHistory("SLOT","","","$tmp, serial $2\n") && + ProcessHistory("SLOT","","","!Slot $slot/MBUS: hvers $1\n"); + next; + } + if (/^\s+MBUS Agent Software version (.*)/) { + local($sw) = $1; + local($tail) = "!\n" if ($board =~ /(CLK|RP)/); + ProcessHistory("SLOT","","","!Slot $slot/MBUS: software $sw\n$tail"); + next; + } + if (/^\s+DRAM size: (\d+)/) { + local($dram) = $1 / 1048576; + $_ = <INPUT>; + /^\s+FrFab SDRAM size: (\d+)/ && + ProcessHistory("SLOT","","","!Slot $slot/MBUS: $dram Mbytes DRAM, " + . $1 / 1024 . " Kbytes SDRAM\n!\n"); + next; + } + # 7200 and 3600 stuff + if (/^(Slot)\s+(\d+):/ || /^\s+(WIC|VIC) Slot (\d):/) { + if ($1 eq "WIC") { + $WIC = "/$2"; + } elsif ($1 eq "VIC") { + $WIC = "/$2"; + } else { + $slot = $2; + undef($WIC); + } + $_ = <INPUT>; tr/\015//d; + + # clean up hideous 7200 format to look more like 7500 output + s/Fast-ethernet on C7200 I\/O card/FE-IO/; + s/ with MII or RJ45/-TX/; + s/Fast-ethernet /100Base/; s/[)(]//g; + + /\s+(.*) port adapter,?\s+(\d+)\s+/i && + ProcessHistory("SLOT","","","!Slot $slot: type $1, $2 ports\n"); + # I/O controller with no interfaces + /\s+(.*)\s+port adapter\s*$/i && + ProcessHistory("SLOT","","","!Slot $slot: type $1, 0 ports\n"); + /\s+(.*)\s+daughter card(.*)$/ && + ProcessHistory("SLOT","","","!Slot $slot$WIC: type $1$2\n"); + /\s+(FT1)$/ && + ProcessHistory("SLOT","","","!Slot $slot$WIC: type $1\n"); + next; + } + /revision\s+(\S+).*revision\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot$WIC: hvers $1 rev $2\n") && + next; + /number\s+(\S+)\s+Part number\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot $slot$WIC: part $2, serial $1\n!\n") && + next; +} + return(0); +} + +# This routine parses "show c7200" for the 7200 +# This will create arrarys for hw info. +sub ShowC7200 { + # Skip if this is not a 7200. + print STDERR " In ShowC7200: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^72/); + /^$/ && next; + if (/C7200 Midplane EEPROM:/) { + $_ = <INPUT>; + /revision\s+(\S+).*revision\s+(\S+)/; + ProcessHistory("SLOT","","","!Slot Midplane: hvers $1 rev $2\n"); + $_ = <INPUT>; + /number\s+(\S+)\s+Part number\s+(\S+)/; + ProcessHistory("SLOT","","","!Slot Midplane: part $2, serial $1\n!\n"); + next; + } + if (/C720\d(VXR)? CPU EEPROM:/) { + $_ = <INPUT>; + /revision\s+(\S+).*revision\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot CPU: hvers $1 rev $2\n"); + $_ = <INPUT>; + /number\s+(\S+)\s+Part number\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot CPU: part $2, serial $1\n!\n"); + next; + } + } + return(0); +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if(/^$prompt/); + /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + # skip the crap + if (/^(\.\.+$|##+$|Building configuration...)/i) { + while (<INPUT>) { + tr/\015//d; + next if (/^Current configuration:/i); + next if (/^(\.+|[%!].*|\s*)$/); + next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S + last; + } + ProcessHistory("","","","!\n"); + tr/\015//d; + } + # some versions have other crap mixed in with the bits in the + # block above + /^! (Last configuration|NVRAM config last)/ && next; + + # Dog gone Cool matches to process the rest of the config + /^#time: / && next; # kill time: + /^tftp-server flash / && next; # kill any tftp remains + /^ntp clock-period / && next; # kill ntp clock-period + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + /^enable password / && + ProcessHistory("ENABLE","","","!enable password <removed>\n") && + next; + /^(username .*) password /&& + ProcessHistory("USER","","","!$1 password <removed>\n") && next; + /^\s*password / && + ProcessHistory("LINE-PASS","","","! password <removed>\n") && next; + /^\s*neighbor (\S*) password / && + ProcessHistory("","","","! neighbor $1 password <removed>\n") && + next; + /^(ip ftp password) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + /^( ip ospf authentication-key) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + /^( ip ospf message-digest-key \d+ md5) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + /fair-queue individual-limit/ && next; + # sort ip explicit-paths. + if (/^ip explicit-path name (\S+)/) { + my($key) = $1; + my($expath) = $_; + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); + if (/^ip explicit-path name (\S+)/) { + ProcessHistory("EXPATH","keysort","$key","$expath"); + $key = $1; + $expath = $_; + } else { + $expath .= $_; + } + } + ProcessHistory("EXPATH","keysort","$key","$expath"); + } + # sort route-maps + if (/^route-map (\S+)/) { + my($key) = $1; + my($routemap) = $_; + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map (\S+)/) { + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + $key = $1; + $routemap = $_; + } else { + $routemap .= $_; + } + } + ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); + } + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + # order access-lists + /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && + ProcessHistory("ACL $1 $2","ipsort","$3","$_") && next; + # order extended access-lists + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && + ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && + ProcessHistory("EACL $1 $2","ipsort","$3","$_") && next; + /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && + ProcessHistory("EACL $1 $2","ipsort","0.0.0.0","$_") && next; + # order arp lists + /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && + ProcessHistory("ARP","ipsort","$1","$_") && next; + /^ip prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\d\S+)(\/.*)$/ && + ProcessHistory("PACL $1 $3","ipsort","$4","ip prefix-list $1 $3 $4$5\n") + && next; + # order logging statements + /^logging (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("LOGGING","ipsort","$1","$_") && next; + # order name-server statements + /^ip name-server (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("NAMESERVER","ipsort","$1","$_") && next; + # order snmp-server host statements + /^snmp-server host (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_") && next; + /^snmp-server community / && + ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; + # order tacacs server statements + /^(tacacs-server key )/ && + ProcessHistory("","","","!$1<removed>\n") && next; + /^tacacs-server host (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("TAC","ipsort","$1","$_") && next; + # order clns host statements + /^clns host \S+ (\S+)/ && + ProcessHistory("CLNS","keysort","$1","$_") && next; + # order alias statements + /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && next; + # delete ntp auth password + /^(ntp authentication-key \d+ md5) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + # order ntp peers/servers + if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { + $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); + ProcessHistory("NTP","keysort",$sortkey,"$_"); + next; + } + # order ip host line statements + /^ip host line(\d+)/ && + ProcessHistory("IPHOST","numsort","$1","$_") && next; + # order ip nat source static statements + /^ip nat (\S+) source static (\S+)/ && + ProcessHistory("IP NAT $1","ipsort","$2","$_") && next; + # order atm map-list statements + /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && + ProcessHistory("ATM map-list","ipsort","$1","$_") && next; + # order ip rcmd lines + /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && next; + + ProcessHistory("","","","$_"); + # end of config + if (/^end$/) { + $found_end = 1; + return(1); + } + } + return(0); +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main +%commands=( + 'show version' => "ShowVersion", + 'show install active' => "ShowInstallActive", + 'show env all' => "ShowEnv", + 'show gsr chassis' => "ShowGSR", + 'show boot' => "ShowBoot", + 'show bootvar' => "ShowBoot", + 'show flash' => "ShowFlash", + 'dir /all bootflash:' => "DirSlotN", + 'dir /all slot0:' => "DirSlotN", + 'dir /all disk0:' => "DirSlotN", + 'dir /all slot1:' => "DirSlotN", + 'dir /all disk1:' => "DirSlotN", + 'show controllers' => "ShowContAll", + 'show controllers cbus' => "ShowContCbus", + 'show diagbus' => "ShowDiagbus", + 'show diag' => "ShowDiag", + 'show c7200' => "ShowC7200", + 'write term' => "WriteTerm" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important (show version first and write term last). pita +@commands=( + "show version", + "show install active", + "show env all", + "show gsr chassis", + "show boot", + "show bootvar", + "show flash", + "dir /all bootflash:", + "dir /all slot0:", + "dir /all disk0:", + "dir /all slot1:", + "dir /all disk1:", + "show controllers", + "show controllers cbus", + "show diagbus", + "show diag", + "show c7200", + "write term" +); +$cisco_cmds=join(";",@commands); +$cmds_regexp=join("|",@commands); + +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); + print STDOUT "opening file $host\n" if ($log); + open(INPUT,"<$host") || die "open failed for $host: $!\n"; +} else { + print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n"; + } +} + +ProcessHistory("COMMENTS","keysort","B0","!\n"); +ProcessHistory("COMMENTS","keysort","F0","!\n"); +ProcessHistory("COMMENTS","keysort","G0","!\n"); +TOP: while(<INPUT>) { + tr/\015//d; + if (/> \(enable\) exit$/) { + $clean_run=1; + last; + } + if (/Error:/) { + s/^.*Error:/Error:/; + print STDOUT ("$host clogin error: $_"); + print STDERR ("$host clogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/> \(enable\)\s*($cmds_regexp)\s*$/) { + $cmd = $1; +# if (!defined($prompt)) {$prompt = ($_ =~ /^([^>]+> .enable.)/)[0]; } + if (!defined($prompt)) {$prompt = ($_ =~ /^([^>]+>)/)[0]; } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last TOP; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last TOP; + } + } +} +print STDOUT "Done $logincmd: $_\n" if ($log); +# Flush History +ProcessHistory("","","",""); +# Cleanup +close(INPUT); +close(OUTPUT); + +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + +# check for completeness +if (scalar(%commands) || !$clean_run || !$found_end) { + if (scalar(%commands)) { + printf(STDOUT "missed cmd(s): %s\n", join(',', keys(%commands))); + printf(STDERR "missed cmd(s): %s\n", join(',', keys(%commands))) if ($debug); + } + if (!$clean_run || !$found_end) { + print STDOUT "End of run not found\n"; + print STDERR "End of run not found\n" if ($debug); + system("/usr/bin/tail -1 $host.new"); + } + unlink "$host.new" if (! $debug); +} @@ -27,10 +27,11 @@ # # Usage line -set usage "Usage: $argv0 \[-u user\] \[-p user-password\] \[-v vty-password\] \ -\[-w enable-username\] \[-e enable-password\] \[-noenable\] \ -\[-f cloginrc-file\] \[-y ssh_cypher_type\] \[-c command\] \[-s script-file\] \ -\[-x command-file\] \[-autoenable\] \[-t timeout\] router \[router...\]\n" +set usage "Usage: $argv0 \[-autoenable\] \[-noenable\] \[-c command\] \ +\[-e enable-password\] \[-f cloginrc-file\] \[-p user-password\] \ +\[-s script-file\] \[-t timeout\] \[-u username\] \ +\[-v vty-password\] \[-w enable-username\] \[-x command-file\] \ +\[-y ssh_cypher_type\] router \[router...\]\n" # env(CLOGIN) may contain: # x == do not set xterm banner or name @@ -125,7 +126,7 @@ for {set i 0} {$i < $argc} {incr i} { exit 1 } set do_script 1 - # cypher type + # 'ssh -c' cypher type } -y* - -Y* { if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { @@ -139,10 +140,14 @@ for {set i 0} {$i < $argc} {incr i} { incr i set password_file [ lindex $argv $i ] } + # Timeout } -t* - -T* { - incr i - set timeout [ lindex $argv $i ] + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { + incr i + set timeout [ lindex $argv $i ] + } + # Command file } -x* - -X { if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { @@ -228,23 +233,28 @@ proc find {var router} { # that a "bad guy" could just as easy put such code in the clogin # script, so I will leave .cloginrc as just an extention of that script proc source_password_file { } { - global env password_file read_password_file - if { [info exists read_password_file] } { return } - if { [info exists password_file] == 0 } { + global env password_file read_password_file + if { [info exists read_password_file] } { return } + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc - } - set read_password_file 1 - file stat $password_file fileinfo - if { [expr ($fileinfo(mode) & 007)] != 0000 } { - send_user "Error: $password_file must not be world readable/writable\n" - exit 1 - } - source $password_file + } + if { ! [file exists $password_file] } { + send_user "Error: password file ($password_file) does not exist\n" + exit 1 + } + set read_password_file 1 + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "Error: $password_file must not be world readable/writable\n" + exit 1 + } + source $password_file } # Log into the router. proc login { router user userpswd passwd enapasswd prompt cyphertype } { global spawn_id in_proc do_command do_script + global u_prompt p_prompt e_prompt set in_proc 1 set tryssh 1 @@ -259,7 +269,7 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { expect_after { timeout { send_user "\nError: TIMEOUT reached\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { @@ -267,7 +277,7 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { } } eof { send_user "\nError: EOF received\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { @@ -317,18 +327,18 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { send "no\r" send_user "Error: The host key for $router has changed. update the known_hosts file accordingly.\n" return 1 } - -re "(Username|login):" { send "$user\r" + -re "$u_prompt" { send "$user\r" expect { eof { send_user "Error: Couldn't login\n"; wait; return 1 } - -re "\[Pp]assword:" { send "$userpswd\r" } + -re "$p_prompt" { send "$userpswd\r" } "$prompt" { set in_proc 0; return 0 } } exp_continue } - "\[Pp]assword:" { send "$passwd\r" + -re "$p_prompt" { send "$passwd\r" expect { eof { send_user "Error: Couldn't login\n"; wait; return 1 } - "Password:" { send "$enapasswd\r" } + -re "$e_prompt" { send "$enapasswd\r" } "$prompt" { set in_proc 0; return 0 } } exp_continue @@ -336,7 +346,7 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { "$prompt" { } denied { send_user "Error: Check your passwd for $router\n" if { $do_command || $do_script } { - send "quit" + send "exit\r" wait return 1 } else { @@ -352,20 +362,22 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { # Enable proc do_enable { enauser enapasswd } { global prompt in_proc + global u_prompt e_prompt set in_proc 1 send "enable\r" expect { - "Username:" { send "$enauser\r"; exp_continue} - "Password:" { send "$enapasswd\r"; exp_continue} - "#" { } + -re "$u_prompt" { send "$enauser\r"; exp_continue} + -re "$e_prompt" { send "$enapasswd\r"; exp_continue} + "#" { set prompt "#" } + "(enable)" { set prompt "> (enable) " } denied { send_user "Error: Check your Enable passwd\n"; return 1} "% Bad passwords" { send_user "Error: Check your Enable passwd\n" return 1 } } - # Set the prompt variable so script files don't need to know what it is. - set prompt "#" + # We set the prompt variable (above) so script files don't need + # to know what it is. set in_proc 0 return 0 } @@ -375,27 +387,36 @@ proc run_commands { prompt command } { global in_proc set in_proc 1 - send "term length 0\r" + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "term length 0". + if [ string compare "> (enable) " "$prompt" ] { + send "term length 0\r" + } else { + send "set length 0\r" + } + expect $prompt {} + regsub -all "\[)(]" $prompt {\\&} reprompt + # Is this a multi-command? if [ string match "*\;*" "$command" ] { set commands [split $command \;] set num_commands [llength $commands] for {set i 0} {$i < $num_commands} { incr i} { - send "[subst [lindex $commands $i]]\r" + send "[subst -nocommands [lindex $commands $i]]\r" expect { - -re "^\[^\n\r]*$prompt." { exp_continue } - -re "^\[^\n\r *]*$prompt" {} + -re "^\[^\n\r]*$reprompt." { exp_continue } + -re "^\[^\n\r *]*$reprompt" {} -re "\[\n\r]" { exp_continue } } } } else { - send "[subst $command]\r" + send "[subst -nocommands $command]\r" expect { - -re "^\[^\n\r]*$prompt." { exp_continue } - -re "^\[^\n\r *]*$prompt" {} + -re "^\[^\n\r]*$reprompt." { exp_continue } + -re "^\[^\n\r *]*$reprompt" {} -re "\[\n\r]" { exp_continue } } } @@ -434,6 +455,11 @@ foreach router [lrange $argv $i end] { } } + # look for noenable option in .cloginrc + if { [find noenable $router] != "" } { + set enable 0 + } + # Figure out passwords if { $do_passwd || $do_enapasswd } { set pswd [find password $router] @@ -476,7 +502,15 @@ foreach router [lrange $argv $i end] { if { "$enauser" == "" } { set enauser $ruser } } - # Figure out cypher tpye + # Figure out prompts + set u_prompt [find userprompt $router] + if { "$u_prompt" == "" } { set u_prompt "(Username|login):" } + set p_prompt [find passprompt $router] + if { "$p_prompt" == "" } { set p_prompt "\[Pp]assword:" } + set e_prompt [find enableprompt $router] + if { "$e_prompt" == "" } { set e_prompt "\[Pp]assword:" } + + # Figure out cypher type if {[info exists cypher]} { # command line cypher type set cyphertype $cypher @@ -503,7 +537,13 @@ foreach router [lrange $argv $i end] { continue } } elseif { $do_script } { - send "term length 0\r" + # If the prompt is (enable), then we are on a switch and the + # command is "set length 0"; otherwise its "term length 0". + if [ string compare "> (enable) " "$prompt" ] { + send "term length 0\r" + } else { + send "set length 0\r" + } expect $prompt {} source $sfile close diff --git a/bin/control_rancid b/bin/control_rancid index 0728e7e..2c367d6 100755 --- a/bin/control_rancid +++ b/bin/control_rancid @@ -112,7 +112,7 @@ then router=$1 touch $router - cvs add $router + cvs add -ko $router cvs commit -m 'new router' $router echo "Added $router" done @@ -172,9 +172,10 @@ do IFS=$OFS router=$1; mfg=$2 - if [ ! -f $router.new ] + if [ ! -s $router.new ] then echo "$router:$mfg" >> $DIR/routers.up.missed + rm -f $router.new fi done @@ -191,6 +192,15 @@ do done echo +# Make sure that all of the new configs are not empty. +for config in *.new +do + if [ ! -s $config ] + then + rm -f $config + fi +done + # Now that we have the new configs, rename them to their proper # name. rename 's/.new$//' *.new @@ -224,18 +234,21 @@ Precedence: bulk EMAIL fi -# If any machines have not been reached within 24 hours, mail -# out a list of them. +# If any machines have not been reached within the last $OLDTIME +# hours, mail out a list of them. cd $DIR/configs rm -f $DIR/routers.failed -perl -F: -ane '{$t = (stat($F[0]))[9]; print `ls -ld $F[0]` - if (time() - $t >= 86400);}' $DIR/routers.up | sort -u > $DIR/routers.failed +if [ "X$OLDTIME" = "X" ] ; then + OLDTIME=24 +fi +perl -F: -ane "{\$t = (stat(\$F[0]))[9]; print \`ls -ld \$F[0]\` + if (time() - \$t >= $OLDTIME*60*60);}" $DIR/routers.up | sort -u > $DIR/routers.failed if [ -s $DIR/routers.failed ] then ( cat <<END -The following routers have not been successfully contacted within the -last 24 hours. +The following routers have not been successfully contacted for more +than $OLDTIME hours. END cat $DIR/routers.failed diff --git a/bin/do-diffs b/bin/do-diffs index 88cc445..fa4acd2 100755 --- a/bin/do-diffs +++ b/bin/do-diffs @@ -21,7 +21,7 @@ fi for GROUP in $LIST_OF_GROUPS do - LOCKFILE=/tmp/.$GROUP.run.lock + LOCKFILE=$TMPDIR/.$GROUP.run.lock ( echo starting: `date` @@ -31,6 +31,23 @@ do then echo hourly config diffs failed: $LOCKFILE exists /bin/ls -l $LOCKFILE + + # Send email if the lock file is old. + if [ "X$LOCKTIME" = "X" ] ; then + LOCKTIME=4 + fi + perl -e "\$t = (stat(\"$LOCKFILE\"))[9]; print \"OLD\\n\" if (time() - \$t >= $LOCKTIME*60*60);" > $TMPDIR/.$GROUP.old + if [ -s $TMPDIR/.$GROUP.old ] + then + ( + cat <<END +rancid $GROUP hung on `hostname`? Old lockfile still exists: +`/bin/ls -l $LOCKFILE` +END + ) | Mail -s "rancid hung - $GROUP" rancid-admin-$GROUP + fi + rm -f $TMPDIR/.$GROUP.old + else /usr/bin/touch $LOCKFILE control_rancid $GROUP @@ -12,6 +12,7 @@ TERM=network;export TERM # use a full path (no sym-links) for BASEDIR. some versions of CVS seemingly # don't take kindly to sym-links. # +TMPDIR=/tmp; export TMPDIR BASEDIR=$HOME/rancid; export BASEDIR PATH=$BASEDIR/bin:/usr/local/bin:/usr/ucb:/usr/bin:/bin:/usr/lib:/usr/sbin;export PATH CVSROOT=$BASEDIR/CVS; export CVSROOT @@ -20,6 +21,10 @@ CVSROOT=$BASEDIR/CVS; export CVSROOT # collection from the router(s). #NOPIPE=YES; export NOPIPE # +# How many hours to go by before complaining about routers that +# can not be reached. +OLDTIME=4; export OLDTIME +# LIST_OF_GROUPS="sl joebobisp" # # For each group, define a list of people to receive the diffs. @@ -262,7 +262,7 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { expect_after { timeout { send_user "\nError: TIMEOUT reached\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { @@ -270,7 +270,7 @@ proc login { router user userpswd passwd enapasswd prompt cyphertype } { } } eof { send_user "\nError: EOF received\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { diff --git a/bin/francid b/bin/francid index 3050aee..54aae8d 100755 --- a/bin/francid +++ b/bin/francid @@ -30,7 +30,7 @@ $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin timeout in seconds +$timeo = 90; # flogin timeout in seconds # This routine is used to print out the router configuration sub ProcessHistory { @@ -172,6 +172,7 @@ sub ShowChassis { tr/\015//d; last if (/^$prompt/); next if (/ from /); + next if (/current temperature/i); ProcessHistory("CHASSIS","","","! $_"); } ProcessHistory("CHASSIS","","","!\n"); @@ -327,7 +328,7 @@ if ($file) { } } -while(<INPUT>) { +TOP: while(<INPUT>) { tr/\015//d; if (/\#exit$/) { $clean_run=1; @@ -347,13 +348,13 @@ while(<INPUT>) { if (! defined($commands{$cmd})) { print STDERR "found unexpected command - \"$cmd\"\n"; $clean_run = 0; - last; + last TOP; } $rval = &{$commands{$cmd}}; delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; - last; + last TOP; } } } @@ -7,7 +7,7 @@ ## This software may be freely copied, modified and redistributed without ## fee for non-commerical purposes provided that this copyright notice is ## preserved intact on all copies and modified copies. -## +## ## There is no warranty or other guarantee of fitness of this software. ## It is provided solely "as is". The author(s) disclaim(s) all ## responsibility and liability with respect to this software's usage @@ -23,8 +23,9 @@ # # Usage line -set usage "Usage: $argv0 \[-e encryption_type\] \[-u username\] \[-p user-password\]\ -\[-f cloginrc-file\] \[-c command\] \[-s script-file\]\ +set usage "Usage: $argv0 \[-c command\] \[-f cloginrc-file\] \ +\[-p user-password\] \[-r passphrase\] \[-s script-file\] \ +\[-u username\] \[-t timeout\] \[-x command-file\] \[-y ssh_cypher_type\] \ router \[router...\]\n" # env(CLOGIN) may contain the following chars: @@ -40,31 +41,41 @@ set enable 1 # The default is to look in the password file to find the passwords. This # tracks if we receive them on the command line. set do_passwd 1 +# No passphrase by default +set passphrase "" # Find the user in the ENV, or use the unix userid. if {[ info exists env(CISCO_USER) ] } { set default_user $env(CISCO_USER) } else { - # This uses "id" which I think is portable. At least it has existed - # (without options) on all machines/OSes I've been on recently - + # This uses "id" which I think is portable. At least it has existed + # (without options) on all machines/OSes I've been on recently - # unlike whoami or id -nu. regexp {\(([^)]*)} [exec id] junk default_user } # Sometimes routers take awhile to answer (the default is 10 sec) -set timeout 45 +set timeout 120 # Process the command line for {set i 0} {$i < $argc} {incr i} { set arg [lindex $argv $i] switch -glob -- $arg { - # Username - -u* - - -U* { - if {! [ regexp .\[uU\](.+) $arg ignore user]} { + # Command to run. + -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { incr i - set username [ lindex $argv $i ] + set command [ lindex $argv $i ] + } + set do_command 1 + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] } # user Password } -p* - @@ -74,14 +85,13 @@ for {set i 0} {$i < $argc} {incr i} { set userpswd [ lindex $argv $i ] } set do_passwd 0 - # Command to run. - } -c* - - -C* { - if {! [ regexp .\[cC\](.+) $arg ignore command]} { + # passphrase + } -r* - + -R* { + if {! [ regexp .\[rR\](.+) $arg ignore passphrase]} { incr i - set command [ lindex $argv $i ] + set passphrase [ lindex $argv $i ] } - set do_command 1 # Expect script to run. } -s* - -S* { @@ -94,19 +104,38 @@ for {set i 0} {$i < $argc} {incr i} { exit 1 } set do_script 1 - # encryption type - } -e* - - -E* { - if {! [ regexp .\[eE\](.+) $arg ignore encrypt]} { + # Timeout + } -t* - + -T* { + if {! [ regexp .\[tT\](.+) $arg ignore timeout]} { incr i - set encrypt [ lindex $argv $i ] + set timeout [ lindex $argv $i ] } - # alternate cloginrc file - } -f* - - -F* { - if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + # Username + } -u* - + -U* { + if {! [ regexp .\[uU\](.+) $arg ignore user]} { incr i - set password_file [ lindex $argv $i ] + set username [ lindex $argv $i ] + } + # command file + } -x* - + -X* { + if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} { + incr i + set cmd_file [ lindex $argv $i ] + } + set cmd_fd [open $cmd_file r] + set cmd_text [read $cmd_fd] + close $cmd_fd + set command [join [split $cmd_text \n] \;] + set do_command 1 + # 'ssh -c' cypher type + } -y* - + -Y* { + if {! [ regexp .\[yY\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] } } -* { send_user "Error: Unknown argument! $arg\n" @@ -158,9 +187,9 @@ proc label { host } { proc add {var args} { global $var ;lappend $var $args } proc find {var router} { - source_password_file - upvar $var list - if { [info exists list] } { + source_password_file + upvar $var list + if { [info exists list] } { foreach line $list { if { [string match [lindex $line 0] $router ] } { return [lrange $line 1 end] @@ -174,31 +203,45 @@ proc find {var router} { # it is sourced, the user better know what to put in there, as it # could install more than just password info... I will assume however, # that a "bad guy" could just as easy put such code in the clogin -# script, so I will leave .cloginrc as just an extention of that script +# script, so I will leave .cloginrc as just an extention of that script proc source_password_file { } { - global env password_file read_password_file - if { [info exists read_password_file] } { return } - if { [info exists password_file] == 0 } { + global env password_file read_password_file + if { [info exists read_password_file] } { return } + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc - } - set read_password_file 1 - file stat $password_file fileinfo - if { [expr ($fileinfo(mode) & 007)] != 0000 } { - send_user "Error: $password_file must not be world readable/writable\n" - exit 1 - } - source $password_file + } + if { ! [file exists $password_file] } { + send_user "Error: password file ($password_file) does not exist\n" + exit 1 + } + + set read_password_file 1 + file stat $password_file fileinfo + if { [expr ($fileinfo(mode) & 007)] != 0000 } { + send_user "Error: $password_file must not be world readable/writable\n" + exit 1 + } + source $password_file } # Log into the router. -proc login { router user passwd prompt encrypttype} { - global spawn_id in_proc do_command do_script +proc login { router user passwd prompt cyphertype identfile} { + global spawn_id in_proc do_command do_script passphrase set in_proc 1 - # ssh to the router & try to login. - if [ catch {spawn ssh -c $encrypttype -x -l $user $router} reason ] { - send_user "Error: failed to ssh: $reason\n" - exit 1 + # ssh to the router & try to login with or without an identfile. + # We use two calls to spawn since spawn does not seem to parse + # spaces correctly. + if {$identfile != ""} { + if [ catch {spawn ssh -c $cyphertype -x -l $user -i $identfile $router} reason ] { + send_user "Error: failed to ssh: $reason\n" + exit 1 + } + } else { + if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { + send_user "Error: failed to ssh: $reason\n" + exit 1 + } } sleep 0.3 @@ -206,7 +249,7 @@ proc login { router user passwd prompt encrypttype} { expect_after { timeout { send_user "\nError: TIMEOUT reached\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { @@ -214,7 +257,7 @@ proc login { router user passwd prompt encrypttype} { } } eof { send_user "\nError: EOF received\n" - close; wait + catch {close}; wait if { $in_proc} { return 1 } else { @@ -231,10 +274,10 @@ proc login { router user passwd prompt encrypttype} { # then it will just send the passwd. expect { eof { send_user "Error: Couldn't login\n"; wait; return 1 } - "Connection refused" { + "Connection refused" { expect eof send_user "Error: Connection Refused\n"; wait; return 1 - } "Unknown host\r\n" { + } "Unknown host\r\n" { expect eof send_user "Error: Unknown host\n"; wait; return 1 } "Host is unreachable" { @@ -244,6 +287,10 @@ proc login { router user passwd prompt encrypttype} { expect eof send_user "Error: Unknown host\n"; wait; return 1 } + -re "Enter passphrase for RSA key '\[^'\]*': " { + send_user "\nKey has passphrase!\n" + send "$passphrase\r" + exp_continue } -re "Host key not found .* \(yes\/no\)\?" { send "yes\r" send_user "Host $router added to the list of known hosts.\n" @@ -253,7 +300,7 @@ proc login { router user passwd prompt encrypttype} { send_user "Error: The host key for $router has changed. update the known_hosts file accordingly.\n" return 1 } -re "(Username|^login):" { send "$user\r" - expect { + expect { eof { send_user "Error: Couldn't login\n"; wait; return 1 } -re "\[Pp]assword:" { send "$passwd\r" } "$prompt" { set in_proc 0; return 0 } @@ -261,15 +308,15 @@ proc login { router user passwd prompt encrypttype} { exp_continue } "\[Pp]assword:" { send "$passwd\r" - expect { + expect { eof { send_user "Error: Couldn't login\n"; wait; return 1 } "$prompt" { set in_proc 0; return 0 } } exp_continue } "$prompt" { } - denied { send_user "Error: Check your passwd for $router\n" - if { $do_command || $do_script } { + denied { send_user "Error: Check your passwd for $router\n" + if { $do_command || $do_script } { send "quit" wait return 1 @@ -339,7 +386,7 @@ foreach router [lrange $argv $i end] { # if { [llength $pswd] == 0 } { # send_user "Error - no password for $router in $password_file.\n" # continue -# } +# } # if { $do_enapasswd && !$autoenable && [llength $pswd] < 2 } { # send_user "Error - no enable password for $router in $password_file." # continue @@ -348,13 +395,13 @@ foreach router [lrange $argv $i end] { # } # Figure out username - if {[info exists username]} { + if {[info exists username]} { # command line username set loginname $username } else { - set loginname [find user $router] + set loginname [find user $router] if { "$loginname" == "" } { set loginname $default_user } - } + } # Figure out loginname's password (if different from the vty password) if {[info exists userpswd]} { @@ -363,18 +410,25 @@ foreach router [lrange $argv $i end] { } else { set passwd [lindex [find password $loginname@$router] 0] if { "$passwd" == "" } { set passwd [lindex [find password $router] 0] } - } + } - # Figure out encryption tpye - if {[info exists encrypt]} { - # command line encryption type - set encrypttype $encrypt + # figure out identity file to use + set identfile "" + if {[info exists identity]} { + set identfile [lindex [find identity $router] 0] + } + + # Figure out ssh cypher type + if {[info exists cypher]} { + # command line ssh cypher type + set cyphertype $cypher } else { - set encrypttype "3des" - } + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } # Login to the router - if {[login $router $loginname $passwd $prompt $encrypttype]} { + if {[login $router $loginname $passwd $prompt $cyphertype $identfile]} { continue } @@ -390,7 +444,7 @@ foreach router [lrange $argv $i end] { source $sfile close } else { - label $router + label $router log_user 1 interact } diff --git a/bin/jrancid b/bin/jrancid index c879737..efc8465 100755 --- a/bin/jrancid +++ b/bin/jrancid @@ -146,6 +146,11 @@ sub ShowChassisClocks { last if(/^$prompt/); /error: the chassis subsystem is not running/ && return; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; ProcessHistory("","","","# $_"); } return; @@ -163,7 +168,11 @@ sub ShowChassisEnvironment { /error: the chassis subsystem is not running/ && return; /Couldn\'t initiate connection/ && return; - / backplane temperature/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + / backplane temperature/ && next; /(\s*Power supply.*), temperature/ && ProcessHistory("","","","# $1\n") && next; /(\s*.+) +\d+ degrees C.*$/ && @@ -184,6 +193,11 @@ sub ShowChassisFirmware { last if(/^$prompt/); /error: the chassis subsystem is not running/ && return; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; ProcessHistory("","","","# $_"); } return; @@ -200,9 +214,14 @@ sub ShowChassisFpcDetail { last if(/^$prompt/); /error: the chassis subsystem is not running/ && return; - / Temperature:/ && next; - / Start time:/ && next; - / Uptime:/ && next; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + / Temperature/ && next; + / Start time/ && next; + / Uptime/ && next; ProcessHistory("","","","# $_"); } return; @@ -219,12 +238,18 @@ sub ShowChassisHardware { last if(/^$prompt/); /error: the chassis subsystem is not running/ && return; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; ProcessHistory("","","","# $_"); } return; } # This routine parses "show chassis routing-engine" +# Most output is ignored. sub ShowChassisRoutingEngine { print STDERR " In ShowChassisRoutingEngine: $_" if ($debug); @@ -234,14 +259,26 @@ sub ShowChassisRoutingEngine { tr/\015//d; last if(/^$prompt/); + /error: the chassis subsystem is not running/ && return; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; /^Routing Engine status:/ && ProcessHistory("","","","# $_") && next; - / DRAM:/ && ProcessHistory("","","","# $_") && next; + / Slot / && ProcessHistory("","","","# $_") && next; + / Current state/ && ProcessHistory("","","","# $_") && next; + / Election priority/ && ProcessHistory("","","","# $_") && next; + / DRAM/ && ProcessHistory("","","","# $_") && next; + / Serial ID/ && ProcessHistory("","","","# $_") && next; /^\s*$/ && ProcessHistory("","","","# $_") && next; } return; } -# This routine parses "show chassis scb" +# This routine parses "show chassis scb", "show chassis ssb", and +# "show chassis feb". +# Only do this routine once. sub ShowChassisSCB { print STDERR " In ShowChassisSCB: $_" if ($debug); @@ -251,20 +288,50 @@ sub ShowChassisSCB { tr/\015//d; last if(/^$prompt/); + return if ($ShowChassisSCB); /error: the chassis subsystem is not running/ && return; - / Temperature:/ && next; - / utilization:/ && next; - /time:/ && next; + /Couldn\'t initiate connection/ && return; + /Unrecognized command/ && return; + /command is not valid/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + / Temperature/ && next; + / utilization/ && next; + / Start time/ && next; + / Uptime/ && next; / (IP|MLPS) routes:/ && next; / used:/ && next; ProcessHistory("","","","# $_"); } + $ShowChassisSCB = 1; + return; +} + +# This routine parses "show system boot-messages" +sub ShowSystemBootMessages { + print STDERR " In ShowSystemBootMessages: $_" if ($debug); + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while (<INPUT>) { + tr/\015//d; + last if(/^$prompt/); + + /Unrecognized command/ && return; + /^\s+\^/ && return; + /syntax error/ && return; + /^JUNOS / && <INPUT> && next; + /^real memory / && next; + /^avail memory / && next; + /^\/dev\// && next; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show version" sub ShowVersion { - print STDERR " In ShowVersionAndBlame: $_" if ($debug); + print STDERR " In ShowVersion: $_" if ($debug); s/^[a-z]+@//; ProcessHistory("","","","# $_"); @@ -272,7 +339,7 @@ sub ShowVersion { tr/\015//d; last if(/^$prompt/); - /^Juniper Networks is:/ && ProcessHistory("","","","\n$_") && return; + /^Juniper Networks is:/ && ProcessHistory("","","","# \n# $_") && next; ProcessHistory("","","","# $_"); } return; @@ -290,8 +357,10 @@ sub ShowConfiguration { next if (/^\s*$/); /^database header mismatch: / && return(-1); + /^version .*;\d+$/ && return(-1); s/(\s*authentication-key ).*$/#$1<removed>;/; s/^(.*\ssecret \")\$9\$.*(\".*)$/#$1<removed>$2/; + s/ # SECRET-DATA$//; ProcessHistory("","","","$_"); } return; @@ -313,6 +382,9 @@ sub DoNothing {print STDOUT;} "show chassis hardware" => "ShowChassisHardware", "show chassis routing-engine" => "ShowChassisRoutingEngine", "show chassis scb" => "ShowChassisSCB", + "show chassis ssb" => "ShowChassisSCB", + "show chassis feb" => "ShowChassisSCB", + "show system boot-messages" => "ShowSystemBootMessages", "show version" => "ShowVersion", "show configuration" => "ShowConfiguration" ); @@ -324,6 +396,9 @@ sub DoNothing {print STDOUT;} "show chassis hardware", "show chassis routing-engine", "show chassis scb", + "show chassis ssb", + "show chassis feb", + "show system boot-messages", "show version", "show configuration" ); @@ -352,7 +427,8 @@ if ($file) { } } -while(<INPUT>) { + +TOP: while(<INPUT>) { tr/\015//d; if (/^Error:/) { s/^.*Error:/Error:/; @@ -374,13 +450,13 @@ while(<INPUT>) { if (! defined($commands{$cmd})) { print STDERR "found unexpected command - \"$cmd\"\n"; $clean_run = 0; - last; + last TOP; } $rval = &{$commands{$cmd}}; delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; - last; + last TOP; } } if (/>\s*quit/) { @@ -177,6 +177,10 @@ sub ShowVersion { $type = "AGS"; } elsif ( $1 eq "CSC4") { $type = "AGS+"; + } elsif ( $1 eq "2511" || $1 eq "2524" || $1 eq "AS2511-RJ") { + $type = "2500"; + } elsif ( $1 eq "3620" || $1 eq "3640") { + $type = "3600"; } elsif ( $1 eq "RSP7000") { $type = "7500"; } elsif ( $1 =~ /RSP\d/) { @@ -185,9 +189,9 @@ sub ShowVersion { $type = "7000"; } elsif ( $1 eq "RP") { $type = "7000"; - } elsif ( $1 eq "7202" || $1 eq "7204" || $1 eq "7206") { + } elsif ( $1 =~ /720[246]/) { $type = "7200"; - } elsif ($1 eq "12004/GRP" || $1 eq "12008/GRP" || $1 eq "12012/GRP") { + } elsif ($1 =~ /1200[48]\/GRP/ || $1 =~ /1201[26]\/GRP/) { $type = "12000"; } else { $type = $1; @@ -229,6 +233,16 @@ sub ShowVersion { "!Memory: pcmcia $2 slot$3 $1\n"); next; } + if(/^WARNING/) { + if (!defined($I0)) { + $I0=1; + ProcessHistory("COMMENTS","keysort","I0","!\n"); + } + ProcessHistory("COMMENTS","keysort","I1","! $_"); + # The line after the WARNING is what to do about it. + $_ = <INPUT>; tr/\015//d; + ProcessHistory("COMMENTS","keysort","I1","! $_"); + } if (/^Configuration register is (.*)$/) { $config_register=$1; next; @@ -237,9 +251,24 @@ sub ShowVersion { return(0); } +# This routine parses "show install active" +sub ShowInstallActive { + print STDERR " In ShowInstallActive: $_" if ($debug); + + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + ProcessHistory("COMMENTS","keysort","F5","!Image: $_") && next; + } + return(0); +} + # This routine parses "show env all" sub ShowEnv { - # Skip if this is not a 7500 or 7000. + # Skip if this is not a 7500, 7200, or 7000. print STDERR " In ShowEnv: $_" if ($debug); while (<INPUT>) { @@ -306,7 +335,8 @@ sub ShowGSR { # This routine parses "show boot" sub ShowBoot { - # Pick up boot variables if 7000/7500/12000; otherwise pick up bootflash. + # Pick up boot variables if 7000/7200/7500/12000; + # otherwise pick up bootflash. print STDERR " In ShowBoot: $_" if ($debug); while (<INPUT>) { @@ -321,7 +351,7 @@ sub ShowBoot { if (!defined($H0)) { $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); } - if ($type !~ /^(1200|7)/) { + if ($type !~ /^(120|7)/) { ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); } elsif (/variable/) { ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); @@ -340,7 +370,7 @@ sub ShowFlash { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if ($type =~ /^(1200|7.0)/); + return(1) if ($type =~ /^(120|7)/); return(1) if /^\s*\^\s*$/; return(1) if /Invalid input detected/; ProcessHistory("FLASH","","","!Flash: $_"); @@ -360,9 +390,10 @@ sub DirSlotN { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if ($type !~ /^(1200|7.0|36.0)/); + return(1) if ($type !~ /^(120|7|36)/); return(1) if /^\s*\^\s*$/; return(1) if /Invalid input detected/; + return(1) if /\%Error: No such file or directory/; return(1) if /No space information available/; return(-1) if /\%Error calling/; return(-1) if /: device being squeezed/; # Flash is busy @@ -382,7 +413,7 @@ sub ShowContAll { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if ($type =~ /^(1200|7[05])/); + return(1) if ($type =~ /^(120|7[05])/); if (/^Interface ([^ \n(]*)/) { $INT = "$1, "; next; } /^(BRI unit \d)/ && ProcessHistory("INT","","","!Interface: $1\n") && next; @@ -393,10 +424,15 @@ sub ShowContAll { /(Media Type is \S+),/ && ProcessHistory("INT","","","!\t$1\n"); if (/(M\dT:) show controller:$/) { + my($ctlr) = $1; + $_ = <INPUT>; tr/\015//d; s/ subunit \d,//; + ProcessHistory("INT","","","!Interface: $ctlr $_"); + } + if (/^(\S+) : show controller:$/) { my($ctlr) = $1; $_ = <INPUT>; tr/\015//d; s/ subunit \d,//; - ProcessHistory("INT","","","!Interface: $ctlr $_"); - } + ProcessHistory("INT","","","!Interface: $ctlr: $_"); + } /^(HD unit \d), idb/ && ProcessHistory("INT","","","!Interface: $1\n") && next; /^HD unit \d, NIM/ && @@ -553,17 +589,17 @@ sub ShowDiagbus { return(0); } -# This routine parses "show diags" for the gsr, 7200, 3600 +# This routine parses "show diag" for the gsr, 7200, 3600, 2600. # This will create arrarys for hw info. -sub ShowDiags { +sub ShowDiag { # Skip if this is not a 12000. - print STDERR " In ShowDiags: $_" if ($debug); + print STDERR " In ShowDiag: $_" if ($debug); while (<INPUT>) { tr/\015//d; last if (/^$prompt/); next if (/^(\s*|\s*$cmd\s*)$/); - return(1) if ($type !~ /^(1200|720|36.0)/); + return(1) if ($type !~ /^(120|720|36|26)/); /^$/ && next; if (!defined($showdiags)) {$showdiags=1; ProcessHistory("SLOT","","","!\n");} s/Port Packet Over SONET/POS/; @@ -606,9 +642,11 @@ sub ShowDiags { next; } # 7200 and 3600 stuff - if (/^(Slot) (\d+):/ || /^\s+(WIC) Slot (\d):/) { + if (/^(Slot)\s+(\d+):/ || /^\s+(WIC|VIC) Slot (\d):/) { if ($1 eq "WIC") { $WIC = "/$2"; + } elsif ($1 eq "VIC") { + $WIC = "/$2"; } else { $slot = $2; undef($WIC); @@ -620,8 +658,11 @@ sub ShowDiags { s/ with MII or RJ45/-TX/; s/Fast-ethernet /100Base/; s/[)(]//g; - /\s+(.*)\s+port adapter?,\s+(\d+)\s+/ && + /\s+(.*) port adapter,?\s+(\d+)\s+/i && ProcessHistory("SLOT","","","!Slot $slot: type $1, $2 ports\n"); + # I/O controller with no interfaces + /\s+(.*)\s+port adapter\s*$/i && + ProcessHistory("SLOT","","","!Slot $slot: type $1, 0 ports\n"); /\s+(.*)\s+daughter card(.*)$/ && ProcessHistory("SLOT","","","!Slot $slot$WIC: type $1$2\n"); /\s+(FT1)$/ && @@ -659,7 +700,7 @@ sub ShowC7200 { ProcessHistory("SLOT","","","!Slot Midplane: part $2, serial $1\n!\n"); next; } - if (/C7200 CPU EEPROM:/) { + if (/C720\d(VXR)? CPU EEPROM:/) { $_ = <INPUT>; /revision\s+(\S+).*revision\s+(\S+)/ && ProcessHistory("SLOT","","","!Slot CPU: hvers $1 rev $2\n"); @@ -700,25 +741,50 @@ sub WriteTerm { /^ntp clock-period / && next; # kill ntp clock-period /^ length / && next; # kill length on serial lines /^ width / && next; # kill width on serial lines + /^ clockrate / && next; # kill clockrate on serial interfaces /^enable password / && ProcessHistory("ENABLE","","","!enable password <removed>\n") && next; - /^(username .*) password \d *(\S)\s*(.*)/ && + /^(username .*) password /&& ProcessHistory("USER","","","!$1 password <removed>\n") && next; /^\s*password / && ProcessHistory("LINE-PASS","","","! password <removed>\n") && next; /^\s*neighbor (\S*) password / && ProcessHistory("","","","! neighbor $1 password <removed>\n") && next; + /^(ip ftp password) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + /^( ip ospf authentication-key) / && + ProcessHistory("","","","!$1 <removed>\n") && next; + /^( ip ospf message-digest-key \d+ md5) / && + ProcessHistory("","","","!$1 <removed>\n") && next; /fair-queue individual-limit/ && next; + # sort ip explicit-paths. + if (/^ip explicit-path name (\S+)/) { + my($key) = $1; + my($expath) = $_; + while (<INPUT>) { + tr/\015//d; + last if (/^$prompt/); + last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); + if (/^ip explicit-path name (\S+)/) { + ProcessHistory("EXPATH","keysort","$key","$expath"); + $key = $1; + $expath = $_; + } else { + $expath .= $_; + } + } + ProcessHistory("EXPATH","keysort","$key","$expath"); + } # sort route-maps - if (/^route-map ([^ ]+)/) { + if (/^route-map (\S+)/) { my($key) = $1; my($routemap) = $_; while (<INPUT>) { tr/\015//d; last if (/^$prompt/ || ! /^(route-map |[ !])/); - if (/^route-map ([^ ]+)/) { + if (/^route-map (\S+)/) { ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); $key = $1; $routemap = $_; @@ -804,6 +870,7 @@ sub DoNothing {print STDOUT;} # Main %commands=( 'show version' => "ShowVersion", + 'show install active' => "ShowInstallActive", 'show env all' => "ShowEnv", 'show gsr chassis' => "ShowGSR", 'show boot' => "ShowBoot", @@ -817,7 +884,7 @@ sub DoNothing {print STDOUT;} 'show controllers' => "ShowContAll", 'show controllers cbus' => "ShowContCbus", 'show diagbus' => "ShowDiagbus", - 'show diag' => "ShowDiags", + 'show diag' => "ShowDiag", 'show c7200' => "ShowC7200", 'write term' => "WriteTerm" ); @@ -825,6 +892,7 @@ sub DoNothing {print STDOUT;} # cmds is important (show version first and write term last). pita @commands=( "show version", + "show install active", "show env all", "show gsr chassis", "show boot", @@ -868,7 +936,7 @@ if ($file) { ProcessHistory("COMMENTS","keysort","B0","!\n"); ProcessHistory("COMMENTS","keysort","F0","!\n"); ProcessHistory("COMMENTS","keysort","G0","!\n"); -while(<INPUT>) { +TOP: while(<INPUT>) { tr/\015//d; if (/\#exit$/) { $clean_run=1; @@ -888,13 +956,13 @@ while(<INPUT>) { if (! defined($commands{$cmd})) { print STDERR "found unexpected command - \"$cmd\"\n"; $clean_run = 0; - last; + last TOP; } $rval = &{$commands{$cmd}}; delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; - last; + last TOP; } } } diff --git a/bin/rancid-fe b/bin/rancid-fe index 8dab8a5..f85d235 100755 --- a/bin/rancid-fe +++ b/bin/rancid-fe @@ -27,6 +27,8 @@ require 5; if ($vendor =~ /^cisco$/i) { exec('rancid', $router); +} elsif ($vendor =~ /^cat5$/i) { + exec('cat5rancid', $router); } elsif ($vendor =~ /^juniper$/i) { exec('jrancid', $router); } elsif ($vendor =~ /^foundry$/i) { |