From owner-rancid-discuss Fri Mar 30 07:06:00 2001 Return-Path: Received: from localhost (localhost [[UNIX: localhost]]) by guelah.shrubbery.net (8.11.0/8.11.1) id f2U6ZLW28634 for rancid-discuss-outgoing; Fri, 30 Mar 2001 06:35:21 GMT Received: from bnc.powerup.com.au (bnc.webcentral.com.au [202.139.236.123]) by guelah.shrubbery.net (8.11.0/8.11.1) with ESMTP id f2U6Ylc28620 for ; Fri, 30 Mar 2001 06:34:47 GMT Received: by bnc.webcentral.com.au with Internet Mail Service (5.5.2650.21) id ; Fri, 30 Mar 2001 16:34:42 +1000 Message-ID: <415DD4BF903BD311A3D900A0C99F902209606A75@bnc.webcentral.com.au> From: Andrew Fort To: rancid-discuss@guelah.shrubbery.net Cc: Andrew Fort Subject: RE: alogin, arancid, anyone? Date: Fri, 30 Mar 2001 16:34:38 +1000 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2650.21) Content-Type: multipart/mixed; boundary="----_=_NextPart_000_01C0B8E3.7E286F40" Sender: owner-rancid-discuss@shrubbery.net Precedence: bulk Status: RO X-Status: A Content-Length: 28522 Lines: 937 This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_000_01C0B8E3.7E286F40 Content-Type: text/plain; charset="iso-8859-1" Okay, I've got a working arancid/alogin for testing, based on rancid-2.1 (2.1 final, not 2.1b). At the moment, it only does a measley '/info/sys' and a '/cfg/dump'. If you notice any other useful info that should go into the CVS, please let me know what commmand you use to get that (perhaps the iSD-SSL stuff, I dont have one of those) and some sample output if it's from something other than a SLB-software AD3. Please note, I would expect this will stall the rancid processes every now and then when it comes across input it doesn't expect. If you notice it do so (check the logs), can you send me what input is causing to stall? (and if the same occurs with alogin alone, let me know this also). The following is a patch against the rancid-2.1 source. Rename the dir to rancid-2.1-alteon, then apply the patch from the /usr/local/src dir, if you extracted your source into /usr/local/src (patch -p0 < patchfile). In addition, you need to take the two files attached and place them in the /usr/local/src/rancid-2.1-alteon/bin dir. Then run autoconf in /usr/local/src/rancid-2.1-alteon directory, then configure. The only files that have changed are alogin, arancid (new) and rancid-fe (changed), so install them manually if you like. If doing a 'make install', backup your $PREFIX/bin/env first. To use it, add hosts to the relevant groups router.db files like so: csw4.bne:alteon:up and place a .cloginrc entry like so add password csw4.bne {adminpass} The password needs to be the 'administrator' level user password (the only userlevel who is allowed to /cfg/dump). I haven't tested with ssh yet; it probably doesn't work at this point, even if you have a client which sends a SSH_VERSION that the 8.1 series SSH software likes (it doesn't like SSH-1.5-OpenBSD.* , for instance, in 8.1.18-SSH). RADIUS auth is likely broken also - I dont use a radius server so I may require some help in testing this, or someone who can hack it to work from my patches. If you run into any other problems, or have badly handled input problems, please let me know. Also, please let me know what hardware it does run on out of the box- I've only tested on the AD3, but a 180 series I hope it would work fine running 8.x software. It may even work on an old AceSwitch 110 running 4.x software for all i know. I'm on holidays for the next week (yay), the best way to reach me is at afort at choqolat.org the patch: diff -ru rancid-2.1/bin/rancid-fe.in rancid-2.1-alteon/bin/rancid-fe.in --- rancid-2.1/bin/rancid-fe.in Tue Feb 6 03:47:12 2001 +++ rancid-2.1-alteon/bin/rancid-fe.in Fri Mar 30 13:58:21 2001 @@ -37,6 +37,8 @@ exec('francid', $router); } elsif ($vendor =~ /^redback$/i) { exec('rrancid', $router); +} elsif ($vendor =~ /^alteon$/i) { + exec('arancid', $router); } printf(STDERR "unknown router manufacturer for $router: $vendor\n"); diff -ru rancid-2.1/configure rancid-2.1-alteon/configure --- rancid-2.1/configure Mon Jan 29 09:06:27 2001 +++ rancid-2.1-alteon/configure Fri Mar 30 13:58:21 2001 @@ -1508,7 +1508,7 @@ # RD_BIN_PROGS are bin/ .in's that need to be installed with execute perms. RD_BIN_PROGS="cat5rancid control_rancid \ -clogin create_cvs do-diffs elogin erancid \ +alogin arancid clogin create_cvs do-diffs elogin erancid \ flogin francid jlogin jrancid par rancid-fe \ rancid rename rrancid" diff -ru rancid-2.1/configure.in rancid-2.1-alteon/configure.in --- rancid-2.1/configure.in Mon Jan 29 09:04:44 2001 +++ rancid-2.1-alteon/configure.in Fri Mar 30 13:58:21 2001 @@ -157,7 +157,7 @@ # RD_BIN_PROGS are bin/ .in's that need to be installed with execute perms. RD_BIN_PROGS="cat5rancid control_rancid \ -clogin create_cvs do-diffs elogin erancid \ +alogin arancid clogin create_cvs do-diffs elogin erancid \ flogin francid jlogin jrancid par rancid-fe \ rancid rename rrancid" AC_SUBST(RD_BIN_PROGS) > Hi, > > I've hacked an alogin - for the Alteon WebOS switches (i'm > testing it using > Alteon AceDirector 3's), but I haven't gotten around to > modifying up all the > regexp parsers to make the 'arancid'. > > Has anyone already done this? > ------_=_NextPart_000_01C0B8E3.7E286F40 Content-Type: application/octet-stream; name="alogin.in" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="alogin.in" #!@EXPECT_PATH@ --=0A= ##=0A= ##=0A= ## Copyright (C) 1997 by Henry Kilmer, Erik Sherk and Pete Whiting.=0A= ## All rights reserved.=0A= ##=0A= ## This software may be freely copied, modified and redistributed = without=0A= ## fee for non-commerical purposes provided that this copyright notice = is=0A= ## preserved intact on all copies and modified copies.=0A= ##=0A= ## There is no warranty or other guarantee of fitness of this = software.=0A= ## It is provided solely "as is". The author(s) disclaim(s) all=0A= ## responsibility and liability with respect to this software's = usage=0A= ## or its effect upon hardware, computer systems, other software, or=0A= ## anything else.=0A= ##=0A= ##=0A= #=0A= # alogin - Alteon WebOS switch login=0A= #=0A= # afort@choqolat.org is responsible for this particular mess=0A= # (andrew fort) =0A= #=0A= =0A= # Usage line=0A= set usage "Usage: $argv0 \[-c command\]\=0A= \[-f cloginrc-file\]\=0A= \[-s script-file\] \[-t timeout\] \[-u username\]\=0A= \[-v vty-password\] \[-x command-file\]\=0A= \[-y ssh_cypher_type\] router \[router...\]\n"=0A= =0A= # env(CLOGIN) may contain:=0A= # x =3D=3D do not set xterm banner or name=0A= =0A= # Password file=0A= set password_file $env(HOME)/.cloginrc=0A= # Default is to login to the router=0A= set do_command 0=0A= set do_script 0=0A= # The default is to automatically enable=0A= set enable 1=0A= # The default is that you login non-enabled (tacacs can have you login = already enabled)=0A= set autoenable 0=0A= # The default is to look in the password file to find the passwords. = This=0A= # tracks if we receive them on the command line.=0A= set do_passwd 1=0A= =0A= # Find the user in the ENV, or use the unix userid.=0A= if {[ info exists env(CISCO_USER) ] } {=0A= set default_user $env(CISCO_USER)=0A= } elseif {[ info exists env(USER) ]} {=0A= set default_user $env(USER)=0A= } else {=0A= # This uses "id" which I think is portable. At least it has = existed=0A= # (without options) on all machines/OSes I've been on recently -=0A= # unlike whoami or id -nu.=0A= if [ catch {exec id} reason ] {=0A= send_error "Error: could not exec id: $reason\n"=0A= exit 1=0A= } =0A= regexp {\(([^)]*)} "$reason" junk default_user=0A= } =0A= =0A= # Sometimes routers take awhile to answer (the default is 10 sec)=0A= set timeout 45=0A= =0A= # Process the command line=0A= for {set i 0} {$i < $argc} {incr i} {=0A= set arg [lindex $argv $i]=0A= =0A= switch -glob -- $arg {=0A= # Username=0A= -u* -=0A= -U* {=0A= if {! [ regexp .\[uU\](.+) $arg ignore user]} {=0A= incr i=0A= set username [ lindex $argv $i ]=0A= }=0A= # VTY Password=0A= } -v* -=0A= -v* {=0A= if {! [ regexp .\[vV\](.+) $arg ignore passwd]} {=0A= incr i=0A= set passwd [ lindex $argv $i ]=0A= }=0A= set do_passwd 0=0A= # Enable Username=0A= } -w* -=0A= -W* {=0A= # ignore -w=0A= # Enable Password=0A= } -e* -=0A= -E* {=0A= # ignore -e=0A= # Command to run.=0A= } -c* -=0A= -C* {=0A= if {! [ regexp .\[cC\](.+) $arg ignore command]} {=0A= incr i=0A= set command [ lindex $argv $i ]=0A= }=0A= set do_command 1=0A= # Expect script to run.=0A= } -s* -=0A= -S* {=0A= if {! [ regexp .\[sS\](.+) $arg ignore sfile]} {=0A= incr i=0A= set sfile [ lindex $argv $i ]=0A= }=0A= if { ! [ file readable $sfile ] } {=0A= send_user "Error: Can't read $sfile\n"=0A= exit 1=0A= }=0A= set do_script 1=0A= # 'ssh -c' cypher type=0A= } -y* -=0A= -Y* {=0A= if {! [ regexp .\[eE\](.+) $arg ignore cypher]} {=0A= incr i=0A= set cypher [ lindex $argv $i ]=0A= }=0A= # alternate cloginrc file=0A= } -f* -=0A= -F* {=0A= if {! [ regexp .\[fF\](.+) $arg ignore password_file]} {=0A= incr i=0A= set password_file [ lindex $argv $i ]=0A= }=0A= # Timeout=0A= } -t* -=0A= -T* {=0A= if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {=0A= incr i=0A= set timeout [ lindex $argv $i ]=0A= }=0A= # Command file=0A= } -x* -=0A= -X {=0A= if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {=0A= incr i=0A= set cmd_file [ lindex $argv $i ]=0A= }=0A= set cmd_fd [open $cmd_file r]=0A= set cmd_text [read $cmd_fd]=0A= close $cmd_fd=0A= set command [join [split $cmd_text \n] \;]=0A= set do_command 1=0A= # Do we enable?=0A= } -noenable {=0A= # ignore -noenable=0A= # Does tacacs automatically enable us?=0A= } -autoenable {=0A= # ignore -autoenable=0A= } -* {=0A= send_user "Error: Unknown argument! $arg\n"=0A= send_user $usage=0A= exit 1=0A= } default {=0A= break=0A= }=0A= }=0A= }=0A= # Process routers...no routers listed is an error.=0A= if { $i =3D=3D $argc } {=0A= send_user "Error: $usage"=0A= }=0A= =0A= # Only be quiet if we are running a script (it can log its output=0A= # on its own)=0A= if { $do_script } {=0A= log_user 0=0A= } else {=0A= log_user 1=0A= }=0A= =0A= #=0A= # Done configuration/variable setting. Now run with it...=0A= #=0A= =0A= # Sets Xterm title if interactive...if its an xterm and the user = cares=0A= proc label { host } {=0A= global env=0A= # if CLOGIN has an 'x' in it, don't set the xterm name/banner=0A= if [info exists env(CLOGIN)] {=0A= if {[string first "x" $env(CLOGIN)] !=3D -1} { return }=0A= }=0A= # take host from ENV(TERM)=0A= if [info exists env(TERM)] {=0A= if [regexp \^(xterm|vs) $env(TERM) ignore ] {=0A= send_user "\033]1;[lindex [split $host "."] 0]\a"=0A= send_user "\033]2;$host\a"=0A= }=0A= }=0A= }=0A= =0A= # This is a helper function to make the password file easier to=0A= # maintain. Using this the password file has the form:=0A= # add password sl* pete cow=0A= # add password at* steve=0A= # add password * hanky-pie=0A= proc add {var args} { global int_$var ; lappend int_$var $args}=0A= proc include {args} {=0A= global env=0A= regsub -all "(^{|}$)" $args {} args=0A= if { [ regexp "^/" $args ignore ] =3D=3D 0 } {=0A= set args $env(HOME)/$args=0A= }=0A= source_password_file $args=0A= }=0A= =0A= proc find {var router} {=0A= upvar int_$var list=0A= if { [info exists list] } {=0A= foreach line $list {=0A= if { [string match [lindex $line 0] $router ] } {=0A= return [lrange $line 1 end]=0A= }=0A= }=0A= }=0A= return {}=0A= }=0A= =0A= =0A= # Loads the password file. Note that as this file is tcl, and that=0A= # it is sourced, the user better know what to put in there, as it=0A= # could install more than just password info... I will assume = however,=0A= # that a "bad guy" could just as easy put such code in the clogin=0A= # script, so I will leave .cloginrc as just an extention of that = script=0A= proc source_password_file { password_file } {=0A= global env=0A= if { ! [file exists $password_file] } {=0A= send_user "Error: password file ($password_file) does not exist\n"=0A= exit 1=0A= }=0A= file stat $password_file fileinfo=0A= if { [expr ($fileinfo(mode) & 007)] !=3D 0000 } {=0A= send_user "Error: $password_file must not be world = readable/writable\n"=0A= exit 1=0A= }=0A= if [ catch {source $password_file} reason ] {=0A= send_user "Error: $reason\n"=0A= exit 1=0A= }=0A= }=0A= =0A= =0A= # Log into the router.=0A= proc login { router user userpswd passwd prompt cmethod cyphertype } = {=0A= global spawn_id in_proc do_command do_script=0A= global u_prompt p_prompt=0A= set in_proc 1=0A= set tryssh 1=0A= =0A= # try each of the connection methods in $cmethod until one is = successful=0A= set progs [llength $cmethod]=0A= foreach prog [lrange $cmethod 0 end] {=0A= if ![string compare $prog "telnet"] {=0A= if [ catch {spawn telnet $router} reason ] {=0A= send_user "Error: telnet failed: $reason\n"=0A= exit 1=0A= }=0A= } elseif ![string compare $prog "ssh"] {=0A= if [ catch {spawn ssh -c $cyphertype -x -l $user $router} = reason ] {=0A= send_user "Error: ssh failed: $reason\n"=0A= exit 1=0A= }=0A= } elseif ![string compare $prog "rsh"] {=0A= if [ catch {spawn rsh -l $user $router} reason ] {=0A= send_user "Error: rsh failed: $reason\n"=0A= exit 1=0A= }=0A= } else {=0A= puts "ERROR: unknown connection method: $prog"=0A= return 1=0A= }=0A= incr progs -1=0A= sleep 0.3=0A= =0A= # This helps cleanup each expect clause.=0A= expect_after {=0A= timeout {=0A= send_user "\nError: TIMEOUT reached\n"=0A= catch {close}; wait=0A= if { $in_proc} {=0A= return 1=0A= } else {=0A= continue=0A= }=0A= } eof {=0A= send_user "\nError: EOF received\n"=0A= catch {close}; wait=0A= if { $in_proc} {=0A= return 1=0A= } else {=0A= continue=0A= }=0A= }=0A= }=0A= =0A= expect {=0A= "Connection refused" {=0A= close; wait=0A= sleep 0.3=0A= expect eof=0A= send_user "Error: Connection Refused\n"; wait; return 1=0A= } eof { send_user "Error: Couldn't login\n"; wait; return 1=0A= } "Unknown host\r\n" {=0A= expect eof=0A= send_user "Error: Unknown host\n"; wait; return 1=0A= } "Host is unreachable" {=0A= expect eof=0A= send_user "Error: Host Unreachable!\n"; wait; return 1=0A= } "No address associated with name" {=0A= expect eof=0A= send_user "Error: Unknown host\n"; wait; return 1=0A= }=0A= -re "$u_prompt" { send "$user\r"=0A= expect {=0A= "Login incorrect" { send_user "Error: Couldn't login\n";=0A= catch {close}; wait; return 1 }=0A= eof { send_user "Error: Couldn't login\n"; wait; return 1 }=0A= -re "$p_prompt" { send "$userpswd\r" }=0A= "$prompt" { set in_proc 0; return 0 }=0A= }=0A= exp_continue=0A= }=0A= -re "$p_prompt" { send "$passwd\r"=0A= expect {=0A= "Password incorrect" { send_user "Error: Couldn't login\n";=0A= catch {close}; wait; return 1 }=0A= eof { send_user "Error: Couldn't login\n"; wait; return 1 }=0A= "$prompt" { set in_proc 0; return 0 }=0A= "Confirm seeing above note" { send "y\r" }=0A= }=0A= exp_continue=0A= }=0A= -re "^Confirm seeing above note" { send "y\r" }=0A= "Password incorrect" { send_user "Error: Check your password for = $router\n";=0A= catch {close}; wait; return 1 }=0A= "$prompt" { }=0A= denied { send_user "Error: Check your passwd for $router\n"=0A= if { $do_command || $do_script } {=0A= send "exit\r"=0A= wait=0A= return 1=0A= } else {=0A= return 1=0A= }=0A= }=0A= "\r\n" { exp_continue; }=0A= }=0A= set in_proc 0=0A= return 0=0A= }=0A= }=0A= =0A= # Run commands given on the command line.=0A= proc run_commands { prompt command } {=0A= global in_proc=0A= set in_proc 1=0A= =0A= send "lines 0\r"=0A= expect $prompt {}=0A= =0A= regsub -all "\[)(]" $prompt {\\&} reprompt=0A= =0A= # Is this a multi-command?=0A= if [ string match "*\;*" "$command" ] {=0A= set commands [split $command \;]=0A= set num_commands [llength $commands]=0A= =0A= for {set i 0} {$i < $num_commands} { incr i} {=0A= send "[subst -nocommands [lindex $commands $i]]\r"=0A= expect {=0A= -re "^\[^\n\r]*$reprompt." {}=0A= -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }=0A= -re "\[\n\r]" { exp_continue }=0A= }=0A= }=0A= } else {=0A= send "[subst -nocommands $command]\r"=0A= expect {=0A= -re "^\[^\n\r]*$reprompt." {}=0A= -re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }=0A= -re "\[\n\r]" { exp_continue }=0A= }=0A= }=0A= send "exit\r"=0A= expect {=0A= -re "^WARNING: There are unsaved configuration changes."=0A= {=0A= send "y\r"=0A= exp_continue=0A= }=0A= "\n" { exp_continue }=0A= "\[^\n\r *]*Session terminated" { return 0 }=0A= timeout { return 0 }=0A= eof { return 0 }=0A= }=0A= set in_proc 0=0A= }=0A= =0A= #=0A= # For each router... (this is main loop)=0A= #=0A= source_password_file $password_file=0A= set in_proc 0=0A= foreach router [lrange $argv $i end] {=0A= set router [string tolower $router]=0A= send_user "$router\n"=0A= =0A= # Figure out prompt.=0A= set prompt "#"=0A= set autoenable 1=0A= set enable 0=0A= =0A= # Figure out passwords=0A= if { $do_passwd } {=0A= set pswd [find password $router]=0A= if { [llength $pswd] =3D=3D 0 } {=0A= send_user "Error - no password for $router in $password_file.\n"=0A= continue=0A= }=0A= set passwd [lindex $pswd 0]=0A= }=0A= =0A= # Figure out username=0A= if {[info exists username]} {=0A= # command line username=0A= set ruser $username=0A= } else {=0A= set ruser [find user $router]=0A= if { "$ruser" =3D=3D "" } { set ruser $default_user }=0A= }=0A= =0A= # Figure out username's password (if different from the vty = password)=0A= if {[info exists userpasswd]} {=0A= # command line username=0A= set userpswd $userpasswd=0A= } else {=0A= set userpswd [find userpassword $router]=0A= if { "$userpswd" =3D=3D "" } { set userpswd $passwd }=0A= }=0A= =0A= # Figure out prompts=0A= set u_prompt [find userprompt $router]=0A= if { "$u_prompt" =3D=3D "" } { set u_prompt "(Username|login| = Login):" }=0A= set p_prompt [find passprompt $router]=0A= if { "$p_prompt" =3D=3D "" } { set p_prompt "\[Pp]assword:" }=0A= =0A= # Figure out cypher type=0A= if {[info exists cypher]} {=0A= # command line cypher type=0A= set cyphertype $cypher=0A= } else {=0A= set cyphertype [find cyphertype $router]=0A= if { "$cyphertype" =3D=3D "" } { set cyphertype "3des" }=0A= }=0A= =0A= # Figure out connection method=0A= set cmethod [find method $router]=0A= if { "$cmethod" =3D=3D "" } { set cmethod {{telnet} {ssh}} }=0A= =0A= # Login to the router=0A= if {[login $router $ruser $userpswd $passwd $prompt $cmethod = $cyphertype]} {=0A= continue=0A= }=0A= =0A= if { $do_command } {=0A= if {[run_commands $prompt $command]} {=0A= continue=0A= }=0A= } elseif { $do_script } {=0A= send "lines 0\r"=0A= expect $prompt {}=0A= source $sfile=0A= close=0A= } else {=0A= label $router=0A= log_user 1=0A= interact=0A= }=0A= =0A= # End of for each router=0A= wait=0A= sleep 0.3=0A= }=0A= exit 0=0A= ------_=_NextPart_000_01C0B8E3.7E286F40 Content-Type: application/octet-stream; name="arancid.in" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="arancid.in" #!@PERLV_PATH@=0A= ##=0A= ## Hacked version of rancid for Alteon WebOS switches =0A= ## tested with: ad3 v8.1.18=0A= ## afort@choqolat.org (andrew fort)=0A= ##=0A= ##=0A= ## Copyright (C) 1997 by Henry Kilmer.=0A= ## All rights reserved.=0A= ##=0A= ## This software may be freely copied, modified and redistributed = without=0A= ## fee for non-commerical purposes provided that this copyright notice = is=0A= ## preserved intact on all copies and modified copies.=0A= ##=0A= ## There is no warranty or other guarantee of fitness of this = software.=0A= ## It is provided solely "as is". The author(s) disclaim(s) all=0A= ## responsibility and liability with respect to this software's = usage=0A= ## or its effect upon hardware, computer systems, other software, or=0A= ## anything else.=0A= ##=0A= ##=0A= #=0A= # RANCID - Really Awesome New Cisco confIg Differ=0A= # =0A= # arancid - Alteon WebOS plugin for rancid=0A= #=0A= # usage: arancid [-d] [-l] [-f filename | $host]=0A= #=0A= use Getopt::Std;=0A= getopts('dflm');=0A= $log =3D $opt_l;=0A= $debug =3D $opt_d;=0A= $file =3D $opt_f;=0A= $host =3D $ARGV[0];=0A= $clean_run =3D 0;=0A= $found_end =3D 0;=0A= $prompt =3D "#";=0A= $timeo =3D 90; # clogin timeout in seconds=0A= =0A= # This routine is used to print out the router configuration=0A= sub ProcessHistory {=0A= my($new_hist_tag,$new_command,$command_string,@string)=3D(@_);=0A= if((($new_hist_tag ne $hist_tag) || ($new_command ne $command))=0A= && defined %history) {=0A= print eval "$command \%history";=0A= undef %history;=0A= }=0A= if (($new_hist_tag) && ($new_command) && ($command_string)) {=0A= if ($history{$command_string}) {=0A= $history{$command_string} =3D = "$history{$command_string}@string";=0A= } else {=0A= $history{$command_string} =3D "@string";=0A= }=0A= } elsif (($new_hist_tag) && ($new_command)) {=0A= $history{++$#history} =3D "@string";=0A= } else {=0A= print "@string";=0A= }=0A= $hist_tag =3D $new_hist_tag;=0A= $command =3D $new_command;=0A= 1;=0A= }=0A= =0A= sub numerically { $a <=3D> $b; }=0A= =0A= # This is a sort routing that will sort numerically on the=0A= # keys of a hash as if it were a normal array.=0A= sub keynsort {=0A= local(%lines)=3D@_;=0A= local($i) =3D 0;=0A= local(@sorted_lines);=0A= foreach $key (sort numerically keys(%lines)) {=0A= $sorted_lines[$i] =3D $lines{$key};=0A= $i++;=0A= }=0A= @sorted_lines;=0A= }=0A= =0A= # This is a sort routing that will sort on the=0A= # keys of a hash as if it were a normal array.=0A= sub keysort {=0A= local(%lines)=3D@_;=0A= local($i) =3D 0;=0A= local(@sorted_lines);=0A= foreach $key (sort keys(%lines)) {=0A= $sorted_lines[$i] =3D $lines{$key};=0A= $i++;=0A= }=0A= @sorted_lines;=0A= }=0A= =0A= # This is a sort routing that will sort on the=0A= # values of a hash as if it were a normal array.=0A= sub valsort{=0A= local(%lines)=3D@_;=0A= local($i) =3D 0;=0A= local(@sorted_lines);=0A= foreach $key (sort values %lines) {=0A= $sorted_lines[$i] =3D $key;=0A= $i++;=0A= }=0A= @sorted_lines;=0A= }=0A= =0A= # This is a numerical sort routing (ascending).=0A= sub numsort {=0A= local(%lines)=3D@_;=0A= local($i) =3D 0;=0A= local(@sorted_lines);=0A= foreach $num (sort {$a <=3D> $b} keys %lines) {=0A= $sorted_lines[$i] =3D $lines{$num};=0A= $i++;=0A= }=0A= @sorted_lines;=0A= }=0A= =0A= # This is a sort routine that will sort on the=0A= # ip address when the ip address is anywhere in=0A= # the strings.=0A= sub ipsort {=0A= local(%lines)=3D@_;=0A= local($i) =3D 0;=0A= local(@sorted_lines);=0A= foreach $addr (sort sortbyipaddr keys %lines) {=0A= $sorted_lines[$i] =3D $lines{$addr};=0A= $i++;=0A= }=0A= @sorted_lines;=0A= }=0A= =0A= # These two routines will sort based upon IP addresses=0A= sub ipaddrval {=0A= my(@a) =3D ($_[0] =3D~ m#^(\d+)\.(\d+)\.(\d+)\.(\d+)$#);=0A= $a[3]+256*($a[2]+256*($a[1]+256*$a[0]));=0A= }=0A= sub sortbyipaddr {=0A= &ipaddrval($a) <=3D> &ipaddrval($b);=0A= }=0A= =0A= # This routine parses "/info/sys" (cf. show version)=0A= sub ShowVersion {=0A= print STDERR " In ShowVersion: $_" if ($debug);=0A= =0A= while () {=0A= tr/\015//d;=0A= last if (/^>>.*$prompt/);=0A= next if(/^(\s*|\s*$cmd\s*)$/); =0A= =0A= /^(ACEdirector.*|ACEswitch.*|Alteon.*)/i && =0A= ProcessHistory("COMMENTS","keysort","A1", "\/\*Model: $1\n") && = next;=0A= /^Software Version\s+(.*?)\s\((.*)\)/i &&=0A= ProcessHistory("COMMENTS","keysort","B1", "\/\*Image: Software: $1 = ($2)\n") && next;=0A= /^Hardware Part No:\s+(.*?)\s+/i &&=0A= ProcessHistory("COMMENTS","keysort","A2", "\/\*Hardware part no: = $1\n") && next;=0A= /^MAC = address:\s+([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:= [0-9a-f]{2})/i &&=0A= ProcessHistory("COMMENTS","keysort","C1", "\/\*Base MAC address: = $1\n") && next; =0A= }=0A= return(0);=0A= }=0A= =0A= # This routine processes a "/cfg/dump"=0A= sub WriteTerm {=0A= print STDERR " In WriteTerm: $_" if ($debug);=0A= =0A= # eat the header line=0A= #$junk =3D ;=0A= =0A= # now just copy it verbatim to the history file=0A= while () {=0A= tr/\015//d;=0A= last if(/^>>.*$prompt/);=0A= chop;=0A= print $ENV{'NOCOMMSTR'};=0A= /(rcomm|wcomm|t1com|t2com)(\s+)(.*)/ && =0A= ProcessHistory("","","","\/\*\t$1$2\"\"\n") && next;=0A= #if (/^\s*snmp/ && defined($ENV{'NOCOMMSTR'})) {=0A= # /snmp (getcomm|setcomm|trapcomm)(\s+)(\S*)/ &&=0A= # ProcessHistory("","","","- snmp $1$2\"\"\n") && = next;=0A= #}=0A= next if (/^\/\* Configuration dump taken/i);=0A= next if (/^\/\* Version.*Base MAC.*/i);=0A= =0A= if (/^\/script end/) { =0A= $found_end =3D 1; =0A= ProcessHistory("","","","$_\n");=0A= return(1);=0A= }=0A= =0A= ProcessHistory("","","","$_\n");=0A= }=0A= return(0);=0A= }=0A= =0A= # dummy function=0A= sub DoNothing {print STDOUT;}=0A= =0A= # Main=0A= %commands=3D(=0A= '/info/sys' =3D> "ShowVersion",=0A= '/cfg/dump' =3D> "WriteTerm",=0A= );=0A= # keys() doesnt return things in the order entered and the order of = the=0A= # cmds is important (show version first and write term last). pita=0A= @commands=3D(=0A= "/info/sys",=0A= "/cfg/dump",=0A= );=0A= $cisco_cmds=3Djoin(";",@commands);=0A= $cmds_regexp=3Djoin("|",@commands);=0A= =0A= open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: = $!\n";=0A= select(OUTPUT);=0A= # make OUTPUT unbuffered if debugging=0A= if ($debug) { $| =3D 1; }=0A= =0A= if ($file) {=0A= print STDERR "opening file $host\n" if ($debug);=0A= print STDOUT "opening file $host\n" if ($log);=0A= open(INPUT,"<$host") || die "open failed for $host: $!\n";=0A= } else {=0A= print STDERR "executing alogin -t $timeo -c\"$cisco_cmds\" $host\n" = if ($debug);=0A= print STDOUT "executing alogin -t $timeo -c\"$cisco_cmds\" $host\n" = if ($log);=0A= if (defined($ENV{NOPIPE})) {=0A= system "alogin -t $timeo -c \"$cisco_cmds\" $host = $host.raw 2>&1" || die "alogin failed for $host: $!\n";=0A= open(INPUT, "< $host.raw") || die "alogin failed for $host: $!\n";=0A= } else {=0A= open(INPUT,"alogin -t $timeo -c \"$cisco_cmds\" $host ) {=0A= tr/\015//d;=0A= if (/^>>.*$prompt exit/) {=0A= $clean_run=3D1;=0A= last;=0A= }=0A= =0A= while (/>>.*$prompt\s*($cmds_regexp)\s*$/) {=0A= $cmd =3D $1;=0A= if (!defined($prompt)) {$prompt =3D ($_ =3D~ /^([^#]+#)/)[0]; = }=0A= print STDERR ("HIT COMMAND:$_") if ($debug);=0A= if (!defined($commands{$cmd})) {=0A= print STDERR "found unexpected command - \"$cmd\"\n";=0A= $clean_run =3D 0;=0A= last TOP;=0A= }=0A= $rval =3D &{$commands{$cmd}};=0A= delete($commands{$cmd});=0A= if ($rval =3D=3D -1) {=0A= $clean_run =3D 0;=0A= last TOP;=0A= }=0A= }=0A= }=0A= print STDOUT "Done $logincmd: $_\n" if ($log);=0A= # Flush History=0A= ProcessHistory("","","","");=0A= # Cleanup=0A= close(INPUT);=0A= close(OUTPUT);=0A= =0A= if (defined($ENV{NOPIPE})) {=0A= unlink("$host.raw") if (! $debug);=0A= }=0A= =0A= # check for completeness=0A= if (scalar(%commands) || !$clean_run || !$found_end) {=0A= if (scalar(%commands)) {=0A= printf(STDOUT "missed cmd(s): %s\n", join(',', keys(%commands)));=0A= printf(STDERR "missed cmd(s): %s\n", join(',', keys(%commands))) if = ($debug);=0A= }=0A= if (!$clean_run || !$found_end) {=0A= print STDOUT "End of run not found\n";=0A= print STDERR "End of run not found\n" if ($debug);=0A= system("/usr/bin/tail -1 $host.new");=0A= }=0A= unlink "$host.new" if (! $debug);=0A= }=0A= ------_=_NextPart_000_01C0B8E3.7E286F40--