Logo address

Plan9 Server

1998/08/27 改訂
2021/09/10 改定
2021/10/12 追加
2022/01/06 追加 (IPv6, netaudit)

以下の解説は 2021 時点での 9front に基づいている

なぜ Plan9 サーバーを?

もしも「コンピュータは1つだけ」と言われれば、僕は MacBook を選ぶであろう。MacBook は現代の文具であり、何かを書くときに役に立つ。文具としてのコンピュータがなければ何もできないのが、現代の物書きであろう。

あとひとつと言われれば、それに何を求めるか?

Linux を候補に挙げる人が多いだろうが、クライアントとして使うなら、所詮は Mac に敵わない。また Mac に敵う日が来るとも思えない。サーバーとして Linux を勉強したいと言うなら、なぜかを考えた方が良い。職のためなら何も言わない。泥沼であっても勇敢に入り込まなくてはならない職業もあるのだから...

プログラミングが好きなら、Plan9 が良い。Plan9 はプログラミングの天才と言われる人たちが作り上げた、いわば芸術作品である。よく練り上げられた設計とプログラミングコードはそれだけで美しく、鑑賞に値する。他の OS はどうかと言えば、パッチワークの世界であり、荒れた密林の中を彷徨う感がある。それに比べると、Plan9 はよく整備された美しい庭園である。

Plan9 は小さいコンパクトな OS である。ソースコードの全てを見ることができる。OS がどのように動いているか、完全に調べることが可能である。解ったことを確認するために、カーネルレベルでの手軽な実験すら可能である。そのような OS は Plan9 以外には存在しない。

Plan9 は Mac の弱点を補ってくれる。Mac はとてもサーバーとして使えたものではない。設計コンセプトはあくまでも現代の文房具である。Mac の Time machine は履歴管理がなっていない。どこまで遡れば目的のファイルに出会えるか、全くわからないので、日常的には役に立った覚えがない。

以下では一番簡単なサーバー構成、すなわち1台のマシンが認証サーバー、ファイルサーバー、CPU サーバーを兼ねている構成を前提にして解説する。この構成が一番使いやすい。信頼できるユーザーしかいない場合、この構成で十分である。特にホームサーバーとしては...

以下では既に端末としての Plan9 が動いていると想定している。
また読者は、ネットワーク(IPv4 レベル)についてのある程度の知識を持ち、ホームルーターの役割を理解し、簡単な設定ができると仮定している。

ネットワークデータベース

2021/10/04
2021/10/11 追加

僕の場合には家庭内に様々な種類のサーバーを抱えている。それらのサーバーに対して名前でアクセスしたいので、それを Plan9 のサーバーに任せている。

例えば FreeBSD をお試しにインストールして使ってみたいとしよう。標準インストールではクライアントとしてインストールするはずである。これをサーバーに変更したければ、名前を与え、固定した IP アドレスを与える必要がある。この部分は OS ごとにやり方が異なり、しかも複数の場所に設定箇所が散らばっているいることが多い。一苦労が要求される。しかし Plan9 のサーバーを持っていれば、そのような苦労は要らない。Plan9 のネットワークデータベースに数行を追加するだけで済む。家庭内のすべてのサーバーの名前と IP アドレスの設定が1箇所で行えるので見通しが良い。

これを持たないと OS ごとに異なる設定法に四苦八苦することになり、しかも全体の見通しがすこぶる悪い。

注意: 以下では、読者はホームルーターをある程度操作できることが想定されている。操作法はルーターごとに異なるので、ここでは解説しない。(ホームルーターのマニュアル参照のこと)
特に、Plan9 を DHCP サーバーとして動かす場合には、ホームルーターの DHCP サービスを停止する必要がある。このサービスは1セグメントに1つである!

/lib/ndb/local の例

ネットワークを設定するときには、動的 IP の範囲をあらかじめ定めておく必要がある。そのための具体的な方法はあとで解説する。家庭にインターネットを引くと、業者からホームルーターが提供される。これまでに僕が扱ってきたホームルーターの初期設定は、どれも、家庭内の IP アドレスの範囲は 192.168.0.* (ここに '*' は 0 から 255 である)であり、特に 192.168.0.1 はホームルーターのアドレスに設定されている。そこで、我が家の場合には DHCP によって割り当てる動的 IP の範囲を 192.168.0.100 から 192.168.0.249 までに設定している。残りは固定である。

ここでは簡単のために2つのコンピュータ(名前は hebebsd )から構成されるネットワーク構成を /lib/ndb/local に反映させることを考える。実際には僕の場合には、この他に多数のコンピュータが /lib/ndb/local に登場するのだが、ここでは省略されている。

#
#  files comprising the database, use as many as you like, see ndb(6)
#
database=
	file=/net/ndb
	file=/lib/ndb/local
	file=/lib/ndb/common

#
#  entries defining the dns root.  these will be overridden by any
#  authentic info obtained from the root.
#
dom=
	ns=A.ROOT-SERVERS.NET
	ns=B.ROOT-SERVERS.NET
	ns=C.ROOT-SERVERS.NET
	ns=D.ROOT-SERVERS.NET
	ns=E.ROOT-SERVERS.NET
	ns=F.ROOT-SERVERS.NET
	ns=G.ROOT-SERVERS.NET
	ns=H.ROOT-SERVERS.NET
	ns=I.ROOT-SERVERS.NET
	ns=J.ROOT-SERVERS.NET
	ns=K.ROOT-SERVERS.NET
	ns=L.ROOT-SERVERS.NET
	ns=M.ROOT-SERVERS.NET

#
#  because the public demands the name localsource
#
ip=127.0.0.1 sys=localhost dom=localhost

#
# 	Home system
#

authdom=local
	auth=hebe

ipnet=local ip=192.168.0.0 ipmask=255.255.255.0
	ipgw=192.168.0.1

sys=bsd
	ether=6805ca00fc34
	ip=192.168.0.2
	dom=bsd.local
	proto=tcp

sys=hebe
	ether=6805ca00fbd2
	ip=192.168.0.6
	dom=hebe.local
	proto=tcp
	fs=hebe

図1: Plan9 network database

このファイルは DNS サービスと DHCP サービスに使われる。
(それだけでなくネットワークに関する全ての情報がここで一括管理されている)

DHCP サービス

DHCP サービスは dhcpd が行う。
このサービスは1セグメントに1つだけであり、重複してはならない。Plan9 のネットワークの場合には、ファイルサーバーがこれを行う。動的 IP の範囲を 192.168.0.100 から始めて、連続した 150 アドレスに設定するには

ip/dhcpd 192.168.0.100 150
をどこかで実行する必要がある。/rc/bin/cpurc はサーバーの初期化プロセスのために存在するのであるが、ここには一切手を加えないのが良い。ここは完全に配布者に任せるべきである。良い方法はサーバに名前を与えて、名前ごとに初期化が行われることである。

ファイルサーバーの名前(sysname)を hebe としよう。Plan9 の場合には、hebe のためだけの初期化ファイルとして、目的ごとに

が準備されている。このファイルは /rc/bin/cpurc の中で参照されている。
dhcpd の場合には cpustart で起動すればよいはずである。

以前には他に /rc/bin/cpurc.hebe も可能であったが、今は廃止されている。

plan9.ini の例

既に端末としての Plan9 が動いていると仮定する。
すると

ls /dev/sd[C-F]*
の中に 9fat が見えているはずである。これは DOS ファイルシステムであり、その内容を見るには
9fs 9fat
を実行する。(しかし現在(2021)の 9front の配布にはバグがあってマウントできない)
僕のものを紹介しておく:
hebe# dos:
mount -c /srv/dos /n/9fat '#S/sdE0/9fat'
mount -c /srv/dos /n/9fat '#σ/usb/sdUd6220.0/9fat'
hebe#
コマンド dos: は単にマウントのやり方を教えてくれる。この例のように usb も調べてくれる。さらに、9fat だけでなく普通の DOS パーティションのマウント方法も教えてくれる。表示されたものの中から好きなものを選べばよい。

dos:

この中に plan9.ini が存在する。この内容の例を示す:

bootfile=9pc64
bootargs=local!/dev/sdE0/fscache -a tcp!*!564
#nobootprompt=local!/dev/sdE0/fscache -a tcp!*!564
nvram=/dev/sdE0/nvram
mouseport=ps2intellimouse
monitor=vesa
vgasize=1920x1080x16
fs=192.168.0.6
auth=192.168.0.6
service=cpu
fileserver=cwfs
timezone=JST 32400 JST 32400
fsmempercent=50
sysname=hebe

plan9.ini

Plan9 のシステムが立ち上がるときに、役に立つ情報が plan9.ini から読み取られる。

service=cpu として立ち上げると NVRAM の設定をどうするか尋ねられるだろう。次の解説を見よ。

plan9.ini の置き場所としては他にいくつかの選択肢があるが、ここでは詳細に立ち入らない。

IPv6

IPv6 に問題があることに気付いた。原因は、今回のリリース(2021)にある可能性が高い。以前は働いていたのだ。

/lib/ndb/local に IP アドレスを設定する。1つの ether に対して複数の IP が指定されてよい。しかしややこしくなる。実際に問題になっているのは次のような例である:

(a)	ip=192.168.0.6
(b)	ip=2402:6b00:7e7a:6200::6
(c)	ipv6=2402:6b00:7e7a:6200::6
(d)	ipv6=2402:6b00:7e7a:6200:76d4:35ff:fe87:6245
これらは1つの ether、 従って1つの sys に割り当てられている。
僕は(a)と(b)の形で間に合わせていた。なぜわざわざ ipv6 が必要なのだろう? アドレスをみれば v4 か v6 の判別はつくはずではないか? マニュアル(NDB(6))を見るに DNS サービスとの関係らしい。実際 (b) の形式は DNS で無視されている1

ここに挙げた IPv6 アドレスの左半分は接続業者が決める。右半分はこちらが決める。(d) の形式では、右半分は MAC アドレスを基にシステムが決める。そして、これがシステム内のネットワークで重要な役割を果たしている2。それゆえ /lib/ndb/local に書かなくても、システムはこのアドレスを理解し、動いてくれる。(d) はある意味ではシステムにとってプライベートな情報で、外部に公開する必要はないはずである。従って (c) の形式で /lib/ndb/local に書けばよいはずである。この形式は管理しやすく、多くの人が推奨している。

なお IPv6 で "::6" にしているのは単に v4 アドレスの ".0.6" から類推しやすいからである。

ところが我がシステムは (c) 形式のアドレスは、なぜか受け取れない3。多分バグだろう。次のリリースに期待しましょう。

補注: /lib/ndb/local の情報を基に自動的に設定されるべきだと思うが、現状では次の補助的な操作が必要である:

hebe% ip=2402:6b00:7e7a:6200::6
hebe% ip/ipconfig ether /net/ether0 add $ip /64
これによって hebe は "$ip" で指定された IP を受け付けてくれる。"/64" は省けない。
この場合 lib/ndb/local
sys=hebe
	ether=6805ca00fbd2
	ip=192.168.0.6
	ip=2402:6b00:7e7a:6200::6
	ipv6=2402:6b00:7e7a:6200::6
	dom=hebe.local
	proto=tcp
	fs=hebe
にしておく。

/net/ipifc/0/status が interface 管理に関する重要な情報を与えている。

取り消しは

hebe% ip=2402:6b00:7e7a:6200::6
hebe% ip/ipconfig ether /net/ether0 remove $ip /64
である。"/64" は省けない。

以上のことは man IP(3) に詳しい。


注1. Plan9 のネットワークでは使われている
注2. /net/iproute および /net/ipselftab を見よ
注3. 以前は確かに受け取れていたのだ

Netaudit

9front には netaudit コマンドがある。困ったときに役に立つかも知れない。
meg% netaudit
	env var $sysname=meg looks ok
checking this host's tuple:
	sys=meg looks ok
	ip=192.168.0.10 looks ok
	ip=2402:6b00:7e7a:6200::10 looks ok
	dom=meg.local looks ok
	ether=001b21d5a3e9 looks ok
checking the network tuple:
	we are in  ipnet=local
	ipgw=192.168.0.1 looks ok
	dns=hebe looks ok
	auth=hebe looks ok
	fs=hebe looks ok
checking auth server configuration:
	we are not the auth server(s): hebe
	if this is a mistake, set auth=meg or auth=meg.local
	run auth/debug to test the auth server
meg%

Related files

NVRAM

2021/09/10

NVRAM とは

Plan 9 は分散 OS である。
サーバーを、

に分け、役割を分担することによって高度なセキュリティを実現しているのである。
これらのサーバーグループを識別するのに使われるのが共通の秘密の情報 NVRAM である。

NVRAM に含まれる情報

NVRAM には次の情報が含まれる:

host owner は default では glenda であるが、誰でもよい。僕の場合には arisawa に設定している。この方が便利だから... この設定がどのように使われるかは、ps コマンドを実行してみれば解る。
des key は host owner の password から生成される。password 長は8文字以上を与えるべきである。7文字以下の password から生成された des key からは、容易に元の password を導ける。
secstore を使わないなら secstore key は持たなくてもよい。
auth domain は /lib/ndb/local に使われているものを設定する。
僕の場合には我が家のサーバー群は local domain として設定されている。それらに対して認証を行いたいのであれば local に設定する。

従って NVRAM によって

NVRAM の作成に失敗しても、破滅的にはならない。もう一度立ち上げると、再度 NVRAM の入力を求められるはずである。以下にもっと詳しい解説を加えておく。

NVRAM はどこにあるのか?

NVRAM の置き場所は
PC の場合には(ATAを使っているとして)

ここに
XC,D,E,F
N0,1
である。
詳しくは文献[1]を見よ。

注意: /dev/nvram が見えるが、これは関係ない。

Plan9 は NVRAM をどのように探しているのか?

文献[1]を見ると、plan9.ini の中に

nvram=...
例えば
nvram=/dev/sdE0/nvram

nvram=/dev/sdE0/9fat	# same as nvram=/dev/sdE0/9fat!plan9.nvr
nvram=/dev/sdE0/9fat!xxx  # xxx is a file name in root dir in 9fat
があれば、それを基にする。

nvram=plan9.nvr は NG.

plan9.ininvram の指定がない場合、9fat partition を

/dev/sdC0/9fat
...
/dev/sdF0/9fat
...
/dev/fd0disk
/dev/fd1disk
の順に調べる。(scsi も可能。文献[1]を見よ)
そこに plan9.nvr があればそれを使う
なければ error とする。

なお文献[1]では /dev とはしないで #S としている。この段階ではファイルシステムが未完成だからである。

USB に NVRAM を置く場合には、plan9.ini で明示的に置き場所を指定しなくてはならない。

NVRAM の作り方

Plan9 や 9front のインストラクションを読むと、いきなり本物の NVRAM を作っている。しかし感心しない。ここでは安全な NVRAM の作り方を紹介する。
練習のつもりで、一旦 ramdisk に NVRAM を作り、気に入ったら /dev/nvram にコピーする。
以下で、"hebe#" はサーバーのプロンプトである。

hebe# ramfs
hebe# cd /tmp
hebe# dd -if /dev/zero -of nvram -bs 512 -count 1
1+0 records in
1+0 records out
hebe# ls -l
--rw-rw-r-- M 44720 arisawa arisawa 512 Sep 10 16:57 nvram
hebe# nvram=nvram auth/wrkey
bad nvram des key
bad authentication id
bad authentication domain
authid: arisawa
authdom: local
secstore key:
password: 		# blackcat
hebe% xd -c -r nvram
0000000   b  v  x bc 1e 87 e9 a3 00 00 00 00 00 00 00 00
0000010  00 00 00 00 00 00 00 00 00 00 00 00 00 00 \t  a
0000020   r  i  s  a  w  a 00 00 00 00 00 00 00 00 00 00
0000030  00 00 00 00 00 00 00 00 00 00 00 f1  l  o  c  a
0000040   l 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000060  00 00 00 00 00 00 00 00 00 00 00 00 14 e8  = c4
0000070  f9 87  |  ; 06 8c 97  N fd 12 a6 ab  i  i 00 00
0000080  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
0000200
0000200
hebe%

ramdisk での nvram の作成に慣れたら (/dev/sdE0/nvram に作るとして)

cp nvram /dev/sdE0/nvram
を実行すればよい。

なお、ramdisk に作業用の NVRAM を作ったのは、安全な場所だからである。(ディスク上に作ると、消すのを忘れる)

補注: 現在の rwkey は問題を抱えている。/dev に直接作ると、古いデータのゴミを残すのである。それでも実際には問題なく動作するのでバグとまでは言えないが、感心しない。NVRAM の下方に見える

14 e8 ...
の部分は aes キーである[2]。これは(現在のところ) /adm/keys で使われている。

文献

[1] /sys/src/libauthsrv/readnvram.c
[2] man authsrv(2)

Backup system

2021/10/12

Plan9 のサーバーを持っていると使い方の幅が広がる。僕のように Web のサーバーとは言わなくても、Plan9 サーバーは、NAS の代わりとしても、バックアップサーバーとしても優秀である。

backup の対象

ここでは最初に、MacBook を Plan9 サーバーにバックアップして行くことを考える。drawterm を使う。drawterm で Plan9 サーバにアクセスすると、サーバー側のファイルとクライアント(MacBook)側のファイルが一つのファイルシステムとして統一されて見える。MacBook のファイルは

/mnt/term/Users/arisawa/....
のように、Plan9 側のファイルの中に溶け合っているのである。これらは Plan9 の通常のツールを使って処理できる。

MacBook を使っている折を見て、時々バックアップのためのコマンドを投入する。バックアップは保険のようなものである。保険に過度な労力を使うことはなかろう。割り切ろう。

何もかもサーバー側にバックアップする必要はない。バックアップに値するファイルを判断するのは我々である。いつでもネットから取り寄せられるファイルはバックアップの価値がない。バックアップに値するのは、自分で作ったファイルだけであると言っても過言ではないだろう。僕はそのようなファイルをいくつかのフォルダーの中に置いている。それらの中のファイルの個数はそれほど多くはならない。僕の場合には、合わせても、せいぜい1万個程度である。

何か調べ物をすれば膨大な小さなメモのようなファイルが発生する。それらは大切な作業メモであるから、あとで簡単に検索できる必要がある。検索の問題に関しては、それ独自の議論が必要である。Mac の Spotlight は多くの問題を抱えている。それらも合わせて議論したい。

backup の方法 (MacBook 編)

以下で紹介する backup は、次のツールを使っている

いずれも僕の自作のツールである。これらは http:/netlib/cmd に置いてある。

以下、mbook を MacBook の名前とする。mbook の $HOME 下の

adm bin doc info issues lib src
の backup を /usr/backup に作るとする。
hebe% cd /usr/backup/mbook
hebe% ls -l
d-rwxr-xr-x M 35548 arisawa arisawa   0 Oct 11 17:54 adm
d-rwxr-xr-x M 35548 arisawa arisawa   0 Oct 11 17:24 bin
--rwxr-xr-x M 35548 arisawa adm     356 Oct 11 18:41 brun
d-rwxr-xr-x M 35548 arisawa adm       0 Aug 19 09:58 dist
d-rwxr-xr-x M 35548 arisawa arisawa   0 Oct 11 17:29 doc
d-rwxr-xr-x M 35548 arisawa adm       0 Apr 15  2017 info
d-rwxr-xr-x M 35548 arisawa adm       0 Jul 15 12:38 issues
d-rwxr-xr-x M 35548 arisawa adm       0 Jun 24  2017 lib
d-rwxr-xr-x M 35548 arisawa adm       0 Jul 12 05:57 log
d-rwxr-xr-x M 35548 arisawa adm       0 Oct 11 17:32 src
hebe%

brun は backup を取るためのサーバー側のスクリプトである。

hebe% cat brun
#!/bin/rc
# exec on hebe using drawterm
# cd /usr/backup/mbook
# brun
#
rfork e
t=`{lr -nld 0 brun}
last=$t(5)	# mtime of brun from unix epoh
echo $last
slist=(adm bin doc src lib info log issues)
s=/mnt/term/Users/arisawa
for(d in $slist)
  lr -pft $last $s/$d/ | grep -v '\.dmg$' | 9xa cpdir -vm -x ../xlist $s/$d $d
touch brun  # the last brun
hebe%

brun の中にはバックアップを効率よく行うための工夫がある。
brun を実行した時刻が brun の time stamp として記録されている。次回の backup は、それ以降に変更された mbook 側のファイルに対して行えばよい。
それらは極く僅かである。

ls コマンドには、時刻を unix epoh で表すオプションがない。lr は再帰的にディレクトリの情報を表示する。これには、このオプションがある。また lr は与えられた時刻以降に変更されたファイルだけを表示するオプションがある。

9xa は Plan9 用の xargs である。これと cpdir を組み合わせて、ファイルのコピーを行っている。僕 adm の中にある db.dmg はバックアップの対象から外している。これはトップシークレットの情報が含まれる暗号化された Mac のファイルであり、管理を別にしている。こういうのは USB disk で管理するのが一番良いのだ。さらにこれを backup の対象から外したい理由がある。dmg ファイルは、中を見ただけで、time stamp が更新する。大きなファイルだけに非常に嫌だ。

/usr/backup/xlist は backup から排除したいファイルパターンを指定する。僕の場合には

*/tmp/*
*/._*
*/.Trash*
*/.Rhistory
*/.Rdata
*/.CFUserTextEncoding
*/.DS_Store
*/.Spotlight-V100/*
*/.TemporaryItems/*
*/.HFS+*
._*
.Trash*
.Rhistory
.Rdata
.CFUserTextEncoding
.DS_Store
.Spotlight-V100/*
.TemporaryItems/*
.HFS+*
となっている。これらは Plan9 を mbook にマウントしたときに作られた Mac の拡張属性である。こういうものは要らない。

注意: 最初の backup は

touch -t 0 brun
として実行する必要がある。backup の内容を変更した場合には、time stamp を戻す必要があろう。Plan9 には history 機能があるので、修正前の time stamp に容易に戻せるだろう。

Plan9 上のファイルは、自動的に Plan9 の backup システムに乗る。従って、history コマンドによって変更履歴を追って行ける。

backup の方法 (unix サーバー編)

僕は FreeBSD のサーバーと Linux(Ubuntu) のサーバーを家庭内で運営している。インストールした後に、メモをサーバー内に残すのであるが、蓄積されない。理由は簡単で、OS のバージョンアップのたびに、システムの調子がおかしくなり、フレッシュインストールを余儀なくされてきたからである。僕が作った文書のバックアップをちゃんと取っていれば後で苦労はしなかったであろうが、良い方法は持っていなかった。

もっとも僕の場合には、mbook 側から ssh と sshfs を使って Linux や FreeBSD を使うことが殆どである。その場合にはメモは mbook 上に残される。しかし本当は Linux や FreeBSD 上に残したほうが良いのだ。なぜなら直接操作しているときに mbook のメモは見れない。それに一般論としては、文書はオブジェクトに貼り付けるべし。

これまで、Plan9 は OpenSSH2 のサポートが弱くて ssh も sshfs も使えない場面が多かった。ところが今回、気が付いた。9front で OpenSSH2 がサポートされていて、ssh と sshfs がちゃんと動くのである。Cinap に感謝。sshfs が使えれば Plan9 側に容易に backup できる。

次は raspi 用に作ったもの。

hebe% cd /usr/backup/pi
hebe% cat brun
#!/bin/rc
# exec on hebe
# cd /usr/backup/pi
# sshfs -m /n/pi -r / pi
# brun
#
rfork e
slist=(bin db doc src lib info log issues)
for(t in $slist)
  cpdir -vm -x ../xlist /n/pi/home/pi/$t $t
hebe%

mbook に比べて非常に簡単になっているのは、バックアップするファイルの個数が少ないからである。

FreeBSD の sshd は何故か古い。アクセスにパスワードの入力が求められる。
Ubuntu では factotum が使える。つまりパスワードの入力の手間が省ける。
この違いは重要である。Ubuntu の場合には cron job でバックアップが自動化される可能性があると言うことである。

今日、多数のレンタルサーバーが動いている。それらのバックアップシステムとして Plan9 が利用できないか、研究する価値があるのではないだろうか? うまく行けば、ユーザーから喜ばれるだろう。

Linux のバックアップには Linux サーバーを使ったら? ダメだろう。手入力でのパスワードが cron job の障害になる。

PXE boot

2021/10/12

ネットワーを通じて OS をブートアップするために、現在ではどのマザーボードにも PXE boot の仕組みが準備されている。小さな OS であれば、この仕組を使って、多数の端末を均一に動かすことが可能である。

仮に大学の実習室がディスクレスの PC で運営できれば、どれほど管理が楽になるか? 一番故障しやすい部品を持たない。PC ごとに環境が均一になる。全ての PC は一箇所で管理できる。

大学でなくても、工場の PC では、このようなニーズは高いだろう。工場でなくても、事務所の PC も同様である。

残念ながら、現在普及している OS の kernel は大きすぎて、PXE boot での実行は困難を伴うはずである。さらに PXE boot ができたとしても、 OS 自体のネットワークへの対応は貧弱である。Plan9 は PXE boot に対応する理想的な OS である。

Plan9 の場合にはファイルサーバーの側に

(A) PXE loader
(B) kernel
(C) OS のファイル
を置いて、端末側が、 (A),(B) をブート時にダウンロードし、(C) を必要に応じて使う。

Plan9 の本格運用では、複数のサーバーを立ち上げる必要がある。その場合、ファイルサーバーを立ち上げておいて、認証サーバーも CPU サーバーも、Plan9 端末も PXE boot で動かす。以下では端末を想定する。

  1. ファイルサーバーの /lib/ndb/local
  2. ファイルサーバーの /cfg/pxe/*
  3. 端末の BIOS

BIOS の設定は危険な作業であり、自信がなければ止めたほうが良い。廃棄覚悟で、まずは練習。目標はブートの順序の設定である。PXE を先頭に置く。

PC が立ち上がると ether の MAC アドレスが表示される。メモをとる。

/lib/ndb/local

我が家のシステムを例にとる。maia を Plan9 端末とせよ。/lib/ndb/local に次のエントリーを入れる。

sys=maia
	dom=maia.local
	ether=6805ca0a0bf2
	ip=192.168.0.3
	bootf=/386/9bootpxe
"ether=" の値は maia の MAC アドレス、"ip=" は IP アドレスで好みのものを設定する。ただし 192.168.0.0192.168.0.1192.168.0.255 はダメ。DHCP で動的に割り当てる IP アド レスの範囲の外に置く。我が家では 192.168.0.100 から 192.168.0.250 までを動的に割り当てている。そのための具体的な方法は後に述べる。

amd64 kernel を使うのであるが、bootf386 を使う。ブートの初期は 386 モードゆえ。

/cfg/pxe/*

/cfg/pxe/6805ca0a0bf2

bootfile=/amd64/9pc64
fs=192.168.0.6
auth=192.168.0.6
bootargs=tcp
mouseport=ps2intellimouse
monitor=vesa
vgasize=1920x1080x16
service=terminal
timezone=JST 32400 JST 32400
user=arisawa
cpu=hebe
これは設定の1例である。
cpu=hebe は必須ではない。
192.168.0.6hebe の IP である。OS がまともに動いていない段階で端末に与えられる情報であるから、fsauth も IP で指定する必要がある。他方 cpu=hebe は OS が立ち上がって、環境が整い、cpu コマンドの実行を楽にするための環境変数であり、端末の立ち上がりには関係なく、サーバー名を名前で与えることができる。
user=arisawa を省略すると user=glenda が想定される。

PXE error

古い PC の PXE loader 例えば

Intel UNDI, PXE-2.0 (build 082)
9bootpxe+ が受け取れないと言って error になる。
何故か PXE クライアントが間違った情報を受け取るのである。

対策: /3869bootpxe のコピー 9bootpxe+ を置けば解決する

端末の応用

Plan9 端末はディスクレスで動くのであるから、MB (mother board) から HD (hard disk) を切り離し、残りのハードウェアの診断に使える。僕もこの間、この方法でいくつかのトラブルを解決した。

こわ~いプログラムの実行環境として理想的である。何しろハングしても、リセットすれば足りる。ディスクを痛めることはない。

HD を取り付けたまま、PXE boot を第一 boot に設定すれば、立ち上がらない原因が判るかも知れない。

Bootable USB Disk

2021/10/10

ここでは Plan9 を載せた起動可能な usbdisk は 9front の配布版

9front-xxxx.iso
から簡単に作ることができる。ここに "xxxx" の部分は配布バージョンによって異なる。

Mac を例にとると、不要な usbdisk (1GB あれば十分)を差し込んで

mbook$ diskutil list
...
/dev/disk3 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *2.0 GB     disk3
   1:                       0x39                         2.0 GB     disk3s1
mbook$ sudo dd if=9front-xxxx.iso of=/dev/disk3 bs=512
mbook$
これでおしまい!
くれぐれも "of=/dev/..." のところを間違わないように!
挿入した usbdisk の容量は選択の手がかりになる。
また usbdisk を挿入する前と後の "diskutil list" の違いに着目してもよい。
また /dev/disk* も挿入の前後で違いが発生する。

インストール用の usbdisk 自体が、起動可能な usbdisk となっている。しかし、この usbdisk はインストール用に特化していて、お試し版としてある程度のことはできるが、これを元にして個人の好みを反映させようとすると難儀する。以下では勉強を兼ねて、他の方法を採る。

目標は 起動可能な usbdisk に Plan9 を載せ、完全に usbdisk 上で Plan9 を動かす事にある。昔、Plan9 の live CD 版があったが、それの usbdisk 版である。何しろ現在では usbdisk は安く、いくつも周りに散らばっていで、容量の小さなものは廃棄される時代である。ここで作る usbdisk は 2GB でも可能であったが、何回も何回もやり直しているうちに、disk full になってしまった、4BG あれば十分だろう。

僕がこのようなものを作ろうと思ったのは、ネットワークは不調、HD からも立ち上がらない古い PC の診断のためである。FreeBSD は black screen になる。昔どこかで使っていた Plan9 の HD も立ち上がらない...
なぜか、このところ、長年使ってきた2つの PC が立て続けにダメになった。重症らしく、廃棄することとした。そのために我が家の PC が不足気味になって、古いものを引っ張り出したのである。

なおこの記事は、Plan9 の HD を入れ替えるときに役に立つはずである。

以下はメモである。英文のメモだが、そのまま書く。

goal:

4GB usbdisk
bootable 9front with 9pc64 kernel

assumption

you are working on the "pxe booted terminal".
注意: このような仮定を置くのは、ファイルサーバーの上で作業すると間違いやすいからである。

The instructions below are based on 9front(2021) with 9pc64 kernel.

STEP 1. creating bootable (but empty) usbdisk

term% ls /dev/sdU*
/dev/sdU5075c/ctl
/dev/sdU5075c/data
/dev/sdU5075c/esp
/dev/sdU5075c/raw
term% sdu=sdU5075c
term% disk/mbr -m /386/mbr /dev/$sdu/data
term% disk/fdisk -abw /dev/$sdu/data
term% ls /dev/$sdu	# confirmation
/dev/sdU5075c/ctl
/dev/sdU5075c/data
/dev/sdU5075c/plan9
/dev/sdU5075c/raw
term% disk/prep -bw -a^(9fat nvram fscache fsworm other swap) /dev/$sdu/plan9
9fat 204800
nvram 1
other 1070616
swap 204800
fscache 1070616
fsworm 5353084
term% ls /dev/$sdu	# confirmation
/dev/sdU5075c/9fat
/dev/sdU5075c/ctl
/dev/sdU5075c/data
/dev/sdU5075c/fscache
/dev/sdU5075c/fsworm
/dev/sdU5075c/nvram
/dev/sdU5075c/other
/dev/sdU5075c/plan9
/dev/sdU5075c/raw
/dev/sdU5075c/swap
term% disk/format -b /386/pbs -d -r 2 /dev/$sdu/9fat /386/9bootfat /amd64/9pc64
add 9bootfat at clust 2
add 9pc64 at clust 4
Initializing FAT file system
type hard, 12 tracks, 255 heads, 63 sectors/track, 512 bytes/sec
Adding file /386/9bootfat, length 7960
add 9bootfat at clust 2
Adding file /amd64/9pc64, length 5228965
add 9pc64 at clust 4
used 5242880 bytes
term% mount -c /srv/dos /n/9fat '#σ/usb'/$sdu/9fat	# confirmation
term% ls /n/9fat
/n/9fat/9bootfat
/n/9fat/9pc64
term% # you need to add your plan9.ini

my /tmp/plan9.ini

bootfile=9pc64
bootargs=local!/dev/sdU5075c/fscache -a tcp!*!564
# we need 564 not 9fs
# usb boot is an emergency use. so avoid nobootprompt
mouseport=ps2intellimouse
monitor=vesa
vgasize=1280x1024x16
fs=192.168.0.6
cpu=192.168.0.6
auth=192.168.0.6
#service=cpu
service=terminal
fileserver=cwfs
timezone=JST 32400 JST 32400
fsmempercent=50
user=arisawa

cp /tmp/plan9.ini /n/9fat

STEP 2. Configure cwfs

term% cwfs64x -csC -f /dev/sdU5075c/fscache
config: config /dev/sdU5075c/fscache
config: service cwfs
config: filsys main c(/dev/sdU5075c/fscache)(/dev/sdU5075c/fsworm)
config: filsys other (/dev/sdU5075c/other)
config: filsys dump o
config: noauth
auth disabled
config: ream other
config: ream main
config: end
current fs is "main"
cmd_users: cannot access /adm/users
63-bit cwfs as of Tue Sep 21 22:49:33 2021
	last boot Fri Oct  8 15:25:42 2021
term%
確認:
term% ps 	# confirmation
...		# many cwfs64x
term% ls /srv 	# confirmation
...
/srv/cwfs
/srv/cwfs.cmd
term% xd -c /dev/$sdu/fscache |p	# confirmation
0000000   s  e  r  v  i  c  e     c  w  f  s \n  f  i  l
0000010   s  y  s     m  a  i  n     c  (  /  d  e  v  /
0000020   s  d  U  5  0  7  5  c  /  f  s  c  a  c  h  e
0000030   )  (  /  d  e  v  /  s  d  U  5  0  7  5  c  /
0000040   f  s  w  o  r  m  ) \n  f  i  l  s  y  s     o
0000050   t  h  e  r     (  /  d  e  v  /  s  d  U  5  0
0000060   7  5  c  /  o  t  h  e  r  ) \n  f  i  l  s  y
0000070   s     d  u  m  p     o \n  n  o  a  u  t  h \n
0000080   n  e  w  c  a  c  h  e \n  b  l  o  c  k  s  i
0000090   z  e     1  6  3  8  4 \n  d  a  d  d  r  b  i
00000a0   t  s     6  4 \n  i  n  d  i  r  b  l  k  s
00000b0   4 \n  d  i  r  b  l  k  s     6 \n  n  a  m  e
00000c0   l  e  n     1  4  4 \n 00 00 00 00 00 00 00 00
00000d0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000e0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000f0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0000150  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00q
term%

停止:

term% echo halt >> /srv/cwfs.cmd
halted at Fri Oct  8 15:44:36 2021.	# need ENTER here
term% ps	# confirmation
... 	# no cwfs for /dev/$sdu
term% ls /srv
...		# no cwfs nor cwfs.cmd
term%

STEP 3. Installing users to the cwfs

now we can invoke cwfs64x by

term% cwfs64x -sC -f /dev/sdU5075c/fscache
current fs is "main"
cmd_users: cannot access /adm/users
63-bit cwfs as of Tue Sep 21 22:49:33 2021
	last boot Fri Oct  8 15:29:38 2021
term%
NB: in invoking cwfs64x, drop "-c":

we need to register users in prior to mount the fs
/usr/arisawa/doc/cwfs/newcwfs

assumption:
* cwfs is running

cwfs has a user table in memory.
authentication follows this table.
/adm/users is the back up file.

term% con -C /srv/cwfs.cmd	# the commands below are one time action
users default	# register default users. "adm" is in them.
create /adm adm adm 775 d
create /adm/users adm adm 644
newuser arisawa
create /usr/arisawa arisawa arisawa 755 d
create failed in walkto: arisawa
	# ctrl-\ + ENTER to exit
>>>q 	# q to exit
term%
the error message says: failed to create /usr/arisawa
donn't worry about.

now we can mount and can use regular tools of Plan9.

term% mount -c /srv/cwfs /n/cwfs
term% ls /n/cwfs
/n/cwfs/adm
term% cat /n/cwfs/adm/users
-1:adm:adm:
0:none:adm:
1:tor:tor:
2:arisawa:arisawa:
10000:sys::
10001:map:map:
10002:doc::
10003:upas:upas:
10004:font::
10005:bootes:bootes:
term%

NB: any user can make the fs "allow mode" because auth is diabled by config.
it is assumed we are in clean world.

auth is complicated process. I donn't recommend auth for usb disk.
In real world, fs should run with auth enabled.
Then enter again config mode. run fs with "-c" flag, and then

config: noauth
auth enabled
config: end

NB: noauth is toggle switch, I dislike though.

STEP 4. Copy files to cwfs

assumption: cwfs is running and mounted on /n/cwfs

we need in "allow mode":

echo allow >> /srv/cwfs.cmd

Let's copy files to the usbdisk.
Make ready a prototype file

usbfsproto
examine the content. http:usbfsproto

some of live files will be exported to the usbdisk.
these may be OK or NG.
after building namespace in the usbdisk, you can remove files that you donn't want to have in the usbdisk

term% disk/mkfs -s /root -d /n/cwfs usbfsproto
processing usbfsproto
file system made
term%

proto examples:

/sys/lib/sysconfig/proto/*
NB: some of them are at the time of Bell-Labs without updating for 9front.

error: "no frame buffer"
I have consumed much time for this error.

suspect:

try to set vgasize the smallest and do again.

command "memory" on gaia to see what happend. the result:

total          7.96 GB
total kernel   2 GB
total user     5.77 GB

used  user     24.8 MB
used  kernel   6.16 MB
used  draw     0 B
I have much memory.

black screen は VGA 出力で発生しやすい。HDMI や DVI と違って VGA は one way である。MB がサポートしている解像度と、ディスプレイがサポートしている解像度との交渉は、VGA ではやる余地がない。そして一致していないと black screen となる。従って black screen でうまくいかない時には DVI か HDMI ポートを試してみる価値がある。

我々は MB がサポートしている vgasize の値を知り、それに基づいて vgasize を設定するる必要がある。マニュアルによれば、この問題は aux/vga コマンドで扱われるはずであるが、どうしたわけかバグがあって上手く行かない(2021)。

次のスクリプトは、この問題を扱う。

#!/bin/rc
rfork e
fn usage{
	echo 'usage: vgasetup'
	echo 'usage: vgasetup [-t] vgasize'
	exit
}

[中略]

@{rfork n; aux/realemu; aux/vga -m $monitor -l $1}
http:vgasetup

次のように使う:

term% vgasetup
vgasetup 1280x1024x8            m8        	packed
vgasetup 1280x1024x16   	r5g6b5    	direct
vgasetup 1280x1024x32   	x8r8g8b8  	direct
vgasetup 1024x768x8     	m8        	packed
vgasetup 1024x768x16    	r5g6b5    	direct
vgasetup 1024x768x32    	x8r8g8b8  	direct
vgasetup 640x480x32     	x8r8g8b8  	direct
vgasetup 800x600x16     	r5g6b5    	direct
vgasetup 800x600x32     	x8r8g8b8  	direct
vgasetup 640x480x8      	m8        	packed
vgasetup 800x600x8      	m8        	packed
vgasetup 640x480x16     	r5g6b5    	direct
vgasetup 1920x1080x8    	m8        	packed
vgasetup 1920x1080x16   	r5g6b5    	direct
vgasetup 1920x1080x32   	x8r8g8b8  	direct
your vgasize: 1920x1080x16
term% vgasetup 1280x1024x16
term%
これで成功すれば、グラフィックスモードに入り、マウスが使える。サイズの小さい方から試すのが無難かも...

一応テストオプション "-t" を持っている。5秒間テストして、元に戻す。

vgasetup の重要なコードは、Cinap のものを借用している。

終わりに

USB ポートは USB2/USB3 の青色ポートを使う。この方が断然速い。9front はまだ USB3 をサポートはしていないけど...
USB だと動きがもっさりして使い物にならないかと思っていた。立ち上がりは確かに遅いのだか、一旦立ち上がってしまえば、サクサクと気持ちよく動く。
ポータビリティも良い。ただし BIOS で usb first にセットしなくてはならないので、他人の PC では使えない。

古い PC を扱うときには、i386 モードで動くものも作っておく必要があろう。

今回、この仕事をしていて VESA とか VGA とか、基本的なことがよく解っていないことに気付いた。定義(仕様書)はどこにあるの? 教えて貰えたら幸いです。

ところで僕の英文は下手だし、ひどく broken なのである。例えば

you are working on the "pxe booted terminal".
と書いている。由緒ある(正しい)書き方は
you are working on the "pxe booted terminal."
であり、'.' をカッコの中に入れなくてはならない。Knuth は『ドキュメント算法』でこの問題に触れていて、「こんなルールは変なのだが要求されている」(趣旨)と述べている。しかし、いくら正しいと言われても、嫌なのである。そんなことを強制されると、意味が誤解される。この問題が RFC の文書の中でどのように扱われているかを調べたことがある。やっぱり僕のようにやっている。扱っている問題によっては、避けられないのだ。昔、英文の論文を書いたときもこの問題に出会って、僕流のやり方を通した。

ツール

ファイル管理に役に立つツールを紹介ししておく。多数あるが暇をみて徐々に追加する。
とりあえず "-f"。

-f

僕が愛用している "-f" コマンドは

-f cmd arg arg ...
のように使う。cmd に対する force option のように働き、unix の sudo 並の威力を発揮する。このコマンドはファイルサーバーでのみ働き、 host owner だけが実行できる。

原理は簡単で、cmd の実行中だけファイルシステムを allow mode にしているだけである。コマンドの内容を次に示す:
-f

Plan9 のファイルサーバーのオーナーは、ファイルサーバーに対して絶対的な権限を有する。それでも通常は permission に従う。unix のように root の下で permission を無視してなんでもやるのではない。そこで unix の世界では、"sudo" が編み出された。"-f" は unix の "sudo" のように振る舞うがパスワードは求められない。プロセスを殺すには使えない。他人のプロセスを殺すのは CPU サーバーのオーナーの仕事である。