Logo address

Lua on Plan9

2023/11/26

Lua and 9Lua

Lua とは、ちょっと癖のあるインタープリターであるが、コードも文法もコンパクトで、速度には定評がある(Python に比べて 10 倍ほど速い)ので一部には強い人気がある。移植性は非常に高い。殆どの OS で動いていると思ってよい。Plan9 にも僕の移植版がある。

Plan9 独自の関数を追加した Lua が 9Lua で、これも僕の移植版がある。
いずれも
http://p9.nyx.link/netlib/lua/
から手に入る。

Sample code

Lua がインストールされているとせよ。
次の a1 はファイルを読み取って、その内容を書きだすプロクラムである。
もちろん
chmod 755
が必要である。
a1
#!/bin/lua
f=io.open(arg[1])
s = f:read("a")
print(s)
f:close()
これで
a1 xxx
とすればファイル xxx を読み取って表示してくれる。
なお read("a")"a" はファイルの全部を読み取るオプションである。この他に1行だけを読み取るオプションなどがある。

Dnsquery

次のプログラムで動くはずであるが...

f = io.open("/net/dns","r+")
f:write("amazon.com ip")
f:seek("set",0)
s = f:read("a")
while s and #s>0 do
	print(s)
	s = f:read("a")
end
f:close()
結果は
amazon.com ip	54.239.28.85amazon.com ip	205.251.242.103amazon.com ip	52.94.236.248
となる。これは実は正しくない。正しくは ndb/dnsquery と同じ
amazon.com ip	54.239.28.85
amazon.com ip	205.251.242.103
amazon.com ip	52.94.236.248
となるべきである。

なぜこのような問題が発生したが?
Lua で使われている読み取り関数が Plan9 の特殊な出力様式に対応していないからと考えられる。
どうやら名前付き pipe による Plan9 のデータベースの応答では、レコードの区切りに 文字が使われていないらしい。

9Lua は Plan9 の I/O 関数をサポートしている。これを使うと問題は解決する。
先のプログラムは次のようになる。

f = p9.open("/net/dns","rw")
p9.write(f,"amazon.com ip")
p9.seek(f,0,"set")
s = p9.read(f)
while s and #s>0 do
	print(s)
	s = p9.read(f)
end
p9.close(f)
となる。

なお while を使って読み取りが行われているのは、実際にはデータは1回で来る保証は無いからである。

IP 通信

次に Lua を使って通信がどのように行われるかを見る。
次は 192.168.0.7 の tcp 80 ポートにアクセスして

GET /
をリクエストをして index.html のデータを手に入れている。すなわち次のコマンド相当のことをしている。
wget http://192.168.0.7:80

function test1()
	cfd = p9.open("/net/tcp/clone","rw")
	assert(cfd>0,"/net/tcp/clone not open")
	cn=p9.read(cfd)	-- connection number in string. 18
	print(cn)
	conreq = "connect 192.168.0.7!80" -- need IP
	n = p9.write(cfd, conreq)
	assert(n == #conreq, "connection request failed")
	data = "/net/tcp/"..cn.."/data"
	print("data",data)
	fd = p9.open(data,"rw")
	assert(fd, data.." not open")
	req = "GET /\r\n"	-- GET request
	n = p9.write(fd,req)
	assert(n == #req, "write error: "..req)
	p9.seek(fd,0,"set")
	s = p9.read(fd)
	while s and #s>0 do
		print(s)	-- OK
		s = p9.read(fd)
	end
	p9.close(fd)
end

test1()

注意しておくが、これで wget と同じことが出来るわけではない。wget 並みのことが出来るためにはもっともっと多くのコードを追加しなくてはならない。

それでもこのプログラムには TCP 通信のエッセンスが含まれている。netcat に近いことは難しくないはずである。