想定される読者
Plan9 からリモートの unix ホストに対して
現在
単にコマンドの実行であれば、vnc は選択肢に入らない。
vnc が必要になるのは、コマンドの実行にグラフィックス環境が要求される場合だけである。(例えば QEMU や VirtualBox に Plan9 をインストールする場合が該当する)
ssh で unix にログインするときには必ずしも vt100 端末の環境は要求されない。むしろ vt
コマンドを使わない方が遥かに使い勝手が良い。以下、それを「生の環境」と言う1。 ssh で相手ホストに入り込むと、相手方のシェルが実行されている。ところが生の環境のままだとプロンプトを出さないので、面食らう。そういうものだと思ってそのまま使ってもよいが、嫌なら
bash -i
rc -i
ctl-D
の問題sudo
コマンドでパスワードの入力を求められるが sudo
の "-S
" フラグを利用すればよい。最大の問題は "ctl-D
" である。unix のツールは行頭の "ctl-D
" をデータ入力の終わりとみなし、そのツールが終了するように設計されている。ところが生の環境では行頭の "ctl-D
" が unix と Plan9 との接続の終了とみなされる。そのために接続が切られ、ssh ログインからやり直しになる。この問題はもしかすれば解決策があるかも知れない。
$TERM
" がセットされていると、その内容に従った加工が行われる。従って ssh が「生の環境」で相手ホストに入り込めるには、$TERM
を設定しないか、さもなくは ssh
コマンドに "-R
" フラグを添える必要がある。
Plan9 側からのアクセスの簡便性は u9fs が遥かに上である。factotum が使えるのでパスワードの手入力の必要はない。"maia
" を unix ホストすれば
9fs maia
/n/maia
にマウントしてくれる。
u9fs とは、Plan9 と 9P プロトコルで通信する unix 側のファイルサーバーのソフト名である。u9fs を unix に組み込むと、その unix を Plan9 側からマウントできる。u9fs は Plan9 の配布の中に含まれている。
u9fs は UNIX のファイルシステムを Plan9 側にマウントしてくれる。sshfs も同様な機能を提供するが、u9fs の方が使いやすい。
以下に簡単な使用例を挙げる。
nx
を UNIX システムとすると、
term% 9fs nx post ... # message term%
nx
のファイルシステムは /n/nx
の下に見える。term% ls /n/nx term% ls /n/nx ... /n/nx/bin /n/nx/dev /n/nx/etc /n/nx/home ... /n/nx/tmp /n/nx/usr term%
パスワードも入れずに認証されているのは、認証エージェント factotum が働いているからである。
9P プロトコルの名称
name | comment |
---|---|
9P1 | used 2'nd and 3'rd edition of Plan9 |
9P2000 | official name for 9P in 4'th edition of Plan9 |
9P2000.u | unix extension proposal[3] |
9P2000.L | subset of 9P000 for unix poposed in DIOD[4] |
9P2010 | successor of 9P2000.u |
9P2000.u は風呂敷を広げすぎていると思う。多分挫折する。(挫折した?)
9P2000.u の後継として 9P2010 が提案されている[6,7]。
Plan9 以外では、現在ともかく動いているらしいのは 9P2000 のサブセットである[4]。主要な OS (macOS, Windows, Linux, FreeBSD) である程度使えるらしい1。しかし僕は(現在のところ)論評するだけの材料を持ち合わせていない。
文献[1]が 9P に関する最も基本的な文献である。9P プロトコルの内容が解説されている。なおこの文献によると 9P は "Plan 9 File Protocol" の略語である。
9P は通信路に関しては何も定めていない。ここで言う「通信路」には、使用される暗号も含まれる。また認証の方式も定めていない。9P による接続が成功するためには認証の方式と暗号の選択に関するホストとクライアントとの交渉が成立しなければならず、それに応じた変種もまた発生し得る。例えば unix の 9P server である u9fs では「信頼できるホスト」による「認証」をも許している。
name | comment |
---|---|
9fs | /lib/ndb/common in Plan9 |
9pfs | /etc/services in FreeBSD |
u9fs | u9fs マニュアル[2] |
注: これらは同じものの別称(方言)である
Plan9 で使われた service ポートは 564 で、service 名は 9fs である。文献[2]によると 9fs は "Plan9 file service" の略語である。
Plan9 の中では 9fs の名称は現在も使われている。サービス名称としても、コマンド名称としても。
文献[2]によれば、u9fs で使用されるプロトコル名は 9fs にする予定だったらしい。しかし inetd のサービス名を数字から始められない unix システムが存在したために u9fs にしたとのことである。
[1] man INTRO(5)
introduction to the Plan 9 File Protocol, 9P
http://man.cat-v.org/plan_9/5/
[2] U9FS(4)
http://man.cat-v.org/plan_9/4/u9fs
[3] E. Van Hensbergen: Plan 9 Remote Resource Protocol Unix Extension
https://ericvh.github.io/9p-rfc/rfc9p2000.u.html
[4] diod/protocol.md
https://github.com/chaos/diod/blob/master/protocol.md
[5] MOUNT_9P(8)
https://www.unix.com/man-page/mojave/8/mount_9p
[6] 9P2010
https://9p.io/wiki/plan9/9p2010/index.html
[7] 9P2010 Operations
https://9p.io/wiki/plan9/9P2010_Operations/index.html
/usr/local/sbin/u9fs
# u9fs 本体/var/log/u9fs.log
# log file/etc/u9fs.key
# 認証情報を含むファイル
Ubuntu はクライアントとして初期設定されている。そのためにサービスに必要な inetd も xinetd も(多分)インストールされていない。インストールされて既に動いている可能性もあるので
ps aux | grep inetd
Mac は全く方法が異なるので、独立して解説する。
/usr/sbin
に inetutils-inetd
がインストールされる。これのマニュアルを表示させると inetd
のマニュアルが表示されるので、互換性を保っているのだろう。
/sys/src/cmd/unix/u9fs
に置かれている。unix$ make unix$ su root# cp u9fs /usr/local/sbin root# touch /var/log/u9fs.log
http:/netlib/u9fs/
Mac にインストールするなら筆者のをダウンロードするのが良いだろう。
理由は
次の図に UTF8-MAC 対策がされていないのと、いるのとの違いを示す。
u9fs | u9fs_mac |
Mac の文字コードが抱える問題に関しては http:/p9p/#mac_nfd
に簡単に解説されている。さらに詳しくは http://ar.nyx.link/unicode/
の「ダ問題」を見よ。
Mac 用のも
http:/netlib/u9fs/
に置かれている。
ネット情報によると macOS はバージョンアップして 10.x から 11.0 にさらに 12.0 に代わったとのことである。macOS が抱えていたファイル名の文字コードの問題は Apple がどこかで手を打つ必要があろうが、(筆者の環境は古く)今回改善されたかどうかは定かではない。
/etc/u9fs.key
に利用者のキーを設定する。(この場所は u9fs の -A
オプションで変更できる)
内容は例えば
blackcat arisawa poeである。ここに
blackcat
はパスワードで poe
は認証ドメインの名称である。認証ドメインの名称はなんでもよい。u9fs.key
の情報は factotum に次のように使われる。key proto=p9sk1 dom=poe user=arisawa !password=blackcat
/lib/ndb/local
は(例えば)sys=xxx dom=xxx.local auth=xxx ether=192.168.0.5 ip=f02f74f8dc80のように自己認証になる。もちろんここでの
ether
も ip
も例に過ぎない。
unix サーバーをいくつも持っている場合にも、共通の factotum キーで代用できる。
FreeBSD では /etc/services
に
9pfs 564/tcp #plan 9 file service
/etc/inetd.conf
に
9pfs stream tcp nowait root /usr/local/sbin/u9fs u9fs -a p9any -l /var/log/u9fs.log
エッセンスは /usr/local/sbin/u9fs
と tcp port 564 が関係づけられていることである。これは /etc/services
の 9pfs
と /etc/inetd
の 9pfs
で実現している。従って "9pfs
" は原理的には何でもよいのであるが、他のサービス名と衝突してはならない。そうは言ってもあまりにも勝手な名前は好ましくはない。IANA 公認の名前は
http://www.iana.org/assignments/port-numbers
で手に入る。
今回は xinetd を使わなかったので、古い記事(2017/06/05)に対して最小限の修正を加える。内容が古くなっているかもしれない。
まず
ps -aux|grep inetd
次に /etc/xinetd.d/
に以下の内容のファイル 9pfs
を追加する
service 9pfs { disable = no socket_type = stream protocol = tcp wait = no user = root server = /usr/local/sbin/u9fs server_args = -a p9any -l /var/log/u9fs.log groups = yes flags = REUSE }
xinetd の設定を変更した場合には root 権限で
-bash$ sudo /etc/init.d/xinetd restart
注意
この辺の話は OS によって異なり、バージョンによっても異なる。
しかも最近は、コロコロ、コロコロと変わる。整理されたら改めて解説する。
Plan9 であれば netstat -n
によってサービスが行われているポートが直ちに分かる。これに相当する macOSX あるいは FreeBSD のコマンドは netstat -anp tcp
である1。次に示すのはその出力例で
-bash$ netstat -anp tcp Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 *.564 *.* LISTEN tcp6 0 0 *.564 *.* LISTEN tcp4 0 0 127.0.0.1.631 *.* LISTEN tcp6 0 0 ::1.631 *.* LISTEN564ポート(9pfs) が開いている事が分かる。ポート名を名前で表示させたい場合には
netstat -ap tcp
netstat -ant tcp
p
" であり、僕は常に混乱する。
OSX Leopard になって xinetd が無くなって launchd による plist に一本化された。設定例は次の通りである。
/Library/LaunchDaemons/com.bell-labs.plan9.u9fs.plist
の内容
補注: Mac の場合、この古い(2008の)設定が、現在でもそのまま生きている。
/etc/services
のサービス名は、あれから 9pfs に代わったが、どうやらこのファイルは使われていない。plist にサービスポート 564 が直接現れ、このポートと u9fs が結び付けられているのが解る。(2021/11/15 追加)
/Library/LaunchDaemons/
の com.bell-labs.plan9.u9fs.plist
の設定を変更した後、それを Launchd に反映させるには
-bash$ sudo launchctl unload /Library/LaunchDaemons/ -bash$ sudo launchctl load /Library/LaunchDaemons/ -bash$を実行すればよい。
僕はこれまで plist を設定した事がなかった。このために今回は大変手間取った。
C プログラミングの世界に住んでいる者にとって、plist における、実行されるプログラムとその引数の指定の方法は "???" になりやすい。つまり "ProgramArguments
" を次のように書きやすいのである。
0 /usr/local/sbin/u9fs 1 u9fs 2 -l 3 /var/log/u9fs.log 4 -a 5 p9anyなぜ "
/usr/local/sbin/u9fs
" を "Program
" に指定しないで "ProgramArguments
" なんだ! と違和感を覚えつつ上記のように設定して、その為に 2 日程無駄な時間を費やした。僕は接続を検証するためにシンプルなプログラム "connect" を持っているが、それを使って 564 ポートにアクセスして、ようやくこの誤りに気付いた次第である。Plan 9 の "con" でも、あるいは OSX からtelnet loaclhost 564
initgroups (xinetd の groups) の値は YES でなくてはならない。Leopard でのデフォールトは YES であるが Tiger では NO なので、ここに上げた plist はそのまま Tiger では使えない。
マニュアルによると plist の置き場所は次の 5 カ所である。
~/Library/LaunchAgents Per-user agents provided by the user. /Library/LaunchAgents Per-user agents provided by the administrator. /Library/LaunchDaemons System wide daemons provided by the administrator. /System/Library/LaunchAgents Mac OS X Per-user agents. /System/Library/LaunchDaemons Mac OS X System wide daemons.最後の 2 つには多数の plist が置かれており、設定サンプルとして役に立つ。
マニュアルは次の 3 つが基本的である。
http://developer.apple.com/macosx/launchd.html
http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man5/launchd.plist.5.html
http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/launchctl.1.html
http://www.itmedia.co.jp/enterprise/articles/0704/26/news009.html
僕は Mac の plist のようなものは嫌いである。
マウスでの操作になるために、初心者は好むかもしれない。しかしそれは初心者の錯覚である。システムを管理する上で難しいのは操作ではなくて、設定の意味を理解することである。plist はそのために何の役にも立たない。
僕が好むのはテーブル形式の設定である。そのような例は /etc/inetd.conf
に見られる。全体像が良く見え、豊富なコメントが含まれており、よく使われるものは、行頭のコメント記号を外せばよいだけである。テキストエディタの使い方さえ知っていれば苦労は要らない。
テーブル形式には欠点もある。よく設計されていないと、重要なフィールドが欠けていたと言うことになる。しかしフィールドの後追加は困難であり、後の祭りである。その点 xnetd で使われている形式は柔軟に対応できる。(面倒だけど... 解りにくいけど...)
しかし、(plist もそうだけど) 全体像が見えにくいのである。そのために設定を困難にする。
Plan9 のはうまくできている。非常に単純で、ポートごとにシェルスクリプトのファイルが指定され、それが実行されるだけである。シェルスクリプトであるから強力無比である。
sshnet を使えば unix 側の u9fs と Plan9 の通信路が暗号で保護される。sshnet のアイデアは如何にも Plan9 らしいので紹介する。
hebe を Plan9 ホストとする。また maia を unix ホストとして u9fs が設定されているとする。すると hebe のコマンド
9fs maia
sshnet maia
種明かしをする。Plan9 では /net/cs
と /net/tcp
がネットアクセスに使われている。/net/cs
は補助的である。tcp 通信には /net/tcp
が使われる。これは仮想ネットワークデバイスのように働いている。従って、これを使わないと tcp 通信ができない。
sshnet を実行する前には
hebe% ls /net /net/arp /net/bootp /net/cs ... /net/tcp /net/udp hebe%と多数見えていたものが sshnet を実行すると
hebe% ls /net /net/cs /net/tcp hebe%である。重要なのはここに見える
/net/tcp
は maia 側のものだと言うことである。
このことを確認するために、実験をしてみる。sshnet を実行した window で
telnet hebe
hebe の IP アドレスは 192.168.0.6
である。hebe から hebe へのアクセスであるから、普通なら source アドレスは 192.168.0.6
となるはずである。ところが実際には telnet ポート 23 は
hebe% netstat -n ... tcp 37 none Established 23 48340 192.168.0.3 ... hebe%となっている。
192.168.0.3
は maia のアドレスである。maia ではもちろんmaia$ netstat -nt tcp ... tcp 0 0 192.168.0.3:48340 192.168.0.6:23 ESTABLISHED ... maia$である。
hebe からのネットアクセスは全て maia を通り、hebe から maia へのルートは暗号化されたトンネルになっている。9fs による u9fs へのアクセスは、その特殊な形態である。
次のような状況を考えてみよう。
alice は ホスト X のユーザーであるとともに、或る unix ホストの Y のユーザーでもある。どちらのホストにおいても alice はエンドユーザーであり、ホストに対する管理権は持たない。
alice は Y の自分のファイルを X にマウントして使いたい。
最近の unix ホストは sshd を動かしている。この場合、ユーザーは ssh でホスト Y にログインできるだけでない。sshfs で Y のファイルを X にマウントできるはずである。ただし X が sshfs をサポートしていれば... 現在 Linux、FreeBSD、macOS、Windows、Plan9 は sshfs によるマウントを許している。従って alice の要求は、現在では(特別なことをしなくても)実現していると考えてよい。
しかし alice は単に u9fs と言うものを使ってみたいのである。alice は既に u9fs をコンパイル済みである。しかしホスト Y の管理者は厳しくて、サービスポートを勝手に使わせてくれない。
ホスト Y が ssh によるログインを許していれば、そして X が Plan9 であれば、srvssh
コマンドで、Y のファイルを X にマウントできる。この方法の利点は、ホスト X,Y の管理者権限を必要としない事にある。
以下を確認する:
$HOME/bin
に置けば大丈夫なはずである(要確認)
term% srvssh Y post... term% mount /srv/Y /n/Y term% ls /n/Y /n/temp/.DS_Store /n/temp/.Trashes ...
srvssh は、9fs ポート 564 を使わずに、ホスト X と ホスト Y を結ぶ(ssh が作った)私的な通信路を使った u9fs だと考えてよい。
この利点は、
/rc/bin/srvssh
はシェルスクリプトであり、やっていることは容易に理解できる。大雑把に言えば以下のとおりである。Plan9 ホスト X で
srvssh Y
srv -e 'ssh Y u9fs -na none -u ''$''USER -l ''$''HOME/u9fs.log' Y /n/Y
srv
コマンドは、"-e
" フラグが与えられた場合、最初の引数 "....
" の部分がコマンドと見做され、それの I/O の口が /srv/Y
に作られ、またそれをマウントした結果が /n/Y
に現れる仕組みになっている。従って、このケースではssh Y u9fs -na none -u '$'USER -l '$'HOME/u9fs.log
u9fs -na none -u $USER -l $HOME/u9fs.log
u9fs は alice のプロセスとして起動される。"$USER
" は alice
であり、"$HOME
" は alice のホームディレクトリである。これを見ると srvssh で起動した場合の u9fs のログファイルの位置が判る。
さて alice はホームディレクトリ /home/alice
に u9fs.log
を作成し srvssh Y
を実行したが
u9fs: cannot open log '$HOME/u9fs.log'
この問題は /rc/bin/srvssh
の中の
-u ''$''USER -l ''$''HOME/u9fs.log
-u alice -l /home/alice/u9fs.log
-u $USER -l $HOME/u9fs.log
svssh
としてUSER=alice HOME=/home/alice svssh Y
このやり方は相手方(Y)が Ubuntu の場合も FreeBSD の場合も問題なく働く1。そこで僕は現在次のような rc スクリプト mnt
を作って使っている。便利だから紹介しておく。
#!/bin/rc rfork e if(~ $#* 0){ echo mnt hebe echo mnt hera echo mnt bsd echo mnt mbook echo mnt pi exit } switch($1){ case hera bsd # FreeBSD sshfs -m /n/bsd -r / arisawa@hera case maia # Ubuntu USER=arisawa HOME=/home/$USER svssh maia case mbook # Macbook 9fs mbook case pi # RasPi sshfs -r / -m /n/$1 pi@$1 }
mnt
汎用にはなっていない。このようなものは、各自の環境と好みに応じて内容を決めればよいだけである。
実は、使っている OS ごとに mnt
コマンドを作っている。実際に実行される内容は X と Y に依存した最適な方法を採用している。
ssh ポートの入出力は、古い(RS232C)時代の通信と相手が人間であると想定しており、そのために byte 通過性が担保しずらい。通信路を byte 透過にする方法は相手 Y(unix) に依存する。旨く働くには多少の試行錯誤が要求されるかも知れない。その場合、やるべきことは
/rc/bin/srvssh
mnt
では FreeBSD に対しては sshfs
が使われている
さて、このような嫌らしい Mac のファイル名が Plan9 に流れ込むのは嫌なので、パッチを当てることにしていた。今回、文字コードの対応を日本語文字だけではなく、全てのラテン系の文字、およびギリシャ文字に拡張した(2017/06/23)。
http:/p9p/
僕は Windows を使わないので、個人的には興味は無い。
現在は unix ホストを unix ホストにマウントする手段として sshfs が広く普及している。また sshfs は unix ホストを Plan9 ホストにマウントするのにも使える。従って sshfs は現在のマウント方式のスタンダードである。しかし近い将来に sshfs に代わって 9P によるマウントが普及する兆しがある。3大OS (Linux、Mac, Windows) が 9P を採用しだしたからである。
9P に基づく unix 側のサーバーとして u9fs を紹介したが、これは個人利用を想定したシンプルな認証メカニズムしか持っていない。Plan9 側から利用するにはこれでも上手くやっていける(srvssh)。unix が Plan9 の srvssh に相当する仕組みを持っていれば問題はないが、筆者はそのような仕組みが存在するか否かは知らない。
u9fs をサーバー仕様に作り変えた(と称する)フリーソフトとして spfs がある。
A multi-threaded replacement of u9fs
Ref[3] によると他にも多数あるようだが... 僕は動作を確認できていない。
References:
[1] https://github.com/nuxlli/spfs
? NO. latest version? No packages published.
[2] https://sourceforge.net/projects/npfs/
? YES.
[3] http://9p.cat-v.org/implementations