rye 0.9.7 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/CHANGES.txt +44 -38
- data/README.rdoc +44 -30
- data/Rakefile +41 -82
- data/VERSION +1 -0
- data/gem-public_cert.pem +20 -0
- data/lib/rye.rb +74 -52
- data/lib/rye/box.rb +7 -4
- data/lib/rye/dsl.rb +100 -0
- data/rye.gemspec +95 -55
- data/try/10_basic_tryouts.rb +44 -0
- data/try/12_batch_tryouts.rb +26 -0
- data/try/13_set_tryouts.rb +42 -0
- data/try/14_auth_methods_tryouts.rb +28 -0
- data/try/15_file_tryouts.rb +12 -0
- data/try/20_file_transfer_tryouts.rb +46 -0
- data/try/25_template_upload.rb +37 -0
- data/try/30_safemode_tryouts.rb +85 -0
- data/try/35_basics_with_hop.rb +36 -0
- data/try/70_rye_cli_tryouts.rb +0 -0
- data/try/copying.rb +18 -0
- data/try/keys.rb +141 -0
- data/tst/10-key1 +27 -0
- data/tst/10-key1.pub +1 -0
- data/tst/10-key2 +30 -0
- data/tst/10-key2.pub +1 -0
- data/tst/10_keys_test.rb +88 -0
- data/tst/50_rset_test.rb +54 -0
- data/tst/60-file.mp3 +0 -0
- data/tst/60_rbox_transfer_test.rb +53 -0
- data/tst/65_rbox_file_append_test.rb +53 -0
- data/tst/70_rbox_env_test.rb +19 -0
- data/tst/dsl_example.rb +80 -0
- data/tst/rye.rb +13 -0
- data/tst/shell.rb +280 -0
- data/tst/shell2.rb +278 -0
- data/tst/shell3.rb +280 -0
- data/tst/test_hop.rb +25 -0
- metadata +86 -25
- metadata.gz.sig +0 -0
- data/bin/try +0 -246
data/tst/shell2.rb
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
|
3
|
+
#
|
4
|
+
# For channel requests, see SSH_MSG_CHANNEL_REQUEST messages
|
5
|
+
# in http://www.snailbook.com/docs/connection.txt
|
6
|
+
DEBUG = true
|
7
|
+
|
8
|
+
module Rye
|
9
|
+
class Box
|
10
|
+
def debug(state, msg='')
|
11
|
+
return unless DEBUG
|
12
|
+
puts " ------ %s: %s" % [state, msg]
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_session_state(channel)
|
16
|
+
debug :start_session, channel[:handler]
|
17
|
+
channel.send_data("unset PS1; stty -echo\n")
|
18
|
+
channel[:state] = :ignore_response
|
19
|
+
end
|
20
|
+
|
21
|
+
def ignore_response_state(channel)
|
22
|
+
debug :ignore_response, channel[:handler]
|
23
|
+
@ignore_response_counter ||= 0
|
24
|
+
if channel[:buffer].available > 0
|
25
|
+
@await_response_counter = 0
|
26
|
+
channel[:buffer].read
|
27
|
+
channel[:state] = :process
|
28
|
+
elsif @ignore_response_counter > 2
|
29
|
+
@await_response_counter = 0
|
30
|
+
channel[:state] = :process
|
31
|
+
end
|
32
|
+
@ignore_response_counter += 1
|
33
|
+
end
|
34
|
+
|
35
|
+
def process_state(channel)
|
36
|
+
debug :process, channel[:handler]
|
37
|
+
if channel[:block]
|
38
|
+
channel[:state] = :run_block
|
39
|
+
else
|
40
|
+
channel[:state] = :await_input
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_data_state(channel)
|
45
|
+
debug :send_data, channel[:handler]
|
46
|
+
#if channel[:stack].empty?
|
47
|
+
# channel[:state] = :await_input
|
48
|
+
#else
|
49
|
+
cmd = channel[:stack].shift
|
50
|
+
#return if cmd.strip.empty?
|
51
|
+
debug :send_data, "calling #{cmd.inspect}"
|
52
|
+
channel[:state] = :await_response
|
53
|
+
channel.send_data("#{cmd}\n") unless channel.eof?
|
54
|
+
#channel.exec("#{cmd}\n", &create_channel)
|
55
|
+
#end
|
56
|
+
end
|
57
|
+
|
58
|
+
def await_input_state(channel)
|
59
|
+
debug :await_input, channel[:handler]
|
60
|
+
|
61
|
+
if channel[:buffer].available > 0
|
62
|
+
channel[:state] = :read_input
|
63
|
+
else
|
64
|
+
ret = STDIN.gets
|
65
|
+
if ret.nil?
|
66
|
+
channel.eof!
|
67
|
+
channel[:state] = :exit
|
68
|
+
else
|
69
|
+
channel[:stack] << ret.chomp
|
70
|
+
channel[:state] = :send_data
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def check_interactive_state(channel)
|
77
|
+
debug :read_input, channel[:handler]
|
78
|
+
channel.send_data("x")
|
79
|
+
end
|
80
|
+
|
81
|
+
def read_input_state(channel)
|
82
|
+
debug :read_input, channel[:handler]
|
83
|
+
if channel[:buffer].available > 0
|
84
|
+
print channel[:buffer].read
|
85
|
+
|
86
|
+
if channel[:stack].empty?
|
87
|
+
channel[:state] = :await_input
|
88
|
+
elsif channel[:buffer].available > 0
|
89
|
+
channel[:state] = :read_input
|
90
|
+
else
|
91
|
+
channel[:state] = :send_data
|
92
|
+
end
|
93
|
+
else
|
94
|
+
channel[:state] = :await_response
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def exit_state(channel)
|
99
|
+
debug :exit_state, channel[:exit_status]
|
100
|
+
puts
|
101
|
+
channel.eof!
|
102
|
+
end
|
103
|
+
|
104
|
+
def handle_error_state(channel)
|
105
|
+
debug :handle_error, channel[:handler]
|
106
|
+
channel.eof!
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def await_response_state(channel)
|
111
|
+
debug :await_response, channel[:handler]
|
112
|
+
@await_response_counter ||= 0
|
113
|
+
if channel[:buffer].available > 0
|
114
|
+
channel[:state] = :read_input
|
115
|
+
elsif @await_response_counter > 20
|
116
|
+
@await_response_counter = 0
|
117
|
+
channel[:state] = :await_input
|
118
|
+
end
|
119
|
+
@await_response_counter += 1
|
120
|
+
end
|
121
|
+
|
122
|
+
def run_block_state(channel)
|
123
|
+
debug :run_block, channel[:handler]
|
124
|
+
channel[:state] = nil
|
125
|
+
blk = channel[:block]
|
126
|
+
channel[:block] = nil
|
127
|
+
instance_eval &blk
|
128
|
+
channel[:state] = :exit
|
129
|
+
end
|
130
|
+
|
131
|
+
def command(name,*args, &blk)
|
132
|
+
debug :command, channel[:handler]
|
133
|
+
return if @channel.eof?
|
134
|
+
cmd = "%s %s" % [name, args.join(' ')]
|
135
|
+
debug :command, "Running: #{cmd}"
|
136
|
+
if self.pty && channel[:buffer].available
|
137
|
+
prompt = channel[:buffer].read
|
138
|
+
end
|
139
|
+
channel.send_data("#{cmd}\n")
|
140
|
+
channel.connection.loop do
|
141
|
+
break if channel[:buffer].available > 0
|
142
|
+
p :loop
|
143
|
+
channel.active?
|
144
|
+
end
|
145
|
+
ret = channel[:buffer].read
|
146
|
+
ret
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
def wait_for_command_state(channel)
|
151
|
+
debug :wait_for_command, channel[:handler]
|
152
|
+
end
|
153
|
+
|
154
|
+
def ls(*args) command(:ls, *args) end
|
155
|
+
def cat(*args) command(:cat, *args) end
|
156
|
+
def echo(*args) command(:echo, *args) end
|
157
|
+
def sudo(*args) command(:sudo, *args) end
|
158
|
+
def date(*args) command(:date, *args) end
|
159
|
+
def uname(*args) command(:uname, *args) end
|
160
|
+
def chroot(*args) command(:chroot, *args) end
|
161
|
+
def bash(*args, &blk) command(:bash, *args, &blk) end
|
162
|
+
def exit(*args, &blk) command(:exit, *args, &blk) end
|
163
|
+
|
164
|
+
attr_reader :session, :channel
|
165
|
+
attr_accessor :running, :pty
|
166
|
+
|
167
|
+
def connect(host, user, opts={})
|
168
|
+
opts = {
|
169
|
+
:auth_methods => %w[keyboard-interactive]
|
170
|
+
}.merge(opts)
|
171
|
+
opts[:auth_methods].unshift 'publickey' unless opts[:keys].nil?
|
172
|
+
opts[:auth_methods].unshift 'password' unless opts[:password].nil?
|
173
|
+
@sessions ||= []
|
174
|
+
@session = Net::SSH.start(host, user, opts)
|
175
|
+
end
|
176
|
+
|
177
|
+
def run(shell, &blk)
|
178
|
+
|
179
|
+
puts "Running #{shell}"
|
180
|
+
@channel = @session.open_channel do |channel|
|
181
|
+
#if blk.nil?
|
182
|
+
channel.request_pty do |ch,success|
|
183
|
+
self.pty = success
|
184
|
+
raise "pty request denied" unless success
|
185
|
+
end
|
186
|
+
#end
|
187
|
+
channel.exec shell, &create_channel
|
188
|
+
end
|
189
|
+
|
190
|
+
channel[:block] = blk
|
191
|
+
|
192
|
+
@session.loop(0.5) do
|
193
|
+
break if !@channel.active?
|
194
|
+
!@channel.eof? # otherwise keep returning true
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
def stop
|
200
|
+
@control.join if @control
|
201
|
+
@ssh.running = false
|
202
|
+
@ssh.close
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
def busy_proc
|
207
|
+
Proc.new { |s| !s.busy? }
|
208
|
+
end
|
209
|
+
|
210
|
+
def create_channel
|
211
|
+
Proc.new do |channel,success|
|
212
|
+
channel[:callback] = Proc.new { p :callback }
|
213
|
+
channel[:buffer ] = Net::SSH::Buffer.new
|
214
|
+
#channel[:batch ] = blk
|
215
|
+
channel[:stderr ] = Net::SSH::Buffer.new
|
216
|
+
channel[:state ] = "start_session"
|
217
|
+
@channel[:stack] ||= []
|
218
|
+
channel.on_close { |ch|
|
219
|
+
channel[:handler] = ":on_close"
|
220
|
+
}
|
221
|
+
channel.on_data { |ch, data|
|
222
|
+
channel[:handler] = ":on_data"
|
223
|
+
channel[:buffer].append(data)
|
224
|
+
}
|
225
|
+
channel.on_extended_data { |ch, type, data|
|
226
|
+
channel[:handler] = ":on_extended_data"
|
227
|
+
channel[:stderr].append(data)
|
228
|
+
channel[:state] = :handle_error
|
229
|
+
}
|
230
|
+
channel.on_request("exit-status") { |ch, data|
|
231
|
+
channel[:handler] = ":on_request (exit-status)"
|
232
|
+
channel[:exit] = data.read_long
|
233
|
+
}
|
234
|
+
channel.on_request("exit-signal") do |ch, data|
|
235
|
+
channel[:handler] = ":on_request (exit-signal)"
|
236
|
+
# This should be the POSIX SIGNAL that ended the process
|
237
|
+
channel[:exit_signal] = data.read_long
|
238
|
+
end
|
239
|
+
channel.on_process {
|
240
|
+
channel[:handler] = :on_process
|
241
|
+
print channel[:stderr].read if channel[:stderr].available > 0
|
242
|
+
begin
|
243
|
+
send("#{channel[:state]}_state", channel) unless channel[:state].nil?
|
244
|
+
rescue Interrupt
|
245
|
+
debug :await_input_interrupt
|
246
|
+
channel[:state] = :exit
|
247
|
+
end
|
248
|
+
}
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
begin
|
255
|
+
puts $$
|
256
|
+
rbox = Rye::Box.new
|
257
|
+
rbox.connect 'ec2-184-72-169-231.compute-1.amazonaws.com', 'ubuntu', :verbose => :fatal, :keys => ['~/.ssh/key-us-east-1b-build-arch']
|
258
|
+
#rbox.run 'bash'
|
259
|
+
rbox.run 'bash' do
|
260
|
+
puts command("date")
|
261
|
+
p cat("/etc/issue")
|
262
|
+
command("SUDO_PS1=''")
|
263
|
+
puts sudo( 'chroot', '/mnt/archlinux-x86_64')
|
264
|
+
command("unset PS1;")
|
265
|
+
p cat("/etc/issue")
|
266
|
+
end
|
267
|
+
puts rbox.channel[:stderr] if rbox.channel[:stderr]
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
__END__
|
272
|
+
http://tldp.org/LDP/abs/html/intandnonint.html
|
273
|
+
case $- in
|
274
|
+
*i*) # interactive shell
|
275
|
+
;;
|
276
|
+
*) # non-interactive shell
|
277
|
+
;;
|
278
|
+
# (Courtesy of "UNIX F.A.Q.," 1993)
|
data/tst/shell3.rb
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
|
3
|
+
#
|
4
|
+
# For channel requests, see SSH_MSG_CHANNEL_REQUEST messages
|
5
|
+
# in http://www.snailbook.com/docs/connection.txt
|
6
|
+
DEBUG = true
|
7
|
+
|
8
|
+
module Rye
|
9
|
+
class Box
|
10
|
+
def debug(state, msg='')
|
11
|
+
return unless DEBUG
|
12
|
+
puts " ------ %s: %s" % [state, msg]
|
13
|
+
end
|
14
|
+
|
15
|
+
def start_session_state(channel)
|
16
|
+
debug :start_session, channel[:handler]
|
17
|
+
#channel.send_data("stty -echo\n")
|
18
|
+
#channel[:state] = :ignore_response
|
19
|
+
channel[:state] = :await_response
|
20
|
+
end
|
21
|
+
|
22
|
+
def await_response_state(channel)
|
23
|
+
debug :await_response, channel[:handler]
|
24
|
+
@await_response_counter ||= 0
|
25
|
+
if channel[:buffer].available > 0
|
26
|
+
channel[:state] = :read_input
|
27
|
+
elsif @await_response_counter > 10
|
28
|
+
@await_response_counter = 0
|
29
|
+
channel[:state] = :await_input
|
30
|
+
end
|
31
|
+
@await_response_counter += 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_input_state(channel)
|
35
|
+
debug :read_input, channel[:handler]
|
36
|
+
if channel[:buffer].available > 0
|
37
|
+
print channel[:buffer].read
|
38
|
+
|
39
|
+
if channel[:stack].empty?
|
40
|
+
channel[:state] = :await_input
|
41
|
+
elsif channel[:buffer].available > 0
|
42
|
+
channel[:state] = :read_input
|
43
|
+
else
|
44
|
+
channel[:state] = :send_data
|
45
|
+
end
|
46
|
+
else
|
47
|
+
channel[:state] = :await_response
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def send_data_state(channel)
|
52
|
+
debug :send_data, channel[:handler]
|
53
|
+
#if channel[:stack].empty?
|
54
|
+
# channel[:state] = :await_input
|
55
|
+
#else
|
56
|
+
cmd = channel[:stack].shift
|
57
|
+
#return if cmd.strip.empty?
|
58
|
+
debug :send_data, "calling #{cmd.inspect}"
|
59
|
+
channel[:state] = :await_response
|
60
|
+
channel.send_data("#{cmd}\n") unless channel.eof?
|
61
|
+
#channel.exec("#{cmd}\n", &create_channel)
|
62
|
+
#end
|
63
|
+
end
|
64
|
+
|
65
|
+
def await_input_state(channel)
|
66
|
+
debug :await_input, channel[:handler]
|
67
|
+
|
68
|
+
if channel[:buffer].available > 0
|
69
|
+
channel[:state] = :read_input
|
70
|
+
else
|
71
|
+
ret = STDIN.gets
|
72
|
+
if ret.nil?
|
73
|
+
channel.eof!
|
74
|
+
channel[:state] = :exit
|
75
|
+
else
|
76
|
+
channel[:stack] << ret.chomp
|
77
|
+
channel[:state] = :send_data
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def check_interactive_state(channel)
|
84
|
+
debug :read_input, channel[:handler]
|
85
|
+
channel.send_data("x")
|
86
|
+
end
|
87
|
+
|
88
|
+
def exit_state(channel)
|
89
|
+
debug :exit_state, channel[:exit_status]
|
90
|
+
puts
|
91
|
+
channel.eof!
|
92
|
+
end
|
93
|
+
|
94
|
+
def handle_error_state(channel)
|
95
|
+
debug :handle_error, channel[:handler]
|
96
|
+
channel.eof!
|
97
|
+
end
|
98
|
+
|
99
|
+
def ignore_response_state(channel)
|
100
|
+
debug :ignore_response, channel[:handler]
|
101
|
+
@ignore_response_counter ||= 0
|
102
|
+
if channel[:buffer].available > 0
|
103
|
+
@await_response_counter = 0
|
104
|
+
channel[:buffer].read
|
105
|
+
channel[:state] = :await_input
|
106
|
+
elsif @ignore_response_counter > 2
|
107
|
+
@await_response_counter = 0
|
108
|
+
channel[:state] = :await_input
|
109
|
+
end
|
110
|
+
@ignore_response_counter += 1
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
def run_block_state(channel)
|
115
|
+
instance_eval &channel[:block]
|
116
|
+
channel[:block] = nil
|
117
|
+
channel[:state] = :await_response
|
118
|
+
end
|
119
|
+
|
120
|
+
def command(name,*args, &blk)
|
121
|
+
return if @channel.eof?
|
122
|
+
channel[:block] = blk
|
123
|
+
cmd = "%s %s" % [name, args.join(' ')]
|
124
|
+
channel.send_data("#{cmd}\n")
|
125
|
+
#channel.wait
|
126
|
+
channel[:state] = :await_response
|
127
|
+
|
128
|
+
#@channel[:buffer]
|
129
|
+
# channel.exec "ls -l /home" do |ch, success|
|
130
|
+
# if success
|
131
|
+
# puts "command has begun executing..."
|
132
|
+
# # this is a good place to hang callbacks like #on_data...
|
133
|
+
# else
|
134
|
+
# puts "alas! the command could not be invoked!"
|
135
|
+
# end
|
136
|
+
# end
|
137
|
+
end
|
138
|
+
|
139
|
+
def ls(*args) command(:ls, *args) end
|
140
|
+
def date(*args) command(:date, *args) end
|
141
|
+
def bash(*args, &blk) command(:bash, *args, &blk) end
|
142
|
+
def exit(*args, &blk) command(:exit, *args, &blk) end
|
143
|
+
|
144
|
+
attr_reader :session, :channel
|
145
|
+
attr_accessor :running
|
146
|
+
|
147
|
+
def connect(host, user, opts={})
|
148
|
+
opts = {
|
149
|
+
:auth_methods => %w[keyboard-interactive]
|
150
|
+
}.merge(opts)
|
151
|
+
opts[:auth_methods].unshift 'publickey' unless opts[:keys].nil?
|
152
|
+
opts[:auth_methods].unshift 'password' unless opts[:password].nil?
|
153
|
+
@sessions ||= []
|
154
|
+
@session = Net::SSH.start(host, user, opts)
|
155
|
+
end
|
156
|
+
|
157
|
+
def run(shell, &blk)
|
158
|
+
|
159
|
+
#@session.process(0.1, &busy_proc)
|
160
|
+
|
161
|
+
#result = nil
|
162
|
+
#@channel = @session.open_channel do |ch|
|
163
|
+
# ch.exec("irb") do |c, success|
|
164
|
+
# ch.on_data { |c, data| puts data }
|
165
|
+
# ch.on_extended_data { |c, type, data| puts data }
|
166
|
+
# ch.on_close { |c| c.close }
|
167
|
+
# end
|
168
|
+
#end
|
169
|
+
|
170
|
+
@channel = @session.open_channel do |channel|
|
171
|
+
channel.request_pty do |ch,success|
|
172
|
+
if success
|
173
|
+
|
174
|
+
else
|
175
|
+
raise "pty request denied"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
channel.exec shell, &create_channel
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
@channel[:stack] ||= []
|
183
|
+
#@channel[:stack] << "require 'gibbler'"
|
184
|
+
#@channel[:stack] << "{}.gibbler"
|
185
|
+
|
186
|
+
#trap("INT") {
|
187
|
+
# p [:INT, @session.closed?, @channel.eof?]
|
188
|
+
# #if channel[:state] == :await_input
|
189
|
+
# @channel.eof!
|
190
|
+
# @session.close unless @session.closed?
|
191
|
+
#}
|
192
|
+
#trap("INT") {
|
193
|
+
#@channel.eof! unless @channel.eof?
|
194
|
+
#@session.close unless @session.closed?
|
195
|
+
# @channel[:state] = :exit
|
196
|
+
#}
|
197
|
+
|
198
|
+
@session.loop(0.1) do
|
199
|
+
break if !@channel.active?
|
200
|
+
!@channel.eof? # otherwise keep returning true
|
201
|
+
end
|
202
|
+
|
203
|
+
#puts @channel[:stderr], @channel[:exit_status]
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
def stop
|
208
|
+
@control.join if @control
|
209
|
+
@ssh.running = false
|
210
|
+
@ssh.close
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
def busy_proc
|
215
|
+
Proc.new { |s| !s.busy? }
|
216
|
+
end
|
217
|
+
|
218
|
+
def create_channel
|
219
|
+
Proc.new do |channel,success|
|
220
|
+
channel[:callback] = Proc.new { p :callback }
|
221
|
+
channel[:buffer ] = Net::SSH::Buffer.new
|
222
|
+
#channel[:batch ] = blk
|
223
|
+
channel[:stderr ] = Net::SSH::Buffer.new
|
224
|
+
channel[:state ] = "start_session"
|
225
|
+
@channel[:stack] ||= []
|
226
|
+
channel.on_close { |ch|
|
227
|
+
channel[:handler] = ":on_close"
|
228
|
+
}
|
229
|
+
channel.on_data { |ch, data|
|
230
|
+
channel[:handler] = ":on_data"
|
231
|
+
channel[:buffer].append(data)
|
232
|
+
}
|
233
|
+
channel.on_extended_data { |ch, type, data|
|
234
|
+
channel[:handler] = ":on_extended_data"
|
235
|
+
channel[:stderr].append(data)
|
236
|
+
channel[:state] = :handle_error
|
237
|
+
}
|
238
|
+
channel.on_request("exit-status") { |ch, data|
|
239
|
+
channel[:handler] = ":on_request (exit-status)"
|
240
|
+
channel[:exit] = data.read_long
|
241
|
+
}
|
242
|
+
channel.on_request("exit-signal") do |ch, data|
|
243
|
+
channel[:handler] = ":on_request (exit-signal)"
|
244
|
+
# This should be the POSIX SIGNAL that ended the process
|
245
|
+
channel[:exit_signal] = data.read_long
|
246
|
+
end
|
247
|
+
channel.on_process {
|
248
|
+
channel[:handler] = :on_process
|
249
|
+
print channel[:stderr].read if channel[:stderr].available > 0
|
250
|
+
begin
|
251
|
+
send("#{channel[:state]}_state", channel)
|
252
|
+
rescue Interrupt
|
253
|
+
debug :await_input_interrupt
|
254
|
+
channel[:state] = :exit
|
255
|
+
end
|
256
|
+
}
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
begin
|
263
|
+
puts $$
|
264
|
+
rbox = Rye::Box.new
|
265
|
+
rbox.connect 'localhost', 'delano', :keys => []
|
266
|
+
rbox.run 'bash'
|
267
|
+
|
268
|
+
#p rbox.channel[:exit], rbox.channel[:exit_signal]
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
|
273
|
+
__END__
|
274
|
+
http://tldp.org/LDP/abs/html/intandnonint.html
|
275
|
+
case $- in
|
276
|
+
*i*) # interactive shell
|
277
|
+
;;
|
278
|
+
*) # non-interactive shell
|
279
|
+
;;
|
280
|
+
# (Courtesy of "UNIX F.A.Q.," 1993)
|