| #! /usr/bin/perl | |
| # | |
| # usage: vrancid [-dV] [-l] [-f filename | hostname] | |
| # | |
| use Getopt::Std; | |
| getopts('dflV'); | |
| if ($opt_V) { | |
| print "rancid 2.3.6\n"; | |
| exit(0); | |
| } | |
| $log = $opt_l; | |
| $debug = $opt_d; | |
| $file = $opt_f; | |
| $host = $ARGV[0]; | |
| $proc = ""; | |
| $ios = "IOS"; | |
| $clean_run = 0; | |
| $found_end = 0; | |
| $found_version = 0; | |
| $found_env = 0; | |
| $found_diag = 0; | |
| $timeo = 90; # clogin timeout in seconds | |
| my(@commandtable, %commands, @commands);# command lists | |
| my($aclsort) = ("ipsort"); # ACL sorting mode | |
| my($config_register); # configuration register value | |
| my($filter_commstr); # SNMP community string filtering | |
| my($filter_pwds); # password filtering mode | |
| # 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)) | |
| && scalar(%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 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 processes a "write term" | |
| sub WriteTerm { | |
| print STDERR " In WriteTerm: $_" if ($debug); | |
| my($lineauto,$comment,$linecnt) = (0,0,0); | |
| while (<INPUT>) { | |
| tr/\015//d; | |
| last if (/^$prompt/); | |
| return(1) if (!$linecnt && /^\s+\^\s*$/); | |
| next if (/^\s*$cmd\s*$/); | |
| return(1) if (/Line has invalid autocommand /); | |
| return(1) if (/(Invalid (input|command) detected|Type help or )/i); | |
| return(1) if (/\%Error: No such file or directory/); | |
| return(1) if (/(Open device \S+ failed|Error opening \S+:)/); | |
| return(0) if ($found_end); # Only do this routine once | |
| return(-1) if (/command authorization failed/i); | |
| return(-1) if (/% ?configuration buffer full/i); | |
| # the pager can not be disabled per-session on the PIX | |
| if (/^(<-+ More -+>)/) { | |
| my($len) = length($1); | |
| s/^$1\s{$len}//; | |
| } | |
| /^! no configuration change since last restart/i && next; | |
| # skip emtpy lines at the beginning | |
| if (!$linecnt && /^\s*$/) { | |
| next; | |
| } | |
| if (!$linecnt && defined($config_register)) { | |
| ProcessHistory("","","", "!\nconfig-register $config_register\n"); | |
| } | |
| /Non-Volatile memory is in use/ && return(-1); # NvRAM is locked | |
| /% Configuration buffer full, / && return(-1); # buffer is in use | |
| $linecnt++; | |
| $lineauto = 0 if (/^[^ ]/); | |
| # skip the crap | |
| if (/^(##+|(building|current) configuration)/i) { | |
| while (<INPUT>) { | |
| next if (/^Current configuration\s*:/i); | |
| next if (/^:/); | |
| next if (/^([%!].*|\s*)$/); | |
| next if (/^ip add.*ipv4:/); # band-aid for 3620 12.0S | |
| last; | |
| } | |
| tr/\015//d; | |
| } | |
| # skip ASA 5520 configuration author line | |
| /^: written by /i && next; | |
| # some versions have other crap mixed in with the bits in the | |
| # block above | |
| /^! (Last configuration|NVRAM config last)/ && next; | |
| # and for the ASA | |
| /^: (Written by \S+ at|Saved)/ && next; | |
| # skip consecutive comment lines to avoid oscillating extra comment | |
| # line on some access servers. grrr. | |
| if (/^!\s*$/) { | |
| next if ($comment); | |
| ProcessHistory("","","",$_); | |
| $comment++; | |
| next; | |
| } | |
| $comment = 0; | |
| # 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 | |
| $lineauto = 1 if /^ modem auto/; | |
| /^ speed / && $lineauto && next; # kill speed on serial lines | |
| /^ clockrate / && next; # kill clockrate on serial interfaces | |
| if (/^(enable )?(password|passwd)( level \d+)? / && $filter_pwds >= 1) { | |
| ProcessHistory("ENABLE","","","!$1$2$3 <removed>\n"); | |
| next; | |
| } | |
| if (/^(enable secret) / && $filter_pwds >= 2) { | |
| ProcessHistory("ENABLE","","","!$1 <removed>\n"); | |
| next; | |
| } | |
| if (/^username (\S+)(\s.*)? secret /) { | |
| if ($filter_pwds >= 2) { | |
| ProcessHistory("USER","keysort","$1", | |
| "!username $1$2 secret <removed>\n"); | |
| } else { | |
| ProcessHistory("USER","keysort","$1","$_"); | |
| } | |
| next; | |
| } | |
| if (/^username (\S+)(\s.*)? password ((\d) \S+|\S+)/) { | |
| if ($filter_pwds >= 2) { | |
| ProcessHistory("USER","keysort","$1", | |
| "!username $1$2 password <removed>\n"); | |
| } elsif ($filter_pwds >= 1 && $4 ne "5"){ | |
| ProcessHistory("USER","keysort","$1", | |
| "!username $1$2 password <removed>\n"); | |
| } else { | |
| ProcessHistory("USER","keysort","$1","$_"); | |
| } | |
| next; | |
| } | |
| # cisco AP w/ IOS | |
| if (/^(wlccp \S+ username (\S+)(\s.*)? password) (\d \S+|\S+)/) { | |
| if ($filter_pwds >= 1) { | |
| ProcessHistory("USER","keysort","$2","!$1 <removed>\n"); | |
| } else { | |
| ProcessHistory("USER","keysort","$2","$_"); | |
| } | |
| next; | |
| } | |
| # filter auto "rogue ap" configuration lines | |
| /^rogue ap classify / && next; | |
| if (/^( set session-key (in|out)bound ah \d+ )/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1<removed>\n"); | |
| next; | |
| } | |
| if (/^( set session-key (in|out)bound esp \d+ (authenticator|cypher) )/ | |
| && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1<removed>\n"); | |
| next; | |
| } | |
| if (/^(\s*)password / && $filter_pwds >= 1) { | |
| ProcessHistory("LINE-PASS","","","!$1password <removed>\n"); | |
| next; | |
| } | |
| if (/^(\s*)secret / && $filter_pwds >= 2) { | |
| ProcessHistory("LINE-PASS","","","!$1secret <removed>\n"); | |
| next; | |
| } | |
| if (/^\s*neighbor (\S*) password / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","! neighbor $1 password <removed>\n"); | |
| next; | |
| } | |
| if (/^(ppp .* password) 7 .*/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| if (/^(ip ftp password) / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| if (/^( ip ospf authentication-key) / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| # isis passwords appear to be completely plain-text | |
| if (/^\s+isis password (\S+)( .*)?/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!isis password <removed>$2\n"); next; | |
| } | |
| if (/^\s+(domain-password|area-password) (\S+)( .*)?/ | |
| && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>$3\n"); next; | |
| } | |
| # this is reversable, despite 'md5' in the cmd | |
| if (/^( ip ospf message-digest-key \d+ md5) / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| # this is also reversable, despite 'md5 encrypted' in the cmd | |
| if (/^( message-digest-key \d+ md5 (7|encrypted)) / | |
| && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| if (/^((crypto )?isakmp key) \S+ / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed> $'"); next; | |
| } | |
| # filter HSRP passwords | |
| if (/^(\s+standby \d+ authentication) / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| # this appears in "measurement/sla" images | |
| if (/^(\s+key-string \d?)/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| if (/^( l2tp tunnel \S+ password)/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| # i am told these are plain-text on the PIX | |
| if (/^(vpdn username (\S+) password)/) { | |
| if ($filter_pwds >= 1) { | |
| ProcessHistory("USER","keysort","$2","!$1 <removed>\n"); | |
| } else { | |
| ProcessHistory("USER","keysort","$2","$_"); | |
| } | |
| next; | |
| } | |
| # ASA/PIX keys in more system:running-config | |
| if (/^( pre-shared-key | key |failover key ).*/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed> $'"); next; | |
| } | |
| if (/(\s+ldap-login-password )\S+(.*)/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed> $'"); next; | |
| } | |
| # | |
| if (/^( cable shared-secret )/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); | |
| next; | |
| } | |
| /fair-queue individual-limit/ && next; | |
| # sort ip explicit-paths. | |
| if (/^ip explicit-path name (\S+)/) { | |
| my($key) = $1; | |
| my($expath) = $_; | |
| while (<INPUT>) { | |
| tr/\015//d; | |
| last if (/^$prompt/); | |
| last if (/^$prompt/ || ! /^(ip explicit-path name |[ !])/); | |
| if (/^ip explicit-path name (\S+)/) { | |
| ProcessHistory("EXPATH","keysort","$key","$expath"); | |
| $key = $1; | |
| $expath = $_; | |
| } else { | |
| $expath .= $_; | |
| } | |
| } | |
| ProcessHistory("EXPATH","keysort","$key","$expath"); | |
| } | |
| # sort route-maps | |
| if (/^route-map (\S+)/) { | |
| my($key) = $1; | |
| my($routemap) = $_; | |
| while (<INPUT>) { | |
| tr/\015//d; | |
| last if (/^$prompt/ || ! /^(route-map |[ !])/); | |
| if (/^route-map (\S+)/) { | |
| ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); | |
| $key = $1; | |
| $routemap = $_; | |
| } else { | |
| $routemap .= $_; | |
| } | |
| } | |
| ProcessHistory("ROUTEMAP","keysort","$key","$routemap"); | |
| } | |
| # filter out any RCS/CVS tags to avoid confusing local CVS storage | |
| s/\$(Revision|Id):/ $1:/; | |
| # order access-lists | |
| /^access-list\s+(\d\d?)\s+(\S+)\s+(\S+)/ && | |
| ProcessHistory("ACL $1 $2","$aclsort","$3","$_") && next; | |
| # order extended access-lists | |
| /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+host\s+(\S+)/ && | |
| ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; | |
| /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+(\d\S+)/ && | |
| ProcessHistory("EACL $1 $2","$aclsort","$3","$_") && next; | |
| /^access-list\s+(\d\d\d)\s+(\S+)\s+ip\s+any/ && | |
| ProcessHistory("EACL $1 $2","$aclsort","0.0.0.0","$_") && next; | |
| # order arp lists | |
| /^arp\s+(\d+\.\d+\.\d+\.\d+)\s+/ && | |
| ProcessHistory("ARP","$aclsort","$1","$_") && next; | |
| /^ip(v6)? prefix-list\s+(\S+)\s+seq\s+(\d+)\s+(permit|deny)\s+(\S+)(\/.*)$/ | |
| && ProcessHistory("PACL $2 $4","$aclsort","$5", | |
| "ip$1 prefix-list $2 $4 $5$6\n") | |
| && next; | |
| # order logging statements | |
| /^logging (\d+\.\d+\.\d+\.\d+)/ && | |
| ProcessHistory("LOGGING","ipsort","$1","$_") && next; | |
| # order/prune snmp-server host statements | |
| # we only prune lines of the form | |
| # snmp-server host a.b.c.d <community> | |
| if (/^snmp-server host (\d+\.\d+\.\d+\.\d+) /) { | |
| if ($filter_commstr) { | |
| my($ip) = $1; | |
| my($line) = "snmp-server host $ip"; | |
| my(@tokens) = split(' ', $'); | |
| my($token); | |
| while ($token = shift(@tokens)) { | |
| if ($token eq 'version') { | |
| $line .= " " . join(' ', ($token, shift(@tokens))); | |
| if ($token eq '3') { | |
| $line .= " " . join(' ', ($token, shift(@tokens))); | |
| } | |
| } elsif ($token eq 'vrf') { | |
| $line .= " " . join(' ', ($token, shift(@tokens))); | |
| } elsif ($token =~ /^(informs?|traps?|(no)?auth)$/) { | |
| $line .= " " . $token; | |
| } else { | |
| $line = "!$line " . join(' ', ("<removed>", | |
| join(' ',@tokens))); | |
| last; | |
| } | |
| } | |
| ProcessHistory("SNMPSERVERHOST","ipsort","$ip","$line\n"); | |
| } else { | |
| ProcessHistory("SNMPSERVERHOST","ipsort","$1","$_"); | |
| } | |
| next; | |
| } | |
| if (/^(snmp-server community) (\S+)/) { | |
| if ($filter_commstr) { | |
| ProcessHistory("SNMPSERVERCOMM","keysort","$_", | |
| "!$1 <removed>$'") && next; | |
| } else { | |
| ProcessHistory("SNMPSERVERCOMM","keysort","$_","$_") && next; | |
| } | |
| } | |
| # prune tacacs/radius server keys | |
| if (/^((tacacs|radius)-server\s(\w*[-\s(\s\S+])*\s?key) (\d )?\w+/ | |
| && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>$'"); 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 - this md5 is a reversable too | |
| if (/^(ntp authentication-key \d+ md5) / && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!$1 <removed>\n"); next; | |
| } | |
| # order ntp peers/servers | |
| if (/^ntp (server|peer) (\d+)\.(\d+)\.(\d+)\.(\d+)/) { | |
| $sortkey = sprintf("$1 %03d%03d%03d%03d",$2,$3,$4,$5); | |
| ProcessHistory("NTP","keysort",$sortkey,"$_"); | |
| next; | |
| } | |
| # order ip host statements | |
| /^ip host (\S+) / && | |
| ProcessHistory("IPHOST","keysort","$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; | |
| # system controller | |
| /^syscon address (\S*) (\S*)/ && | |
| ProcessHistory("","","","!syscon address $1 <removed>\n") && | |
| next; | |
| if (/^syscon password (\S*)/ && $filter_pwds >= 1) { | |
| ProcessHistory("","","","!syscon password <removed>\n"); | |
| next; | |
| } | |
| /^ *Cryptochecksum:/ && next; | |
| # catch anything that wasnt matched above. | |
| ProcessHistory("","","","$_"); | |
| # end of config. the ": " game is for the PIX | |
| if (/^(: +)?}$/) { | |
| $found_end = 1; | |
| return(0); | |
| } | |
| } | |
| # The ContentEngine lacks a definitive "end of config" marker. If we | |
| # know that it is a CE, SAN, or NXOS and we have seen at least 5 lines | |
| # of write term output, we can be reasonably sure that we got the config. | |
| if (($type == "CE" || $type == "SAN" || $type == "NXOS" ) && $linecnt > 5) { | |
| $found_end = 1; | |
| return(0); | |
| } | |
| return(0); | |
| } | |
| # dummy function | |
| sub DoNothing {print STDOUT;} | |
| # Main | |
| @commandtable = ( | |
| {'show configuration' => '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("|", map quotemeta($_), @commands); | |
| if (length($host) == 0) { | |
| if ($file) { | |
| print(STDERR "Too few arguments: file name required\n"); | |
| exit(1); | |
| } else { | |
| print(STDERR "Too few arguments: host name required\n"); | |
| exit(1); | |
| } | |
| } | |
| open(OUTPUT,">$host.new") || die "Can't open $host.new for writing: $!\n"; | |
| select(OUTPUT); | |
| # make OUTPUT unbuffered if debugging | |
| if ($debug) { $| = 1; } | |
| if ($file) { | |
| print STDERR "opening file $host\n" if ($debug); | |
| print STDOUT "opening file $host\n" if ($log); | |
| open(INPUT,"<$host") || die "open failed for $host: $!\n"; | |
| } else { | |
| print STDERR "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($debug); | |
| print STDOUT "executing clogin -t $timeo -c\"$cisco_cmds\" $host\n" if ($log); | |
| if (defined($ENV{NOPIPE})) { | |
| system "clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null > $host.raw 2>&1" || die "clogin failed for $host: $!\n"; | |
| open(INPUT, "< $host.raw") || die "clogin failed for $host: $!\n"; | |
| } else { | |
| open(INPUT,"clogin -t $timeo -c \"$cisco_cmds\" $host </dev/null |") || die "clogin failed for $host: $!\n"; | |
| } | |
| } | |
| # determine ACL sorting mode | |
| if ($ENV{"ACLSORT"} =~ /no/i) { | |
| $aclsort = ""; | |
| } | |
| # determine community string filtering mode | |
| if (defined($ENV{"NOCOMMSTR"}) && | |
| ($ENV{"NOCOMMSTR"} =~ /yes/i || $ENV{"NOCOMMSTR"} =~ /^$/)) { | |
| $filter_commstr = 1; | |
| } else { | |
| $filter_commstr = 0; | |
| } | |
| # determine password filtering mode | |
| if ($ENV{"FILTER_PWDS"} =~ /no/i) { | |
| $filter_pwds = 0; | |
| } elsif ($ENV{"FILTER_PWDS"} =~ /all/i) { | |
| $filter_pwds = 2; | |
| } else { | |
| $filter_pwds = 1; | |
| } | |
| ProcessHistory("","","","!RANCID-CONTENT-TYPE: vyatta\n!\n"); | |
| ProcessHistory("COMMENTS","keysort","B0","!\n"); | |
| ProcessHistory("COMMENTS","keysort","D0","!\n"); | |
| ProcessHistory("COMMENTS","keysort","F0","!\n"); | |
| ProcessHistory("COMMENTS","keysort","G0","!\n"); | |
| TOP: while(<INPUT>) { | |
| tr/\015//d; | |
| if (/[>#]\s?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; | |
| print STDERR ("PROMPT MATCH: $prompt\n") if ($debug); | |
| } | |
| print STDERR ("HIT COMMAND:$_") 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 $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 "$host: missed cmd(s): %s\n", join(',', keys(%commands))); | |
| 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"; | |
| print STDERR "$host: End of run not found\n" if ($debug); | |
| system("/usr/bin/tail -1 $host.new"); | |
| } | |
| unlink "$host.new" if (! $debug); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment