Skip Menu |

This queue is for tickets about the Net-SCP-Expect CPAN distribution.

Report information
The Basics
Id: 68516
Status: new
Priority: 0/
Queue: Net-SCP-Expect

People
Owner: Nobody in particular
Requestors: SHAW [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.16
Fixed in: (no value)



Subject: Module can hang when using an identity file & auto_yes => 1
Some transfers can complete before the first call to expect(). When this happens & auto_yes is true EOF is not detected, this causes a latter call to expect() to hang indefinitely if $timeout_err has not been specified which, by default, isn't. From the code: # EOF is sent here but is not detected if($auto_yes){ while($scp->expect($timeout_auto,-re=>'[Yy]es\/[Nn]o')){ $scp->send("yes\n"); } } #... # # EOF is never detected here and we hang unless($no_check || $verbose){ $error = ($scp->expect($timeout_err, # other matches ['eof' => sub{ $eof = 1 } ], ))[1]; } else{ $error = ($scp->expect($timeout_err, ['eof' => sub { $eof = 1 }])) [1]; } Here's a sample that includes Expect output: [sshaw@localhost ~]$ cat scp.pl $Expect::Exp_Internal = 1; my $scp = Net::SCP::Expect->new(host => 'hostey', identity_file => "$ENV{HOME}/id_rsa", auto_yes => 1); $scp->scp(shift); [sshaw@localhost ~]$ perl scp.pl a.out Spawned 'scp -q -i '/home/sshaw/id_rsa' 'a.out' 'sshaw@hostey:a.out'' spawn id(5) Pid: 10902 Tty: /dev/pts/6 at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 181 Expect::spawn('Expect', 'scp -q -i \'/home/sshaw/id_rsa\' \'a.out\' \'sshaw@pstor3:a...') called at /usr/lib/perl5/ site_perl/5.8.8/Net/SCP/Expect.pm line 204 Net::SCP::Expect::scp('Net::SCP::Expect=HASH(0x841cb44)', 'a.out') called at scp.pl line 18 Starting EXPECT pattern matching... at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 561 Expect::expect('Expect=GLOB(0x8529304)', 1, '-re', '[Yy]es\/ [Nn]o') called at /usr/lib/perl5/site_perl/5.8.8/Net/SCP/Expect.pm line 213 Net::SCP::Expect::scp('Net::SCP::Expect=HASH(0x841cb44)', 'a.out') called at scp.pl line 18 spawn id(5): list of patterns: #1: -re `[Yy]es\\/[Nn]o' spawn id(5): Does `' match: pattern #1: -re `[Yy]es\\/[Nn]o'? No. Waiting for new data (1 seconds)... Returning from expect with TIMEOUT or EOF Starting EXPECT pattern matching... at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 561 Expect::expect('Expect=GLOB(0x8529304)', 'undef', 'ARRAY (0x85297fc)', 'ARRAY(0x852985c)', 'ARRAY(0x8529ec8)') called at /usr/ lib/perl5/site_perl/5.8.8/Net/SCP/Expect.pm line 273 Net::SCP::Expect::scp('Net::SCP::Expect=HASH(0x841cb44)', 'a.out') called at scp.pl line 18 spawn id(5): list of patterns: #1: -re `(?-xism:[Pp]ass.*)' #2: -re `(?-xism:\w+.*)' #3: -eof `' spawn id(5): Does `' match: pattern #1: -re `(?-xism:[Pp]ass.*)'? No. pattern #2: -re `(?-xism:\w+.*)'? No. pattern #3: -eof `'? No. Waiting for new data (unlimited seconds)... I've attached a path that fixes this with minimal code restructuring. -Skye
Subject: Net-SCP-Expect-0.16.expect-eof.patch
--- Net-SCP-Expect-0.16/Expect.pm 2009-02-06 09:16:10.000000000 -0800 +++ Net-SCP-Expect-0.16a/Expect.pm 2011-05-27 04:24:42.000000000 -0700 @@ -210,10 +210,21 @@ sub scp{ $scp->log_stdout(0); + my $eof = 0; + my $error; + ################################################################ + # Some transfers can finish by the time we get here. + # If $timeout_err is not set and we don't check for EOF + # we would wait indefinitely below for an EOF that will never happen. + ################################################################ if($auto_yes){ - while($scp->expect($timeout_auto,-re=>'[Yy]es\/[Nn]o')){ - $scp->send("yes\n"); - } + $error = ($scp->expect($timeout_auto, + [qr/[Yy]es\/[Nn]o/ => sub { + $scp->send("yes\n"); + exp_continue; + } + ], + ['eof' => sub { $eof = 1 }]))[1]; } if ($password) { @@ -243,38 +254,37 @@ sub scp{ # The exception to this is verbose output, which can mistakenly # be picked up by Expect. ################################################################ - my $error; - my $eof = 0; - unless($no_check || $verbose){ - - $error = ($scp->expect($timeout_err, - [qr/[Pp]ass.*/ => sub{ - my $error = $scp->before() || $scp->match(); - if($handler){ - $handler->($error); - return; - } - else{ - croak("Error: Bad password [$error]"); - } - } - ], - [qr/\w+.*/ => sub{ - my $error = $scp->match() || $scp->before(); - if($handler){ - $handler->($error); - return; - } - else{ - croak("Error: last line returned was: $error"); - } - } - ], - ['eof' => sub{ $eof = 1 } ], - ))[1]; - } - else{ - $error = ($scp->expect($timeout_err, ['eof' => sub { $eof = 1 }]))[1]; + unless($eof) { + unless($no_check || $verbose){ + $error = ($scp->expect($timeout_err, + [qr/[Pp]ass.*/ => sub{ + my $error = $scp->before() || $scp->match(); + if($handler){ + $handler->($error); + return; + } + else{ + croak("Error: Bad password [$error]"); + } + } + ], + [qr/\w+.*/ => sub{ + my $error = $scp->match() || $scp->before(); + if($handler){ + $handler->($error); + return; + } + else{ + croak("Error: last line returned was: $error"); + } + } + ], + ['eof' => sub{ $eof = 1 } ], + ))[1]; + } + else{ + $error = ($scp->expect($timeout_err, ['eof' => sub { $eof = 1 }]))[1]; + } } if($verbose){ print $scp->after(),"\n" }