[rancid] Re: Nortel Alteons (UNCLASSIFIED)
Roeun, Don T Mr CTR USA HRC
don.t.roeun at us.army.mil
Thu Jul 23 16:31:37 UTC 2009
Classification: UNCLASSIFIED
Caveats: NONE
Hi Bill,
What needs to be modified to use alogin? As of right now, I have all of
my logins for Cisco & Alteon gear in .cloginrc. 12 of 14 alteons are
backing up correctly. Do alteon logins need to be in a separate file?
I really appreciate your help.
-----Original Message-----
From: Bill Petrisko [mailto:bill at limelightnetworks.com]
Sent: Thursday, July 23, 2009 12:06 PM
To: Roeun, Don T Mr CTR USA HRC
Subject: Re: [rancid] Nortel Alteons (UNCLASSIFIED)
On Thu, 23 Jul 2009, Roeun, Don T Mr CTR USA HRC wrote:
> Classification: UNCLASSIFIED
> Caveats: NONE
>
> We have a total of 14 Nortel Alteons, and clogin fails on a couple of
> them. I tried testing with bin/clogin 5x in a row and it is hit or
> miss, sometimes it works and sometimes it doesn't. I can see the
> username get filled in but not the password. When it fails with
> clogin, I can always connect straight to the device from the rancid
> box outside of clogin using the same credentials. I tested it 5 times
> on a single device & it worked once or twice. This is only happening
> on 2 of the 14 Alteons that we have. Any thoughts?
>
> cloginrc:
>
> #Alteons#
> add user a184-* {password}
> add userprompt a184-* {"Enter radius username"} add userpassword
> a184-* {password} add passprompt a184-* {"Enter radius password"}
>
> log:
>
> a184-dmz13: missed cmd(s): /info/sys,/cfg/dump
> > a184-dmz13: End of run not found
> > /*
> > a184-dmz14: missed cmd(s): /info/sys,/cfg/dump
> > a184-dmz14: End of run not found
Not sure if this will help, but we used to use a modified version of
clogin (we called it "alogin") for collecting from alteon boxes:
also below is the "arancid" we used with it....
bill
#!/usr/bin/expect --
##
##
## Copyright (C) 1997-2001 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.
##
##
#
# alogin - Alteon WebOS switch login
#
# afort at choqolat.org is responsible for this particular mess # (andrew
fort) #
# Usage line
set usage "Usage: $argv0 \[-c command\] \ \[-Evar=x\] \[-f
cloginrc-file\] \ \[-s script-file\] \[-t timeout\] \[-u username\] \
\[-v vty-password\] \[-x command-file\] \ \[-y ssh_cypher_type\] 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
# Find the user in the ENV, or use the unix userid.
if {[ info exists env(CISCO_USER) ] } {
set default_user $env(CISCO_USER)
} elseif {[ info exists env(USER) ]} {
set default_user $env(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.
if [ catch {exec id} reason ] {
send_error "Error: could not exec id: $reason\n"
exit 1
}
regexp {\(([^)]*)} "$reason" 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
} -v* -
-v* {
if {! [ regexp .\[vV\](.+) $arg ignore passwd]} {
incr i
set passwd [ lindex $argv $i ]
}
set do_passwd 0
# Enable Username
} -w* -
-W* {
# ignore -w
# Environment variable to pass to -s scripts
} -E*
{
if {[ regexp .\[E\](.+)=(.+) $arg ignore varname varvalue]}
{
incr i
set E$varname $varvalue
} else {
send_user "Error: invalid format for -E in $arg\n"
exit 1
}
# Enable Password
} -e*
{
# ignore -e
# 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
# 'ssh -c' 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 ]
}
# Timeout
} -t* -
-T* {
if {! [ regexp .\[tT\](.+) $arg ignore timeout]} {
incr i
set timeout [ lindex $argv $i ]
}
# Command file
} -x* -
-X {
if {! [ regexp .\[xX\](.+) $arg ignore cmd_file]} {
incr i
set cmd_file [ lindex $argv $i ]
}
if [ catch {set cmd_fd [open $cmd_file r]} reason ] {
send_user "\nError: $reason\n"
exit 1
}
set cmd_text [read $cmd_fd]
close $cmd_fd
set command [join [split $cmd_text \n] \;]
set do_command 1
# Do we enable?
} -noenable {
# ignore -noenable
# Does tacacs automatically enable us?
} -autoenable {
# ignore -autoenable
} -* {
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 int_$var ; lappend int_$var $args} proc
include {args} {
global env
regsub -all "(^{|}$)" $args {} args
if { [ regexp "^/" $args ignore ] == 0 } {
set args $env(HOME)/$args
}
source_password_file $args
}
proc find {var router} {
upvar int_$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 { password_file } {
global env
if { ! [file exists $password_file] } {
send_user "Error: password file ($password_file) does not
exist\n"
exit 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
}
if [ catch {source $password_file} reason ] {
send_user "Error: $reason\n"
exit 1
}
}
# Log into the router.
proc login { router user userpswd passwd prompt cmethod cyphertype } {
global spawn_id in_proc do_command do_script
global u_prompt p_prompt
set in_proc 1
set uprompt_seen 0
# try each of the connection methods in $cmethod until one is
successful
set progs [llength $cmethod]
foreach prog [lrange $cmethod 0 end] {
if [string match "telnet*" $prog] {
regexp {telnet(:([^[:space:]]+))*} $prog command suffix port
if {"$port" == ""} {
set retval [ catch {spawn telnet $router} reason ]
} else {
set retval [ catch {spawn telnet $router $port} reason ]
}
if { $retval } {
send_user "\nError: telnet failed: $reason\n"
exit 1
}
} elseif ![string compare $prog "ssh"] {
if [ catch {spawn ssh -c $cyphertype -x -l $user $router}
reason ] {
send_user "Error: ssh failed: $reason\n"
exit 1
}
} elseif ![string compare $prog "rsh"] {
if [ catch {spawn rsh -l $user $router} reason ] {
send_user "Error: rsh failed: $reason\n"
exit 1
}
} else {
puts "ERROR: unknown connection method: $prog"
return 1
}
incr progs -1
sleep 0.3
# This helps cleanup each expect clause.
expect_after {
timeout {
send_user "\nError: TIMEOUT reached\n"
catch {close}; wait
if { $in_proc} {
return 1
} else {
continue
}
} eof {
send_user "\nError: EOF received\n"
catch {close}; wait
if { $in_proc} {
return 1
} else {
continue
}
}
}
expect {
"Connection refused" {
close; wait
sleep 0.3
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 "$u_prompt" {
send "$user\r"
set uprompt_seen 1
exp_continue
}
-re "$p_prompt" {
sleep 1
if {$uprompt_seen == 1} {
send "$userpswd\r"
} else {
send "$passwd\r"
}
exp_continue
}
-re "^Confirm seeing above note" {
send "y\r"
exp_continue
}
"Password incorrect" { send_user "Error: Check your password
for $router\n";
catch {close}; wait; return 1 }
-re "$prompt" { break; }
denied { send_user "Error: Check your passwd for
$router\n"
if { $do_command || $do_script } {
send "exit\r"
wait
return 1
} else {
return 1
}
}
"\r\n" { exp_continue; }
}
}
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 "lines 0\r"
expect -re $prompt {}
regsub -all "\[)(]" $prompt {\\&} reprompt
# 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 -nocommands [lindex $commands $i]]\r"
expect {
-re "^\[^\n\r]*$reprompt" {}
-re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }
-re "\[\n\r]+" { exp_continue }
}
}
} else {
send "[subst -nocommands $command]\r"
expect {
-re "^\[^\n\r]*$reprompt" {}
-re "^\[^\n\r ]*>>.*$reprompt" { exp_continue }
-re "\[\n\r]+" { exp_continue }
}
}
send "exit\r"
expect {
-re "^WARNING: There are unsaved configuration changes."
{
send "y\r"
exp_continue
}
"\n" { exp_continue }
"\[^\n\r *]*Session terminated" { return 0 }
timeout { return 0 }
eof { return 0 }
}
set in_proc 0
}
#
# For each router... (this is main loop) # source_password_file
$password_file set in_proc 0 foreach router [lrange $argv $i end] {
set router [string tolower $router]
send_user "$router\n"
# Figure out prompt.
set prompt ">> \[^\r\n]*\[#|>] "
# alteon only "enables" based on the password used at login time
set autoenable 1
set enable 0
# Figure out passwords
if { $do_passwd } {
set pswd [find password $router]
if { [llength $pswd] == 0 } {
send_user "Error - no password for $router in $password_file.\n"
continue
}
set passwd [lindex $pswd 0]
}
# 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 prompts
set u_prompt [find userprompt $router]
if { "$u_prompt" == "" } { set u_prompt "(Username|login| Login):"
}
set p_prompt [find passprompt $router]
if { "$p_prompt" == "" } { set p_prompt "\[Pp]assword:" }
# Figure out cypher type
if {[info exists cypher]} {
# command line cypher type
set cyphertype $cypher
} else {
set cyphertype [find cyphertype $router]
if { "$cyphertype" == "" } { set cyphertype "3des" }
}
# Figure out connection method
set cmethod [find method $router]
if { "$cmethod" == "" } { set cmethod {{telnet} {ssh}} }
# Login to the router
if {[login $router $ruser $userpswd $passwd $prompt $cmethod
$cyphertype]} {
continue
}
if { $do_command } {
if {[run_commands $prompt $command]} {
continue
}
} elseif { $do_script } {
send "lines 0\r"
expect -re $prompt {}
source $sfile
close
} else {
label $router
log_user 1
interact
}
# End of for each router
wait
sleep 0.3
}
exit 0
and arancid:
#!/usr/bin/perl
##
## Hacked version of rancid for Alteon WebOS switches ## tested with:
ad3 v8.1.18 ## afort at choqolat.org (andrew fort) ## ## ## Copyright (C)
1997-2001 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
#
# arancid - Alteon WebOS plugin for rancid # # usage: arancid [-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; $prompt = "#";
$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, at 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 "/info/sys" (cf. show version) sub ShowVersion {
print STDERR " In ShowVersion: $_" if ($debug);
while (<INPUT>) {
tr/\015//d;
last if (/^>>.*$prompt/);
next if(/^(\s*|\s*$cmd\s*)$/);
/^(ACEdirector.*|ACEswitch.*|Alteon.*)/i &&
ProcessHistory("COMMENTS","keysort","A1", "\/\*Model: $1\n")
&& next;
/^Software Version\s+(.*?)\s\((.*)\)/i &&
ProcessHistory("COMMENTS","keysort","B1", "\/\*Image:
Software: $1 ($2)\n") && next;
/^Hardware Part No:\s+(.*?)\s+/i &&
ProcessHistory("COMMENTS","keysort","A2", "\/\*Hardware part
no: $1\n") && next;
/^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 &&
ProcessHistory("COMMENTS","keysort","C1", "\/\*Base MAC
address: $1\n") && next;
}
return(0);
}
# This routine processes a "/cfg/dump"
sub WriteTerm {
print STDERR " In WriteTerm: $_" if ($debug);
# eat the header line
#$junk = <INPUT>;
# now just copy it verbatim to the history file
$is_bwm = 0;
while (<INPUT>) {
tr/\015//d;
last if(/^>>.*$prompt/);
chop;
if (/(rcomm|wcomm|t1com|t2com)(\s+)(.*)/ &&
defined($ENV{'NOCOMMSTR'})) {
ProcessHistory("","","","\/\*\t$1$2\"<removed>\"\n") &&
next;
}
if (/^\/c\/bwm\/cont (\d+)/) {
$cur_bwm_item = $1;
$is_bwm = 1;
} elsif (/^\/c\/bwm\/pol (\d+)/) {
$cur_bwm_item = $1;
$is_bwm = 2;
} elsif (/^\/c/ || /^\s*resv/) {
if ($is_bwm == 2) {
if (!$got_hard{$cur_bwm_item}) {
ProcessHistory("","","","\/\*\thard <dynamic>\n");
}
if (!$got_soft{$cur_bwm_item}) {
ProcessHistory("","","","\/\*\tsoft <dynamic>\n");
}
}
$is_bwm = 0;
}
if (/name \"DYN/ && ($is_bwm == 1)) {
$is_dyn{$cur_bwm_item} = 1;
} elsif (/^(\s*(hard|soft) )/ && ($is_bwm == 2) && exists
$is_dyn{$cur_bwm_item}) {
$limit_type = $2;
$limit_line = $1;
if ($limit_type eq 'hard') {
$got_hard{$cur_bwm_item} = 1;
} elsif ($limit_type eq 'soft') {
if (!$got_hard{$cur_bwm_item}) {
ProcessHistory("","","","\/\*\thard <dynamic>\n");
}
$got_soft{$cur_bwm_item} = 1;
}
ProcessHistory("","","","\/\*${limit_line}<dynamic>\n") &&
next;
}
/^(\s+.{2,3}pw )\S+/ &&
ProcessHistory("","","","\/\*$1<removed>\n") && next;
/^(\/cfg\/sys\/sshd\/scpadm\s+)(.*)/ &&
ProcessHistory("","","","\/\*$1<removed>\n") && next;
next if (/^\/\* Configuration dump taken/i);
next if (/^\/\* Version.*Base MAC.*/i);
if (/^\/?script end/) {
$found_end = 1;
ProcessHistory("","","","$_\n");
return(1);
}
ProcessHistory("","","","$_\n");
}
return(0);
}
# dummy function
sub DoNothing {print STDOUT;}
# Main
%commands=(
'/info/sys' => "ShowVersion",
'/cfg/dump' => "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=(
"/info/sys",
"/cfg/dump",
);
$cisco_cmds=join(";", at commands);
$cmds_regexp=join("|", at 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 alogin -t $timeo -c\"$cisco_cmds\" $host\n"
if ($debug);
print STDOUT "executing alogin -t $timeo -c\"$cisco_cmds\" $host\n"
if ($log);
if (defined($ENV{NOPIPE})) {
system "alogin -t $timeo -c \"$cisco_cmds\" $host </dev/null >
$host.raw 2>&1" || die "alogin failed for $host: $!\n";
open(INPUT, "< $host.raw") || die "alogin failed for $host:
$!\n";
} else {
open(INPUT,"alogin -t $timeo -c \"$cisco_cmds\" $host </dev/null
|") || die "alogin failed for $host: $!\n";
}
}
ProcessHistory("","","","\/\*RANCID-CONTENT-TYPE: alteon\n\/\*\n");
ProcessHistory("COMMENTS","keysort","B0","\/\*\n");
ProcessHistory("COMMENTS","keysort","F0","\/\*\n");
TOP: while(<INPUT>) {
tr/\015//d;
if (/^>>.*$prompt exit/) {
$clean_run=1;
last;
}
while (/>>.*$prompt\s*($cmds_regexp)\s*$/) {
$cmd = $1;
if (!defined($prompt)) {$prompt = ($_ =~ /^([^#]+#)/)[0]; }
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);
}
Classification: UNCLASSIFIED
Caveats: NONE
More information about the Rancid-discuss
mailing list