From b24aa5051db5d4bf9757efe7df06cb1892898382 Mon Sep 17 00:00:00 2001 From: Tar Committer Date: Thu, 3 Feb 2000 17:55:28 +0000 Subject: Imported from rancid-1.4.tar.gz. --- bin/clogin | 181 ++++---- bin/control_rancid | 107 +++-- bin/create_cvs | 32 +- bin/cvs_helper | 28 -- bin/do-diffs | 4 +- bin/env | 14 +- bin/flogin | 530 ++++++++++++++++++++++++ bin/francid | 383 +++++++++++++++++ bin/jrancid | 242 +++++++---- bin/rancid | 1172 +++++++++++++++++++++++++++++----------------------- bin/rancid-fe | 6 + bin/rrancid | 347 ++++++++++++++++ bin/run-me | 35 -- 13 files changed, 2301 insertions(+), 780 deletions(-) delete mode 100644 bin/cvs_helper create mode 100755 bin/flogin create mode 100755 bin/francid create mode 100755 bin/rrancid delete mode 100755 bin/run-me (limited to 'bin') diff --git a/bin/clogin b/bin/clogin index b8b693e..cad94cd 100755 --- a/bin/clogin +++ b/bin/clogin @@ -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 @@ -29,8 +29,8 @@ # Usage line set usage "Usage: $argv0 \[-u user\] \[-p user-password\] \[-v vty-password\] \ \[-w enable-username\] \[-e enable-password\] \[-noenable\] \ -\[-f cloginrc-file\] \[-c command\] \[-s script-file\] \[-autoenable\] \ -\[-t timeout\] router \[router...\]\n" +\[-f cloginrc-file\] \[-y ssh_cypher_type\] \[-c command\] \[-s script-file\] \ +\[-x command-file\] \[-autoenable\] \[-t timeout\] router \[router...\]\n" # env(CLOGIN) may contain: # x == do not set xterm banner or name @@ -53,8 +53,8 @@ set do_enapasswd 1 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 } @@ -125,6 +125,13 @@ for {set i 0} {$i < $argc} {incr i} { exit 1 } set do_script 1 + # cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } # alternate cloginrc file } -f* - -F* { @@ -136,17 +143,17 @@ for {set i 0} {$i < $argc} {incr i} { -T* { incr i set timeout [ lindex $argv $i ] - } -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 + } -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 # Do we enable? } -noenable { set enable 0 @@ -192,20 +199,20 @@ proc label { host } { if [regexp \^(xterm|vs) $env(TERM) ignore ] { send_user "\033]1;[lindex [split $host "."] 0]\a" send_user "\033]2;$host\a" - } + } } } # This is a helper function to make the password file easier to # maintain. Using this the password file has the form: -# add password sl* pete cow -# add password at* steve +# add password sl* pete cow +# add password at* steve # add password * hanky-pie -proc add {var args} { global $var ;lappend $var $args} +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] @@ -219,11 +226,11 @@ 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 } { + if { [info exists password_file] == 0 } { set password_file $env(HOME)/.cloginrc } set read_password_file 1 @@ -236,9 +243,10 @@ proc source_password_file { } { } # Log into the router. -proc login { router user userpswd passwd enapasswd prompt } { +proc login { router user userpswd passwd enapasswd prompt cyphertype } { global spawn_id in_proc do_command do_script set in_proc 1 + set tryssh 1 # Telnet to the router & try to login. if [ catch {spawn telnet $router} reason ] { @@ -253,19 +261,19 @@ proc login { router user userpswd passwd enapasswd prompt } { send_user "\nError: TIMEOUT reached\n" close; wait if { $in_proc} { - return 1 + return 1 } else { - continue + continue } - } eof { + } eof { send_user "\nError: EOF received\n" close; wait if { $in_proc} { - return 1 + return 1 } else { - continue + continue } - } + } } # Here we get a little tricky. There are several possibilities: @@ -274,12 +282,24 @@ proc login { router user userpswd passwd enapasswd prompt } { # TACACS server is not working, then it will use the enable # passwd. Or, the router might not have TACACS turned on, # then it will just send the passwd. + # if telnet fails with connection refused, try ssh expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } - "Connection refused" { - expect eof - send_user "Error: Connection Refused\n"; wait; return 1 - } "Unknown host\r\n" { + "Connection refused" { + close; wait + if { $tryssh } { + if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { + send_user "Error: failed to ssh: $reason\n" + exit 1 + } + set tryssh 0 + sleep 0.3 + exp_continue + } else { + expect eof + send_user "Error: Connection Refused\n"; wait; return 1 + } + } eof { send_user "Error: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { expect eof send_user "Error: Unknown host\n"; wait; return 1 } "Host is unreachable" { @@ -289,32 +309,40 @@ proc login { router user userpswd passwd enapasswd prompt } { expect eof send_user "Error: Unknown host\n"; wait; return 1 } + -re "Host key not found .* \(yes\/no\)\?" { + send "yes\r" + send_user "Host $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + 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" - expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } -re "\[Pp]assword:" { send "$userpswd\r" } "$prompt" { set in_proc 0; return 0 } } exp_continue } - "Password:" { send "$passwd\r" - expect { - eof { send_user "Error: Couldn't login\n"; wait; return 1 } + "\[Pp]assword:" { send "$passwd\r" + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } "Password:" { send "$enapasswd\r" } - "$prompt" { set in_proc 0; return 0 } + "$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 } { + "$prompt" { } + denied { send_user "Error: Check your passwd for $router\n" + if { $do_command || $do_script } { send "quit" wait return 1 } else { return 1 } - } + } "% Bad passwords" {send_user "Error: Check your passwd for $router\n"; return 1 } } set in_proc 0 @@ -358,17 +386,17 @@ proc run_commands { prompt command } { for {set i 0} {$i < $num_commands} { incr i} { send "[subst [lindex $commands $i]]\r" expect { - -re "^\[^\n\r]*$prompt." { exp_continue } + -re "^\[^\n\r]*$prompt." { exp_continue } -re "^\[^\n\r *]*$prompt" {} - "\n" { exp_continue } - } + -re "\[\n\r]" { exp_continue } + } } } else { send "[subst $command]\r" expect { -re "^\[^\n\r]*$prompt." { exp_continue } -re "^\[^\n\r *]*$prompt" {} - "\n" { exp_continue } + -re "\[\n\r]" { exp_continue } } } send "exit\r" @@ -410,49 +438,58 @@ foreach router [lrange $argv $i end] { if { $do_passwd || $do_enapasswd } { set pswd [find password $router] 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 password for $router in $password_file.\n" + continue + } + if { $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { send_user "Error - no enable password for $router in $password_file.\n" - continue + continue } - set passwd [lindex $pswd 0] - set enapasswd [lindex $pswd 1] + set passwd [lindex $pswd 0] + set enapasswd [lindex $pswd 1] } # Figure out username - if {[info exists username]} { + if {[info exists username]} { # command line username set ruser $username } else { - set ruser [find user $router] + set ruser [find user $router] if { "$ruser" == "" } { set ruser $default_user } - } + } # Figure out username's password (if different from the vty password) if {[info exists userpasswd]} { # command line username set userpswd $userpasswd } else { - set userpswd [find userpassword $router] - if { "$userpswd" == "" } { set userpswd $passwd } - } - + set userpswd [find userpassword $router] + if { "$userpswd" == "" } { set userpswd $passwd } + } + # Figure out enable username - if {[info exists enausername]} { + if {[info exists enausername]} { # command line enausername set enauser $enausername } else { - set enauser [find enauser $router] - if { "$enauser" == "" } { set enauser $ruser } - } + set enauser [find enauser $router] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out cypher tpye + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } # Login to the router - if {[login $router $ruser $userpswd $passwd $enapasswd $prompt]} { + if {[login $router $ruser $userpswd $passwd $enapasswd $prompt $cyphertype]} { continue } - if { $enable } { + if { $enable } { if {[do_enable $enauser $enapasswd]} { if { $do_command || $do_script } { close; wait @@ -471,7 +508,7 @@ foreach router [lrange $argv $i end] { source $sfile close } else { - label $router + label $router log_user 1 interact } diff --git a/bin/control_rancid b/bin/control_rancid index 89ec0df..0728e7e 100755 --- a/bin/control_rancid +++ b/bin/control_rancid @@ -52,26 +52,58 @@ fi # generate the list of routers we should try to fetch cd $DIR -rm -f $DIR/allrouters.new +grep -v '^#' router.db > routers.db +cut -d: -f1,2 routers.db | sort -u > routers.all.new +diff routers.all routers.all.new > /dev/null 2>&1; RALL=$? perl -F: -ane '{($F[0] =~ tr@A-Z@a-z@,print "$F[0]:$F[1]\n") - if ($F[2] =~ /^up$/i);}' $DIR/router.db | sort -u > $DIR/allrouters.new + if ($F[2] =~ /^down$/i);}' routers.db | sort -u > routers.down.new +diff routers.down routers.down.new > /dev/null 2>&1; RDOWN=$? +perl -F: -ane '{($F[0] =~ tr@A-Z@a-z@,print "$F[0]:$F[1]\n") + if ($F[2] =~ /^up$/i);}' routers.db | sort -u > routers.up.new +diff routers.up routers.up.new > /dev/null 2>&1; RUP=$? -if diff $DIR/allrouters $DIR/allrouters.new > $DIR/allrouters.diffs +if [ $RALL -ne 0 -o $RDOWN -ne 0 -o $RUP -ne 0 ] then - rm -f $DIR/allrouters.new -else ( - echo New routers: - comm -13 $DIR/allrouters $DIR/allrouters.new | sed -e 's/^/ /' -e 's/:.*$//' - echo - echo Deleted routers: - comm -23 $DIR/allrouters $DIR/allrouters.new | sed -e 's/^/ /' -e 's/:.*$//' - ) | Mail -s "changes in $GROUP routers" rancid-admin-$GROUP + if [ $RUP -ne 0 ] ; then + if [ $RUP -eq 1 ] ; then + echo Routers changed to up: + comm -13 routers.up routers.up.new | sed -e 's/^/ /' -e 's/:.*$//' + echo + elif [ -s routers.up.new ] ; then + echo Routers changed to up: + sed -e 's/^/ /' -e 's/:.*$//' routers.up.new + echo + fi + fi + if [ $RDOWN -ne 0 ] ; then + if [ $RDOWN -eq 1 ] ; then + echo Routers changed to down: + comm -13 routers.down routers.down.new | sed -e 's/^/ /' -e 's/:.*$//' + echo + elif [ -s routers.down.new ] ; then + echo Routers changed to down: + sed -e 's/^/ /' -e 's/:.*$//' routers.down.new + echo + fi + fi + WC=`wc -l routers.all | sed -e 's/^ *\([^ ]*\) .*$/\1/'` + WCNEW=`wc -l routers.all.new | sed -e 's/^ *\([^ ]*\) .*$/\1/'` + if [ $RALL -eq 1 -a $WC -gt $WCNEW ] ; then + echo Deleted routers: + comm -23 routers.all routers.all.new | sed -e 's/^/ /' -e 's/:.*$//' + fi + ) > routers.mail + + if [ -s routers.mail ] ; then + Mail -s "changes in $GROUP routers" rancid-admin-$GROUP < routers.mail + fi + rm -f routers.mail cd $DIR/configs # Add new routers to the CVS structure. - for router in `comm -13 $DIR/allrouters $DIR/allrouters.new` + for router in `comm -13 $DIR/routers.up $DIR/routers.up.new` do OFS=$IFS IFS=: @@ -87,14 +119,31 @@ else echo cd $DIR - mv $DIR/allrouters.new $DIR/allrouters fi -rm -f $DIR/allrouters.diffs $DIR/allrouters.new +mv routers.all.new routers.all +mv routers.down.new routers.down +mv routers.up.new routers.up +rm -f routers.db + +# cvs delete configs for routers not listed in routers.up. +cd $DIR/configs +for router in `find . \( -name \*.new -prune -o -name CVS -prune \) -o -type f -print | sed -e 's/^.\///'` ; do + grep "^$router:" ../router.db > /dev/null 2>&1 + if [ $? -eq 1 ]; then + rm -f $router + cvs delete $router + cvs commit -m 'deleted router' $router + echo "Deleted $router" + fi +done +cd $DIR # no routers, empty list or all 'down' -if [ ! -s $DIR/allrouters ] +if [ ! -s routers.up ] then - exit; + # commit router.db + cvs commit -m updates router.db > /dev/null + exit; fi # Now we can actually try to get the configs @@ -103,22 +152,19 @@ cd $DIR/configs # The number of processes running at any given time can be # tailored to the specific installation. echo "Trying to get all of the configs." -par -q -n $PAR_COUNT -c "rancid-fe \{}" $DIR/allrouters +par -q -n $PAR_COUNT -c "rancid-fe \{}" $DIR/routers.up # This section will generate a list of missed routers # and try to grab them again. It will run through # $pass times. pass=4 round=1 -if [ -f $DIR/allrouters.missed ]; then - rm -f $DIR/allrouters.missed +if [ -f $DIR/routers.up.missed ]; then + rm -f $DIR/routers.up.missed fi while [ $round -le $pass ] do - echo "=====================================" - echo "Getting missed routers: round $round." - - for router in `cat $DIR/allrouters` + for router in `cat $DIR/routers.up` do OFS=$IFS IFS=':' @@ -126,15 +172,17 @@ do IFS=$OFS router=$1; mfg=$2 - if [ ! -f $DIR/configs/$router.new ] + if [ ! -f $router.new ] then - echo "$router:$mfg" >> $DIR/allrouters.missed + echo "$router:$mfg" >> $DIR/routers.up.missed fi done - if [ -f $DIR/allrouters.missed ]; then - par -q -n $PAR_COUNT -c "rancid-fe \{}" $DIR/allrouters.missed - rm -f $DIR/allrouters.missed + if [ -f $DIR/routers.up.missed ]; then + echo "=====================================" + echo "Getting missed routers: round $round." + par -q -n $PAR_COUNT -c "rancid-fe \{}" $DIR/routers.up.missed + rm -f $DIR/routers.up.missed round=`expr $round + 1` else echo "All routers sucessfully completed." @@ -152,6 +200,7 @@ rename 's/.new$//' *.new cd $DIR #cvs diff -c3 >$TMP.diff #cvs diff -C 3 >$TMP.diff +# Change the output of a unified diff to make it a bit more readable. cat > $TMP.sedf << EOF /^RCS file: /d #/^retrieving revision /d @@ -180,7 +229,7 @@ fi 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/allrouters | sort -u > $DIR/routers.failed + if (time() - $t >= 86400);}' $DIR/routers.up | sort -u > $DIR/routers.failed if [ -s $DIR/routers.failed ] then ( diff --git a/bin/create_cvs b/bin/create_cvs index 675cda8..df7e56e 100755 --- a/bin/create_cvs +++ b/bin/create_cvs @@ -26,14 +26,21 @@ ENVFILE="`dirname $0`/env" . $ENVFILE +# Base dir +if [ ! -d $BASEDIR ]; then + mkdir -p $BASEDIR +fi + +cd $BASEDIR + # Top level CVS stuff if [ ! -d $CVSROOT ]; then cvs init fi # Log dir -if [ ! -d $BASEDIR/logs ]; then - mkdir $BASEDIR/logs +if [ ! -d logs ]; then + mkdir logs fi # Which groups to do @@ -57,25 +64,26 @@ do cd $BASEDIR cvs co $GROUP fi - if [ -d $DIR -a ! -d $DIR/configs ]; then - cd $DIR + cd $DIR + if [ ! -d configs ]; then mkdir configs cvs add configs cvs commit -m 'new' configs - cd $BASEDIR fi # main files - if [ ! -f $DIR/allrouters ]; then - cd $DIR - touch $DIR/allrouters - cd $BASEDIR + if [ ! -f routers.all ]; then + touch routers.all fi - if [ ! -f $DIR/router.db ]; then - cd $DIR + if [ ! -f routers.down ]; then + touch routers.down + fi + if [ ! -f routers.up ]; then + touch routers.up + fi + if [ ! -f router.db ]; then touch router.db cvs add router.db cvs commit -m 'new' router.db - cd $BASEDIR fi done diff --git a/bin/cvs_helper b/bin/cvs_helper deleted file mode 100644 index fe46435..0000000 --- a/bin/cvs_helper +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -## -## -## Copyright (C) 1996 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. -## -## -# -# cvs_helper -# - -# Remove old config -rm -cvs remove - -# Look at an old revision...put file in -cvs export -d -rX.YZ - diff --git a/bin/do-diffs b/bin/do-diffs index 3b5eced..88cc445 100755 --- a/bin/do-diffs +++ b/bin/do-diffs @@ -37,7 +37,7 @@ do /bin/rm -f $LOCKFILE fi - echo ending: `date` echo - ) >$BASEDIR/logs/$GROUP.`date +%y%m%d.%H%M%S` 2>&1 + echo ending: `date` + ) >$BASEDIR/logs/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 done diff --git a/bin/env b/bin/env index 14ae8a1..236ceca 100644 --- a/bin/env +++ b/bin/env @@ -9,13 +9,25 @@ TERM=network;export TERM # a log directory for the logs from rancid and a directory for each group # of routers. In addition to these directories, there will be the CVS # repositories as well. +# use a full path (no sym-links) for BASEDIR. some versions of CVS seemingly +# don't take kindly to sym-links. # 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 +# +# if NOPIPE is set, temp files will be used instead of a cmd pipe during +# collection from the router(s). +#NOPIPE=YES; export NOPIPE +# LIST_OF_GROUPS="sl joebobisp" -# For each group, define a list of people to receive the diffs +# +# For each group, define a list of people to receive the diffs. # in a .mailrc file in the following format: # alias rancid-$GROUP hank@rem.com pwhiting@sprint.net +# or sendmail's /etc/aliases. +# rancid-group: joe,moe@foo +# rancid-group-admin: hostmaster +# be sure to read ../README regarding aliases. # umask 007 diff --git a/bin/flogin b/bin/flogin new file mode 100755 index 0000000..b168762 --- /dev/null +++ b/bin/flogin @@ -0,0 +1,530 @@ +#!/usr/local/bin/expect -- +## +## +## Copyright (C) 1997 by Henry Kilmer, Erik Sherk and Pete Whiting. +## 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. +## +## +# +# flogin - foundry login +# +# Most options are intuitive for logging into a foundry switch. +# this should be the clogin, but foundry can't seem to dislodge +# their heads and make the UI consistent. i think the UI +# development has been outsourced to Fisher Price. +# The default is to enable (thus -noenable). Some folks have +# setup tacacs to have a user login at priv-lvl = 15 (enabled) +# so the -autoenable flag was added for this case (don't go through +# the process of enabling and the prompt will be the "#" prompt. +# The default username password is the same as the vty password. +# + +# 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\] \ +\[-autoenable\] \[-t timeout\] router \[router...\]\n" + +# env(CLOGIN) may contain: +# x == do not set xterm banner or name + +# Password file +set password_file $env(HOME)/.cloginrc +# Default is to login to the router +set do_command 0 +set do_script 0 +# The default is to automatically enable +set enable 1 +# The default is that you login non-enabled (tacacs can have you login already enabled) +set autoenable 0 +# 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 +set do_enapasswd 1 + +# 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 - + # 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 + +# 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]} { + incr i + set username [ lindex $argv $i ] + } + # VTY Password + } -p* - + -P* { + if {! [ regexp .\[pP\](.+) $arg ignore userpasswd]} { + incr i + set userpasswd [ lindex $argv $i ] + } + set do_passwd 0 + # VTY Password + } -v* - + -v* { + if {! [ regexp .\[vV\](.+) $arg ignore passwd]} { + incr i + set passwd [ lindex $argv $i ] + } + set do_passwd 0 + # Enable Username + } -w* - + -W* { + if {! [ regexp .\[wW\](.+) $arg ignore enauser]} { + incr i + set enausername [ lindex $argv $i ] + } + # Enable Password + } -e* - + -E* { + if {! [ regexp .\[eE\](.+) $arg ignore enapasswd]} { + incr i + set enapasswd [ lindex $argv $i ] + } + set do_enapasswd 0 + # Command to run. + } -c* - + -C* { + if {! [ regexp .\[cC\](.+) $arg ignore command]} { + incr i + set command [ lindex $argv $i ] + } + set do_command 1 + # Expect script to run. + } -s* - + -S* { + if {! [ regexp .\[sS\](.+) $arg ignore sfile]} { + incr i + set sfile [ lindex $argv $i ] + } + if { ! [ file readable $sfile ] } { + send_user "Error: Can't read $sfile\n" + exit 1 + } + set do_script 1 + # cypher type + } -y* - + -Y* { + if {! [ regexp .\[eE\](.+) $arg ignore cypher]} { + incr i + set cypher [ lindex $argv $i ] + } + # alternate cloginrc file + } -f* - + -F* { + if {! [ regexp .\[fF\](.+) $arg ignore password_file]} { + incr i + set password_file [ lindex $argv $i ] + } + } -t* - + -T* { + incr i + set timeout [ lindex $argv $i ] + } -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 + # Do we enable? + } -noenable { + set enable 0 + # Does tacacs automatically enable us? + } -autoenable { + set autoenable 1 + set enable 0 + } -* { + send_user "Error: Unknown argument! $arg\n" + send_user $usage + exit 1 + } default { + break + } + } +} +# Process routers...no routers listed is an error. +if { $i == $argc } { + send_user "Error: $usage" +} + +# Only be quiet if we are running a script (it can log its output +# on its own) +if { $do_script } { + log_user 0 +} else { + log_user 1 +} + +# +# Done configuration/variable setting. Now run with it... +# + +# Sets Xterm title if interactive...if its an xterm and the user cares +proc label { host } { + global env + # if CLOGIN has an 'x' in it, don't set the xterm name/banner + if [info exists env(CLOGIN)] { + if {[string first "x" $env(CLOGIN)] != -1} { return } + } + # take host from ENV(TERM) + if [info exists env(TERM)] { + if [regexp \^(xterm|vs) $env(TERM) ignore ] { + send_user "\033]1;[lindex [split $host "."] 0]\a" + send_user "\033]2;$host\a" + } + } +} + +# This is a helper function to make the password file easier to +# maintain. Using this the password file has the form: +# add password sl* pete cow +# add password at* steve +# add password * hanky-pie +proc add {var args} { global $var ;lappend $var $args} +proc find {var router} { + 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] + } + } + } + return {} +} + +# Loads the password file. Note that as this file is tcl, and that +# 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 +proc source_password_file { } { + 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 +} + +# Log into the router. +proc login { router user userpswd passwd enapasswd prompt cyphertype } { + global spawn_id in_proc do_command do_script + set in_proc 1 + set tryssh 1 + + # Telnet to the router & try to login. + if [ catch {spawn telnet $router} reason ] { + send_user "Error: failed to telnet: $reason\n" + exit 1 + } + sleep 0.3 + + # This helps cleanup each expect clause. + expect_after { + timeout { + send_user "\nError: TIMEOUT reached\n" + close; wait + if { $in_proc} { + return 1 + } else { + continue + } + } eof { + send_user "\nError: EOF received\n" + close; wait + if { $in_proc} { + return 1 + } else { + continue + } + } + } + + # Here we get a little tricky. There are several possibilities: + # the router can ask for a username and passwd and then + # talk to the TACACS server to authenticate you, or if the + # TACACS server is not working, then it will use the enable + # passwd. Or, the router might not have TACACS turned on, + # then it will just send the passwd. + # if telnet fails with connection refused, try ssh + expect { + "Connection refused" { + close; wait + if { $tryssh } { + if [ catch {spawn ssh -c $cyphertype -x -l $user $router} reason ] { + send_user "Error: failed to ssh: $reason\n" + exit 1 + } + set tryssh 0 + sleep 0.3 + exp_continue + } else { + expect eof + send_user "Error: Connection Refused\n"; wait; return 1 + } + } eof { send_user "Error: Couldn't login\n"; wait; return 1 + } "Unknown host\r\n" { + expect eof + send_user "Error: Unknown host\n"; wait; return 1 + } "Host is unreachable" { + expect eof + send_user "Error: Host Unreachable!\n"; wait; return 1 + } "No address associated with name" { + expect eof + send_user "Error: Unknown host\n"; wait; return 1 + } + -re "Host key not found .* \(yes\/no\)\?" { + send "yes\r" + send_user "Host $router added to the list of known hosts.\n" + exp_continue } + -re "HOST IDENTIFICATION HAS CHANGED.* \(yes\/no\)\?" { + 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:|Name :)" { + sleep 1; + send "$user\r" + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } + -re "\[Pp]assword:" { send "$userpswd\r" } + "$prompt" { set in_proc 0; return 0 } + } + exp_continue + } + "\[Pp]assword:" { send "$passwd\r" + expect { + eof { send_user "Error: Couldn't login\n"; wait; return 1 } + "Password:" { send "$enapasswd\r" } + "$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 } { + send "quit" + wait + return 1 + } else { + return 1 + } + } + "% Bad passwords" {send_user "Error: Check your passwd for $router\n"; return 1 } + } + set in_proc 0 + return 0 +} + +# Enable +proc do_enable { enauser enapasswd } { + global prompt in_proc + set in_proc 1 + + sleep 1; # dont go too fast for it now... + send "enable\r" + expect { + -re "(Username|User Name):" { send "$enauser\r"; exp_continue} + "Password:" { send "$enapasswd\r"; exp_continue} + "#" { } + 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 "#" + set in_proc 0 + return 0 +} + +# Run commands given on the command line. +proc run_commands { prompt command } { + global in_proc + set in_proc 1 + + send "skip-page-display\r" + expect $prompt {} + + # 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" + expect { + -re "^\[^\n\r]*$prompt." { exp_continue } + -re "^\[^\n\r *]*$prompt" {} + -re "\[\n\r]" { exp_continue } + } + } + } else { + send "[subst $command]\r" + expect { + -re "^\[^\n\r]*$prompt." { exp_continue } + -re "^\[^\n\r *]*$prompt" {} + -re "\[\n\r]" { exp_continue } + } + } + send "exit\r" + expect { + "\n" { exp_continue } + -re "^\[^ ]+>" { + send "exit\r" + exp_continue } + timeout { return 0 } + eof { return 0 } + } + set in_proc 0 +} + +# +# For each router... (this is main loop) +# +set in_proc 0 +foreach router [lrange $argv $i end] { + set router [string tolower $router] + send_user "$router\n" + + # Figure out prompt. + # Since autoenable is off by default, if we have it defined, it + # was done on the command line. If it is not specifically set on the + # command line, check the password file. + if $autoenable { + set prompt "#" + } else { + set ae [find autoenable $router] + if { "$ae" == "1" } { + set autoenable 1 + set enable 0 + set prompt "#" + } else { + set autoenable 0 + set prompt ">" + } + } + + # Figure out passwords + if { $do_passwd || $do_enapasswd } { + set pswd [find password $router] + if { [llength $pswd] == 0 } { + send_user "Error - no password for $router in $password_file.\n" + continue + } + if { $do_enapasswd && $autoenable == 0 && [llength $pswd] < 2 } { + send_user "Error - no enable password for $router in $password_file.\n" + continue + } + set passwd [lindex $pswd 0] + set enapasswd [lindex $pswd 1] + } + + # Figure out username + if {[info exists username]} { + # command line username + set ruser $username + } else { + set ruser [find user $router] + if { "$ruser" == "" } { set ruser $default_user } + } + + # Figure out username's password (if different from the vty password) + if {[info exists userpasswd]} { + # command line username + set userpswd $userpasswd + } else { + set userpswd [find userpassword $router] + if { "$userpswd" == "" } { set userpswd $passwd } + } + + # Figure out enable username + if {[info exists enausername]} { + # command line enausername + set enauser $enausername + } else { + set enauser [find enauser $router] + if { "$enauser" == "" } { set enauser $ruser } + } + + # Figure out cypher tpye + if {[info exists cypher]} { + # command line cypher type + set cyphertype $cypher + } else { + set cyphertype [find cyphertype $router] + if { "$cyphertype" == "" } { set cyphertype "3des" } + } + + # Login to the router + if {[login $router $ruser $userpswd $passwd $enapasswd $prompt $cyphertype]} { + continue + } + if { $enable } { + if {[do_enable $enauser $enapasswd]} { + if { $do_command || $do_script } { + close; wait + continue + } + } + } + + if { $do_command } { + if {[run_commands $prompt $command]} { + continue + } + } elseif { $do_script } { + # fucking foundry + send "skip-page-display\r" + expect $prompt {} + source $sfile + close + } else { + label $router + log_user 1 + interact + } + + # End of for each router + wait + sleep 0.3 +} +exit 0 diff --git a/bin/francid b/bin/francid new file mode 100755 index 0000000..3050aee --- /dev/null +++ b/bin/francid @@ -0,0 +1,383 @@ +#!/usr/local/bin/perl +## +## Amazingly hacked version of Hank's rancid - this one tries to +## deal with foundrys. +## +## 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 { + my($slot); + + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + next if /^\s*$/; + last if(/^$prompt/); + + next if (/^The system /); + + s/^\s*(HW|SW)/$1/; + s/^\s*(Compiled on)/SW: $1/; + #s/^(HW.*)/$1\n/; + if (/^SL (\d)/) { + $slot = "Slot $1"; + s/^SL \d+/$slot/; + } + if (/MHz .* processor/) { + $slot = "MGMT"; + } + s/^(\s*\d+ )/$slot:$1/; + s/^===*//; + + ProcessHistory("VERSION","","","!$_"); + } + ProcessHistory("VERSION","","","!\n"); + return(0); +} + +# This routine parses "show chassis" +sub ShowChassis { + print STDERR " In ShowChassis: $_" if ($debug); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/ from /); + ProcessHistory("CHASSIS","","","! $_"); + } + ProcessHistory("CHASSIS","","","!\n"); + return(0); +} + +# This routine parses "show flash" +sub ShowFlash { + print STDERR " In ShowFlash: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if /^\s*$/; + ProcessHistory("FLASH","","","!Flash: $_"); + } + ProcessHistory("","","","!\n"); + return; +} + +# This routine parses "show module" +sub ShowModule { + print STDERR " In ShowModule: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + next if /^\s*$/; + next if /:\s*$/; + ProcessHistory("MODULE","","","!Module: $_"); + } + ProcessHistory("","","","!\n"); + return(0); +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + + /Current configuration:/i && next; + /^ver \d+\.\d+/ && next; + /^module \d+ / && next; + + /^ntp clock-period / && next; # kill ntp clock-period + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + # filter out any RCS/CVS tags to avoid confusing local CVS storage + s/\$(Revision|Id):/ $1:/; + # order access-lists + /^access-list\s+(\d+)\s+(perm|deny)\s+(\d\S+)(\/\d+)\s*$/ && + ProcessHistory("PACL $1 $2","ipsort","$3","$_") + && next; + /^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; + # 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\n") && next; + /^tacacs-server host (\d+\.\d+\.\d+\.\d+)/ && + ProcessHistory("TAC","ipsort","$1","$_") && next; + + # delete ntp auth password + /^(ntp authentication-key \d+ md5) / && + ProcessHistory("","","","!$1 \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; + + 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 chassis' => "ShowChassis", + 'show module' => "ShowModule", + 'show flash' => "ShowFlash", + 'write term' => "WriteTerm" +); +# keys() doesnt return things in the order entered and the order of the +# cmds is important. pita +@commands=( + "show version", + "show chassis", + "show module", + "show flash", + "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 flogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); + print STDOUT "executing flogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); + if (defined($ENV{NOPIPE})) { + system "flogin -t $timeo -c \"$cisco_cmds\" $host $host.raw 2>&1" || die "flogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "flogin failed for $host: $!\n"; + } else { + open(INPUT,"flogin -t $timeo -c \"$cisco_cmds\" $host ) { + tr/\015//d; + if (/\#exit$/) { + $clean_run=1; + last; + } + if (/Error:/) { + s/^.*Error:/Error:/; + print STDOUT ("$host flogin error: $_"); + print STDERR ("$host flogin error: $_") if ($debug); + $clean_run=0; + last; + } + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + 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; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last; + } + } +} +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); +} diff --git a/bin/jrancid b/bin/jrancid index b5b968e..c879737 100755 --- a/bin/jrancid +++ b/bin/jrancid @@ -138,86 +138,162 @@ sub sortbyipaddr { # This routine parses "show chassis clocks" sub ShowChassisClocks { print STDERR " In ShowChassisClocks: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show chassis environment" sub ShowChassisEnvironment { print STDERR " In ShowChassisEnvironment: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - /Couldn\'t initiate connection/ && return; - / backplane temperature/ && return; - /(\s*Power supply.*), temperature/ && ProcessHistory("","","","# $1\n") && return; - /(\s*.+) +\d+ degrees C.*$/ && ProcessHistory("","","","# $1\n") && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + /Couldn\'t initiate connection/ && return; + / backplane temperature/ && return; + /(\s*Power supply.*), temperature/ && + ProcessHistory("","","","# $1\n") && next; + /(\s*.+) +\d+ degrees C.*$/ && + ProcessHistory("","","","# $1\n") && next; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show chassis firmware" sub ShowChassisFirmware { print STDERR " In ShowChassisFirmware: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show chassis fpc detail" sub ShowChassisFpcDetail { print STDERR " In ShowChassisFpcDetail: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - / Temperature:/ && return; - / Start time:/ && return; - / Uptime:/ && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + / Temperature:/ && next; + / Start time:/ && next; + / Uptime:/ && next; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show chassis hardware" sub ShowChassisHardware { print STDERR " In ShowChassisHardware: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show chassis routing-engine" sub ShowChassisRoutingEngine { print STDERR " In ShowChassisRoutingEngine: $_" if ($debug); - /^Routing Engine status:/ && ProcessHistory("","","","# $_") && return; - / DRAM:/ && ProcessHistory("","","","# $_") && return; - /^\s*$/ && ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /^Routing Engine status:/ && ProcessHistory("","","","# $_") && next; + / DRAM:/ && ProcessHistory("","","","# $_") && next; + /^\s*$/ && ProcessHistory("","","","# $_") && next; + } return; } # This routine parses "show chassis scb" sub ShowChassisSCB { print STDERR " In ShowChassisSCB: $_" if ($debug); - /error: the chassis subsystem is not running/ && return; - / Temperature:/ && return; - / utilization:/ && return; - /time:/ && return; - / (IP|MLPS) routes:/ && return; - / used:/ && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /error: the chassis subsystem is not running/ && return; + / Temperature:/ && next; + / utilization:/ && next; + /time:/ && next; + / (IP|MLPS) routes:/ && next; + / used:/ && next; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show version" sub ShowVersion { print STDERR " In ShowVersionAndBlame: $_" if ($debug); - /^Juniper Networks is:/ && ProcessHistory("","","","\n$_") && return; - ProcessHistory("","","","# $_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + + /^Juniper Networks is:/ && ProcessHistory("","","","\n$_") && return; + ProcessHistory("","","","# $_"); + } return; } # This routine parses "show configuration" sub ShowConfiguration { print STDERR " In ShowConfiguration: $_" if ($debug); - /^database header mismatch: / && return(-1); - s/(\s*authentication-key ).*$/#$1;/; - ProcessHistory("","","","$_") && return; + + s/^[a-z]+@//; + ProcessHistory("","","","# $_"); + while () { + tr/\015//d; + last if(/^$prompt/); + next if (/^\s*$/); + + /^database header mismatch: / && return(-1); + s/(\s*authentication-key ).*$/#$1;/; + s/^(.*\ssecret \")\$9\$.*(\".*)$/#$1$2/; + ProcessHistory("","","","$_"); + } return; } @@ -228,39 +304,37 @@ sub ShowConfiguration { # dummy function sub DoNothing {print STDOUT;} -# Main subroutine that splits up the work -# All Subs return the name of the next function to use. -# If the sub returns a new funtion name, that name will be used -# else the main loop keeps using the current function -sub FlailHelplessly { - print STDERR "Flailing: $_" if ($debug); - print STDOUT "Flailing: $_" if ($log); - /(show chassis clocks)/ && delete($commands{$1}) && return("ShowChassisClocks"); - /(show chassis environment)/ && delete($commands{$1}) && return("ShowChassisEnvironment"); - /(show chassis firmware)/ && delete($commands{$1}) && return("ShowChassisFirmware"); - /(show chassis fpc detail)/ && delete($commands{$1}) && return("ShowChassisFpcDetail"); - /(show chassis hardware)/ && delete($commands{$1}) && return("ShowChassisHardware"); - /(show chassis routing-engine)/ && delete($commands{$1}) && return("ShowChassisRoutingEngine"); - /(show chassis scb)/ && delete($commands{$1}) && return("ShowChassisSCB"); - /(show version)/ && delete($commands{$1}) && return("ShowVersion"); - /(show configuration)/ && delete($commands{$1}) && return("ShowConfiguration"); - return "FlailHelplessly"; -} - # Main -@commands=("show chassis clocks", "show chassis environment", - "show chassis firmware", "show chassis fpc detail", - "show chassis hardware", "show chassis routing-engine", - "show chassis scb", "show version", "show configuration"); +%commands=( + "show chassis clocks" => "ShowChassisClocks", + "show chassis environment" => "ShowChassisEnvironment", + "show chassis firmware" => "ShowChassisFirmware", + "show chassis fpc detail" => "ShowChassisFpcDetail", + "show chassis hardware" => "ShowChassisHardware", + "show chassis routing-engine" => "ShowChassisRoutingEngine", + "show chassis scb" => "ShowChassisSCB", + "show version" => "ShowVersion", + "show configuration" => "ShowConfiguration" +); +@commands=( + "show chassis clocks", + "show chassis environment", + "show chassis firmware", + "show chassis fpc detail", + "show chassis hardware", + "show chassis routing-engine", + "show chassis scb", + "show version", + "show configuration" +); -foreach $c (@commands) { $commands{$c} = 1; } $jnx_commands=join(";",@commands); $cmds_regexp=join("|",@commands); -$func = FlailHelplessly; open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; +select(OUTPUT); # make OUTPUT unbuffered -select(OUTPUT); $| = 1; +if ($debug) { $| = 1; } if ($file) { print STDERR "opening file $host\n" if ($debug); @@ -269,17 +343,19 @@ if ($file) { } else { print(STDERR "executing echo jlogin -c\"$jnx_commands\" $host\n") if ($debug); print(STDOUT "executing echo jlogin -c\"$jnx_commands\" $host\n") if ($debug); - open(INPUT,"jlogin -c\"$jnx_commands\" $host $host.raw" || die "jlogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "jlogin failed for $host: $!\n"; + } else { + open(INPUT,"jlogin -c \"$jnx_commands\" $host ) { tr/\015//d; - if (/quit/) { - delete($commands{"quit"}); - $clean_run=1; - last; - } if (/^Error:/) { + s/^.*Error:/Error:/; print STDOUT ("$host jlogin error: $_"); print STDERR ("$host jlogin error: $_") if ($debug); $clean_run=0; @@ -291,17 +367,25 @@ while() { $clean_run = 0; last; } - if (/($cmds_regexp)/) { - ProcessHistory("","","","# $host> $1\n"); - $func = FlailHelplessly; + while (/>\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) {$prompt = ($_ =~ /^([^>]+>)/)[0]; } print STDERR ("HIT COMMAND:$_") if ($debug); - } else { - $rval=eval $func; + if (! defined($commands{$cmd})) { + print STDERR "found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; last; - } - $func=$rval if ($rval); + } + } + if (/>\s*quit/) { + $clean_run=1; + last; } } print STDOUT "Done jlogin: $_\n" if ($log); @@ -311,17 +395,21 @@ ProcessHistory("","","",""); close(INPUT); close(OUTPUT); +if (defined($ENV{NOPIPE})) { + unlink("$host.raw") if (! $debug); +} + # check for completeness $commands = join(", ", keys(%commands)); if (scalar(%commands) || !$clean_run) { if (scalar(%commands)) { - print STDOUT "missed cmd(s): $commands\n"; - print STDERR "missed cmd(s): $commands[0]\n" if ($debug); + 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) { - print STDOUT "End of run not found - removing $host.new\n"; - print STDERR "End of run not found - removing $host.new\n" if ($debug); + 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"; + unlink "$host.new" if (! $debug); } diff --git a/bin/rancid b/bin/rancid index 9b346fe..cd0cb8c 100755 --- a/bin/rancid +++ b/bin/rancid @@ -28,7 +28,7 @@ $file = $opt_f; $host = $ARGV[0]; $clean_run = 0; $found_end = 0; -$timeo = 90; # clogin time in seconds +$timeo = 90; # clogin timeout in seconds # This routine is used to print out the router configuration sub ProcessHistory { @@ -89,8 +89,8 @@ sub valsort{ local($i) = 0; local(@sorted_lines); foreach $key (sort values %lines) { - $sorted_lines[$i] = $key; - $i++; + $sorted_lines[$i] = $key; + $i++; } @sorted_lines; } @@ -133,113 +133,141 @@ sub sortbyipaddr { # This routine parses "show version" sub ShowVersion { print STDERR " In ShowVersion: $_" if ($debug); - if (/^Slave in slot (\d+) is running/) { - $slave = " Slave:"; - return; - } - /^IOS .* Software \(([A-Za-z-0-9]*)\), .*Version\s+(.*)$/ && - ProcessHistory("COMMENTS","keysort","F1","!Image:$slave Software: $1, $2\n") && return; - /^([A-Za-z-0-9_]*) Synced to mainline version: (.*)$/ && - ProcessHistory("COMMENTS","keysort","F2", - "!Image:$slave $1 Synced to mainline version: $2\n") && return; - /^Compiled (.*)$/ && - ProcessHistory("COMMENTS","keysort","F3","!Image:$slave Compiled: $1\n") && return; - /^ROM: (System )?Bootstrap.*(Version.*)$/ && - ProcessHistory("COMMENTS","keysort","G1","!ROM Bootstrap: $2\n") && return; - /^ROM: \d+ Bootstrap .*(Version.*)$/ && - ProcessHistory("COMMENTS","keysort","G2","!ROM Image: Bootstrap$1\n") && - return; - /^ROM: .*(Version.*)$/ && - ProcessHistory("COMMENTS","keysort","G3","!ROM Image: $1\n") && return; - /^BOOTFLASH: .*(Version.*)$/ && - ProcessHistory("COMMENTS","keysort","G4","!BOOTFLASH: $1\n") && return; - /^System image file is "([^\"]*)", booted via (\S*)/ && + + while () { + 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") && - return; - /^System image file is "([^\"]*)"$/ && - ProcessHistory("COMMENTS","keysort","F5","!Image: $1\n") && - return; - if (/(\S+)\s+\((\S+)\)\s+processor.*with (\S+K) bytes/) { - if ( $1 eq "CSC") { - $type = "AGS"; - } elsif ( $1 eq "CSC4") { - $type = "AGS+"; - } elsif ( $1 eq "RSP1") { - $type = "7500"; - } elsif ( $1 eq "RSP2") { - $type = "7500"; - } elsif ( $1 eq "RSP4") { - $type = "7500"; - } elsif ( $1 eq "RSP7000") { - $type = "7500"; - } elsif ( $1 eq "RP1") { - $type = "7000"; - } elsif ( $1 eq "RP") { - $type = "7000"; - } elsif ( $1 eq "7202" || $1 eq "7204" || $1 eq "7206") { - $type = "7200"; - } elsif ($1 eq "12004/GRP" || $1 eq "12008/GRP" || $1 eq "12012/GRP") { - $type = "12000"; - } else { - $type = $1; + 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 "RSP7000") { + $type = "7500"; + } elsif ( $1 =~ /RSP\d/) { + $type = "7500"; + } elsif ( $1 eq "RP1") { + $type = "7000"; + } elsif ( $1 eq "RP") { + $type = "7000"; + } elsif ( $1 eq "7202" || $1 eq "7204" || $1 eq "7206") { + $type = "7200"; + } elsif ($1 eq "12004/GRP" || $1 eq "12008/GRP" || $1 eq "12012/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 (/^Configuration register is (.*)$/) { + $config_register=$1; + next; } - print STDERR "TYPE = $type\n" if ($debug); - ProcessHistory("COMMENTS","keysort","A1","!Chassis type:$slave $1 - a $type router\n"); - ProcessHistory("COMMENTS","keysort","B1","!Memory:$slave main $3\n"); - ProcessHistory("COMMENTS","keysort","A3","!CPU:$slave $2\n"); - return; - } - 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; - return; - } - /^(\d+K) bytes of multibus/ && - ProcessHistory("COMMENTS","keysort","B2","!Memory: multibus $1\n") && return; - /^(\d+K) bytes of non-volatile/ && - ProcessHistory("COMMENTS","keysort","B3","!Memory: nvram $1\n") && return; - /^(\d+K) bytes of flash memory/ && - ProcessHistory("COMMENTS","keysort","B5","!Memory: flash $1\n") && - return; - /^(\d+K) bytes of .*flash partition/ && - ProcessHistory("COMMENTS","keysort","B6","!Memory: flash partition $1\n") && - return; - /^(\d+K) bytes of Flash internal/ && - ProcessHistory("COMMENTS","keysort","B4","!Memory: bootflash $1\n") && - return; - /^(\d+K) bytes of Flash PCMCIA card at slot 0 / && - ProcessHistory("COMMENTS","keysort","B7","!Memory: pcmcia slot0 $1\n") && return; - /^(\d+K) bytes of Flash PCMCIA card at slot 1 / && - ProcessHistory("COMMENTS","keysort","B8","!Memory: pcmcia slot1 $1\n") && return; - if (/^Configuration register is (.*)$/) { - $config_register=$1; - return; } - return; + return(0); } # This routine parses "show env all" sub ShowEnv { # Skip if this is not a 7500 or 7000. print STDERR " In ShowEnv: $_" if ($debug); - return 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"); - return; + + while () { + 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; } - /^\s*(Power .*)/ && - ProcessHistory("COMMENTS","keysort","E1","!Power: $1\n") && return; - /^\s*(Lower Power .*)/i && - ProcessHistory("COMMENTS","keysort","E2","!Power: $1\n") && return; - return; + ProcessHistory("COMMENTS","","","!\n"); + return(0); } # This routine parses "show gsr chassis-info" for the gsr @@ -247,135 +275,153 @@ sub ShowEnv { sub ShowGSR { # Skip if this is not a 1200n. print STDERR " In ShowGSR: $_" if ($debug); - return if ($type !~ /^120/); - /^$/ && return; - /^\s+Chassis: type (\S+) Fab Ver: (\S+)/ && - ProcessHistory("COMMENTS","keysort","D0","!\n") && - ProcessHistory("COMMENTS","keysort","D1","!GSR Chassis type: $1 Fab Ver: $2\n") && return; - /^\s+Chassis S\/N: (.*)$/ && - ProcessHistory("COMMENTS","keysort","D2","!GSR Chassis S/N: $1\n") && return; - /^\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") && return; - /^\s+Backplane S\/N: (\S+)$/ && - ProcessHistory("COMMENTS","keysort","D4","!GSR Backplane S/N: $1\n") && return; - return; + while () { + 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/7500/12000; otherwise pick up bootflash. print STDERR " In ShowBoot: $_" if ($debug); - return if /^\s*$/; - return if /^\s*\^\s*$/; - return if /Invalid input detected/; - return if /(Open device \S+ failed|Error opening \S+:)/; - if (!defined($H0)) {$H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n");} - if ($type !~ /^(1200|7)/) { - ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); - } elsif (/variable/) { - ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + + while () { + 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 /(Open device \S+ failed|Error opening \S+:)/; + next if /CONFGEN variable/; + if (!defined($H0)) { + $H0=1; ProcessHistory("COMMENTS","keysort","H0","!\n"); + } + if ($type !~ /^(1200|7)/) { + ProcessHistory("COMMENTS","keysort","H2","!BootFlash: $_"); + } elsif (/variable/) { + ProcessHistory("COMMENTS","keysort","H1","!Variable: $_"); + } } - return; + 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); - return if /^\s*$/; - return if ($type =~ /^(1200|7.0)/); - return if /^\s*\^\s*$/; - return if /Invalid input detected/; - ProcessHistory("FLASH","","","!Flash: $_"); - return; -} - -# This routine parses "dir /all bootflash:" -sub DirBootflash { - # Skip if this is not a 7000, 7200, 7500, or 12000. - print STDERR " In DirBootflash: $_" if ($debug); - return if /^\s*$/; - return if ($type !~ /^(1200|7.0)/); - return if /^\s*\^\s*$/; - return if /Invalid input detected/; - /: device being squeezed/ && return(-1); # Flash is busy - return if /(Open device \S+ failed|Error opening \S+:)/; - ProcessHistory("FLASH","","","!Flash: BootFlash: $_"); - return; -} -# This routine parses "dir /all slot0:" -sub DirSlot0 { - # Skip if this is not a 3600, 7000, 7200, 7500, or 12000. - print STDERR " In DirSlot0: $_" if ($debug); - return if /^\s*$/; - return if ($type !~ /^(1200|7.0|36.0)/); - return if /^\s*\^\s*$/; - return if /Invalid input detected/; - /: device being squeezed/ && return(-1); # Flash is busy - return if /(Open device \S+ failed|Error opening \S+:)/; - ProcessHistory("FLASH","","","!Flash: Slot0: $_"); + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type =~ /^(1200|7.0)/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + ProcessHistory("FLASH","","","!Flash: $_"); + } + ProcessHistory("","","","!\n"); return; } -# This routine parses "dir /all slot1:" -sub DirSlot1 { +# 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 DirSlot1: $_" if ($debug); - return if /^\s*$/; - return if ($type !~ /^(1200|7.0|36.0)/); - return if /^\s*\^\s*$/; - return if /Invalid input detected/; - /: device being squeezed/ && return(-1); # Flash is busy - return if /(Open device \S+ failed|Error opening \S+:)/; - ProcessHistory("FLASH","","","!Flash: Slot1: $_"); - return; + print STDERR " In DirSlotN: $_" if ($debug); + + my($dev) = (/\s([^\s]+):/); + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^(1200|7.0|36.0)/); + return(1) if /^\s*\^\s*$/; + return(1) if /Invalid input detected/; + 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); - return if ($type =~ /^(1200|7[05])/); - if (/^Interface (\S*)$/) { $INT = "$1, "; return; } - /^(BRI unit \d)/ && - ProcessHistory("INT","","","!Interface: $1\n") && return; - /^LANCE unit \d, NIM/ && - ProcessHistory("INT","","","!Interface: $_") && return; - /^(LANCE unit \d)/ && - ProcessHistory("INT","","","!Interface: $1\n") && return; - /(Media Type is \S+),/ && - ProcessHistory("INT","","","!\t$1\n"); - if (/(M\dT:) show controller:$/) { - my($ctlr) = $1; - $_ = ; tr/\015//d; s/ subunit \d,//; - ProcessHistory("INT","","","!Interface: $ctlr $_"); - } - /^(HD unit \d), idb/ && - ProcessHistory("INT","","","!Interface: $1\n") && return; - /^HD unit \d, NIM/ && - ProcessHistory("INT","","","!Interface: $_") && return; - /^buffer size \d+ HD unit \d, (.*)/ && - ProcessHistory("INT","","","!\t$1\n") && return; - /^AM79970 / && ProcessHistory("INT","","","!Interface: $_") && return; - /^buffer size \d+ (Universal Serial: .*)/ && - ProcessHistory("INT","","","!\t$1\n") && return; - /^Hardware is (.*)/ && - ProcessHistory("INT","","","!Interface: $INT$1\n") && return; - /^(QUICC Serial unit \d),/ && - ProcessHistory("INT","","","!$1\n") && return; - /^QUICC Ethernet .*/ && - ProcessHistory("INT","","","!$_") && return; - /^DTE .*\.$/ && - ProcessHistory("INT","","","!\t$_") && return; - /^(cable type :.*),/ && - ProcessHistory("INT","","","!\t$1\n") && return; - /^(.* cable.*), received clockrate \d+$/ && - ProcessHistory("INT","","","!\t$1\n") && return; - /^.* cable.*$/ && - ProcessHistory("INT","","","!\t$_") && return; - return; + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type =~ /^(1200|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; + $_ = ; 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" @@ -383,37 +429,43 @@ sub ShowContAll { sub ShowContCbus { # Skip if this is not a 7000 or 7500. print STDERR " In ShowContCbus: $_" if ($debug); - return 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"); - return; - } 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"); - return; + + while () { + 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; + return(0); } # This routine parses "show diagbus" @@ -421,73 +473,84 @@ sub ShowContCbus { sub ShowDiagbus { # Skip if this is not a 7000, 70[01]0, or 7500. print STDERR " In ShowDiagbus: $_" if ($debug); - return if ($type !~ /^7[05]/); - if (/^\s*Slot (\d+):/i) { - $slot = $1; - return; - } elsif (/^\s*Slot (\d+) \(virtual\):/i) { - $slot = $1; - return; - } 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) { + + while () { + 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; - } - # 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") + $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}); - return; - } - /Serial number: (\S+)\s*Part number: (\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: part $2, serial $1\n") && return; - /^\s*Controller Memory Size: (.*)$/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: $1\n") && - return; - 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"; + ProcessHistory("SLOT","","","!Slot $slot/$board: $hwbuf{$slot}\n") if (defined $hwbuf{$slot}); + next; } - return; - } - /\s+(.*) PA, (\d) ports?, (\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: type $3, $2 ports\n") && return; - /\s+(.*) PA( \(\S+\))?, (\d) ports?/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: type $1$2, $3 ports\n") && return; - /^\s*HW rev (\S+), Board revision (\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: hvers $1 rev $2\n") && return; - /Serial number: (\S+)\s*Part number: (\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot/$board: part $2, serial $1\n") && return; - return; + /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 diags" for the gsr, 7200, 3600 @@ -495,75 +558,84 @@ sub ShowDiagbus { sub ShowDiags { # Skip if this is not a 12000. print STDERR " In ShowDiags: $_" if ($debug); - return if ($type !~ /^(1200|720|36.0)/); - /^$/ && return; - 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/); - return; - } - if (/^\s+PCA:\s+(.*)/){ - local($part) = $1; - $_ = ; - /^\s+HW version (\S+)\s+S\/N (\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot/PCA: part $part, serial $2\n") && + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^(1200|720|36.0)/); + /^$/ && 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; + $_ = ; + /^\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"); - return; - } + next; + } - if (/^\s+MBUS: .*\)\s+(.*)/) { - local($tmp) = "!Slot $slot/MBUS: part $1"; - $_ = ; - /^\s+HW version (\S+)\s+S\/N (\S+)/ && - ProcessHistory("SLOT","","","$tmp, serial $2\n") && + if (/^\s+MBUS: .*\)\s+(.*)/) { + local($tmp) = "!Slot $slot/MBUS: part $1"; + $_ = ; + /^\s+HW version (\S+)\s+S\/N (\S+)/ && + ProcessHistory("SLOT","","","$tmp, serial $2\n") && ProcessHistory("SLOT","","","!Slot $slot/MBUS: hvers $1\n"); - return; - } - 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"); - return; - } - if (/^\s+DRAM size: (\d+)/) { - local($dram) = $1 / 1048576; - $_ = ; - /^\s+FrFab SDRAM size: (\d+)/ && - ProcessHistory("SLOT","","","!Slot $slot/MBUS: $dram Mbytes DRAM, " + 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; + $_ = ; + /^\s+FrFab SDRAM size: (\d+)/ && + ProcessHistory("SLOT","","","!Slot $slot/MBUS: $dram Mbytes DRAM, " . $1 / 1024 . " Kbytes SDRAM\n!\n"); - return; - } - # 7200 and 3600 stuff - if (/^(Slot) (\d+):/ || /^\s+(WIC) Slot (\d):/) { - if ($1 eq "WIC") { - $WIC = "/$2"; - } else { - $slot = $2; - undef($WIC); + next; } - $_ = ; 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+(.*)\s+port adapter?,\s+(\d+)\s+/ && - ProcessHistory("SLOT","","","!Slot $slot: type $1, $2 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"); - return; - } - /revision\s+(\S+).*revision\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot$WIC: hvers $1 rev $2\n") && return; - /number\s+(\S+)\s+Part number\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot $slot$WIC: part $2, serial $1\n!\n") && return; - return; + # 7200 and 3600 stuff + if (/^(Slot) (\d+):/ || /^\s+(WIC) Slot (\d):/) { + if ($1 eq "WIC") { + $WIC = "/$2"; + } else { + $slot = $2; + undef($WIC); + } + $_ = ; 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+(.*)\s+port adapter?,\s+(\d+)\s+/ && + ProcessHistory("SLOT","","","!Slot $slot: type $1, $2 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 @@ -571,173 +643,212 @@ sub ShowDiags { sub ShowC7200 { # Skip if this is not a 7200. print STDERR " In ShowC7200: $_" if ($debug); - return if ($type !~ /^72/); - /^$/ && return; - if (/C7200 Midplane EEPROM:/) { - $_ = ; - /revision\s+(\S+).*revision\s+(\S+)/; - ProcessHistory("SLOT","","","!Slot Midplane: hvers $1 rev $2\n"); - $_ = ; - /number\s+(\S+)\s+Part number\s+(\S+)/; - ProcessHistory("SLOT","","","!Slot Midplane: part $2, serial $1\n!\n"); - return; - } - if (/C7200 CPU EEPROM:/) { - $_ = ; - /revision\s+(\S+).*revision\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot CPU: hvers $1 rev $2\n"); - $_ = ; - /number\s+(\S+)\s+Part number\s+(\S+)/ && - ProcessHistory("SLOT","","","!Slot CPU: part $2, serial $1\n!\n"); - return; + + while () { + tr/\015//d; + last if (/^$prompt/); + next if (/^(\s*|\s*$cmd\s*)$/); + return(1) if ($type !~ /^72/); + /^$/ && next; + if (/C7200 Midplane EEPROM:/) { + $_ = ; + /revision\s+(\S+).*revision\s+(\S+)/; + ProcessHistory("SLOT","","","!Slot Midplane: hvers $1 rev $2\n"); + $_ = ; + /number\s+(\S+)\s+Part number\s+(\S+)/; + ProcessHistory("SLOT","","","!Slot Midplane: part $2, serial $1\n!\n"); + next; + } + if (/C7200 CPU EEPROM:/) { + $_ = ; + /revision\s+(\S+).*revision\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot CPU: hvers $1 rev $2\n"); + $_ = ; + /number\s+(\S+)\s+Part number\s+(\S+)/ && + ProcessHistory("SLOT","","","!Slot CPU: part $2, serial $1\n!\n"); + next; + } } - return; + return(0); } # This routine processes a "write term" sub WriteTerm { print STDERR " In WriteTerm: $_" if ($debug); - /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked - # skip the crap - if (/^(##+$|Building configuration...)/i) { - while () { - next if (/^Current configuration:/i); - next if (/^([%!].*|\s*)$/); - next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S - last; + + while () { + 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 () { + next if (/^Current configuration:/i); + next if (/^([%!].*|\s*)$/); + next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S + last; + } + ProcessHistory("","","","!\nconfig-register $config_register\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 + /^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 \n") && + next; + /^(username .*) password \d *(\S)\s*(.*)/ && + ProcessHistory("USER","","","!$1 password \n") && next; + /^\s*password / && + ProcessHistory("LINE-PASS","","","! password \n") && next; + /^\s*neighbor (\S*) password / && + ProcessHistory("","","","! neighbor $1 password \n") && + next; + /fair-queue individual-limit/ && next; + # sort route-maps + if (/^route-map ([^ ]+)/) { + my($key) = $1; + my($routemap) = $_; + while () { + tr/\015//d; + last if (/^$prompt/ || ! /^(route-map |[ !])/); + if (/^route-map ([^ ]+)/) { + 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\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 \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); } - ProcessHistory("","","","!\nconfig-register $config_register\n"); - tr/\015//d; - } - # Dog gone Cool matches to process the rest of the config - /^tftp-server flash / && return; # kill and tftp remains - /^ntp clock-period / && return; # kill ntp clock-period - /^ length / && return; # kill length on serial lines - /^ width / && return; # kill width on serial lines - /^enable password / && - ProcessHistory("ENABLE","","","!enable password \n") && - return; - /^(username .*) password \d *(\S)\s*(.*)/ && - ProcessHistory("USER","","","$1 password \n") && - return; - /^\s*password / && - ProcessHistory("LINE-PASS","","","! password \n") && - return; - /^\s*neighbor (\S*) password / && - ProcessHistory("","","","! neighbor $1 password \n") && - return; - /fair-queue individual-limit/ && return; - # 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","$_") && return; - # order extended access-lists - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && - ProcessHistory("EACL $1 $2","ipsort","$3","$_") && return; - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && - ProcessHistory("EACL $1 $2","ipsort","$3","$_") && return; - /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && - ProcessHistory("EACL $1 $2","ipsort","0.0.0.0","$_") && return; - /^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") - && return; - # order logging statements - /^logging (\d+\.\d+\.\d+\.\d+)/ && - ProcessHistory("LOGGING","ipsort","$1","$_") && return; - # order name-server statements - /^ip name-server (\d+\.\d+\.\d+\.\d+)/ && - ProcessHistory("NAMESERVER","ipsort","$1","$_") && return; - # order snmp-server host statements - /^snmp-server host (\d+\.\d+\.\d+\.\d+)/ && - ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_") && return; - /^snmp-server community / && - ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && return; - # order tacacs server statements - /^tacacs-server host (\d+\.\d+\.\d+\.\d+)/ && - ProcessHistory("TAC","ipsort","$1","$_") && return; - # order clns host statements - /^clns host \S+ (\S+)/ && ProcessHistory("CLNS","keysort","$1","$_") && return; - # order alias statements - /^alias / && ProcessHistory("ALIAS","keysort","$_","$_") && return; - # delete ntp auth password - /^(ntp authentication-key \d+ md5) / && - ProcessHistory("","","","!$1 \n") && return; - # 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,"$_"); - return; - } - # order ip host line statements - /^ip host line(\d+)/ && - ProcessHistory("IPHOST","numsort","$1","$_") && return; - # order ip nat source static statements - /^ip nat (\S+) source static (\S+)/ && - ProcessHistory("IP NAT $1","ipsort","$2","$_") && return; - # order atm map-list statements - /^\s+ip\s+(\d+\.\d+\.\d+\.\d+)\s+atm-vc/ && - ProcessHistory("ATM map-list","ipsort","$1","$_") && return; - # order ip rcmd lines - /^ip rcmd/ && ProcessHistory("RCMD","keysort","$_","$_") && return; - ProcessHistory("","","","$_"); - # end of config - if (/^end$/) { - $found_end = 1; - return "FlailHelplessly"; } - return; + return(0); } # dummy function sub DoNothing {print STDOUT;} -# Main subroutine that splits up the work -# All Subs return the name of the next function to use. -# If the sub returns a new funtion name, that name will be used -# else the main loop keeps using the current function -sub FlailHelplessly { - print STDERR "Flailing: $_" if ($debug); - print STDOUT "Flailing: $_" if ($log); - /#(show version)$/ && delete($commands{$1}) && return("ShowVersion"); - /#(show env all)$/ && delete($commands{$1}) && return("ShowEnv"); - /#(show gsr chassis)$/ && delete($commands{$1}) && return("ShowGSR"); - /#(show boot.*)$/ && delete($commands{$1}) && return("ShowBoot"); - /#(show flash)$/ && delete($commands{$1}) && - (ProcessHistory("FLASH","","","!\n"),return("ShowFlash")); - /#(dir \/all bootflash\:)$/ && delete($commands{$1}) && - (ProcessHistory("FLASH","","","!\n"), return("DirBootflash")); - /#(dir \/all slot0\:)$/ && delete($commands{$1}) && - (ProcessHistory("FLASH","","","!\n"),return("DirSlot0")); - /#(dir \/all slot1\:)$/ && delete($commands{$1}) && - (ProcessHistory("FLASH","","","!\n"),return("DirSlot1")); - # These three generate a list of the hw. - # There are a few variable created in ShowContCbus - # That are printed out in ShowDiagbus. - /#(show controllers cbus)$/ && delete($commands{$1}) && return("ShowContCbus"); - /#(show controllers)$/ && delete($commands{$1}) && return("ShowContAll"); - /#(show diagbus)$/ && delete($commands{$1}) && return("ShowDiagbus"); - /#(show diag)$/ && delete($commands{$1}) && return("ShowDiags"); - /#(show c7200)$/ && delete($commands{$1}) && return("ShowC7200"); - /#(write term)$/ && delete($commands{$1}) && return("WriteTerm"); - return "FlailHelplessly"; -} - # Main -@commands=("show version","show env all","show gsr chassis", - "show boot","show bootvar","show flash","dir /all bootflash:", - "dir /all slot0:", "dir /all slot1:","show controllers", - "show controllers cbus", "show diagbus","show diag","show c7200", - "write term"); - -foreach $c (@commands) { $commands{$c} = 1; } +%commands=( + 'show version' => "ShowVersion", + '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' => "ShowDiags", + '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 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); -$func = FlailHelplessly; open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; -# make OUTPUT unbuffered -select(OUTPUT); $| = 1; +select(OUTPUT); +# make OUTPUT unbuffered if debugging +if ($debug) { $| = 1; } if ($file) { print STDERR "opening file $host\n" if ($debug); @@ -746,9 +857,12 @@ if ($file) { } 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); - open(INPUT,"clogin -t $timeo -c\"$cisco_cmds\" $host $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 ) { $clean_run=1; last; } - if (/^Error:/) { + if (/Error:/) { + s/^.*Error:/Error:/; print STDOUT ("$host clogin error: $_"); print STDERR ("$host clogin error: $_") if ($debug); $clean_run=0; last; } - if (/#\s*($cmds_regexp)/) { - $func = FlailHelplessly; + while (/#\s*($cmds_regexp)\s*$/) { + $cmd = $1; + if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; } print STDERR ("HIT COMMAND:$_") if ($debug); - } else { - $rval=eval $func; + if (! defined($commands{$cmd})) { + print STDERR "found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); if ($rval == -1) { $clean_run = 0; last; - } - $func=$rval if ($rval); + } } } print STDOUT "Done $logincmd: $_\n" if ($log); @@ -785,16 +905,20 @@ ProcessHistory("","","",""); 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)) { - print STDOUT "missed cmd(s): $commands\n"; - print STDERR "missed cmd(s): $commands[0]\n" if ($debug); + 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 - removing $host.new\n"; - print STDERR "End of run not found - removing $host.new\n" if ($debug); + 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"; + unlink "$host.new" if (! $debug); } diff --git a/bin/rancid-fe b/bin/rancid-fe index e3dc94e..8dab8a5 100755 --- a/bin/rancid-fe +++ b/bin/rancid-fe @@ -21,12 +21,18 @@ # usage: rancid-fe : # +require 5; + ($router, $vendor) = split('\:', $ARGV[0]); if ($vendor =~ /^cisco$/i) { exec('rancid', $router); } elsif ($vendor =~ /^juniper$/i) { exec('jrancid', $router); +} elsif ($vendor =~ /^foundry$/i) { + exec('francid', $router); +} elsif ($vendor =~ /^redback$/i) { + exec('rrancid', $router); } printf(STDERR "unknown router manufacturer for $router: $vendor\n"); diff --git a/bin/rrancid b/bin/rrancid new file mode 100755 index 0000000..40113aa --- /dev/null +++ b/bin/rrancid @@ -0,0 +1,347 @@ +#!/usr/local/bin/perl +## +## hacked version of Hank's rancid - this one tries to deal with redbacks. +## +## 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 "dir /" +sub DirFlash { + print STDERR " In DirFlash: $_" if ($debug); + + my($dev) = (/\/(.*)$/); + while () { + tr/\015//d; + last if(/^$prompt/); + /^\s*$/ && next; + + /(Can\'t open|No such device)/ && return; + ProcessHistory("FLASH","keysort",$dev,"!Flash: $dev: $_"); + } + ProcessHistory("FLASH","keysort",$dev,"!\n"); + return; +} + +# This routine parses "show hardware" +sub ShowHardware { + print STDERR " In ShowHardware: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + s/\s*$/\n/; + + #ProcessHistory("","","","!Chassis: $_") && next; + ProcessHistory("COMMENTS","keysort","B1","!Chassis: $_"); + } + ProcessHistory("COMMENTS","keysort","B1","!\n"); + return; +} + +# This routine parses "show version" +sub ShowVersion { + print STDERR " In ShowVersion: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + + /(uptime|restarted|^\s*$)/ && next; + ProcessHistory("COMMENTS","keysort","A1","!Image: $_"); + } + return; +} + +# This routine parses "show slot table" +sub ShowSlotTable { + print STDERR " In ShowSlotTable: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + + /(Slot Table|^$)/ && next; + s/^\s*//; + ProcessHistory("COMMENTS","keysort","D1","!Slot Table: $_"); + } + ProcessHistory("COMMENTS","keysort","D1","!\n"); + return; +} + +# This routine processes a "write term" +sub WriteTerm { + print STDERR " In WriteTerm: $_" if ($debug); + + while () { + tr/\015//d; + last if(/^$prompt/); + +# /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked + # Dog gone Cool matches to process the rest of the config + /^! last updated: .*$/ && next; # kill last updated line + /^ length / && next; # kill length on serial lines + /^ width / && next; # kill width on serial lines + # 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; + ProcessHistory("","","","$_"); + # end of config + if (/^end$/) { + $found_end = 1; + last; + } + } + return; +} + +# dummy function +sub DoNothing {print STDOUT;} + +# Main subroutine that splits up the work +# All Subs return the name of the next function to use. +# If the sub returns a new funtion name, that name will be used +# else the main loop keeps using the current function +sub FlailHelplessly { + print STDERR "Flailing: $_" if ($debug); + print STDOUT "Flailing: $_" if ($log); + /#(show hardware)$/ && delete($commands{$1}) && return("ShowHardware"); + /#(show version)$/ && delete($commands{$1}) && return("ShowVersion"); + /#(show slot table)$/ && delete($commands{$1}) && return("ShowSlotTable"); + /#(show config)$/ && delete($commands{$1}) && return("WriteTerm"); + return "FlailHelplessly"; +} + +# Main +%commands=( + 'show version' => "ShowVersion", + "dir /flash" => "DirFlash", + "dir /pcmcia0" => "DirFlash", + "dir /pcmcia1" => "DirFlash", + 'show hardware' => "ShowHardware", + 'show slot table' => "ShowSlotTable", + 'show config' => "WriteTerm" +); +@commands=( + "show version", + "dir /flash", + "dir /pcmcia0", + "dir /pcmcia1", + "show hardware", + "show slot table", + "show config" +); +# dir /flash +# dir /pcmcia0 +# dir /pcmcia1 + +$redback_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 ($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 \"$redback_cmds\" $host $host.raw" || die "clogin failed for $host: $!\n"; + open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; + } else { + open(INPUT,"clogin -t $timeo -c \"$redback_cmds\" $host ) { + tr/\015//d; + if (/\#exit$/) { + $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)) { + $prompt = ($_ =~ /^([^#]*#)/)[0]; + $prompt =~ s/([][])/\\$1/g; # quote the damn []'s + } + print STDERR ("HIT COMMAND:$_") if ($debug); + if (! defined($commands{$cmd})) { + print STDERR "found unexpected command - \"$cmd\"\n"; + $clean_run = 0; + last; + } + $rval = &{$commands{$cmd}}; + delete($commands{$cmd}); + if ($rval == -1) { + $clean_run = 0; + last; + } + } +} +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); +} diff --git a/bin/run-me b/bin/run-me deleted file mode 100755 index b17d850..0000000 --- a/bin/run-me +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -ENVFILE="`dirname $0`/env" - -. $ENVFILE - -if [ $# -lt 1 ]; then - DOME="$LIST_OF_GROUPS" -else - DOME="$*" -fi - -for GROUP in $DOME -do - - LOCKFILE=/tmp/.$GROUP.run.lock - - ( - echo starting: `date` - echo - - if [ -f $LOCKFILE ] - then - echo hourly cisco diffs failed: $LOCKFILE exists - /bin/ls -l $LOCKFILE - else - /usr/bin/touch $LOCKFILE - control_rancid $GROUP - /bin/rm -f $LOCKFILE - fi - - echo - echo ending: `date` - ) >$BASEDIR/logs/$GROUP.`date +%Y%m%d.%H%M%S` 2>&1 -done -- cgit