-=pod
-
-=head1 NAME $RCSfile: Rexec.pm,v $
-
-Execute commands remotely and returning the output and status of the
-remotely executed command.
-
-=head1 VERSION
-
+=pod
+
+=head1 NAME $RCSfile: Rexec.pm,v $
+
+Execute commands remotely and returning the output and status of the
+remotely executed command.
+
+=head1 VERSION
+
=over
-
-=item Author:
-
-Andrew DeFaria <Andrew@ClearSCM.com>
-
-=item Revision:
-
-$Revision: 1.21 $
-
-=item Created:
-
-Mon Oct 9 18:28:28 CDT 2006
-
-=item Modified:
-
-$Date: 2012/04/07 00:39:48 $
-
-=back
-
-=head1 SYNOPSIS
-
- use Rexec;
-
- my $status;
- my $cmd;
- my @lines;
-
- my $remote = new Rexec (host => $host);
-
- if ($remote) {
- print "Connected using " . $remote->{protocol} . " protocol\n";
-
- $cmd = "ls /tmp";
- @lines = $remote->execute ($cmd);
- $status = $remote->status;
- print "$cmd status: $status\n";
- $remote->print_lines;
-
- print "$_\n" foreach ($remote->execute ("cat /etc/passwd"));
- } else {
- print "Unable to connect to $username\@$host\n";
- } # if
-
-=head1 DESCRIPTION
-
-This module provides an object oriented interface to executing remote
-commands on Linux/Unix system (or potentially well configured Windows
-machines with Cygwin installed). Upon object creation a connection is
-attempted to the specified host in a cascaded fashion. First ssh is
-attempted, then rsh/rlogin and finally telnet. This clearly favors
-secure methods over those less secure ones. If username or password is
-prompted for, and if they are supplied, then they are used, otherwise
-the attempted connection is considered failed.
-
-Once connected the caller can use the exec method to execute commands
-on the remote host. Upon object destruction the connection is
-shutdown. Output from the remotely executed command is returned
-through the exec method and also avaiable view the lines
-method. Remote status is available via the status method. This means
-you can now more reliably obtain the status of the command executed
-remotely instead of just the status of the ssh/rsh command itself.
-
-Note: Currently no attempt has been made to differentiate output
-written to stdout and stderr.
-
-As Expect is used to drive the remote session particular attention
-should be defining a regex to locate the prompt. The standard prompt
-regex (if not specified by the caller at object creation) is qr'[#>:$]
-$'. This covers most default and common prompts.
-
-=head1 Handling Timeouts
-
-The tricky thing when dealing with remote execution is attempting to
-determine if the remote machine has finished, stopped responding or
-otherwise crashed. It's more of an art than a science! The best one
-can do it send the command along and wait for a response. But how long
-to wait is the question. If your wait is too short then you run the
-risk of timing out before the remote command is finished. If you wait
-too long then you can be possibly waiting for something that will not
-be happening because the remote machine is either down or did not
-behave in a manner that you expected it to.
-
-To a large extent this module attempts to mitigate these issues on the
-principal that remote command execution is pretty well known. You log
-in and get a prompt. Issue a command and get another prompt. If the
-prompts are well known and easily determinable things go
-smoothly. However what happens if you execute a command remotely that
-will take 30 minutes to finish?
-
-This module has two timeout values. The first is login timeout. It's
-assumed that logins should happen fairly quickly. The default timeout
-for logins is 5 seconds.
-
-Command timeouts are set by default to 30 seconds. Most commands will
-finish before then. If you expect a command to take much longer then
-you can set an alternate timeout period.
-
-You can achieve longer timeouts in several ways. To give a longer
-login timeout specify your timeout to the new call. To give a longer
-exec timeout either pass a longer timeout to exec or set it view
-setTimeout. The current exec timeout is returned by getTimeout.
-
-=head1 METHODS
-
-The following routines are exported:
-
-=cut
-
-package Rexec;
-
-use strict;
-use warnings;
-
-use base 'Exporter';
-
-use Carp;
-use Expect;
-
-our $VERSION = '1.0';
-
-# This is the "normal" definition of a prompt. However what's normal?
-# For example, my prompt it typically the machine name followed by a
-# colon. But even that appears in error messages such as <host>: not
-# found and will be mistaken for a prompt. No real good way to handle
-# this so we define a standard prompt here and allow the caller to
-# override that. But overriding it is tricky and left as an exercise
-# to the caller.
-
-# Here we have a number of the common prompt characters [#>:%$]
-# followed by a space and end of line.
-our $DEFAULT_PROMPT = qr'[#>:%$] $';
-
-my $default_login_timeout = 5;
-my $default_exec_timeout = 30;
-
-my $debug = $ENV{DEBUG} || 0;
-
-our @EXPORT = qw (
- exec
- host
- lines
- login
- logout
- new
- print_lines
- status
-);
-
-my @lines;
-
-sub ssh {
- my ($self) = @_;
-
- my ($logged_in, $timedout, $password_attempts) = 0;
-
- $self->{protocol} = 'ssh';
-
- my $user = $self->{username} ? "$self->{username}\@" : '';
-
- my $remote = Expect->new ("ssh $self->{opts} $user$self->{host}");
-
- return if !$remote;
-
- $remote->log_user ($debug);
-
- $remote->expect (
- $self->{timeout},
-
- # If password is prompted for, and if one has been specified, then
- # use it
- [ qr "[P|p]assword: $",
- sub {
- # If we already supplied the password then it must not have
- # worked so this protocol is no good.
- return if $password_attempts;
-
- my $exp = shift;
-
- # If we're being prompted for password and there is no
- # password to supply then there is nothing much we can do but
- # return undef since we can't get in with this protocol
- return if !$self->{password};
-
- $exp->send ("$self->{password}\n") if $self->{password};
- $password_attempts++;
-
- exp_continue;
- }
- ],
-
- # Discard lines that begin with "ssh:" (like "ssh: <host>: not
- # found")
- [ qr'\nssh: ',
- sub {
- return;
- }
- ],
-
- # If we find a prompt then everything's good
- [ $self->{prompt},
- sub {
- $logged_in = 1;
- }
- ],
-
- # Of course we may time out...
- [ timeout =>
- sub {
- $timedout = 1;
- }
- ],
- );
-
- if ($logged_in) {
- return $remote;
- } elsif ($timedout) {
- carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
- undef $remote;
- return;
- } else {
+=item Author:
+
+Andrew DeFaria <Andrew@ClearSCM.com>
+
+=item Revision:
+
+$Revision: 1.21 $
+
+=item Created:
+
+Mon Oct 9 18:28:28 CDT 2006
+
+=item Modified:
+
+$Date: 2012/04/07 00:39:48 $
+
+=back
+
+=head1 SYNOPSIS
+
+ use Rexec;
+
+ my $status;
+ my $cmd;
+ my @lines;
+
+ my $remote = new Rexec (host => $host);
+
+ if ($remote) {
+ print "Connected using " . $remote->{protocol} . " protocol\n";
+
+ $cmd = "ls /tmp";
+ @lines = $remote->execute ($cmd);
+ $status = $remote->status;
+ print "$cmd status: $status\n";
+ $remote->print_lines;
+
+ print "$_\n" foreach ($remote->execute ("cat /etc/passwd"));
+ } else {
+ print "Unable to connect to $username\@$host\n";
+ } # if
+
+=head1 DESCRIPTION
+
+This module provides an object oriented interface to executing remote
+commands on Linux/Unix system (or potentially well configured Windows
+machines with Cygwin installed). Upon object creation a connection is
+attempted to the specified host in a cascaded fashion. First ssh is
+attempted, then rsh/rlogin and finally telnet. This clearly favors
+secure methods over those less secure ones. If username or password is
+prompted for, and if they are supplied, then they are used, otherwise
+the attempted connection is considered failed.
+
+Once connected the caller can use the exec method to execute commands
+on the remote host. Upon object destruction the connection is
+shutdown. Output from the remotely executed command is returned
+through the exec method and also avaiable view the lines
+method. Remote status is available via the status method. This means
+you can now more reliably obtain the status of the command executed
+remotely instead of just the status of the ssh/rsh command itself.
+
+Note: Currently no attempt has been made to differentiate output
+written to stdout and stderr.
+
+As Expect is used to drive the remote session particular attention
+should be defining a regex to locate the prompt. The standard prompt
+regex (if not specified by the caller at object creation) is
+
+qr'[#>:$](\s*|\e.+)$'.
+
+This covers most default and common prompts.
+
+=head1 Handling Timeouts
+
+The tricky thing when dealing with remote execution is attempting to
+determine if the remote machine has finished, stopped responding or
+otherwise crashed. It's more of an art than a science! The best one
+can do it send the command along and wait for a response. But how long
+to wait is the question. If your wait is too short then you run the
+risk of timing out before the remote command is finished. If you wait
+too long then you can be possibly waiting for something that will not
+be happening because the remote machine is either down or did not
+behave in a manner that you expected it to.
+
+To a large extent this module attempts to mitigate these issues on the
+principal that remote command execution is pretty well known. You log
+in and get a prompt. Issue a command and get another prompt. If the
+prompts are well known and easily determinable things go smoothly.
+However what happens if you execute a command remotely that will take
+30 minutes to finish?
+
+This module has two timeout values. The first is login timeout. It's
+assumed that logins should happen fairly quickly. The default timeout
+for logins is 5 seconds.
+
+Command timeouts are set by default to 30 seconds. Most commands will
+finish before then. If you expect a command to take much longer then
+you can set an alternate timeout period.
+
+You can achieve longer timeouts in several ways. To give a longer
+login timeout specify your timeout to the new call. To give a longer
+exec timeout either pass a longer timeout to exec or set it view
+setTimeout. The current exec timeout is returned by getTimeout.
+
+=head1 METHODS
+
+The following routines are exported:
+
+=cut
+
+package Rexec;
+
+use strict;
+use warnings;
+
+use base 'Exporter';
+
+use Carp;
+use Expect;
+
+our $VERSION = '1.0';
+
+# This is the "normal" definition of a prompt. However what's normal?
+# For example, my prompt it typically the machine name followed by a
+# colon. But even that appears in error messages such as <host>: not
+# found and will be mistaken for a prompt. No real good way to handle
+# this so we define a standard prompt here and allow the caller to
+# override that. But overriding it is tricky and left as an exercise
+# to the caller.
+
+# Here we have a number of the common prompt characters [#>:%$]
+# followed by zero or more spaces and end of line.
+our $DEFAULT_PROMPT = qr'[#>:%$](\s*|\e.+)$';
+
+my $default_login_timeout = 5;
+my $default_exec_timeout = 30;
+
+my $debug = $ENV{DEBUG} || 0;
+
+our @EXPORT = qw (
+ exec
+ host
+ lines
+ login
+ logout
+ new
+ print_lines
+ status
+);
+
+my @lines;
+
+sub _debug ($) {
+ my ($msg) = @_;
+
+ my $logfile = "/tmp/rexex_debug.log";
+
+ open my $file, '>>', $logfile or croak "Unable to open $logfile for writing - $!";
+
+ print $file "DEBUG: $msg\n";
+
+ close $file;
+
+ return;
+} # _debug
+
+sub ssh {
+ my ($self) = shift;
+
+ my ($logged_in, $timedout, $password_attempts) = 0;
+
+ $self->{protocol} = 'ssh';
+
+ my $user = $self->{username} ? "$self->{username}\@" : '';
+
+ my $remote = Expect->new ("ssh $self->{opts} $user$self->{host}");
+
+ return unless $remote;
+
+ $remote->log_user ($debug);
+
+ $remote->expect (
+ $self->{timeout},
+
+ # If password is prompted for, and if one has been specified, then
+ # use it
+ [ qr "[P|p]assword: $",
+ sub {
+ # If we already supplied the password then it must not have
+ # worked so this protocol is no good.
+ return if $password_attempts;
+
+ my $exp = shift;
+
+ # If we're being prompted for password and there is no
+ # password to supply then there is nothing much we can do but
+ # return undef since we can't get in with this protocol
+ return unless $self->{password};
+
+ $exp->send ("$self->{password}\n") if $self->{password};
+ $password_attempts++;
+
+ exp_continue;
+ }
+ ],
+
+ # Discard lines that begin with "ssh:" (like "ssh: <host>: not
+ # found")
+ [ qr'\nssh: ',
+ sub {
+ return;
+ }
+ ],
+
+ # If we find a prompt then everything's good
+ [ $self->{prompt},
+ sub {
+ $logged_in = 1;
+ }
+ ],
+
+ # Of course we may time out...
+ [ timeout =>
+ sub {
+ $timedout = 1;
+ }
+ ],
+ );
+
+ if ($logged_in) {
+ # It's always hard to find the prompt. So let's make a distintive one
+ $self->{prompt} = "\n@@@";
+ $self->{handle} = $remote;
+
+ # OK this is real tricky. If we call execute with a command of PS1=@@@
+ # and we've changed our prompt to '@@@' then we'll see the '@@@' in the
+ # PS1=@@@ statement as the prompt! That'll screw us up so we instead say
+ # PS1=\@\@\@. The shell then removes the extra backslashes for us and sets
+ # the prompt to just "@@@" for us. We catch that as our prompt and now we
+ # have a unique prompt that we can easily recognize.
+ if ($self->{shellstyle} eq 'sh') {
+ $self->execute ('PS1=\@\@\@');
+ } else {
+ $self->execute ('set prompt=\@\@\@');
+ } # if
+
+ $self->{handle}->flush;
+ return $remote;
+ } elsif ($timedout) {
+ carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
+ undef $remote;
+ return;
+ } else {
carp "WARNING: Unable to connect to $self->{host} using $self->{protocol} protocol";
- return;
- } # if
-} # ssh
-
-sub rlogin {
- my ($self) = @_;
-
- my ($logged_in, $timedout, $password_attempts) = 0;
-
- $self->{protocol} = "rlogin";
-
- my $user = $self->{username} ? "-l $self->{username}" : "";
-
- my $remote = Expect->new ("rsh $user $self->{host}");
-
- return if !$remote;
-
- $remote->log_user ($debug);
-
- $remote->expect (
- $self->{timeout},
-
- # If password is prompted for, and if one has been specified, then
- # use it
- [ qr "[P|p]assword: $",
- sub {
- # If we already supplied the password then it must not have
- # worked so this protocol is no good.
- return if $password_attempts;
-
- my $exp = shift;
-
- # If we're being prompted for password and there is no
- # password to supply then there is nothing much we can do but
- # return undef since we can't get in with this protocol
- return if !$self->{password};
-
- $exp->send ("$self->{password}\n");
- $password_attempts++;
-
- exp_continue;
- }
- ],
-
- # HACK! rlogin may return "<host>: unknown host" which clashes
- # with some prompts (OK it clashes with my prompt...)
- [ ": unknown host",
- sub {
- return;
- }
- ],
-
- # If we find a prompt then everything's good
- [ $self->{prompt},
- sub {
- $logged_in = 1;
- }
- ],
-
- # Of course we may time out...
- [ timeout =>
- sub {
- $timedout = 1;
- }
- ],
- );
-
- if ($logged_in) {
- return $remote;
- } elsif ($timedout) {
- carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
- undef $remote;
- return;
- } else {
+ return;
+ } # if
+} # ssh
+
+sub rlogin {
+ my ($self) = shift;
+
+ my ($logged_in, $timedout, $password_attempts) = 0;
+
+ $self->{protocol} = "rlogin";
+
+ my $user = $self->{username} ? "-l $self->{username}" : "";
+
+ my $remote = Expect->new ("rsh $user $self->{host}");
+
+ return unless $remote;
+
+ $remote->log_user ($debug);
+
+ $remote->expect (
+ $self->{timeout},
+
+ # If password is prompted for, and if one has been specified, then
+ # use it
+ [ qr "[P|p]assword: $",
+ sub {
+ # If we already supplied the password then it must not have
+ # worked so this protocol is no good.
+ return if $password_attempts;
+
+ my $exp = shift;
+
+ # If we're being prompted for password and there is no
+ # password to supply then there is nothing much we can do but
+ # return undef since we can't get in with this protocol
+ return unless $self->{password};
+
+ $exp->send ("$self->{password}\n");
+ $password_attempts++;
+
+ exp_continue;
+ }
+ ],
+
+ # HACK! rlogin may return "<host>: unknown host" which clashes
+ # with some prompts (OK it clashes with my prompt...)
+ [ ": unknown host",
+ sub {
+ return;
+ }
+ ],
+
+ # If we find a prompt then everything's good
+ [ $self->{prompt},
+ sub {
+ $logged_in = 1;
+ }
+ ],
+
+ # Of course we may time out...
+ [ timeout =>
+ sub {
+ $timedout = 1;
+ }
+ ],
+ );
+
+ if ($logged_in) {
+ # It's always hard to find the prompt. So let's make a distintive one
+ $self->{prompt} = '@@@';
+ $self->{handle} = $remote;
+
+ # OK this is real tricky. If we call execute with a command of PS1=@@@
+ # and we've changed our prompt to '@@@' then we'll see the '@@@' in the
+ # PS1=@@@ statement as the prompt! That'll screw us up so we instead say
+ # PS1=\@\@\@. The shell then removes the extra backslashes for us and sets
+ # the prompt to just "@@@" for us. We catch that as our prompt and now we
+ # have a unique prompt that we can easily recognize.
+ if ($self->{shellstyle} eq 'sh') {
+ $self->execute ('PS1=\@\@\@');
+ } else {
+ $self->execute ('set prompt=\@\@\@');
+ } # if
+
+ return $remote;
+ } elsif ($timedout) {
+ carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
+ undef $remote;
+ return;
+ } else {
carp "WARNING: Unable to connect to $self->{host} using $self->{protocol} protocol";
- return;
- } # if
-} # rlogin
-
-sub telnet {
- my ($self) = @_;
-
- my ($logged_in, $timedout, $password_attempts) = 0;
-
- $self->{protocol} = "telnet";
-
- my $remote = Expect->new ("telnet $self->{host}");
-
- return if !$remote;
-
- $remote->log_user ($debug);
-
- $remote->expect (
- $self->{timeout},
-
- # If login is prompted for, and if what has been specified, then
- # use it
- [ qr "login: $",
- sub {
- my $exp = shift;
-
- # If we're being prompted for username and there is no
- # username to supply then there is nothing much we can do but
- # return undef since we can't get in with this protocol
- return if !$self->{username};
-
- $exp->send ("$self->{username}\n");
- exp_continue;
- }
- ],
-
- # If password is prompted for, and if one has been specified, then
- # use it
- [ qr "[P|p]assword: $",
- sub {
- # If we already supplied the password then it must not have
- # worked so this protocol is no good.
- return if $password_attempts;
-
- my $exp = shift;
-
- # If we're being prompted for password and there is no
- # password to supply then there is nothing much we can do but
- # return undef since we can't get in with this protocol
- return if !$self->{password};
-
- $exp->send ("$self->{password}\n");
- $password_attempts++;
-
- exp_continue;
- }
- ],
-
- # HACK! rlogin may return "<host>: Unknown host" which clashes
- # with some prompts (OK it clashes with my prompt...)
- [ ": Unknown host",
- sub {
- return;
- }
- ],
-
- # If we find a prompt then everything's good
- [ $self->{prompt},
- sub {
- $logged_in = 1;
- }
- ],
-
- # Of course we may time out...
- [ timeout =>
- sub {
- $timedout = 1;
- }
- ],
- );
-
- if ($logged_in) {
- return $remote;
- } elsif ($timedout) {
- carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
- undef $remote;
- return;
- } else {
+ return;
+ } # if
+} # rlogin
+
+sub telnet {
+ my ($self) = shift;
+
+ my ($logged_in, $timedout, $password_attempts) = 0;
+
+ $self->{protocol} = "telnet";
+
+ my $remote = Expect->new ("telnet $self->{host}");
+
+ return unless $remote;
+
+ $remote->log_user ($debug);
+
+ $remote->expect (
+ $self->{timeout},
+
+ # If login is prompted for, and if what has been specified, then
+ # use it
+ [ qr "login: $",
+ sub {
+ my $exp = shift;
+
+ # If we're being prompted for username and there is no
+ # username to supply then there is nothing much we can do but
+ # return undef since we can't get in with this protocol
+ return unless $self->{username};
+
+ $exp->send ("$self->{username}\n");
+ exp_continue;
+ }
+ ],
+
+ # If password is prompted for, and if one has been specified, then
+ # use it
+ [ qr "[P|p]assword: $",
+ sub {
+ # If we already supplied the password then it must not have
+ # worked so this protocol is no good.
+ return if $password_attempts;
+
+ my $exp = shift;
+
+ # If we're being prompted for password and there is no
+ # password to supply then there is nothing much we can do but
+ # return undef since we can't get in with this protocol
+ return unless $self->{password};
+
+ $exp->send ("$self->{password}\n");
+ $password_attempts++;
+
+ exp_continue;
+ }
+ ],
+
+ # HACK! rlogin may return "<host>: Unknown host" which clashes
+ # with some prompts (OK it clashes with my prompt...)
+ [ ": Unknown host",
+ sub {
+ return;
+ }
+ ],
+
+ # If we find a prompt then everything's good
+ [ $self->{prompt},
+ sub {
+ $logged_in = 1;
+ }
+ ],
+
+ # Of course we may time out...
+ [ timeout =>
+ sub {
+ $timedout = 1;
+ }
+ ],
+ );
+
+ if ($logged_in) {
+ # It's always hard to find the prompt. So let's make a distintive one
+ $self->{prompt} = '@@@';
+ $self->{handle} = $remote;
+
+ # OK this is real tricky. If we call execute with a command of PS1=@@@
+ # and we've changed our prompt to '@@@' then we'll see the '@@@' in the
+ # PS1=@@@ statement as the prompt! That'll screw us up so we instead say
+ # PS1=\@\@\@. The shell then removes the extra backslashes for us and sets
+ # the prompt to just "@@@" for us. We catch that as our prompt and now we
+ # have a unique prompt that we can easily recognize.
+ if ($self->{shellstyle} eq 'sh') {
+ $self->execute ('PS1=\@\@\@');
+ } else {
+ $self->execute ('set prompt=\@\@\@');
+ } # if
+
+ return $remote;
+ } elsif ($timedout) {
+ carp "WARNING: $self->{host} is not responding to $self->{protocol} protocol";
+ undef $remote;
+ return;
+ } else {
carp "WARNING: Unable to connect to $self->{host} using $self->{protocol} protocol";
- return;
- } # if
-} # telnet
-
-sub login () {
- my ($self) = @_;
-
-=pod
-
-=head2 login
-
-Performs a login on the remote host. Normally this is done during
-construction but this method allows you to login, say again, as maybe
-another user...
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item Nothing
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- # Close any prior opened sessions
- $self->logoff if ($self->{handle});
-
- my $remote;
-
- if ($self->{protocol}) {
- if ($self->{protocol} eq "ssh") {
- return $self->ssh;
- } elsif ($self->{protocol} eq "rsh" or $self->{protocol} eq "rlogin") {
- return $self->rlogin;
- } elsif ($self->{protocol} eq "telnet") {
- return $self->telnet;
- } else {
- croak "ERROR: Invalid protocol $self->{protocol} specified", 1;
- } # if
- } else {
- return $remote if $remote = $self->ssh;
- return $remote if $remote = $self->rlogin;
- return $self->telnet;
- } # if
-
- return;
-} # login
-
-sub logoff {
- my ($self) = @_;
-
-=pod
-
-=head3 logoff
-
-Performs a logout on the remote host. Normally handled in the
-destructor but you could call logout to logout if you wish.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item Nothing
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- $self->{handle}->soft_close;
-
- undef $self->{handle};
- undef $self->{status};
- undef $self->{lines};
-
- return;
-} # logoff
-
-sub new {
- my ($class) = shift;
-
-=pod
-
-=head3 new (<parms>)
-
-This method instantiates a new Rexec object. Currently only hash style
-parameter passing is supported.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item host => <host>:
-
-Specifies the host to connect to. Default: localhost
-
-=item username => <username>
-
-Specifies the username to use if prompted. Default: No username specified.
-
-=item password => <password>
-
-Specifies the password to use if prompted. Default: No password
-specified. Note passwords must be in cleartext at this
-time. Specifying them makes you insecure!
-
-=item prompt => <prompt regex>
-
-Specifies a regex describing how to identify a prompt. Default: qr'[#>:$] $'
-
-=item protocol => <ssh|rsh|rlogin|telnet>
-
-Specifies the protocol to use when connecting. Default: Try them all
-starting with ssh.
-
-=item opts => <options>
-
-Additional options for protocol (e.g. -X for ssh and X forwarding)
-
-=item verbose => <0|1>
-
-If true then status messages are echoed to stdout. Default: 0.
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item Rexec object
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- my %parms = @_;
-
- my $self = {};
-
- $self->{host} = $parms{host} ? $parms{host} : 'localhost';
- $self->{username} = $parms{username};
- $self->{password} = $parms{password};
- $self->{prompt} = $parms{prompt} ? $parms{prompt} : $DEFAULT_PROMPT;
- $self->{protocol} = $parms{protocol};
- $self->{verbose} = $parms{verbose};
- $self->{shellstyle} = $parms{shellstyle} ? $parms{shellstyle} : 'sh';
- $self->{opts} = $parms{opts} ? $parms{opts} : '';
+ return;
+ } # if
+} # telnet
+
+sub login () {
+ my ($self) = shift;
+
+=pod
+
+=head2 login
+
+Performs a login on the remote host. Normally this is done during
+construction but this method allows you to login, say again, as maybe
+another user...
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item Nothing
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ # Close any prior opened sessions
+ $self->logoff if ($self->{handle});
+
+ # Check to see if this machines is known in DNS. If not then the chance is
+ # good that we will not be able to log in
+ return unless gethostbyname $self->{host};
+
+ my $remote;
+
+ if ($self->{protocol}) {
+ if ($self->{protocol} eq "ssh") {
+ return $self->ssh;
+ } elsif ($self->{protocol} eq "rsh" or $self->{protocol} eq "rlogin") {
+ return $self->rlogin;
+ } elsif ($self->{protocol} eq "telnet") {
+ return $self->telnet;
+ } else {
+ croak "ERROR: Invalid protocol $self->{protocol} specified", 1;
+ } # if
+ } else {
+ return $remote if $remote = $self->ssh;
+ return $remote if $remote = $self->rlogin;
+ return $self->telnet;
+ } # if
+
+ return;
+} # login
+
+sub logoff {
+ my ($self) = shift;
+
+=pod
+
+=head3 logoff
+
+Performs a logout on the remote host. Normally handled in the
+destructor but you could call logout to logout if you wish.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item Nothing
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ $self->{handle}->soft_close;
+
+ undef $self->{handle};
+ undef $self->{status};
+ undef $self->{lines};
+
+ return;
+} # logoff
+
+sub new {
+ my ($class, %parms) = @_;
+
+=pod
+
+=head3 new (<parms>)
+
+This method instantiates a new Rexec object. Currently only hash style
+parameter passing is supported.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item host => <host>:
+
+Specifies the host to connect to. Default: localhost
+
+=item username => <username>
+
+Specifies the username to use if prompted. Default: No username specified.
+
+=item password => <password>
+
+Specifies the password to use if prompted. Default: No password
+specified. Note passwords must be in cleartext at this
+time. Specifying them makes you insecure!
+
+=item prompt => <prompt regex>
+
+Specifies a regex describing how to identify a prompt. Default:
+qr'[#>:$](\s*|\e.+)$'
+
+=item protocol => <ssh|rsh|rlogin|telnet>
+
+Specifies the protocol to use when connecting. Default: Try them all
+starting with ssh.
+
+=item opts => <options>
+
+Additional options for protocol (e.g. -X for ssh and X forwarding)
+
+=item verbose => <0|1>
+
+If true then status messages are echoed to stdout. Default: 0.
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item Rexec object
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ my $self = {};
+
+ $self->{host} = $parms{host} ? $parms{host} : 'localhost';
+ $self->{username} = $parms{username};
+ $self->{password} = $parms{password};
+ $self->{prompt} = $parms{prompt} ? $parms{prompt} : $DEFAULT_PROMPT;
+ $self->{protocol} = $parms{protocol};
+ $self->{verbose} = $parms{verbose};
+ $self->{shellstyle} = $parms{shellstyle} ? $parms{shellstyle} : 'sh';
+ $self->{opts} = $parms{opts} ? $parms{opts} : '';
$self->{timeout} = $parms{timeout} ? $parms{timeout} : $default_login_timeout;
-
- if ($self->{shellstyle} ne 'sh' and $self->{shellstyle} ne 'csh') {
- croak 'ERROR: Unknown shell style specified. Must be one of "sh" or "csh"', 1;
- } # if
-
- bless ($self, $class);
-
- # now login...
- $self->{handle} = $self->login;
-
- # Set timeout to $default_exec_timeout
- $self->{timeout} = $default_exec_timeout;
-
- return $self->{handle} ? $self : undef;
-} # new
-
-sub execute ($$) {
- my ($self, $cmd, $timeout) = @_;
-
-=pod
-
-=head3 exec ($cmd, $timeout)
-
-This method executes a command on the remote host returning an array
-of lines that the command produced, if any. Status of the command is
-stored in the object and accessible via the status method.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item $cmd:
-
-Command to execute remotely
-
-=item $timeout
-
-Set timeout for this execution. If timeout is 0 then wait forever. If
-you wish to interrupt this then set up a signal handler.
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item @lines
-
-An array of lines from STDOUT of the command. If STDERR is also wanted
-then add STDERR redirection to $cmd. Exit status is not returned by
-retained in the object. Use status method to retrieve it.
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- # If timeout is specified for this exec then use it - otherwise
- # use the object's defined timeout.
- $timeout = $timeout ? $timeout : $self->{timeout};
-
- # If timeout is set to 0 then the user wants an indefinite
- # timeout. But Expect wants it to be undefined. So undef it if
- # it's 0. Note this means we do not support Expect's "check it
- # only one time" option.
- undef $timeout if $timeout == 0;
-
- # If timeout is < 0 then the user wants to run the command in the
- # background and return. We still need to wait as we still may
- # timeout so change $timeout to the $default_exec_timeout in this
- # case and add a "&" to the command if it's not already there.
- # because the user has added a & to the command to run it in the
- if ($timeout && $timeout < 0) {
- $timeout = $default_exec_timeout;
- $cmd .= "&" if $cmd !~ /&$/;
- } # if
-
- # Set status to -2 indicating nothing happened! We should never
- # return -2 (unless a command manages to set $? to -2!)
- $self->{status} = -2;
-
- # Empty lines of any previous command output
- @lines = ();
-
- # Hopefully we will not see the following in the output string
- my $errno_str = "ReXeCerRoNO=";
- my $start_str = "StaRT";
-
- my $compound_cmd;
-
- # If cmd ends in a & then it makes no sense to compose a compound
- # command. The original command will be in the background and thus
- # we should not attempt to get a status - there will be none.
- if ($cmd !~ /&$/) {
- $compound_cmd = "echo $start_str; $cmd; echo $errno_str";
- $compound_cmd .= $self->{shellstyle} eq "sh" ? "\$?" : "\$status";
- } else {
- $compound_cmd = $cmd;
- } # if
-
- $self->{handle}->send ("$compound_cmd\n");
-
- $self->{handle}->expect (
- $timeout,
-
- [ timeout =>
- sub {
- $self->{status} = -1;
- }
- ],
-
- [ qr "\n$start_str",
- sub {
- exp_continue;
- }
- ],
-
- [ qr "\n$errno_str",
- sub {
- my ($exp) = @_;
-
- my $before = $exp->before;
- my $after = $exp->after;
-
- if ($after =~ /(\d+)/) {
- $self->{status} = $1;
- } # if
-
- my @output = split /\n/, $before;
-
- chomp @output;
- chop @output if $output[0] =~ /\r$/;
-
- foreach (@output) {
- next if /^$/;
- last if /$errno_str=/;
-
- push @lines, $_;
- } # foreach
-
- exp_continue;
- }
- ],
-
- [ $self->{prompt},
- sub {
- print 'Hit prompt!' if $debug;
- }
- ],
- );
-
- $self->{lines} = \@lines;
-
- return @lines;
-} # exec
-
-sub abortCmd (;$) {
- my ($self, $timeout) = @_;
-
-=pod
-
-=head3 abortCmd
-
-Aborts the current command by sending a Control-C (assumed to be the
-interrupt character).
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item $status
-
-1 if abort was successful (we got a command prompt back) or 0 if it
-was not.
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- # If timeout is specified for this exec then use it - otherwise
- # use the object's defined timeout.
- $timeout = $timeout ? $timeout : $self->{timeout};
-
- # If timeout is set to 0 then the user wants an indefinite
- # timeout. But Expect wants it to be undefined. So undef it if
- # it's 0. Note this means we do not support Expect's "check it
- # only one time" option.
- undef $timeout if $timeout == 0;
-
- # Set status to -2 indicating nothing happened! We should never
- # return -2 (unless a command manages to set $? to -2!)
- $self->{status} = -2;
-
- $self->{handle}->send ("\cC");
-
- $self->{handle}->expect (
- $timeout,
-
- [ timeout =>
- sub {
- $self->{status} = -1;
- }
- ],
-
- [ $self->{prompt},
- sub {
- print "Hit prompt!" if $debug;
- }
- ],
- );
-
- return $self->{status};
-} # abortCmd
-
-sub status {
- my ($self) = @_;
-
-=pod
-
-=head3 status
-
-Returns the status of the last command executed remotely.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item $status
-
-Last status from exec.
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- return $self->{status};
-} # status
-
-sub shellstyle {
- my ($self) = @_;
-
-=pod
-
-=head3 shellstyle
-
-Returns the shellstyle
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item "sh"|"csh"
-
-sh: Bourne or csh: for csh style shells
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- return $self->{shellstyle};
-} # shellstyle
-
-sub lines () {
- my ($self) = @_;
-
-=pod
-
-=head3 lines
-
-Returns the lines array from the last command called by exec.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item @lines
-
-An array of lines from the last call to exec.
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- return @{$self->{lines}};
-} # lines
-
-sub print_lines () {
- my ($self) = @_;
-
-=pod
-
-=head3 print_lines
-
-Essentially prints the lines array to stdout
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item Nothing
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- print "$_\n" foreach ($self->lines);
-
- return;
-} # print_lines
-
-sub getHost () {
- my ($self) = @_;
-
-=pod
-
-=head3 host
-
-Returns the host from the object.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item $hostname
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- return $self->{host};
-} # getHost
-
-sub DESTROY {
- my ($self) = @_;
-
- $self->{handle}->hard_close
- if $self->{handle};
-
- return;
-} # destroy
-
-sub getTimeout {
- my ($self) = @_;
-
-=head3 getTimeout
-
-Returns the timeout from the object.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item None
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item $timeout
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- return $self->{timeout} ? $self->{timeout} : $default_login_timeout;
-} # getTimeout
-
-sub setTimeout ($) {
- my ($self, $timeout) = @_;
-
-=pod
-
-=head3 setTimeout ($timeout)
-
-Sets the timeout value for subsequent execution.
-
-Parameters:
-
-=for html <blockquote>
-
-=over
-
-=item $timeout
-
-New timeout value to set
-
-=back
-
-=for html </blockquote>
-
-Returns:
-
-=for html <blockquote>
-
-=over
-
-=item $timeout
-
-Old timeout value
-
-=back
-
-=for html </blockquote>
-
-=cut
-
- my $oldTimeout = $self->getTimeout;
- $self->{timeout} = $timeout;
-
- return $oldTimeout;
-} # setTimeout
-
-1;
-
-=head1 DIAGNOSTICS
-
-=head2 Errors
-
-If verbose is turned on then connections or failure to connect will be
-echoed to stdout.
-
-=head3 Error text
-
- <host> is not responding to <protocol>
- Connected to <host> using <protocol> protocol
- Unable to connect to <host> using <protocol> protocol
-
-=head2 Warnings
-
-Specifying cleartext passwords is not recommended for obvious security concerns.
-
-=head1 CONFIGURATION AND ENVIRONMENT
-
-Configuration files and environment variables.
-
-=over
-
-=item None
-
-=back
-
-=head1 DEPENDENCIES
-
-=head2 Perl Modules
-
-=for html <a href="http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod">Expect</a><b
-
-=head3 ClearSCM Perl Modules
-
-=for html <p><a href="/php/cvs_man.php?file=lib/Display.pm">Display</a></p>
-
-=head1 INCOMPATABILITIES
-
-None yet...
-
-=head1 BUGS AND LIMITATIONS
-
-There are no known bugs in this module.
-
-Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
-
-=head1 LICENSE AND COPYRIGHT
-
-This Perl Module is freely available; you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation; either version 2 of the
-License, or (at your option) any later version.
-
-This Perl Module is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-General Public License (L<http://www.gnu.org/copyleft/gpl.html>) for more
-details.
-
-You should have received a copy of the GNU General Public License
-along with this Perl Module; if not, write to the Free Software Foundation,
-Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-reserved.
-
-=cut
\ No newline at end of file
+
+ if ($self->{shellstyle} ne 'sh' and $self->{shellstyle} ne 'csh') {
+ croak 'ERROR: Unknown shell style specified. Must be one of "sh" or "csh"',
+ } # if
+
+ bless ($self, $class);
+
+ # now login...
+ $self->{handle} = $self->login;
+
+ # Set timeout to $default_exec_timeout
+ $self->{timeout} = $default_exec_timeout;
+
+ return $self->{handle} ? $self : undef;
+} # new
+
+sub execute ($$) {
+ my ($self, $cmd, $timeout) = @_;
+
+=pod
+
+=head3 exec ($cmd, $timeout)
+
+This method executes a command on the remote host returning an array
+of lines that the command produced, if any. Status of the command is
+stored in the object and accessible via the status method.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item $cmd:
+
+Command to execute remotely
+
+=item $timeout
+
+Set timeout for this execution. If timeout is 0 then wait forever. If
+you wish to interrupt this then set up a signal handler.
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item @lines
+
+An array of lines from STDOUT of the command. If STDERR is also wanted
+then add STDERR redirection to $cmd. Exit status is not returned by
+retained in the object. Use status method to retrieve it.
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ # If timeout is specified for this exec then use it - otherwise
+ # use the object's defined timeout.
+ $timeout = $timeout ? $timeout : $self->{timeout};
+
+ # If timeout is set to 0 then the user wants an indefinite
+ # timeout. But Expect wants it to be undefined. So undef it if
+ # it's 0. Note this means we do not support Expect's "check it
+ # only one time" option.
+ undef $timeout if $timeout == 0;
+
+ # If timeout is < 0 then the user wants to run the command in the
+ # background and return. We still need to wait as we still may
+ # timeout so change $timeout to the $default_exec_timeout in this
+ # case and add a "&" to the command if it's not already there.
+ # because the user has added a & to the command to run it in the
+ if ($timeout && $timeout < 0) {
+ $timeout = $default_exec_timeout;
+ $cmd .= "&" if $cmd !~ /&$/;
+ } # if
+
+ # Set status to -2 indicating nothing happened! We should never
+ # return -2 (unless a command manages to set $? to -2!)
+ $self->{status} = -2;
+
+ # Empty lines of any previous command output
+ @lines = ();
+
+ # Hopefully we will not see the following in the output string
+ my $errno_str = "ReXeCerRoNO=";
+ my $start_str = "StaRT";
+
+ my $compound_cmd;
+
+ # If cmd ends in a & then it makes no sense to compose a compound
+ # command. The original command will be in the background and thus
+ # we should not attempt to get a status - there will be none.
+ if ($cmd !~ /&$/) {
+ $compound_cmd = "echo $start_str; $cmd; echo $errno_str";
+ $compound_cmd .= $self->{shellstyle} eq "sh" ? "\$?" : "\$status";
+ } else {
+ $compound_cmd = $cmd;
+ } # if
+
+ $self->{handle}->send ("$compound_cmd\n");
+
+ $self->{handle}->expect (
+ $timeout,
+
+ [ timeout =>
+ sub {
+ $self->{status} = -1;
+ }
+ ],
+
+ [ qr "\n$start_str",
+ sub {
+ exp_continue;
+ }
+ ],
+
+ [ qr "\n$errno_str",
+ sub {
+ my ($exp) = @_;
+
+ my $before = $exp->before;
+ my $after = $exp->after;
+
+ if ($after =~ /(\d+)/) {
+ $self->{status} = $1;
+ } # if
+
+ my @output = split /\n/, $before;
+
+ chomp @output;
+ chop @output if $output[0] =~ /\r$/;
+
+ foreach (@output) {
+ next if /^$/;
+ last if /$errno_str=/;
+
+ push @lines, $_;
+ } # foreach
+
+ exp_continue;
+ }
+ ],
+
+ [ $self->{prompt},
+ sub {
+ print 'Hit prompt!' if $debug;
+ }
+ ],
+ );
+
+ $self->{lines} = \@lines;
+
+ return @lines;
+} # exec
+
+sub abortCmd (;$) {
+ my ($self, $timeout) = @_;
+
+=pod
+
+=head3 abortCmd
+
+Aborts the current command by sending a Control-C (assumed to be the
+interrupt character).
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item $status
+
+1 if abort was successful (we got a command prompt back) or 0 if it
+was not.
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ # If timeout is specified for this exec then use it - otherwise
+ # use the object's defined timeout.
+ $timeout = $timeout ? $timeout : $self->{timeout};
+
+ # If timeout is set to 0 then the user wants an indefinite
+ # timeout. But Expect wants it to be undefined. So undef it if
+ # it's 0. Note this means we do not support Expect's "check it
+ # only one time" option.
+ undef $timeout if $timeout == 0;
+
+ # Set status to -2 indicating nothing happened! We should never
+ # return -2 (unless a command manages to set $? to -2!)
+ $self->{status} = -2;
+
+ $self->{handle}->send ("\cC");
+
+ $self->{handle}->expect (
+ $timeout,
+
+ [ timeout =>
+ sub {
+ $self->{status} = -1;
+ }
+ ],
+
+ [ $self->{prompt},
+ sub {
+ print "Hit prompt!" if $debug;
+ }
+ ],
+ );
+
+ return $self->{status};
+} # abortCmd
+
+sub status {
+ my ($self) = @_;
+
+=pod
+
+=head3 status
+
+Returns the status of the last command executed remotely.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item $status
+
+Last status from exec.
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ return $self->{status};
+} # status
+
+sub shellstyle {
+ my ($self) = @_;
+
+=pod
+
+=head3 shellstyle
+
+Returns the shellstyle
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item "sh"|"csh"
+
+sh: Bourne or csh: for csh style shells
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ return $self->{shellstyle};
+} # shellstyle
+
+sub lines () {
+ my ($self) = @_;
+
+=pod
+
+=head3 lines
+
+Returns the lines array from the last command called by exec.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item @lines
+
+An array of lines from the last call to exec.
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ return @{$self->{lines}};
+} # lines
+
+sub print_lines () {
+ my ($self) = @_;
+
+=pod
+
+=head3 print_lines
+
+Essentially prints the lines array to stdout
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item Nothing
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ print "$_\n" foreach ($self->lines);
+
+ return;
+} # print_lines
+
+sub getHost () {
+ my ($self) = @_;
+
+=pod
+
+=head3 host
+
+Returns the host from the object.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item $hostname
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ return $self->{host};
+} # getHost
+
+sub DESTROY {
+ my ($self) = @_;
+
+ $self->{handle}->hard_close
+ if $self->{handle};
+
+ return;
+} # destroy
+
+sub getTimeout {
+ my ($self) = @_;
+
+=head3 getTimeout
+
+Returns the timeout from the object.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item None
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item $timeout
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ return $self->{timeout} ? $self->{timeout} : $default_login_timeout;
+} # getTimeout
+
+sub setTimeout ($) {
+ my ($self, $timeout) = @_;
+
+=pod
+
+=head3 setTimeout ($timeout)
+
+Sets the timeout value for subsequent execution.
+
+Parameters:
+
+=for html <blockquote>
+
+=over
+
+=item $timeout
+
+New timeout value to set
+
+=back
+
+=for html </blockquote>
+
+Returns:
+
+=for html <blockquote>
+
+=over
+
+=item $timeout
+
+Old timeout value
+
+=back
+
+=for html </blockquote>
+
+=cut
+
+ my $oldTimeout = $self->getTimeout;
+ $self->{timeout} = $timeout;
+
+ return $oldTimeout;
+} # setTimeout
+
+1;
+
+=head1 DIAGNOSTICS
+
+=head2 Errors
+
+If verbose is turned on then connections or failure to connect will be
+echoed to stdout.
+
+=head3 Error text
+
+ <host> is not responding to <protocol>
+ Connected to <host> using <protocol> protocol
+ Unable to connect to <host> using <protocol> protocol
+
+=head2 Warnings
+
+Specifying cleartext passwords is not recommended for obvious security concerns.
+
+=head1 CONFIGURATION AND ENVIRONMENT
+
+Configuration files and environment variables.
+
+=over
+
+=item None
+
+=back
+
+=head1 DEPENDENCIES
+
+=head2 Perl Modules
+
+=for html <a href="http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod">Expect</a>
+
+=head3 ClearSCM Perl Modules
+
+=for html <p><a href="/php/scm_man.php?file=lib/Display.pm">Display</a></p>
+
+=head1 INCOMPATABILITIES
+
+None yet...
+
+=head1 BUGS AND LIMITATIONS
+
+There are no known bugs in this module.
+
+Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
+
+=head1 LICENSE AND COPYRIGHT
+
+This Perl Module is freely available; you can redistribute it and/or
+modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This Perl Module is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License (L<http://www.gnu.org/copyleft/gpl.html>) for more
+details.
+
+You should have received a copy of the GNU General Public License
+along with this Perl Module; if not, write to the Free Software Foundation,
+Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+reserved.
+
+=cut