1#!/usr/local/bin/perl 2## 3## @PACKAGE@ @VERSION@ 4## Copyright (c) @COPYYEARS@ by Henry Kilmer and John Heasley 5## All rights reserved. 6## 7## This code is derived from software contributed to and maintained by 8## Henry Kilmer, John Heasley, Andrew Partan, 9## Pete Whiting, Austin Schutz, and Andrew Fort. 10## 11## Redistribution and use in source and binary forms, with or without 12## modification, are permitted provided that the following conditions 13## are met: 14## 1. Redistributions of source code must retain the above copyright 15## notice, this list of conditions and the following disclaimer. 16## 2. Redistributions in binary form must reproduce the above copyright 17## notice, this list of conditions and the following disclaimer in the 18## documentation and/or other materials provided with the distribution. 19## 3. Neither the name of RANCID nor the names of its 20## contributors may be used to endorse or promote products derived from 21## this software without specific prior written permission. 22## 23## THIS SOFTWARE IS PROVIDED BY Henry Kilmer, John Heasley AND CONTRIBUTORS 24## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS 27## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33## POSSIBILITY OF SUCH DAMAGE. 34## 35## It is the request of the authors, but not a condition of license, that 36## parties packaging or redistributing RANCID NOT distribute altered versions 37## of the etc/rancid.types.base file nor alter how this file is processed nor 38## when in relation to etc/rancid.types.conf. The goal of this is to help 39## suppress our support costs. If it becomes a problem, this could become a 40## condition of license. 41# 42# The expect login scripts were based on Erik Sherk's gwtn, by permission. 43# 44# The original looking glass software was written by Ed Kern, provided by 45# permission and modified beyond recognition. 46# 47# hacked version of Hank's rancid - this one tries to deal with Xirrus arrays. 48# 49# RANXID - Really Awesome New Xirrus confIg Differ 50# 51# usage: xirancid [-dltCV] [-f filename | hostname] 52# 53use Getopt::Std; 54getopts('dflt:CV'); 55if ($opt_V) { 56 print "@PACKAGE@ @VERSION@\n"; 57 exit(0); 58} 59$log = $opt_l; 60$debug = $opt_d; 61$file = $opt_f; 62$host = $ARGV[0]; 63$clean_run = 0; 64$timeo = 90; # xilogin timeout in seconds 65 66my(@commandtable, %commands, @commands);# command lists 67my($filter_commstr); # SNMP community string filtering 68my($filter_osc); # oscillating data filtering mode 69my($filter_pwds); # password filtering mode 70 71# This routine is used to print out the router configuration 72sub ProcessHistory { 73 my($new_hist_tag,$new_command,$command_string,@string) = (@_); 74 if ((($new_hist_tag ne $hist_tag) || ($new_command ne $command)) 75 && scalar(%history)) { 76 print eval "$command \%history"; 77 undef %history; 78 } 79 if (($new_hist_tag) && ($new_command) && ($command_string)) { 80 if ($history{$command_string}) { 81 $history{$command_string} = "$history{$command_string}@string"; 82 } else { 83 $history{$command_string} = "@string"; 84 } 85 } elsif (($new_hist_tag) && ($new_command)) { 86 $history{++$#history} = "@string"; 87 } else { 88 print "@string"; 89 } 90 $hist_tag = $new_hist_tag; 91 $command = $new_command; 92 1; 93} 94 95# This routine parses "show config" 96sub ShowConfig { 97 print STDERR " In ShowConfig: $_\n" if ($debug); 98 99 while (<INPUT>) { 100 tr/\015//d; 101 last if (/^$prompt/); 102 next if (/^(\s*|\s*$cmd\s*)$/); 103 ProcessHistory("","","","$_"); 104 } 105 return(0); 106} 107 108# Main 109@commandtable = ( 110 {'show boot-env' => "ShowConfig"}, 111 {'show running-config inc-defaults' => "ShowConfig"} 112); 113# Use an array to preserve the order of the commands and a hash for mapping 114# commands to the subroutine and track commands that have been completed. 115@commands = map(keys(%$_), @commandtable); 116%commands = map(%$_, @commandtable); 117$commandcnt = scalar(keys %commands); 118 119$xirrus_cmds=join(";",@commands); 120$cmds_regexp = join("|", map quotemeta($_), @commands); 121 122if (length($host) == 0) { 123 if ($file) { 124 print(STDERR "Too few arguments: file name required\n"); 125 exit(1); 126 } else { 127 print(STDERR "Too few arguments: host name required\n"); 128 exit(1); 129 } 130} 131if ($opt_C) { 132 print "xilogin -t $timeo -c\'$xirrus_cmds\' $host\n"; 133 exit(0); 134} 135open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; 136select(OUTPUT); 137# make OUTPUT unbuffered if debugging 138if ($debug) { $| = 1; } 139 140if ($file) { 141 print(STDERR "opening file $host\n") if ($debug || $log); 142 open(INPUT,"<$host") || die "open failed for $host: $!\n"; 143} else { 144 print(STDERR "executing xilogin -t $timeo -c\"$xirrus_cmds\" $host\n") if ($debug || $log); 145 system "xilogin -t $timeo -c \"$xirrus_cmds\" $host </dev/null > $host.raw 2>&1" || die "xilogin failed for $host: $!\n"; 146 open(INPUT, "< $host.raw") || die "xilogin failed for $host: $!\n"; 147} 148 149# determine community string filtering mode 150if (defined($ENV{"NOCOMMSTR"}) && 151 ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) { 152 $filter_commstr = 1; 153} else { 154 $filter_commstr = 0; 155} 156# determine oscillating data filtering mode 157if (defined($ENV{"FILTER_OSC"}) && $ENV{"FILTER_OSC"} =~ /no/i) { 158 $filter_osc = 0; 159} else { 160 $filter_osc = 1; 161} 162# determine password filtering mode 163if ($ENV{"FILTER_PWDS"} =~ /no/i) { 164 $filter_pwds = 0; 165} elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { 166 $filter_pwds = 2; 167} else { 168 $filter_pwds = 1; 169} 170 171ProcessHistory("","","","!RANCID-CONTENT-TYPE: xirrus\n!\n"); 172TOP: while(<INPUT>) { 173 tr/\015//d; 174 if (/^end/) { 175 $clean_run=1; 176 last; 177 } 178 if (/^Error:/) { 179 print STDOUT ("$host xilogin error: $_"); 180 print STDERR ("$host xilogin error: $_") if ($debug); 181 $clean_run=0; 182 last; 183 } 184 while (/[>#]\s*($cmds_regexp)\s*$/) { 185 $cmd = $1; 186 if (!defined($prompt)) { 187 $prompt = ($_ =~ /^([^:]+:)/)[0]; 188 } 189 print STDERR ("HIT COMMAND:$_") if ($debug); 190 if (! defined($commands{$cmd})) { 191 print STDERR "$host: found unexpected command - \"$cmd\"\n"; 192 $clean_run = 0; 193 last TOP; 194 } 195 $rval = &{$commands{$cmd}}(*INPUT, *OUTPUT, $cmd); 196 delete($commands{$cmd}); 197 if ($rval == -1) { 198 $clean_run = 0; 199 last TOP; 200 } 201 } 202} 203print STDOUT "Done $logincmd: $_\n" if ($log); 204# Flush History 205ProcessHistory("","","",""); 206# Cleanup 207close(INPUT); 208close(OUTPUT); 209 210unlink("$host.raw") if (! $debug); 211 212# check for completeness 213if (scalar(%commands) || !$clean_run ) { 214 if (scalar(keys %commands) eq $commandcnt) { 215 printf(STDERR "$host: missed cmd(s): all commands\n"); 216 } elsif (scalar(%commands)) { 217 my($count, $i) = 0; 218 for ($i = 0; $i < $#commands; $i++) { 219 if ($commands{$commands[$i]}) { 220 if (!$count) { 221 printf(STDERR "$host: missed cmd(s): %s", $commands[$i]); 222 } else { 223 printf(STDERR ", %s", $commands[$i]); 224 } 225 $count++; 226 } 227 } 228 if ($count) { 229 printf(STDERR "\n"); 230 } 231 } 232 if (!$clean_run) { 233 print(STDERR "$host: End of run not found\n"); 234 if ($debug) { 235 print(STDERR "$host: clean_run is false\n") if (!$clean_run); 236 } 237 system("/usr/bin/tail -1 $host.new"); 238 } 239 unlink "$host.new" if (! $debug); 240} 241