How can I get command's result code, which executing via ssh

I

Ivan Samonov

I use net/ssh library.
My code:
require 'rubygems'
require 'net/ssh'
Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
ch.exec('false') { |ch, success| puts success } } }
"false" is a console program and it always return 1.
Why result of this program is "true"? What mean "success" here? I think
I misunderstand something.
 
R

Robert Klemme

I use net/ssh library.
My code:
require 'rubygems'
require 'net/ssh'
Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
ch.exec('false') { |ch, success| puts success } } }
"false" is a console program and it always return 1.
Why result of this program is "true"? What mean "success" here? I think
I misunderstand something.

This is likely because SSH does not propagate the result of the remote
process. You can find the details on SSH's manpage.

One way would be to send something like

echo "$?"

as last command and read this.

Kind regards

robert
 
B

Brian Candler

Robert said:
This is likely because SSH does not propagate the result of the remote
process. You can find the details on SSH's manpage.

Ahem??

'man ssh' on my system (Ubuntu Hardy) says:

ssh exits with the exit status of the remote command or with 255 if
an
error occurred.

A quick test confirms this to be true. So clearly the exit status *is*
propagated back. More likely it's just a problem with the OP's use of
the Net::SSH API.

Now, the Net::SSH API documentation (*) for exec tells you:

"success means that the command is being executed, not that it has
completed"

And if it hasn't completed, obviously you can't get the exit status. I
admit the documentation doesn't make it easy to see at a glance how you
*should* get the exit status.

But in any case, I think it's not helpful to post unverified guesses
about the behaviour of such a system.

Regards,

Brian.

(*) http://net-ssh.rubyforge.org/ssh/v2/api/index.html
 
B

Brian Candler

A quick check of the SSH protocol spec in RFC 4254 says, in section
6.10:

When the command running at the other end terminates, the following
message can be sent to return the exit status of the command.
Returning the status is RECOMMENDED. No acknowledgement is sent for
this message. The channel needs to be closed with
SSH_MSG_CHANNEL_CLOSE after this message.

The client MAY ignore these messages.

byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-status"
boolean FALSE
uint32 exit_status

(and it then goes on to describe the "exit-signal" message as well)

Grepping for exit-status in the net-ssh source turns up an example of
how to get it:

# * "exit-status" : the exit status of the remote process will be
reported
# as a long integer in the data buffer, which you can grab via
# data.read_long.
# * "exit-signal" : if the remote process died as a result of a
signal
# being sent to it, the signal will be reported as a string in the
# data, via data.read_string. (Not all SSH servers support this
channel
# request type.)
#
# channel.on_request "exit-status" do |ch, data|
# puts "process terminated with exit status: #{data.read_long}"
# end
 
B

Brian Candler

One other point. It's very dangerous to do

ch.foo { |ch| ... }

because (in ruby 1.8) 'ch' is bound to the same variable in both cases.
That is, the value assigned to the block parameter also changes the
outer 'ch'. So you should call them something different.

The finished program becomes:

require 'rubygems'
require 'net/ssh'
Net::SSH.start('localhost', 'yourname') { |ssh|
ssh.open_channel { |chan|
chan.on_request('exit-status') { |ch, data|
puts "process terminated with exit status: #{data.read_long}"
}
chan.exec('false') { |ch, success| puts success }
}
}
 
A

Aaron Turner

I use net/ssh library.
My code:
require 'rubygems'
require 'net/ssh'
Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
ch.exec('false') { |ch, success| puts success } =A0} }
"false" is a console program and it always return 1.
Why result of this program is "true"? =A0What mean "success" here? I thin= k
I misunderstand something.

I just ran into the same problem last week and I ended up doing what
Robert suggested:

retcode =3D ch.exec('my_command >/dev/null 2>&1 ; echo $?')

you can also do things like is:
results =3D ch.exec('my_command && echo SUCCESS || echo FAILURE')

--=20
Aaron Turner
http://synfin.net/
http://tcpreplay.synfin.net/ - Pcap editing and replay tools for Unix & Win=
dows
Those who would give up essential Liberty, to purchase a little temporary
Safety, deserve neither Liberty nor Safety.
-- Benjamin Franklin
 
R

Robert Klemme

But in any case, I think it's not helpful to post unverified guesses
about the behaviour of such a system.

I am pretty sure that the ssh on at least one system we have at work
does not return the remote command's exit status. This is not a guess
but I cannot verify it at the moment now because I do not have access to
the system right now.

robert
 
B

Brian Candler

Robert said:
I am pretty sure that the ssh on at least one system we have at work
does not return the remote command's exit status. This is not a guess
but I cannot verify it at the moment now because I do not have access to
the system right now.

You said: "SSH does not propagate the result of the remote process. You
can find the details on SSH's manpage", but a check of the manpage says
otherwise.

Of course, perhaps older versions of ssh are different. However the
system I checked on was Ubuntu Hardy, which isn't exactly bleeding edge.
 
I

Ivan Samonov

Brian said:
One other point. It's very dangerous to do

ch.foo { |ch| ... }

because (in ruby 1.8) 'ch' is bound to the same variable in both cases.
That is, the value assigned to the block parameter also changes the
outer 'ch'. So you should call them something different.

We use 1.9
The finished program becomes:

require 'rubygems'
require 'net/ssh'
Net::SSH.start('localhost', 'yourname') { |ssh|
ssh.open_channel { |chan|
chan.on_request('exit-status') { |ch, data|
puts "process terminated with exit status: #{data.read_long}"
}
chan.exec('false') { |ch, success| puts success }
}
}

Thanks! It's what I need!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top