シリアルポートを UNIX ドメインソケットに見立てる
追記: socat で stdio を指定すればいいような気がしてきた。
VMWare には、ゲストOSのシリアルポートを、ホストOSの UNIX ドメインソケットに見立てる機能がある *1。これを有効に活用するためには、現在使用している端末とそのソケットをつなぐプロキシがあればいいのだけど、ちょっと探した限りそのような要求を満たすものが見つからなかったのでざっくり書いてみたのが次の Ruby スクリプト。ツッコミどころ満載な気がするけども、何かの役に立つことを願いつつ。
端末には VT220 互換のものを想定している。F12 を押すとプロキシを終了する。使用するときは sockaddr_un('/tmp/aho') の /tmp/aho を、VMWare のソケットへのパス名に変えてください。
追記: そういえばこのままだとエスケープキー効かなくなるということに後で気づいた。そのうち直す。
追記2: ESC がバッファの最後の文字でなければエスケープシーケンスだとみなすようにしてみた。とりあえずはこれでおk。
require 'socket' require 'termios' ci = IO.open(0) co = IO.open(1) orig_term_state = Termios.tcgetattr(ci); term_state = orig_term_state.clone() term_state.lflag &= ~(Termios::ISIG | Termios::ECHO | Termios::ICANON) Termios.tcsetattr(ci, Termios::TCSANOW, term_state) s = Socket.open(Socket::PF_UNIX, Socket::SOCK_STREAM, 0) s.connect(Socket.sockaddr_un('/tmp/aho')) outbuf = '' inbuf = '' escbuf = '' state = 0 running = true while running r = IO.select([ci,s],[co,s],nil,1) if r[0].include?(s) inbuf += s.sysread(16384) end if r[1].include?(co) and not inbuf.empty? co.syswrite(inbuf) inbuf = '' end if r[0].include?(ci) buf = ci.sysread(16384) p = 0 while p < buf.length case state when 0 i = buf.index(0x1b, p) if i != nil and i != buf.length - 1 outbuf += buf[p...i] p = i esc_buf = '' state = 1 else outbuf += buf[p..-1] p = buf.length end when 1 if esc_buf.length < 5 c = buf.length - p c = 5 - esc_buf.length if c > 5 - esc_buf.length esc_buf += buf[p, c] p += c end if esc_buf.length >= 5 case esc_buf when "\x1b[24~": # VT220 F12 running = false end state = 0 end end end end if r[1].include?(s) and not outbuf.empty? s.syswrite(outbuf) outbuf = '' end end Termios.tcsetattr(ci, Termios::TCSANOW, orig_term_state)