require "net/ssh"
Net::SSH.start("192.168.0.12", "testuser", {:password => "testpass"}) {|ssh|
# ログイン時の Message of the day 消し
ssh.exec! "ls"
# ステートマシンとして実装しなおしたほうがいい、今は実験中
expected = false
su_cmd_sended = false
su_exited = false
skip_head = false
end_load = false
stdout_data = ""
# channel = ssh.open_channel
# channel.close
#
# って書式は例外飛ばされるのでブロック必須、中がすげぇカオスになりがち
ssh.open_channel {|channel|
# (出力としては断片的な)パケットをもらったとき
# ls -al /etc すると
# "total 764" ってdataでこのイベントが走り
# "drwxr-xr-x 83 root root 4096 Mar 24 16:00 ." ってdataが来るイベント発動 orz
channel.on_data {|ch, data|
if !expected
if data =~ /assword:/
channel.send_data "rootpass\n"
channel.process
expected = true
end
else
# ターミナルでsu - した直後
if !su_cmd_sended
channel.send_data "stty -echo\n"
channel.process
# コマンドの終了を判定するための文言を無理やり追加なう
channel.send_data "PS1='__currently__auto__mode__'\n"
channel.process
# したいことをおくろう
channel.send_data "ls -al\n"
channel.process
su_cmd_sended = true
elsif !skip_head
# PS1で設定した文言来るまではエコーバック、コマンド実行結果じゃない
if data =~ /__currently__auto__mode__$/
skip_head = true
end
elsif !end_load
# PS1で設定したあの文言が来たら出力は終わったと思われ
if data =~ /__currently__auto__mode__/
# rootからexit
channel.send_data "exit\n"
channel.process
# 一般ユーザーからexit (でリモート側がeof)、こっちからのchannel.eof!はNet::SSHにシカトされた
channel.send_data "exit\n"
channel.process
end_load = true
else
# まだPS1の文言は来てないから出力でそ、コマンド出力の一部分しか来ないねん
stdout_data += data
end
end
end
}
# ptyがくっつきますた、on_dataコールバックの"data"に user@machine: ~$ とか拾うようになります
channel.request_pty
channel.send_channel_request "shell" do |ch, success|
channel.send_data "su - \n"
channel.process
end
}
ssh.loop
print stdout_data.chomp
# 問題: su - の後にぶっぱしたコマンドの戻り値が取れない
}