#!/usr/local/bin/perl
# 
# check status of a 6140 disk array
# 
# by Doke Scott, doke at udel dot edu, 2007.8.10
#
# $Header: /opt/home/doke/work/nagios/RCS/check_6140,v 1.11 2010/04/05 22:30:02 doke Exp $


use strict;   
use warnings;   
no warnings 'uninitialized';
use Expect;  # written using Expect-1.15
use Getopt::Long;

########################

my $username = "nagios";
my $password_file = "/usr/local/nagios/etc/nagios.pw";

# If you're already logged into sscs, commands are relatively quick, 
# ie under 5 seconds.
# If you're not logged in, it takes at least 55 seconds.  
my $timeout = 90;    

my $bindir = "/opt/SUNWsesscs/cli/bin";
my $logfile = "/tmp/check_6140.log";

my $verbose = 0;
my $help = 0;

my( $exp, $array, @crits, @warns, @unknowns, @oks, @ignores, $need_login,
    $internal_error );


##########################

sub usage { 
    my( $rc ) = @_;
    print "Usage: $0 [-vdh] -H <array> 
    -H array   6140 disk array to check
    -v   verbose, repeat for more detail
    -h   help
";
    exit $rc;
    }


Getopt::Long::Configure ("bundling");
GetOptions( 
    'H:s' => \$array,
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );
&usage( 1 ) if ( ! $array );
    
if ( $verbose > 1 ) { 
    if ( ! open( lH, ">>$logfile" ) ) { 
	warn "can't open log file $logfile: $!\n";
	}
    else { 
	select lH; $| = 1;
	print lH "\n\nstarting ", scalar( localtime( time ) ), "\n";
	select STDOUT;
	}
    }

&list_fru();
&list_vdisk();
&list_alarm();

&log( 1, "crits $#crits, warns $#warns, unknowns $#unknowns, oks $#oks, ignores $#ignores\n" );

$verbose > 1 && close lH;


my $rc = 0;
my $sep = '';
if ( $#crits >= 0 ) {
    $rc = 2;
    print "CRITICAL ", join( ", ", @crits );
    $sep = '; ';
    }
if ( $#warns >= 0 ) {
    $rc = 1 if ( $rc == 0 );
    print $sep, "Warning ", join( ", ", @warns );
    $sep = '; ';
    }
if ( $#unknowns >= 0 ) {
    $rc = -1 if ( $rc == 0 );
    print $sep, "Unknown ", join( ", ", @unknowns );
    }
if ( $rc == 0 ) {
    print "Ok ", join( ", ", @oks );
    $sep = '; ';
    }
if ( $#ignores >= 0 ) {
    print $sep, "Ignoring ", join( ", ", @ignores );
    }
print "\n";
exit $rc;



#####################################



# Takes a level, and a list of strings.
# If global $verbose < level then just return.
# If global $verbose >= level then, 
#     print the strings to stdout.
#     If global $verbose > 2, then also append the strings to the log file.
# 
sub log { 
    my( $level, $msg );

    $level = shift @_;
    return if ( $verbose < $level );

    $msg = join( ' ', @_ );
    $msg .= "\n" if ( $msg !~ m/\n$/ );
    print $msg;
    if ( $verbose > 1 ) { 
	print lH $msg;
	}
    }



    


## ./sscs.sh list -d STRONGMAD fru
#Name                                 FRU      Alarm State   Status  Revision    Unique Id                    
#------------------------------------ -------- ----- ------- ------- ----------- ---------------------------- 
#Tray.85.Battery.A                    battery  -     Enabled OK      N/A         130763500                    
#Tray.85.Battery.B                    battery  -     Enabled OK      N/A         130763358                    
#Tray.85.Controller.A                 ctrl     -     Enabled OK      06.19.25.10 SG70609092                   
#Tray.85.Controller.B                 ctrl     -     Enabled OK      06.19.25.10 SG70836497                   
#Tray.01.Drive.01                     disk     -     Enabled OK      2A08        09VWHKEL          55VAWHKELA 
#Tray.01.Drive.02                     disk     -     Enabled OK      2A08        09VWMG1Z          55VAWMG1ZA 
#Tray.01.Drive.03                     disk     -     Enabled OK      2A08        09VWHKXA          55VAWHKXAA 
#Tray.01.Drive.04                     disk     -     Enabled OK      2A08        09VWMVRZ          55VAWMVRZA 
#Tray.01.Drive.05                     disk     -     Enabled OK      2A08        09VWMTXS          55VAWMTXSA 
#Tray.01.Drive.06                     disk     -     Enabled OK      2A08        09VWMS37          55VAWMS37A 
#Tray.01.Drive.07                     disk     -     Enabled OK      2A08        09VWMVWY          55VAWMVWYA 
#Tray.01.Drive.08                     disk     -     Enabled OK      2A08        09VWMVX8          55VAWMVX8A 
#Tray.01.Drive.09                     disk     -     Enabled OK      2A08        09VWMSBL          55VAWMSBLA 
#Tray.01.Drive.10                     disk     -     Enabled OK      2A08        09VWMNUY          55VAWMNUYA 
#Tray.01.Drive.11                     disk     -     Enabled OK      2A08        09VWMVUX          55VAWMVUXA 
#Tray.01.Drive.12                     disk     -     Enabled OK      2A08        09VWMVZH          55VAWMVZHA 
#Tray.01.Drive.13                     disk     -     Enabled OK      2A08        09VWMS39          55VAWMS39A 
#Tray.01.Drive.14                     disk     -     Enabled OK      2A08        09VWMSWG          55VAWMSWGA 
#Tray.01.Drive.15                     disk     -     Enabled OK      2A08        09VWMSTV          55VAWMSTVA 
#Tray.01.Drive.16                     disk     -     Enabled OK      2A08        13VWS4DE          55VAWS4DEA 
#Tray.85.Drive.01                     disk     -     Enabled OK      055A        0953KLWP            3KR3KLWP 
#Tray.85.Drive.02                     disk     -     Enabled OK      055A        0953PZ6Y            3KR3PZ6Y 
#Tray.85.Drive.03                     disk     -     Enabled OK      055A        0953PD02            3KR3PD02 
#Tray.85.Drive.04                     disk     -     Enabled OK      055A        1153RW6W            3KR3RW6W 
#Tray.85.Drive.05                     disk     -     Enabled OK      055A        0953PNW9            3KR3PNW9 
#Tray.85.Drive.06                     disk     -     Enabled OK      055A        0953Q0GH            3KR3Q0GH 
#Tray.85.Drive.07                     disk     -     Enabled OK      055A        0953PRNC            3KR3PRNC 
#Tray.85.Drive.08                     disk     -     Enabled OK      055A        0953PYJD            3KR3PYJD 
#Tray.85.Drive.09                     disk     -     Enabled OK      055A        0953PF2P            3KR3PF2P 
#Tray.85.Drive.10                     disk     -     Enabled OK      055A        0753N6ZJ            3KR3N6ZJ 
#Tray.85.Drive.11                     disk     -     Enabled OK      055A        0953PN6Q            3KR3PN6Q 
#Tray.85.Drive.12                     disk     -     Enabled OK      055A        0953PMH0            3KR3PMH0 
#Tray.85.Drive.13                     disk     -     Enabled OK      055A        0953Q6ZT            3KR3Q6ZT 
#Tray.85.Drive.14                     disk     -     Enabled OK      055A        0253FYRF            3KR3FYRF 
#Tray.85.Drive.15                     disk     -     Enabled OK      055A        0953PKWN            3KR3PKWN 
#Tray.85.Drive.16                     disk     -     Enabled OK      055A        0953HYZ4            3KR3HYZ4 
#Tray.01.IOM.A                        iom      -     Enabled OK      9884        SG72406114                   
#Tray.01.IOM.B                        iom      -     Enabled OK      9884        SG72406195                   
#Tray.01                              midplane -     Enabled OK      N/A         0726AWF064                   
#Tray.85                              midplane -     Enabled OK      N/A         0717AWF01Q                   
#Tray.01.PowerSupply.A                pcu      -     Enabled OK      N/A         YPT071757214                 
#Tray.01.PowerSupply.B                pcu      -     Enabled OK      N/A         YPT071757186                 
#Tray.85.PowerSupply.A                pcu      -     Enabled OK      N/A         YPT070796160                 
#Tray.85.PowerSupply.B                pcu      -     Enabled OK      N/A         YPT070796172                 
#Tray.01.IOM.A.SFP.Port1A             sfp      -     Removed Removed                                          
#Tray.01.IOM.A.SFP.Port1B             sfp      -     Enabled OK      N/A         C716RQ025                    
#Tray.01.IOM.A.SFP.Port2A             sfp      -     Removed Removed                                          
#Tray.01.IOM.A.SFP.Port2B             sfp      -     Removed Removed                                          
#Tray.01.IOM.B.SFP.Port1A             sfp      -     Removed Removed                                          
#Tray.01.IOM.B.SFP.Port1B             sfp      -     Enabled OK      N/A         C714RQ1YS                    
#Tray.01.IOM.B.SFP.Port2A             sfp      -     Removed Removed                                          
#Tray.01.IOM.B.SFP.Port2B             sfp      -     Removed Removed                                          
#Tray.85.Controller.A.SFP.DrivePortP1 sfp      -     Enabled OK      N/A         C715RQ0K6                    
#Tray.85.Controller.A.SFP.DrivePortP2 sfp      -     Removed Removed                                          
#Tray.85.Controller.A.SFP.HostCh1     sfp      -     Enabled OK      N/A         C711RQ4CN                    
#Tray.85.Controller.A.SFP.HostCh2     sfp      -     Enabled OK      N/A         C711RQ4CM                    
#Tray.85.Controller.A.SFP.HostCh3     sfp      -     Enabled OK      N/A         C711RQ4CR                    
#Tray.85.Controller.A.SFP.HostCh4     sfp      -     Enabled OK      N/A         C711RQ4CQ                    
#Tray.85.Controller.B.SFP.DrivePortP1 sfp      -     Enabled OK      N/A         C719RQ0N6                    
#Tray.85.Controller.B.SFP.DrivePortP2 sfp      -     Removed Removed                                          
#Tray.85.Controller.B.SFP.HostCh1     sfp      -     Enabled OK      N/A         C711RQ3Y3                    
#Tray.85.Controller.B.SFP.HostCh2     sfp      -     Enabled OK      N/A         C711RQ3Y0                    
#Tray.85.Controller.B.SFP.HostCh3     sfp      -     Enabled OK      N/A         C711RQ3Y5                    
#Tray.85.Controller.B.SFP.HostCh4     sfp      -     Enabled OK      N/A         C711RQ3Y2

sub list_fru { 
    my( @lines, $name, $fru, $alarm, $state, $status, $oks );

    $oks = 0;
    @lines = &sscs( "list -d $array fru" );
    if ( $#lines < 0 ) { 
        push @unknowns, "couldn't get fru status";
	return;
	}
    foreach $_ ( @lines ) { 
	&log( 1, ">$_" );
	if ( m/^ \s* Name \s+ FRU \s+ Alarm |^--+/ix ) { 
	    }
	elsif ( m/Unable to find device/ ) { 
	    push @crits, "Unable to find device.";
	    }
	elsif ( m/^ (\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) \s+ (\S+) /ix ) { 
	    ( $name, $fru, $alarm, $state, $status ) = ( $1, $2, $3, $4, $5 );
	    if ( $alarm eq "Critical" ) { 
		push @crits, "$name in $alarm alarm";
		}
	    elsif ( $alarm ne "-" ) { 
		push @warns, "$name in $alarm alarm";
		}
	    elsif ( $state eq 'Removed' && $status eq 'Removed' ) { 
		# ignore for now
		}
	    elsif ( $status eq "OK" ) { 
		$oks++;
		}
	    else { 
		push @crits, "$name status $status";
		}

	    }
	elsif ( m/^\s*$/ ) { 
	    # ignore blank lines
	    }
	else { 
	    &log( 1, "unknown line $.: $_" );
	    push @unknowns, "unknown line $_";
	    }
	}
    &log( 1, "$oks ok frus" );
    push @oks, sprintf( "%d ok frus", $oks );
    }




## ./sscs.sh list -a STRONGBAD vdisk
#Virtual Disk: 1
## ./sscs.sh list -a STRONGBAD vdisk 1
#Virtual Disk: 1
#  Status:               Optimal
#  State:                Ready
#  Number of Disks:      14
#  RAID Level:           1
#  Total Capacity:       1.906 TB
#  Configured Capacity:  1.757 TB
#  Available Capacity:   152.258 GB
#  Array Name:           STRONGBAD
#  Array Type:           6140
#  Disk Type:            Fibre Channel
#  Maximal Volume Size:  152.258 GB
#  Associated Disks:     
#    Disk:               t85d14
#    Disk:               t85d13
#    Disk:               t85d12
#    Disk:               t85d11
#    Disk:               t85d10
#    Disk:               t85d09
#    Disk:               t85d08
#    Disk:               t85d07
#    Disk:               t85d06
#    Disk:               t85d05
#    Disk:               t85d04
#    Disk:               t85d03
#    Disk:               t85d02
#    Disk:               t85d01
#  Associated Volumes:   
#    Volume:             HOME
#    Volume:             VOL1
#    Volume:             VOL2
#    Volume:             VOL3
#    Volume:             VOL4
#    Volume:             VOL5
#    Volume:             VOL6
#    Volume:             VOL7
#

sub list_vdisk { 
    my( @lines, @vdisks, $vdisk, $name, $state, $status, $oks );

    @lines = &sscs( "list -a $array vdisk" );
    if ( $#lines < 0 ) { 
        push @unknowns, "couldn't list vdisk";
	return;
	}
    undef @vdisks;
    foreach $_ ( @lines ) { 
	&log( 1, ">$_" );
	if ( m/Unable to find device/ ) { 
	    push @crits, "Unable to find device.";
	    }
	elsif ( m/The resource was not found/ ) { 
	    push @crits, "vdisk resource was not found";
	    }
	elsif ( m/^ Virtual \s+ Disk: \s+ (\S+) /ix ) { 
	    push @vdisks, $1;
	    }
	}
    if ( $#vdisks < 0 ) { 
	push @unknowns, "no vdisks found";
	return;
	}

    $oks = 0;
    foreach $vdisk ( @vdisks ) { 
	@lines = &sscs( "list -a $array vdisk $vdisk" );
	if ( $#lines < 0 ) { 
	    push @unknowns, "couldn't list vdisk $vdisk";
	    next;
	    }
	foreach $_ ( @lines ) { 
	    &log( 1, ">$_" );
	    if ( m/Unable to find device/ ) { 
		push @crits, "Unable to find device.";
		}
	    elsif ( m/^ Virtual \s+ Disk: \s+ (\S+) /ix ) { 
		$name = $1;
		}
	    elsif ( m/^ \s* Status: \s+ (\S+) /ix ) { 
		$status = $1;
		if ( $status eq "Optimal" ) { 
		    $oks++;
		    }
		else { 
		    push @crits, "$name status $status";
		    }
		}
	    elsif ( m/^ \s* State: \s+ (\S+) /ix ) { 
		$state = $1;
		&log( 1, "vdisk $name status $status state $state\n" );
		if ( $state ne "Ready" ) { 
		    push @crits, "$name state $state";
		    }
		}
	    # else ignore it
	    }
	}
    push @oks, sprintf( "%d ok vdisks", $oks );
    }



## ./sscs.sh list alarm
#Alarm Id    : alarm20
#Severity    : Critical
#Type        : 6140.ProblemEvent
#Topic       : REC_SPEED_NEG_ERROR
#Event Code  : 57.66.1073
#Date        : 2007-08-10 16:59:50
#Device      : STRONGBAD[SUN.54065460150.0715AWF042]
#Description : Data rate negotiation failed on controller Tray.85.Controller.A, channel  2
#
#Alarm Id    : alarm21
#Severity    : Critical
#Type        : 6140.ProblemEvent
#Topic       : REC_SPEED_NEG_ERROR
#Event Code  : 57.66.1073
#Date        : 2007-08-10 17:14:50
#Device      : STRONGBAD[SUN.54065460150.0715AWF042]
#Description : Data rate negotiation failed on controller Tray.85.Controller.B, channel  2
#
#
#Found 2 alert entries in health database.


sub list_alarm { 
    my( @lines, $severity, $device, $desc, $alarms );

    $alarms = 0;
    @lines = &sscs( "list alarm" );
    foreach $_ ( @lines ) { 
	&log( 1, ">$_" );
	if ( m/Unable to find device/ ) { 
	    push @crits, "Unable to find device.";
	    }
	elsif ( m/^ Severity \s* : \s+ (\S+) /ix ) { 
	    $severity = $1;
	    }
	elsif ( m/^ Device \s* : \s+ ([\w]+) /ix ) { 
	    $device = $1;
	    }
	elsif ( m/^ Description \s* : \s+ (\S.+) /ix ) { 
	    $desc = $1;
	    &log( 1, "device $device severity $severity desc $desc\n" );
	    next if ( $array !~ m/^$device/i );
	    $alarms++;
	    if ( $severity eq 'Critical' ) { 
		push @crits, "alarm $desc";
		}
	    else { 
		if ( $desc =~ m/ is at revision "([^"]+)" baseline version is "([^"]+)"/i ) { 
		    push @ignores, "alarm $desc";
		    }
		else { 
		    push @warns, "alarm $desc";
		    }
		}
	    }
	}
    if ( ! $alarms ) { 
	push @oks, "no alarms";
	}
    }



#############################################



sub sscs { 
    my( $subcmd ) = @_;
    my( $cmd, @lines, $line, $rc, $tried_login, $m, $sscs_conf, 
	$probably_logged_in, $key, $port );

    # HOME isn't set when running under nrpe
    if ( ! -d $ENV{HOME} ) { 
	my( $name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell, $expire ) = getpwuid( $< );
	$ENV{HOME} = $dir;
	}

    $ENV{PATH} = "/usr/j2se/bin/:/usr/bin";

    $ENV{JAVA_HOME} = "/usr/j2se";

    #$ENV{LD_LIBRARY_PATH} = "/usr/j2se/jre/lib/sparc/server:/usr/j2se/jre/lib/sparc:/usr/j2se/jre/../lib/sparc:/tmp/istemp2059107111848/_bundledJRE_/jre/lib/sparc/client:/tmp/istemp2059107111848/_bundledJRE_/jre/lib/sparc:/tmp/istemp2059107111848/_bundledJRE_/jre/../lib/sparc:/usr/openwin/lib:/opt/lib:/usr/lib";
    $ENV{LD_LIBRARY_PATH} = "/usr/j2se/jre/lib/i386/server:/usr/j2se/jre/lib/i386:/usr/j2se/lib:/usr/openwin/lib:/opt/lib:/usr/lib";

    #$ENV{SSCS_DEBUG} = '1';

    &log( 2, "chdir $bindir\n" );
    if ( ! chdir $bindir ) { 
	&log( 1, "can't chdir $bindir: $!\n" );
	push @crits, "can't chdir $bindir: $!";
	return;
	}

    # Try to predict if we need to login.
    # This sometimes avoids the long delay on the normal command.
    # This isn't definate, you can have a running proxy server and 
    # not be logged in.
    # 
    &log( 2, "checking for ~/.sscs_conf file" );
    $probably_logged_in = 0;
    $sscs_conf = "$ENV{HOME}/.sscs_conf"; 
    if ( -f $sscs_conf ) { 
	if ( open( fH, $sscs_conf ) ) { 
	    $key = <fH>;
	    $port = <fH>;
	    close fH;

	    if ( $port =~ m/^\d{4,5}$/ && $port >= 1024 && $port < 65536 ) { 

		# FIXME: try to connect to the tcp port?
		# FIXME: check the tcp port in netstat?

		&log( 2, "probably logged in" );
		$probably_logged_in = 1;
		}
	    }
	}
    if ( $probably_logged_in ) { 
	$tried_login = 0;
	}
    else { 
	$rc = &sscs_login();
	if ( $rc ) { 
	    # login failed
	    return undef;
	    }
	$tried_login = 1;
	}

    while ( 1 ) { 
	$cmd = "./sscs $subcmd";
	&log( 1, "trying $cmd\n" );

	$need_login = 0;
	if ( 0 ) { 
	    # this is faster in in the normal case, but 
	    # hangs on errors.  Perhaps because there's no timeout?
	    # Perhaps because there's no pty?
	    &log( 2, "before popen $cmd\n" );
	    if ( ! open( pH, "$cmd |" ) ) { 
		push @unknowns, "Cannot spawn $cmd: $!\n";
		return;
		}
	    &log( 2, "after popen\n" );
	    undef @lines;
	    $need_login = 0;
	    while( <pH> ) { 
		&log( 2, ">$_" );
		chomp;
		push @lines, $_;
		#You have not logged in or your session has expired.
		#Try logging in again.
		if ( $line =~ m/You are not currently logged in|Connection failed|You have not logged in or your session has expired|Try logging in again/i ) { 
		    $need_login = 1;
		    }
		}
	    close pH;
	    &log( 2, "after pclose\n" );
	    }
	else { 

	    if ( $verbose < 2 )  { 
		# need to explicitly turn off copying spawed cmd's output to stdout
		# supposedly you can do $exp->log_stdout(0), but it doesn't work.
		$Expect::Log_Stdout = 0;
		}

	    #print lH "before new expect\n";
	    $Expect::Do_Soft_Close = 1;
	    $exp = new Expect;
	    &log( 2, "before spawn $cmd\n" );
	    unless ( $exp->spawn( $cmd ) ) { 
		&log( 1, "cannot spawn $cmd: $!\n" );
		push @unknowns, "Cannot spawn $cmd: $!\n";
		$exp->soft_close();
		return;
		}
	    #&log( 2, "after spawn\n" );

	    if ( $verbose > 1 )  { 
		$exp->exp_internal(1);
		$exp->debug(1);
		}

	    undef @lines;
	    $need_login = 0;
	    $internal_error = 0;
	    $m = $exp->expect( $timeout, 
		[ qr/^[^\n]*\n/, sub { 
		    $line = $exp->match(); 
		    &log( 2, ">$line" );
		    if ( $line =~ m/An invalid resource-type value was used/i ) { 
			&log( 1, "internal error: $cmd => $line" );
			push @unknowns, "internal error: $cmd => $line";
			$internal_error = $line;
			}
		    #You have not logged in or your session has expired.
		    #Try logging in again.
		    elsif ( $line =~ m/You have not logged in or your session has expired|Try logging in again|You are not currently logged in|Connection failed/i ) { 
			&log( 2, "need login: $line" );
			$need_login = $line;
			}
		    else { 
			chomp $line;
			push @lines, $line;
			exp_continue;
			}
		    } ],
		);
	    &log( 2, "after expect loop, m $m\n" );
	    $exp->soft_close();
	    }


	if ( $internal_error ) { 
	    return undef;
	    }

	elsif ( $need_login ) { 
	    if ( $tried_login ) {
		return undef;
		}
	    $tried_login = 1;
	    $rc = &sscs_login();
	    if ( $rc ) { 
		# login failed
		return undef;
		}
	    }

	else { 
	    return @lines;
	    }
	}
    }






    

sub sscs_login { 
    my( $cmd, $m, $enabled );

    &log( 1, "in sscs_login()" );

    my $password_login = &get_password( $password_file ); 
    if ( ! $password_login ) { 
	return 0;
	}

    if ( $verbose < 2 )  { 
	# supposedly you can do $exp->log_stdout(0), but it doesn't work.
	$Expect::Log_Stdout = 0;
	}

    $cmd = "./sscs login -h localhost -u $username -f";

    #&log( 2, "before new expect\n" );
    $Expect::Do_Soft_Close = 1;
    $exp = new Expect;
    &log( 2, "before spawn $cmd\n" );
    unless ( $exp->spawn( $cmd ) ) { 
	&log( 1, "cannot spawn $cmd: $!\n" );
	push @unknowns, "Cannot spawn $cmd: $!\n";
	$exp->soft_close();
	return 1;
	}
    #&log( 2, "after spawn\n" );

    if ( $verbose > 1 )  { 
	$exp->exp_internal(1);
	$exp->debug(1);
	$exp->log_file( $logfile );
	}

    $m = $exp->expect( $timeout, 
	"assword:"
	);
    if ( $m != 1 ) { 
        push @unknowns, "Never got password prompt: " . $exp->exp_error();
        &log( 1, "Never got password prompt\n" );
	$exp->soft_close();
	return 1;
        }

    &log( 2, "sending password\n" );
    $exp->clear_accum();
    $exp->send( "$password_login\r" );

    $m = $exp->expect( $timeout, 
	[ "failed", sub { 
	    push @unknowns, "login failed";
	    &log( 1, "login failed\n" );
	    } ],
	[ 'TIMEOUT', sub { 
	    push @unknowns, "login timed out";
	    &log( 1, "login timed out\n" );
	    } ],
	[ 'eof', sub { } ],
	);
    &log( 2, "login expect returned $m, exp_error =", $exp->exp_error() );
    if ( $m == 3 && $exp->exp_exitstatus() == 0 ) { 
	&log( 2, "login succeeded\n" );
	$exp->soft_close();
	return 0;
	}

    &log( 2, "about to soft close login \n" );
    $exp->soft_close();
    return 1;
    }






sub get_password{ 
    my( $file ) = @_;
    my( $password );

    &log( 1, "reading password from $file\n" );

    if ( ! open( pwfH, $file ) )  { 
	&log( 1, "can't open $file: $!\n" );
	push @unknowns, "can't open $file: $!\n";
	return undef;
	}
    $password = <pwfH>;
    chomp( $password );
    close pwfH;
    &log( 2, "got passwd from $file\n" );
    return $password
    }



