madhurikl has asked for the wisdom of the Perl Monks concerning the following question:

I am using Net::SSH2::Channel to execute commands on a remote machine. The below code works perfectly fine on a ubuntu system, but on an opensuse system, the read call always returns 0 bytes. I however get the right exit status for any command that I give, even on the opensuse system.
use Net::SSH2; my $ssh2 = Net::SSH2->new(); $ssh2->connect($ip) or die "Unable to connect host $@ \n"; $ssh2->auth(username => 'test', password => '1234'); $ssh2->debug(1); my $chan = $ssh2->channel(); $chan->blocking(1); $chan->ext_data('merge'); $chan->exec('who'); my $output; my $len = $chan->read($output,8192); print "output is $output\n"; my $status = $chan->exit_status(); print "status is $status\n";
Someone please help me through this problem.
  • Comment on Net::SSH2::Channel with exec, reads 0 bytes on suse while works fine on ubuntu
  • Download Code

Replies are listed 'Best First'.
Re: Net::SSH2::Channel with exec, reads 0 bytes on suse while works fine on ubuntu
by Illuminatus (Curate) on Apr 03, 2011 at 00:32 UTC
    I have not personally used Net::SSH2:Channel, and the cpan documentation does not make it clear what the flag means for blocking. I would assume that 1 means blocking, but are you sure? You are not checking the results of any of the methods after the connect. However, if the auth was failing, I'm pretty sure the channel would return undef, so your first use of it would fail in an obvious way.

    Your example program is not displaying $len, so I'm assuming that in some previous incarnation, you printed it out. If you did not, and are going by the print statement for $output, then the read method could have failed.

    Have you compared the ssh2 library versions for the 2 remote systems? I would make sure I was using the same lib version on both before I checked anything else.

    fnord

      Hi fnord,

      I just didnt include the error handling stuff to make the question and the code simple to understand.

      a) The channel is successfully created.

      b) I tried with both blocking(0) and blocking(1). However, I need a blocking call, and as per my knowledge, blocking(1) sets the blocking.

      c) $len returns 0. I can see the number of bytes read because I have debug enabled.

      d) Yes. ssh2 library versions are same on both the ubuntu machine and the opensuse machine. I am also connecting to the same remote machine from both the systems.

Re: Net::SSH2::Channel with exec, reads 0 bytes on suse while works fine on ubuntu
by syphilis (Archbishop) on Apr 03, 2011 at 00:46 UTC
    Some questions:
    1) Do the opensuse and ubuntu systems both execute commands on the *same* remote machine ?
    2) Do the opensuse and ubuntu systems run the same version of Net::SSH2 ?
    3) Is Net::SSH2 built against the same version of the libssh2 library ?
    4) Do the opensuse and ubuntu systems both run the same version of perl ?

    On my Win32 machine (perl-5.12.0, Net-SSH2-0.33, libssh2-1.2.7) connecting to a linux server, your script runs fine.
    It also runs fine if I remove the ext_data() call - so try removing that line of code from your script and see if that makes any difference.

    Cheers,
    Rob
      Hi Rob,

      1) Yes. Both execute same commands on the same remote machine.

      2) Yes. Both run the same version of Net::SSH2

      3) Yes. Both have the same libssh2

      4) Yes. Both run the same perl 5.10.0

      This is the debug output of my script : ------------
      libssh2_channel_open_ex(ss->session, pv_channel_type, len_channel_type +, window_size, packet_size, ((void *)0) , 0 ) -> 0x844420c Net::SSH2::Channel::read(size = 8192, ext = 0) - read 0 bytes - read 0 total output is status is 0 Net::SSH2::Channel::DESTROY Net::SSH2::DESTROY object 0x83aaa3c
        Sorry - only other idea I've got is to update the "problem" box to the latest Net::SSH2 and libssh2 (if that's not already the case) and hope that fixes it.

        And just try doing stuff until something happens that makes sense. Do you know if the sent command gets executed on the remote machine ? (I would guess that it does, and that it's only the output that gets lost, but it's something that should be verified.)

        Cheers,
        Rob
Re: Net::SSH2::Channel with exec, reads 0 bytes on suse while works fine on ubuntu
by salva (Canon) on Apr 05, 2011 at 08:36 UTC
    If you only need to run your program on Linux/Unix systems (no Windows), Net::OpenSSH may be a better option than Net::SSH2.
      I run on windows too using cygwin. And I am using Net::SSH2 because it is threadsafe, and I need to use threads.
        Here is the code I use under cygwin or linux redhat
        — # connect $ssh2->connect($remote_server) or die "\nERROR02 - Unable to connect H +ost $@ \n"; ($code, $error_name, $error_string) = $ssh2->error(); if ($code ne 0) { &log("error001","code = $code"); &log("error002","error_name = $error_name"); &log("error003","error_string = $error_string"); } if ($ssh_pattern eq '/passphrase/') { # authenticate with key and passphrase $ssh2->auth_publickey($remote_login, $pub_key_file, $priv_key_file +, $remote_password) or die "\nERROR03 Unable to login $@ \n"; ($code, $error_name, $error_string) = $ssh2->error(); if ($code ne 0) { &log("error011","code = $code"); &log("error012","error_name = $error_name"); &log("error013","error_string = $error_string"); } } else { # authenticate with user and password $ssh2->auth_password($remote_login,$remote_password) or die "\nERR +OR04 Unable to login $@ \n"; ($code, $error_name, $error_string) = $ssh2->error(); if ($code ne 0) { &log("error021","code = $code"); &log("error022","error_name = $error_name"); &log("error023","error_string = $error_string"); } } # DE-Block SSH2 for channel open (blocking to 1) $ssh2->blocking(1); # open channel 1 $chan1 = $ssh2->channel(); ($code, $error_name, $error_string) = $ssh2->error(); if ($code ne 0) { &log("error031","code = $code"); &log("error032","error_name = $error_name"); &log("error033","error_string = $error_string"); } # Block SSH2 for channel shell (blocking to 0) $ssh2->blocking(0); ($code, $error_name, $error_string) = $ssh2->error(); if ($code ne 0) { &log("error051","code = $code"); &log("error052","error_name = $error_name"); &log("error053","error_string = $error_string"); } # start channel shell $chan1->shell(); # send a CR to initialize the session print $chan1 "\n";
        Regards Charles.