Package: rancid
Version: 2.3.2-1
Severity: wishlist
Tags: patch

While RANCID supposely suppports IOS XR (IOX) since 2.3.2, this support is
merely a tweak of the IOS-code, and not a proper IOS XR module.

This tweak makes things suboptimal. For example you must turn on autoenable
for all XR devices and all commands are run from "user mode" when some
commands benefits being run from "admin mode".

The introduction of an own module for IOS XR (named xrrancid) forced me to
change a couple of automake/autoconf files. This in turn makes
automake/autoconf generation a lot of new files for the build system. This
makes lintian warn about changes to files outside the patch system. My
lintian-fuu is too weak to resolve that issus.

-- System Information:
Debian Release: 5.0.3
  APT prefers stable
  APT policy: (990, 'stable'), (400, 'testing'), (300, 'unstable')
Architecture: i386 (i686)

Kernel: Linux 2.6.26-2-686 (SMP w/2 CPU cores)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=ISO-8859-1)
Shell: /bin/sh linked to /bin/bash

Versions of packages rancid depends on:
ii  adduser                  3.110           add and remove users and groups
ii  cvs                      1:1.12.13-12    Concurrent Versions System
ii  debconf [debconf-2.0]    1.5.24          Debian configuration management sy
ii  expect                   5.43.0-17       A program that can automate intera
ii  iputils-ping [ping]      3:20071127-1    Tools to test the reachability of 
ii  libc6                    2.7-18          GNU C Library: Shared libraries
ii  openssh-client           1:5.1p1-5       secure shell client, an rlogin/rsh
ii  passwd                   1:4.1.1-6       change and administer password and
ii  perl                     5.10.0-19lenny2 Larry Wall's Practical Extraction 
ii  ssh                      1:5.1p1-5       secure shell client and server (me
ii  subversion               1.5.1dfsg1-4    Advanced version control system

rancid recommends no packages.

Versions of packages rancid suggests:
ii  diffstat                      1.45-2     produces graph of changes introduc

-- debconf information:
* rancid/warning:
* rancid/go_on: true
#! /bin/sh /usr/share/dpatch/dpatch-run
## PC_iosxr.dpatch by  <per...@gmail.com>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Proper support for Cisco IOS XR devices

@DPATCH@
--- rancid-2.3.2/configure.in.orig	2009-11-12 09:24:29.000000000 +0100
+++ rancid-2.3.2/configure.in	2009-11-12 09:24:43.000000000 +0100
@@ -466,6 +466,7 @@
 AC_CONFIG_FILES(bin/tntlogin bin/tntrancid, [chmod a+x $ac_file])
 AC_CONFIG_FILES(bin/trancid, [chmod a+x $ac_file])
 AC_CONFIG_FILES(bin/xrancid, [chmod a+x $ac_file])
+AC_CONFIG_FILES(bin/xrrancid, [chmod a+x $ac_file])
 AC_CONFIG_FILES(bin/zrancid, [chmod a+x $ac_file])
 AC_CONFIG_FILES(share/rtrfilter, [chmod a+x $ac_file])
 
--- rancid-2.3.2/bin/Makefile.am.orig	2009-04-17 00:04:43.000000000 +0200
+++ rancid-2.3.2/bin/Makefile.am	2009-11-12 09:42:06.000000000 +0100
@@ -55,7 +55,7 @@
 	jerancid jlogin jrancid mrancid mrvlogin mrvrancid nlogin nrancid \
 	nslogin nsrancid nxrancid par prancid rancid-fe rancid rivlogin \
 	rivrancid rrancid srancid tlogin tntlogin tntrancid trancid xrancid \
-	zrancid
+	xrrancid zrancid
 
 bin_SCRIPTS += lg.cgi lgform.cgi rancid-cvs rancid-run
 EXTRA_DIST= lg.cgi.in lgform.cgi.in rancid-cvs.in rancid-run.in
--- rancid-2.3.2/man/rancid.1.orig	2009-11-12 09:03:05.000000000 +0100
+++ rancid-2.3.2/man/rancid.1	2009-11-12 09:03:44.000000000 +0100
@@ -101,6 +101,9 @@
 .B xrancid
 Extreme switches
 .TP
+.B xrrancid
+Cisco IOS-XR devices
+.TP
 .B zrancid
 Zebra routing software
 .PP
--- /dev/null	2009-11-09 09:44:53.507217821 +0100
+++ rancid-2.3.2/man/xrrancid.1	2009-11-12 09:04:02.000000000 +0100
@@ -0,0 +1 @@
+.so man1/rancid.1
--- rancid-2.3.2/bin/rancid-fe.in.orig	2009-11-12 15:43:33.000000000 +0100
+++ rancid-2.3.2/bin/rancid-fe.in	2009-11-12 15:44:06.000000000 +0100
@@ -58,6 +58,7 @@
     'cat5'		=> 'cat5rancid',
     'cisco'		=> 'rancid',
     'cisco-nx'		=> 'nxrancid',
+    'cisco-xr'          => 'xrrancid',
     'css'		=> 'cssrancid',
     'enterasys'		=> 'rivrancid',
     'erx'		=> 'jerancid',
--- /dev/null	2009-11-09 09:44:53.507217821 +0100
+++ rancid-2.3.2/bin/xrrancid.in	2009-11-13 13:52:16.000000000 +0100
@@ -0,0 +1,854 @@
+#! @PERLV_PATH@
+##
+## $Id$
+##
+## @PACKAGE@ @VERSION@
+## Copyright (c) 1997-2007 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This code is derived from software contributed to and maintained by
+## Terrapin Communications, Inc. by Henry Kilmer, John Heasley, Andrew Partan,
+## Pete Whiting, Austin Schutz, and Andrew Fort.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted provided that the following conditions
+## are met:
+## 1. Redistributions of source code must retain the above copyright
+##    notice, this list of conditions and the following disclaimer.
+## 2. Redistributions in binary form must reproduce the above copyright
+##    notice, this list of conditions and the following disclaimer in the
+##    documentation and/or other materials provided with the distribution.
+## 3. All advertising materials mentioning features or use of this software
+##    must display the following acknowledgement:
+##        This product includes software developed by Terrapin Communications,
+##        Inc. and its contributors for RANCID.
+## 4. Neither the name of Terrapin Communications, Inc. nor the names of its
+##    contributors may be used to endorse or promote products derived from
+##    this software without specific prior written permission.
+## 5. It is requested that non-binding fixes and modifications be contributed
+##    back to Terrapin Communications, Inc.
+##
+## THIS SOFTWARE IS PROVIDED BY Terrapin Communications, INC. AND CONTRIBUTORS
+## ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+## TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+## PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COMPANY OR CONTRIBUTORS
+## BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+## POSSIBILITY OF SUCH DAMAGE.
+# 
+#  RANCID - Really Awesome New Cisco confIg Differ
+#
+# usage: xrrancid [-dV] [-l] [-f filename | hostname]
+#
+use Getopt::Long;
+use English;
+
+my $log = 0;
+my $debug = 0;
+my $file = undef;
+my $version = 0;
+my $filter_commstr = undef;		# SNMP community string filtering
+my $filter_pwds = undef;		# password filtering mode
+
+GetOptions(
+  'debug!'       => \$debug,
+  'log!'         => \$log,
+  'file=s'       => \$file,
+  'version|V!'   => \$version,
+  'community!'   => \$filter_commstr,
+  'passwords=s'  => \$filter_pwds,
+);
+
+if ($version) {
+  print "@PACKAGE@ @vers...@\n";
+  exit(0);
+}
+
+$host = $ARGV[0];
+$clean_run = 0;
+$found_end = 0;
+$timeo = 90;			# clogin timeout in seconds
+
+my $TIMESTAMP = qr{ \A (Mon|Tue|Wed|Thu|Fri|Sat|Sun) \s* 
+		       (Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \s* \d+ }xms;
+
+# straighten up the filtering options
+# cli setting takes precedence over env setting
+
+# determine community string filtering mode
+unless (defined $filter_commstr) {
+  if (defined($ENV{"NOCOMMSTR"}) &&
+      ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) {
+    $filter_commstr = 1;
+  } 
+  else {
+    $filter_commstr = 0;
+  }
+}
+
+# determine password filtering mode
+if (defined $filter_pwds || defined $ENV{"FILTER_PWDS"}) {
+  my $str = $filter_pwds || $ENV{"FILTER_PWDS"};
+  
+  if ($str =~ /no/i) {
+    $filter_pwds = 0;
+  } 
+  elsif ($str =~ /all/i) {
+    $filter_pwds = 2;
+  } 
+  else {
+    $filter_pwds = 1;
+  }
+} 
+else {
+  $filter_pwds = 1;
+}
+
+if ($debug) {
+  print STDERR "Options:\n";
+  print STDERR " file: ", defined $file ? $file : "<undef>", "\n";
+  print STDERR " host: ", defined $host ? $host : "<undef>", "\n";
+  print STDERR " community filter is: ", $filter_commstr ? "on" : "off", "\n";
+  print STDERR " password filter is : ";
+  if ($filter_pwds == 0) {
+    print STDERR "off\n";
+  }
+  elsif ($filter_pwds == 1) {
+    print STDERR "on (limited)\n";
+  }
+  else {
+    print STDERR "on (all)\n";
+  }
+}
+
+
+my(@commandtable, %commands, @commands); # command lists
+
+# 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_stri...@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 routine 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 routine 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 routine 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 routine (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 install summary"
+sub ShowInstallSummary {
+  print STDERR "    In ShowInstallSummary: $_" if ($debug);
+  
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    next if (/^\s*$/);
+    
+    ProcessHistory("COMMENTS", "keysort", "A1", "! $_");
+  }
+  ProcessHistory("COMMENTS", "keysort", "A99", "!\n");
+  
+  return(0);
+}
+
+
+
+
+# This routine parses "show redundancy"
+sub ShowRedundancy {
+  print STDERR "    In ShowRedundancy: $_" if ($debug);
+  
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    
+    /^Node\s+(\S+).*ACTIVE/ && do { 
+      ProcessHistory("COMMENTS", "keysort", "B1", "! Node $1 is Active RP\n");
+      next;
+    };
+    
+    /^Partner node \((.*)\).*STANDBY/ && do { 
+      ProcessHistory("COMMENTS", "keysort", "B2", "! Node $1 is Standby RP\n");
+      next;
+    };
+    
+    /^Standby node.*is (.*)/ && do { 
+      ProcessHistory("COMMENTS", "keysort", "B3", "! Standby RP is $1\n"); 
+      next;
+    };
+  }
+  ProcessHistory("COMMENTS", "keysort", "B99", "!\n"); 
+  
+  return(0);
+}
+
+
+# This routine parses "dir /all ((disk|slot)N|bootflash|nvram):"
+sub DirSlotN {
+  print STDERR "    In DirSlotN: $_" if ($debug);
+  
+  my($dev) = (/\s([^\s]+):/);
+  
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    next if (/^\s*$/);
+    
+    return(1) if /^\s*\^\s*$/;
+    return(1) if /Line has invalid autocommand /;
+    return(1) if /(Invalid input detected|Type help or )/;
+    return(1) if /(No such device|Error Sending Request)/i;
+    return(1) if /\%Error: No such file or directory/;
+    return(1) if /No space information available/;
+    return(-1) if /\%Error calling/;
+    return(-1) if /(: device being squeezed|ATA_Status time out)/i; # busy
+    return(-1) if (/command authorization failed/i);
+    return(1) if /(Open device \S+ failed|Error opening \S+:)/;
+    
+    if (/.*\((\d+) bytes free\)/) {
+      my($tmp) = int($1 / (1024 * 1024));
+      s/$1 bytes free/$tmp MB free/;
+    }
+    ProcessHistory("COMMENTS", "keysort", "C1", "! $dev: $_");
+  }
+  
+  ProcessHistory("COMMENTS", "keysort", "C1", "!\n");
+  return(0);
+}
+
+
+
+# This routine parses "show platform"
+# This will create arrays for hw info.
+sub ShowPlatform {
+  print STDERR "    In ShowPlatform: $_" if ($debug);
+  
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    next if (/^\s*$/);
+    
+    ProcessHistory("COMMENTS", "keysort", "D4", "! $_");
+  }
+  ProcessHistory("COMMENTS", "keysort", "D4", "!\n");
+  
+  return(0);
+}
+
+
+
+# This routine parses "show version"
+sub ShowVersion {
+  print STDERR "    In ShowVersion: $_" if ($debug);
+  
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    next if (/^\s*$/);
+      
+    /(\S+)\s+(?:\((\S+)\)\s+processor|\(revision[^)]+\)).*\s+with (\S+k) bytes/i && do {
+      my $model = $1;
+      my $cpu   = $2 || "";
+      my $mem   = $3;
+      
+      # the next line ought to be the more specific cpu info, grab it.
+      $_ = <INPUT>;
+      if (/^$cpu processor at/i) {
+	$cpu = $_;
+	chomp($cpu);
+      }
+
+      ProcessHistory("COMMENTS", "keysort", "D1", "! Chassis: $model\n");
+      ProcessHistory("COMMENTS", "keysort", "D2", "! Memory: main $mem\n");
+      if ($cpu) {
+	ProcessHistory("COMMENTS", "keysort", "D1", "! CPU: $cpu\n");
+      }
+      next;
+    };
+
+    /^(\d+[kKmM]) bytes of non-volatile/ && do {
+      ProcessHistory("COMMENTS", "keysort", "D3", "! Memory: nvram $1\n"); 
+      next;
+    };
+
+    /^(\d+[kKmM]) bytes of (?:compact )*flash/ && do {
+      ProcessHistory("COMMENTS", "keysort", "D3", "! Memory: flash $1\n"); 
+      next;
+    };
+
+    /^(\d+[kKmM]) bytes of Flash internal/ && do {
+      ProcessHistory("COMMENTS", "keysort", "D3", "! Memory: bootflash $1\n"); 
+      next;
+    };
+
+    /^(\d+[kKmM]) bytes of hard disk/ && do {
+      ProcessHistory("COMMENTS", "keysort", "D3", "! Memory: hard disk $1\n"); 
+      next;
+    };
+
+    /^(\d+[kKmM]) bytes of ATA PCMCIA card at disk (\d+)/i && do {
+      ProcessHistory("COMMENTS", "keysort", "D3", "! Memory: pcmcia disk$2 $1\n");
+      next;
+    };
+  }
+  ProcessHistory("COMMENTS", "keysort", "D3", "!\n");
+  
+  return(0);
+}
+
+
+# This routine parses "show inventory".
+sub ShowInventory {
+  print STDERR "    In ShowInventory: $_" if ($debug);
+
+  my $key = "D6";
+
+  while (<INPUT>) {
+    tr/\015//d;
+
+    return if (/^\s*\^$/);
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if /\s*$cmd\s*$/;
+    next if (/^\s*$/);
+
+    if (/^NAME: ([^,]+), DESCR: (.*)/) {
+      my $slot = $1;
+      my $desc = $2;
+      $key = ($slot =~ /Chassi/i ? "D5" : "D6");
+      ProcessHistory("COMMENTS", "keysort", $key, "! SLOT: $slot\n");
+      ProcessHistory("COMMENTS", "keysort", $key, "! DESC: $desc\n");
+      next;
+    }
+
+    # split PID/VID/SN line
+    if (/^PID: (\S*)\s*, VID: (\S*)\s*, SN: (\S*)\s*$/) {
+      my $entries = "";
+      $entries .= "! PID : $1\n" if ($1);
+      $entries .= "! VID : $2\n" if ($2 && $2 !~ m!N/A!i);
+      $entries .= "! SN  : $3\n" if ($3);
+      ProcessHistory("COMMENTS", "keysort", $key, "$entries!\n");
+      next;
+    }
+  }
+  ProcessHistory("COMMENTS", "keysort", "D6", "!\n");
+
+  return(0);
+}
+
+
+# This routine parses "show debug"
+sub ShowDebug {
+  print STDERR "    In ShowDebug: $_" if ($debug);
+
+  my $lines = 0;
+
+  while (<INPUT>) {
+    tr/\015//d;
+    last if /^$prompt/;
+    next if /$TIMESTAMP/;
+    next if /\s*$cmd\s*$/;
+    next if (/^\s*$/);
+
+    ProcessHistory("DEBUG", "keysort", "F1", "! $_");
+    $lines++;
+  }
+
+  if ($lines) {
+    ProcessHistory("DEBUG", "keysort", "F", "!\n! DEBUG\n");
+  }
+
+  return(0);
+}
+
+
+
+# This routine processes a "write term"
+sub WriteTerm {
+  print STDERR "    In WriteTerm: $_" if ($debug);
+
+  my $mode = '';
+
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+ 
+    /Non-Volatile memory is in use/  && return(-1); # NvRAM is locked
+
+    # skip some initial crap
+    next if /^\s*Building configuration/;
+    next if /^!+\s+Last configuration/;
+    next if /^!*\s*IOS XR Configuration/;
+
+    # username/secret command
+    /^(\s*secret\s*)/ && do {
+      if ($filter_pwds >= 2) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+
+    # username/password and bgp-ne/password commands
+    /^(\s*password(?:\s+encrypted)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+
+    # system wide tacacs-key
+    /^(\s*tacacs-server key)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+
+    # per radius/tacacs-server key
+    /^(\s*key)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+    
+    
+    # services passwords
+    /^(\s*ftp client (?:anonymous-)*password (?:encrypted\s+)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+    
+    /^(\s*sftp-password (clear|password)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+    
+    /(\s*autentication-key \d+ md5 (?:encrypted\s+)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+    
+    
+    # protocols autentication
+    /^(\s*hsrp \d+ autentication)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1" . " <removed>\n"); 
+	next;
+      }
+    };
+    
+    /^(\s*vrrp \d+ text-autentication)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n"); 
+	next;
+      }
+    };
+    
+    /^(\s*ppp (?:ms-)chap password (?:encrypted\s+)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+    
+    /^(\s*ppp pap sent-username \S+ password (?:encrypted\s+)*)/ && do {
+      if ($filter_pwds >= 1) {
+	ProcessHistory("", "", "", "!$1<removed>\n");
+	next;
+      }
+    };
+    
+    /^(\s*neighbor.*password (?:encrypted\s+)*)/ && do {
+      if ($filter_pwd >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+    
+    # matches "lsp-password" and "lsp-password accept" commands
+    /^(\s*lsp-password.*(?:encrypted)*\s+)\S+(.*)/ && do {
+      if ($filter_pwd >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>$2\n");
+	next;
+      }
+    };
+    
+    /^(\s*hello-password.*(?:encrypted)*\s+)\S+(.*)/ && do {
+      if ($filter_pwd >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>$2\n");
+	next;
+      }
+    };
+    
+    /^(\s*authentication-key.*(?:encrypted\s+)*)/ && do {
+      if ($filter_pwd >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+    
+    
+    /(\s*pre-shared-key.*key)/ && do {
+      if ($filter_pwd >= 1) {
+	ProcessHistory("", "", "", "!$1 <removed>\n");
+	next;
+      }
+    };
+    
+    
+    /^\s*snmp-server host [\d\.]+/ && do {
+      if ($filter_commstr) {
+	my($line) = $MATCH;
+	my(@tokens) = split(' ', $POSTMATCH);
+	my($token);
+	while ($token = shift(@tokens)) {
+	  if ($token eq 'version') {
+	    my $ver = shift(@tokens);
+	    $line .= " version $ver"; 
+	    if ($ver eq '3') {
+	      $line .= " " . shift(@tokens);
+	    }
+	  }
+	  
+	  elsif ($token =~ /clear|encrypted|traps/) {
+	    $line .= " $token";
+	  }
+	  
+	  elsif ($token =~ /^\s*$/) {
+	    # do nothing on empty/all white-space strings
+	  }
+	  
+	  else {
+	    # ok the rest are <community> { other options }
+	    # get rid of community
+	    shift(@tokens);
+	    
+	    $line .= " " . join(' ', "<removed>", @tokens); 
+	    last;
+	  }
+	}
+	ProcessHistory("", "", "", "!$line\n");
+      } else {
+	ProcessHistory("", "", "", "$_");
+      }
+      next;
+    };
+    
+    /^(snmp-server community (?:clear|encrypted)*)\s*(\S+)/ && do {
+      if ($filter_commstr) {
+	ProcessHistory("", "", "", "!$1<removed>$POSTMATCH");
+	next;
+      } 
+      else {
+	ProcessHistory("", "", "", "$_");
+	next;
+      }
+    };
+    
+    /^end$/ && do {
+      $found_end = 1;
+      last;
+    };
+    
+    # catch anything that wasn't matched above.
+    ProcessHistory("", "", "", "$_");
+    
+  }
+  
+  ProcessHistory("", "", "", "$_");
+  return 0;
+}
+
+# dummy function
+sub DoNothing {
+  print STDERR "    In DoNothing: $_" if ($debug);
+
+  while (<INPUT>) {
+    tr/\015//d;
+    last if (/^$prompt/);
+    next if /$TIMESTAMP/;
+    next if (/\s*$cmd\s*$/);
+    next if (/^\s*$/);
+  }
+  
+  return 0;
+}
+
+# Main
+...@commandtable = 
+(
+ # Disable timestamps in output
+ {'terminal no-timestamp'             => 'DoNothing' },  # XR 3.6 style
+ {'terminal exec prompt no-timestamp' => 'DoNothing' },  # XR 3.8 style
+
+ # XR IMAGE commands
+ {'show install summary'	=> 'ShowInstallSummary'},
+
+ # REDUNDANCY commands
+ {'show redundancy'	        => 'ShowRedundancy'},
+
+ # FILESYSTEMS comamnds
+ {'dir /all bootflash:'	        => 'DirSlotN'},
+ {'dir /all disk0:'		=> 'DirSlotN'},
+ {'dir /all disk0a:'		=> 'DirSlotN'},
+ {'dir /all disk1:'		=> 'DirSlotN'},
+ {'dir /all disk1a:'		=> 'DirSlotN'},
+ {'dir /all compactflash:'	=> 'DirSlotN'},
+ {'dir /all compactflasha:'	=> 'DirSlotN'},
+ {'dir /all harddisk:'	        => 'DirSlotN'},
+ {'dir /all harddiska:'	        => 'DirSlotN'},
+ {'dir /all harddiskb:'	        => 'DirSlotN'},
+
+ # HARDWARE commands
+ {'show version'		=> 'ShowVersion'},
+ {'show platform'	        => 'ShowPlatform'},
+ {'admin'                       => 'DoNothing'},
+ {'show inventory'		=> 'ShowInventory'},
+ {'exit'                        => 'DoNothing'},
+
+ # DEBUG commands
+ {'show debug'			=> 'ShowDebug'},
+
+ # RUNNING-CONFIG commands
+ {'show running-config'		=> 'WriteTerm'},
+);
+
+# Use an array to preserve the order of the commands and a hash for mapping
+# commands to the subroutine and track commands that have been completed.
+...@commands = map(keys(%$_), @commandtable);
+%commands = map(%$_, @commandtable);
+
+$cisco_cmds = join(";", @commands);
+$cmds_regexp = join("|", @commands);
+
+unless ($host) {
+  unless ($file) {
+    print(STDERR "Too few arguments: file or host name required\n");
+    exit(1);
+  }
+  else {
+    $host = $file;
+  }
+} 
+
+open(OUTPUT, "> $host.new") 
+  or 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") 
+    or die "open failed for $host: $!\n";
+} else {
+  print STDERR "executing clogin -autoenable -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug);
+  print STDOUT "executing clogin -autoenable -t $timeo -c\"$cisco_cmds\" $host\n" if ($log);
+  if (defined($ENV{NOPIPE})) {
+    system "clogin -autoenable -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" 
+      or die "clogin failed for $host: $!\n";
+    open(INPUT, "< $host.raw") 
+      or die "clogin failed for $host: $!\n";
+  } else {
+    open(INPUT,"clogin -autoenable -t $timeo -c \"$cisco_cmds\" $host </dev/null |") 
+      or die "clogin failed for $host: $!\n";
+  }
+}
+
+ProcessHistory("","","","! RANCID-CONTENT-TYPE: cisco ios-xr\n!\n");
+ProcessHistory("COMMENTS", "keysort", "A", "! IOS-XR IMAGE INFORMATION\n");
+ProcessHistory("COMMENTS", "keysort", "B", "! REDUNDANCY INFORMATION\n");
+ProcessHistory("COMMENTS", "keysort", "C", "! FILE SYSTEMS INFORMATION\n");
+ProcessHistory("COMMENTS", "keysort", "D", "! HARDWARE INFORMATION\n");
+
+TOP: 
+while(<INPUT>) {
+  tr/\015//d;
+
+  # only match exit from exec mode, i.e NOT from admin mode
+  if (/(?<!\(admin\))#\s*exit$/) {
+    $clean_run = 1;
+    last;
+  }
+  
+  if (/^Error:/) {
+    print STDOUT ("$host clogin error: $_") unless $debug;
+    print STDERR ("$host clogin error: $_") if ($debug);
+    $clean_run = 0;
+    last;
+  }
+  
+  while (/#\s*($cmds_regexp)\s*$/) {
+    $cmd = $1;
+    if (!defined($prompt)) {
+      $prompt = ($_ =~ /^([^#]+)/)[0];
+      #$prompt .= "(admin)*#";
+      $prompt =~ s/([][}{)(\\])/\\$1/g;
+      print STDERR ("PROMPT MATCH: $prompt\n") if ($debug);
+    }
+    
+    print STDERR ("HIT COMMAND: $cmd\n") if ($debug);
+    
+    if (! defined($commands{$cmd})) {
+      print STDERR "$host: found unexpected command - \"$cmd\"\n";
+      $clean_run = 0;
+      last TOP;
+    }
+
+    $rval = &{$commands{$cmd}};
+    delete($commands{$cmd});
+    if ($rval == -1) {
+      $clean_run = 0;
+      last TOP;
+    }
+  }
+}
+
+print STDOUT "Done: $_\n" if ($log);
+
+# Flush History
+ProcessHistory("", "", "", "");
+
+# Cleanup
+close(INPUT);
+close(OUTPUT);
+
+if (defined($ENV{NOPIPE})) {
+  unlink("$host.raw") unless $debug;
+}
+
+# check for completeness
+if (scalar(%commands) || !$clean_run || !$found_end) {
+  if (scalar(%commands)) {
+    printf(STDOUT "$host: missed cmd(s): %s\n", join(', ', keys(%commands))) unless $debug;
+    printf(STDERR "$host: missed cmd(s): %s\n", join(', ', keys(%commands))) if ($debug);
+  }
+  if (!$clean_run || !$found_end) {
+    print STDOUT "$host: End of run not found\n" unless $debug;
+    print STDERR "$host: End of run not found\n" if ($debug);
+    system("/usr/bin/tail -1 $host.new") unless $debug;
+  }
+  unlink "$host.new" unless $debug;
+}
+
+
+# Local variables: #
+# mode: perl #
+# End: #

Reply via email to