X-Git-Url: https://defaria.com/gitweb/?a=blobdiff_plain;ds=inline;f=lib%2FRexec.pm;h=2eecab803b2bb682d2775b27cfa25c0b31629713;hb=2dca9460aaac20e49c409da4f9e59c85027c3605;hp=7632dd777141a0cb966435f0012beaa4bbde8cbc;hpb=020a4a5ea2be725b155cae3a2cadc9aba3911b9b;p=clearscm.git
diff --git a/lib/Rexec.pm b/lib/Rexec.pm
index 7632dd7..2eecab8 100644
--- a/lib/Rexec.pm
+++ b/lib/Rexec.pm
@@ -1,1176 +1,1244 @@
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item Nothing
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item Nothing
-
-=back
-
-=for html
-
-=cut
-
- $self->{handle}->soft_close;
-
- undef $self->{handle};
- undef $self->{status};
- undef $self->{lines};
-
- return;
-} # logoff
-
-sub new {
- my ($class) = shift;
-
-=pod
-
-=head3 new (
-
-=over
-
-=item host =>
-
-Returns:
-
-=for html
-
-=over
-
-=item Rexec object
-
-=back
-
-=for html
-
-=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
+
+=over
+
+=item None
+
+=back
+
+=for html
+
+Returns:
+
+=for html
+
+=over
+
+=item Nothing
+
+=back
+
+=for html
+
+=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
+
+=over
+
+=item None
+
+=back
+
+=for html
+
+Returns:
+
+=for html
+
+=over
+
+=item Nothing
+
+=back
+
+=for html
+
+=cut
+
+ $self->{handle}->soft_close;
+
+ undef $self->{handle};
+ undef $self->{status};
+ undef $self->{lines};
+
+ return;
+} # logoff
+
+sub new {
+ my ($class, %parms) = @_;
+
+=pod
+
+=head3 new (
+
+=over
+
+=item host =>
+
+Returns:
+
+=for html
+
+=over
+
+=item Rexec object
+
+=back
+
+=for html
+
+=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
-
-=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
-
-Returns:
-
-=for html
-
-=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
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item $status
-
-1 if abort was successful (we got a command prompt back) or 0 if it
-was not.
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item $status
-
-Last status from exec.
-
-=back
-
-=for html
-
-=cut
-
- return $self->{status};
-} # status
-
-sub shellstyle {
- my ($self) = @_;
-
-=pod
-
-=head3 shellstyle
-
-Returns the shellstyle
-
-Parameters:
-
-=for html
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item "sh"|"csh"
-
-sh: Bourne or csh: for csh style shells
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item @lines
-
-An array of lines from the last call to exec.
-
-=back
-
-=for html
-
-=cut
-
- return @{$self->{lines}};
-} # lines
-
-sub print_lines () {
- my ($self) = @_;
-
-=pod
-
-=head3 print_lines
-
-Essentially prints the lines array to stdout
-
-Parameters:
-
-=for html
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item Nothing
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item $hostname
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item None
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item $timeout
-
-=back
-
-=for html
-
-=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
-
-=over
-
-=item $timeout
-
-New timeout value to set
-
-=back
-
-=for html
-
-Returns:
-
-=for html
-
-=over
-
-=item $timeout
-
-Old timeout value
-
-=back
-
-=for html
-
-=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
-
-
+ +=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+ +Returns: + +=for html
+ +=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+ +=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
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item $status + +1 if abort was successful (we got a command prompt back) or 0 if it +was not. + +=back + +=for html+ +=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
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item $status + +Last status from exec. + +=back + +=for html+ +=cut + + return $self->{status}; +} # status + +sub shellstyle { + my ($self) = @_; + +=pod + +=head3 shellstyle + +Returns the shellstyle + +Parameters: + +=for html
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item "sh"|"csh" + +sh: Bourne or csh: for csh style shells + +=back + +=for html+ +=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
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item @lines + +An array of lines from the last call to exec. + +=back + +=for html+ +=cut + + return @{$self->{lines}}; +} # lines + +sub print_lines () { + my ($self) = @_; + +=pod + +=head3 print_lines + +Essentially prints the lines array to stdout + +Parameters: + +=for html
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item Nothing + +=back + +=for html+ +=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
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item $hostname + +=back + +=for html+ +=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
+ +=over + +=item None + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item $timeout + +=back + +=for html+ +=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
+ +=over + +=item $timeout + +New timeout value to set + +=back + +=for html+ +Returns: + +=for html
+ +=over + +=item $timeout + +Old timeout value + +=back + +=for html+ +=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 + +