rye 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|