Logo address

MacFUSE 9P Bridge

2013/03/24 更新
2016/02/17 補足追加
2017/05/20 9PFUSE 更新 (最近の知識に基づいて大幅に書き換え)
2017/05/21 評価 更新
2017/06/08 9pfs 追加

Aug 2007
夏休みになって時間が取れたので懸案であった問題に取り組んでみた。
MacFUSE を使って Plan 9 ホストのファイルシステムを Mac のノートブックにマウントする実験である。ノートブックは PowerBook と MacBook を試した。いずれもマウントに成功した。

May 2017
退職して時間が取れようになったので懸案であった問題に取り組んでみた。MacBook の環境改善である。その一つに Plan9 サーバーのマウント問題がある。FUSE を使うのであるが、新しい OSXFUSE をインストールしたら使えなくなった。1か月ほど悪戦苦闘の末、動く様になったので、その成果を纏める。

FUSE

FUSE とは

Plan9 を除く普通のOSではファイルシステムのコードはカーネルの中に存在し、そのことが新しいファイルシステムをOSに組み込むことを困難(開発が困難なばかりか、OSの配布者以外は事実上配布不可能)にしていた。Plan9 ではファイルシステムのコードをカーネルの外に置き、カーネルにはファイルシステムとのインターフェースに関するコードを置く。この考え方はFUSE(Filesystem in Userspace)として他のOSでも採用されつつある1。

FUSE(Filesystem in Userspace) を使うと、ユーザースペースのプログラムによってファイルシステムを構成できる。このメリットは計り知れない。例えば

などを挙げる事ができる。ユーザはファイルシステムに対して多様なニーズとアイデアを持っており、カーネルを拡張する事なく、必要に応じてファイルシステムの一部として使えるようになった訳である。FUSE は現在カーネルに組み込まれている多くのファイルシステムを時代遅れのものとし、カーネルのスリム化に役立つであろう。

現在までに FUSE を基にした多様なファイルシステムが作成されているが、僕とっては sshfs が役に立っている。
また僕が作った FUSE のサンプルが Maxim があり、MacOS, Linux, FreeBSD で動作が確認されている。
FUSE の面白さが分かるサンプルにしたつもりである。

ファイルシステムをユーザスペースで構成するアプローチは Plan 9 由来のものである。

FUSE に関する Russ Cox の批評

現在 Plan 9 の開発の中心になって活躍している Russ Cox は次のように述べている1

From: rsc@plan9.bell-labs.com
Subject: [9fans] user-level file systems for Linux
Date: 2004年2月19日 10:57:42:JST
To: 9fans@cse.psu.edu
Reply-To: 9fans@cse.psu.edu

There is a user-level file system driver for Linux called FUSE that has just released a new stable version:
http://sourceforge.net/forum/forum.php?forum_id=350517
They have user-level servers to mount various archives and various network protocols (http, ftp, smb).

The protocol itself looks fairly similar to the old 9P:
http://tinyurl.com/28f2y

There is another similar project called LUFS
http://lufs.sourceforge.net/lufs/
though it seems more complicated than necessary and makes at least one (imo) critical mistake: no fids.

Actually there have been a handful of projects doing similar things over the past few years, and they've all died out. I'm optimistic about FUSE because it's almost an exact translation of the VFS layer, meaning that it's simple and as expressive as possible.

Russ


注1: Bell-Labs の Plan9 は、開発チームが Google に移って以来、止まっている。9front 及び 9atom が Plan9 を引き継いでいる。特に 9front の動きは注目に値する。Russ Cox は Bell-Labs の Plan9 開発チームが解散して以来 Plan9 の開発に関わっていない。(2017-05-23)

MacFUSE (OSXFUSE)

MacFUSE は OS X 10.4 以降で使える。発行元の Google のページには次のように書かれている。

Examples of file systems that work and have been tested (to varying degrees) include sshfs, ntfs-3g (read/write NTFS), ftpfs (read/write FTP), wdfs (WebDAV), cryptofs, encfs, bindfs, unionfs, beaglefs (yes, including the entire Beagle paraphernalia), and so on.
(http://code.google.com/p/macfuse/)
SpotlightFS と sshfs しか Google のページには見つからないが、これらのプロジェクトに関しては
http://fuse.sourceforge.net/wiki/index.php/FileSystems
に詳しい一覧が載っている。(2017現在ではリンク切れ)

注意: MacFUSE は現在では開発が止まっており、OSXFUSE が後を継いでいる。(2016/02/17)
OSXFUSE は
https://osxfuse.github.io/
から手に入る。基本的な使い方は MacFUSE と同じなので、以下の説明は変更の必要はないであろう。
GITHUB には OSXFUSE のソースコードが付属しているのであるがコンパイルできない。コンパイルできれば動作についていろいろ調べられるのだが...
他のオプションは Plan9port に含まれる 9pfuse である。筆者はこれを使っている。
9pfuse の著者は Russ Cox で、彼は非常に有能であり、Rob Pike の良いパートナーでもある。

インストール (OSXFUSE)

2017-05-23 更新

https://osxfuse.github.io/
からダウンロードすれば良いと思う。"FUSE for macOS" のパッケージが置かれており、最新版は2017年5月時点で 3.5.8 である。パッケージのファイルは osxfuse-3.5.8.dmg である。

このバージョンのネーミングは非常に誤解を招く。FUSE を使ったアプリケーションにとって重要なのはライブラリである。

ライブラリのバージョン選択に関しては以下の点に注意する必要がある。

この2つはアプリケーションのインターフェースが大きく違っており、FUSE を使ったアプリケーションの選択に影響を与える。
(Mac の場合には FUSE2 を使ったアプリは全滅するはずである)

注意すべきは osxfuse-3.5.8.dmg のインストールで生成されるライブラリは FUSE2 である事である。

インストールすると /dev/osxfuse0, /dev/osxfuse1,..., が作成される。

Plan9port の 9PFUSE は FUSE の API(ライブラリ) は使っていないが、FUSE の提供するカーネル拡張とマウンタを使っている。従って FUSE バージョンの影響を受ける。
さらに重要なことは、9PFUSE は現時点では osxfuse.3.x.x の下では動かない。 → 動く様にしました(2017/05/27)

Mac は OS のバージョンアップが激しく、その度にアプケーションは大きな影響を受ける。

動作の確認

(以下の記事は古くなっている可能性がある)

動作確認には SpotlightFS を使うのが簡便であろう。
Gogle のページには次の例が載ってはいるが...

$ mkdir /Volumes/SpotlightFS/Hasselhoff
$ ls -lrt /Volumes/SpotlightFS/Hasselhoff
[... output omitted to avoid embarrassment ...]
mkdir が効かない!

-bash$ mkdir /Volumes/SpotlightFS/Google
mkdir: /Volumes/SpotlightFS/Google: Permission denied
-bash$ ls -ld /Volumes/SpotlightFS
dr-x------   2 arisawa  arisawa  0 Aug 20 11:58 /Volumes/SpotlightFS
-bash$ ls -l /Volumes/SpotlightFS
total 0
dr-x------   2 arisawa  arisawa  0 Aug 20 11:58 SmarterFolder
-bash$

chmod も効かない!

-bash$ chmod 700  /Volumes/SpotlightFS
-bash$ ls -ld /Volumes/SpotlightFS
dr-x------   2 arisawa  arisawa  0 Aug 20 12:08 /Volumes/SpotlightFS
-bash$
これは使い方の説明が悪いのだ。ネット上の次の記事を見つけて解決:

正しい SpotlightFS の使い方

(以下の記事は古くなっている可能性がある)

まず SpotlightFS を立ち上げておいて

Finder ⇒ ファイル ⇒ 新規スマートフォルダ
によって検索する。それを「保存済みの検索条件」に名前を付けて保存する。するとその結果が
/Volumes/SpotlightFS/
に反映する。

macwiki http://macwiki.sourceforge.jp/wiki/index.php/MacFUSE の説明

SporlightFS を起動すると、「SpotlightFS」というボリュームがマウントされます。このボリューム内にディレクトリを作成すると、作成したディレクトリ名を使って Spotlight の検索がおこなわれ、その結果がディレクトリ中にファイルとして表示されるようになります。
が悪い! 次のように書き換えるべきであろう。
SporlightFS を起動すると、「SpotlightFS」というボリュームがマウントされます。ファインダーから新規スマートフォルダを実行し Spotlight の検索を行い、その結果を「保存済みの検索条件」に名前を付けて保存すると、その名前が「SpotlightFS」に生成されます。

References

Plan9port

2017/05/24

インストール

Mac の FUSE を使って Plan 9 のファイルシステムをマウントするには MacFUSE(OSXFUSE) の他に Plan9port が必要である。
Plan9port は PowerPC Mac、intel Mac 共にサポートしている。

Plan9port のコードは以下のサイトに置かれている。(いた)

Plan9port の作者は Russ Cox で、最初は彼の個人サイト swtch.com に Plan9port を置いていたが、彼が Bell-Labs から Google に移ってしばらくして code.google に移した。(彼は Google のコードサーチの作者でもある。) そして現在は GITHUB にコードを移して共同作業の体制をとってる。

GITHUB 版の Plan9port のインストールに関すしては別ページに解説する。→ http:/p9p/index.html

Plan9port には Plan9 の使いやすいライブラリやコマンドが多数含まれており、特に rc は、unix 系の分かり難くて継ぎ接ぎの貧弱なシェルに比べると天地の違いであり、きっと好きになると思う。なお rc はスクリプト言語に特化しているので、コマンド環境として使うには rlwrap との組み合わせが良いと思う(コマンド履歴が使えるようになる)。

rc については以下の筆者の記事が参考になる。

9PFUSE

2017/05/20 大幅に書き換え

ネットの記事を見ていると FUSE の能力を示すデモとして sshfs が注目されているようだ。確かに sshfs は UNIX ユーザにとっては驚きであろう。しかし僕としてはこのようなまがい物ではなく、リモートファイルシステムとの本物のリンクが欲しい。Plan 9 の 9P2000 は本物だ。

9PFUSE を使う場合にはバグの修正が必要

2017/05/19 追加

筆者の実験では

Russ の Plan9port にはバグが含まれ、そのために chmod コマンドが働かない、また大きなファイルの書き込みで(Linux は問題はないが) Mac ではエラーが発生する。
現在のところ僕が見つけた問題箇所は3つで、修正の理由もコメントとして加えている。

このバグは FUSE カーネルのバージョンに依存している可能性が高いので、最新版では修正されているかも知れない。→ GITHUB の最新版でも同じ

必要な修正に関しては、先の http:/p9p/index.html に解説されている。(9pfuse の修正されたプログラムも含まれている)

Mac に関しては、この修正を行ってもまだ問題が残っていて、Finder でファイルを生成するような操作でエラーになる。sshfs に関してはそのような問題は発生していないので、sshfs を研究すれば問題の回避法が分かると思えるが、残念ながら sshfs の Mac 版のソースコドをコンパイルできない。

コマンドでの操作に関しては以上の修正で(現在のところ) Mac、Linux、FreeBSD で実用になっている。

ndb/local

我が家のシステムではホスト hebe がファイルサーバー、認証サーバー、HTTP サーバーを兼ねている。僕が文房具代わりに使っているのは MacBook Pro であり、Plan9port はこれにインストールされている。以下、$PLAN9 をインストールディレクトリとする。

$PLAN9/ndb/localの設定:

# ndb - only used for authdial right now

# database - would add extra file= lines here
# probably need some kind of syntax to avoid hard-coding paths.

database
	file=root-servers

# authentication domains

authdom=outside.plan9.bell-labs.com
	auth=sources.cs.bell-labs.com
authdom=hebe.local

dom=local
	# we need this entry for non Plan9 client
	# the ns value is the name server for dom=local
	ns=hebe.local	# for speed up
	auth=hebe

#
#	--- WARNING ---
#	ipv4 must be first, then ipv6
#	otherwise ndb/ipquery does not work!
#

#	plan9port does not support il protocol
#	look $plan9/src/lib9/_p9dialparse.c
#

ipnet=local ip=192.168.0.0 ipmask=255.255.255.0
	ipgw=192.168.0.1
	proto=tcp
	auth=hebe
	fs=hebe
	dns=io
	# these values are advertised by DHCP or BOOTP. (look dhcpd(8))
	# we assume that dhcpd is running on the same ip. look /cfg/common/cpurc
	# search domains are given by dnsdomain
	# if query is ar, then ar.local and then ar.aichi-u.ac.jp is looked
	# they are not advertised by DHCP server
	# therefore DHCP client should add (if unix):
	#	search local
	#	search aichi-u.ac.jp
	#  are used only for ndb/dnsquery
	dnsdomain=local

sys=router
	dom=router.local
	# the IPs below are LAN sid
	# ether=1066820ced19	# WAN
	# ether=1066820ced18	# LAN
	ip=192.168.0.1

sys=hebe
	dom=hebe.local
	ip=192.168.0.6
	# proto=il	# il is not supported in p9p

Plan9 ホスト

9front

Bell-Labs 純正の Plan9 は(チームが Google に移ったために)現在はメンテされていない。ここから派生した OS が2つある。9tom と 9front である。筆者は 9front を推奨する。推奨する理由は、
(a) Cinap の存在である。Cinap の能力は素晴らしく、僕のような凡人100人以上の力を発揮する。多分天才なのだろう。(それでいて謙虚であると言うか、優しくて親切なんだね)
(b) 9front を推奨する他の理由はファイルシステムに Ken Thompson の CWFS が採用されていることにある。こんなことを言うと Fossil のコードを書いた Russ には悪いが、Plan9 の Fossil は回避した方が良い。理由は(Venti との組み合わせで使うために)仕組みが複雑すぎる点にある。Ventiの設定が難しく性能が出にくい。僕が CWFS に移った時点では Fossil にはバグが残っていた。そのバグはまだ残っているかも知れない。Fossil を使う場合には Venti スコアの管理が重要である。このデータを失うと全てを失うことになる。僕が Fossil を使っていた時には、過去10回分のスコアを安全な場所に保管しており、それによって全滅を免れた経験がある。
(c) 9front が採用しているブートプロセスが素晴らしい。これは Cinap がいたから出来たのであろう。Plan9 のブートプロセスが抱えている問題点は、Bell-Labs にチームが存在すした時代から問題視されていたが、これが 9front で見事に解決されたわけである。Cinap は Rob Pike, Russ Cox に並ぶ天才である。

CWFS

CWFS(Cached WORM FS) は WORM(Write Once Read Many) と、その Cache の組み合わせで動く。この FS(File System) は Ken Thompson の設計とコーディングである。Ken Thompson のものは FS 専用に1つのコンピュータが要求されたが、Geoff によってユーザーランドのファイルシステムとして再設計された。

Plan9 のファイルシステムの最大の特徴は WORM をベースにしていることだろう。どの OS でもファイルは断片に分けて管理されるが、Unix などで採用されている普通のファイルシステムは(メデイアの価格が高価だった時代に設計されたこともあり)断片を再利用する。そのために断片の繋がりを示す情報を失うと致命的な問題を引き起こす。WORM では断片を再利用しない。1度作られた断片は消されないで残す。それによって過去のファイルシステムの履歴を残せるようになった。 また断片はデバイスのパーティション上に積み上げ方式で作られていく。ファイルは1日の内で何度も修正されたり、作られたり、消されたりする。そうした1日の中で発生する全ての変化を WORM が直接扱う訳ではない。それらは WORM Cache が処理する。 WORM Cache は普通のファイルシステムであり Cache の中のファイルは必要に応じて1日単位で WORM にダンプ(バックアップ)されると言う仕組みである。

CWFS は僕が全面的に信頼している唯一のファイルシステムである。僕は Plan9 を使うようになってから無停電源装置を入れたことがない。突然の電源OFFの場合に発生するダメッジは高々 Cache にしか及ばない。Cache が潰れても前日の状態には回復可能である。(業務用はともかく、個人用にはそれで十分である) WORM への書き込みは数分で終わるが、その間に電源 OFF になったらどうか? WORM には正常にダンプされたことを示すマークが積み上げのトップに書き込まれる。ダンプ失敗なら(多分)もう一度ダンプすれば良いだけであろう。推測でしか言えないのは、経験が無いからである。Ken Thompson のことだ、そこまで考えていると思う。

ハードディスクのような機械装置はやがては壊れる。従って結局は WORM のバックアップが欠かせないであろう。実際に僕もバックアップを取っていた。しかし最近はそれも止めた。理由は大容量 SSD が安価に手に入るようになったからである。SSD では可能な上書き回数はハードディスクに比べて少ないので unix などではサーバーには使われないのであるが WORM では上書きが発生しない。コストの面を別にすれば SSD は WORM に最適である。(安くなったから僕は WORM のために1TBの SSD を使っている。多分使い切れないであろう) もちろん Cache には小容量の SSD を別に割り当てている。

fscons

僕は記憶力が悪く(母によれば僕の子供の頃の病気が原因なのだそうだ) CWFS のコンソールへのアクセス方法が分からなくなるので覚えやすいコマンドを持っている。

fscons:

#!/bin/rc
if(test -e /srv/fscons)
	exec con /srv/fscons
if(test -e /srv/cwfs.cmd)
	exec con -C /srv/cwfs.cmd
echo 'no fscons'
ls /srv

ここで fscons を取り上げるのは、認証問題に関係しているからである。

CWFS は次のオプションを持っている。

これらはコンソールから noauthnonone で制御できる。僕にとって理解し難いのは、こうしたセキュリティセンシティブなコマンドがトグルになっていることだ。打ってみて初めてどうなったかが理解できる。(この問題は簡単なパッチで解決は可能である)

noauth

nonone

Plan9 をやっていて感じる難しさは認証に絡む問題である。認証プロセスを外すオプションは、認証以外の部分が正しく働いていることを確認する上で役に立つ。このオプションを使う場合には、もちろん、ルーターなどによって外部からのアクセスを遮断しておく必要がある。

認証プロトコル

9front では新しい認証プロトコルが追加された。dp9ik である。これは p9sk1 の代替えである。p9sk1 は現在では古く、インターネットレベルで使用するには危険である。 Plan9port を使って Plan9 ホストに接続するには以下の点に注意を払う必要がある。

つまりインターネット環境から家庭などの Plan9 ホストに cpu コマンドなどによるアクセスを許し、かつ p9sk1 を許したく無い場合にはそれ用に認証サーバが必要になると言うことである。僕はそのためにもう一つの認証サーバーとして Raspi を使っている。

9front の標準設定では /rc/bin/service.auth/tcp567p9sk1 を禁止している。僕は Unix 環境からのアクセスを必要としているので家庭内ネットワーク用の認証サーバ(ファイルサーバーと兼用)で次のように古いプロトコルも(p9sk1)を許している。

#!/bin/rc1
#exec /bin/auth/authsrv -N $3 	# -N disables old des key
exec /bin/auth/authsrv $3

ファイルサーバーの factotum キー:

key proto=p9sk1 dom=local user=arisawa !password=XXXXXX
key proto=dp9ik dom=local user=arisawa !password=XXXXXX
...

マウント

マウントに絡む問題はコードの修正が必要とされるものが多い。必要な修正は p9p_patch ( http:/p9p/p9p_patch.tgz ) に含まれている。
以下、これが使用されていると仮定する。

準備 (one time action)

筆者のコンピューターライフは殆どが居間で使う MacBook Pro である。(以下 mbook とする)
mbook からアクセスする Plan9 サーバーは hebe である。hebe はインターネットからは様々な名前で呼ばれる。例えば ar.nyx.link とか p9.nyx.link である。家庭内のパソコンのブラウザからもアクセスしたいので、そのために ar.local とか p9.local のような名前でも呼ばれる。かなり複雑なのであるが、以下では複雑な部分を省いて、関係していることだけを説明する。もちろん Plan9port がインストールされている必要がある。

mbook から hebe をマウントするために、以下のディレクトリが mbook に追加されている。

この構成にしたのは Plan9 のやり方に合わせたからである。Unix の教義によると、個人用のディレクトリは $HOME 以下に置くべきであって、そうした教義を信じる人から言えばクレームがつくであろうが、mbook は完全に個人使用であるので便利さを優先して構わない。
/n はホストのマウントポイントである。

hebe のマウントポイントを作ると仮定して、ユーザー(例えば arisawa)から

sudo mkdir /n /srv /mnt
sudo chown arisawa /n /srv /mnt
chmod 700 /n /srv /mnt
mkdir /mnt/factotum
mkdir /n/hebe
を実行しておく。(one time action)
/n の下に置くホストに関しては、後からいくつでも追加できる。筆者は sshfs でマウントする他の unix ホストの名前もここに登録している。その方が楽。

環境変数 NAMESPACE の設定が必要である。

NAMESPACE=/srv ; export NAMESPACE
これは $HOME/.profile にでも設定しておけばよい。

Plan9port のインストール時に $HOME/.profile

PLAN9=/usr/local/plan9 export PLAN9
PATH=$PATH:$PLAN9/bin export PATH
追加されたと思うが、ついでに確認しておく。$PLAN9は、Plan9port の置き場所で、ここでコンパイルしなくてはならない。(他の場所でコンパイルしてもよいが SYMLINK が必要になる)

/srv には Plan9 ホストとの接続が成功すれば、自動的に /srv/hebe などが生成される。

/mnt は認証エージェント factotum が使う。

接続実験 (認証なし)

初めてトライする人は CWFS を認証なしの設定にし、接続の確認をする。9p コマンドが役に立つ。

9p -a hebe ls
これで hebe 側の FS root が見えれば接続成功。もちろんパスワードは聞かれない。

成功したら以下のコマンドを順に実行してみよう。

-bash$ srv hebe
-bash$ ls /srv
hebe
-bash$ 9 mount /srv/hebe /n/hebe
-bash$ ls /n/hebe

/n/hebe へのマウントに成功しているはずである。

接続実験 (認証あり)

認証ありにすると難しくなる。

-bash$ ls /n/hebe	# not mounted yet
-bash$ factotum -a hebe	# wait a few seconds
-bash$ ls /srv		# you should see "factotum"
factotum
-bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ ls /mnt/factotum	# you should see "ctl" ...
confirm	conv	ctl	log	needkey	proto	rpc
-bash$ srv -a -k 'dom=local' hebe

!adding key: role=client proto=p9sk1 dom=local
user[arisawa]:
password: XXXXX
!
-bash$ ls /srv		# you should see "factotum" and "hebe"
factotum	hebe
-bash$ cat /mnt/factotum/ctl
key dom=local proto=p9sk1 role=client user=arisawa !password?
-bash$ 9 mount /srv/hebe /n/hebe
-bash$ ls /n/hebe
386	68020	adm	amd64	cfg	fd	lib	...
-bash$

図1: mount までの流れ

認証には少し時間がかかるかも知れない(5秒程度)。

なお、

9 mount /srv/hebe /n/hebe
の先頭の 9 は 環境変数の PATH に依存しないで Plan9port のコマンドを明示的に指定して呼び出すのに使われる。同様に unix のコマンドを呼び出すには u を先頭につければよい。Plan9 の mount コマンドはシェルスクリプトで、内部では結局 9pfuse コマンドが実行されている。つまり
9pfuse /srv/hebe /n/hebe
としてもよい。

図1には現れないかせ、9p コマンドはデバッグにおいて非常に役に立つ。このコマンドの機能は ftp の 9p プロトコル版だと思ってよい。通信状態の基礎が分かるのである。特に認証が正しく働いているか否かの判断が可能である。 9p コマンドは FUSE には関係していない。 Russ の mount のコードは FUSE に強く依存しており、FUSE が抱えている問題点がそのまま Russ の mount に反映される。Russ が FUSE のコードに問題を感じていてもままならない面があるのである。その点で、9p は 100% Russ であり、信頼性は高い。

クリーンな状態から出発すれば上記の通りになるはずだか、しばしは途中からになる。例えば factotum が認証データを得るのは one time action に近い。
他方、1日の内に何回でも サーバーへの mount や unmount が発生する。そうした場合には発生しがちなエラーを整理する。

Address already in use:

-bash$ srv -a -k 'dom=local' hebe
9pserve: announce unix!/srv/hebe: Address already in use
srv: post9p: 9pserve failed
-bash$ rm /srv/hebe 	# and retry

Address already in use:

-bash$ factotum -a hebe
9pserve: announce unix!/srv/factotum: Address already in use
factotum: post9pservice factotum: 9pserve failed
-bash$
このケースでは認証ずみの場合である。

mount point /n/hebe is itself ...:

-bash$ 9 mount /srv/hebe /n/hebe
mount_osxfusefs: mount point /n/hebe is itself on a OSXFUSE volume
-bash$ unmount /n/hebe 	# and retry
なお unmount は Plan9port のコマンドである。

Connection refused:

-bash$ 9 mount /srv/hebe /n/hebe
9pfuse: dial /srv/hebe: connect /srv/hebe: Connection refused
認証されないとか...

9fs コマンド

認証からマウントまでのプロセスをもっと簡便にやりたければ、9fs コマンドがあるので、使ってみるとよい。
ただし Plan9port 付属の 9fs は認証不要なホストにマウントするのは良いのだけど、認証が必要な場合にはもう少し丁寧にやった方が良い。
僕の場合は次のように変更している。(2017/05/28 コードを追加)

#!/usr/local/plan9/bin/rc
if(! ~ $#* 1){
	echo 'usage: 9fs sysname'
	exit usage
}

fn srv1 {
	flag=()
	while(~ $1 -*){
	switch($1){
	case -a -n
		flag=($flag $1)
		shift
	case -k
		flag=($flag $1 $2)
		shift 2
	}
	}
	if(! 9p stat $1 >/dev/null >[2=1]){
		rm -f $ns/$1
		srv $flag $2 $1
	}
}

ns=`{namespace}
switch($1){
case sources
	srv1 -n sources sources.cs.bell-labs.com
case *
	if(test -e /n/$1/usr){
		echo already mounted
		exit
	}
	if(! test -e /srv/factotum)
		factotum -a $1
	if(! test -e /mnt/factotum/ctl)
		9 mount /srv/factotum /mnt/factotum
	srv1 -a -k 'dom=local' $1 $1
	if(! test -e /srv/$1){
		echo 'srv failed'
		exit srv
	}
	if(u mount | 9 grep -s /n/$1)
		unmount /n/$1
	9 mount /srv/$1 /n/$1
}

譜1: customized 9fs (2017-06-07 update)

認証が必要な場合には '-a' も 'dom=' も指定した方が良い。dom の値は環境に依存する。
この値はファイルサーバ上で cat /mnt/factotum/ctl を実行しなければ分からない。

シェルスクリプトなるものは、利用者の環境と好みに合わせて書けば良いのであって、実際には僕の場合には 9fs の中で sshfs ホストもマウントしている。(unix と Plan9 の混在環境のもとでは、その方が扱いやすい)

僕が現在使用している 9fs が p9p_patch ( http:/p9p/p9p_patch.tgz ) に含まれている。

クリーンアップ

クリーンアップしてやり直ししたいこともあろう。 one time action の部分は残すことにすれば、次のようになろう。

#!/usr/local/plan9/bin/rc
# usage: un9fs
# un9p cleans up all 9fs related processes
#
rfork e
path=(/usr/local/plan9/bin $path)
if(! ~ $#* 0){
  echo 'usage: un9fs'
  exit usage
}
pid=`{/bin/ps axg|awk '$5 ~ /factotum|9pserve|srv|9pfs!sshfs/{print $1}'}
if(~ $#pid 0)
  echo 'no 9p related processes'
if not
  /bin/kill -KILL $pid
for(f in `{ls /n})
  unmount /n/$f
unmount /mnt/factotum
rm /srv/*

un9fs (クリーンアップ用のコード)

このコードは p9p_patch ( http:/p9p/p9p_patch.tgz ) に含まれている。

9pfs

2017/06/08

9pfuse に代わって

ネットを検索していると、9pfs と言うのに出会った[1]。これは Russ の 9pfuse の置き換えを狙っているらしい。こののサイトによると、9pfuse に比べて相当に速いらしい。(キャッシュのお陰だと思う)

Russ は FUSE のライブラリを使用せずに、FUSE のカーネルだけを直接的に利用してコードを書いている。他人の書いたコードに依存したくないのであろう。Russ ほどの力量があればこそ可能な事である。実際に Russ のコードはシンプルで良くわかる。他方 FUSE のライブラリのコードを見ていると、何で... と思う部分が多い。

9pfs の方は FUSE のライブラリを利用している。少々手を加えればコンパイルは成功する。

コードの修正

libc.h

 typedef uint32_t u32int;
 typedef int32_t s32int;
 typedef unsigned char uchar;
+typedef unsigned long ulong;
 typedef unsigned long long uvlong;
 typedef long long vlong;

9pfs.c

 		size = CACHECTLSIZE;
 		if(off >= size)
 			return 0;
-		memcpy(buf, "cleared\n" + off, size - off);
+		memcpy(buf, &("cleared\n"[off]), size - off);
 		clearcache(path);
 		return size;

9p.c

つまらない GNU 拡張が使われているために数10行の修正が必要になっている。

問題の部分は

char *calls2str[] = {
  [Tversion]	"Tversion",
  [Tauth]	"Tauth",
  [Tattach]	"Tattach",
  ...

これは clang で蹴られる。この部分は

char *calls2str[] = {
  [Tversion] =	"Tversion",
  [Tauth] =	"Tauth",
  [Tattach] =	"Tattach",
  ...
で書き換えれば解決する。

それにしても GNU は、こんなに詰まらない(酷い)拡張をするのだね~~~
拡張というのは、常に副作用を伴う。従って、拡張が許されるのは相当な理由(合理性)が無くてはならない。例えば、論理的、必然的にあるべき姿が実現していない場合は許されるだろう。しかし、この場合には、文法エラーになって当然の書き方を、1文字の入力の節約のために許してしまおうとする拡張であって、コンパイラのバグと見なして良いものだ。

9pfs.tgz

コードを修正してパッケージにしたものを次に置く。
http:9pfs.tgz

Makefile_osxMakefile_bsdMakefile_linux を新たに含めた。
MacOS、FreeBSD、Linux でコンパイルできる事が確認されている。

FreeBSD ではマウントが NG である。

MacOS、Linux ではマウントは OK。しかし、僕はまだ使い込んでいない。
使い込めば、修正が必要な箇所が発見されるかも知れない。

使い方

マウントは 9pfs で統一したいと思っても、factotum とミスマッチがあるらしい。

筆者の環境では

-bash$ factotum -a hebe
-bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ export FACTOTUM=/mnt/factotum
-bash$ 9pfs -a hebe /n/hebe
!adding key: role=client proto=p9sk1 dom=local
user[arisawa]:
password:

ここに

あるいは、譜1の最後の 9 mount に代わって

9pfs -U /srv/$1 /n/$1
としてもよい。

追加コメント

使ってみて

FUSE API の限界

FUSE では setattr が使えると思っていたが、fuse-2.9.7 のコードを見ている限り、使えるのは FUSE kernel との low level interface みのであって、普通のプログラマが使う API レベルではサポートされていない。

9pfs では API レベルを使っているので setattr がサポートされていない。そのために local のファイルをホスト側にコピーしたときに、元のファイルが持っていた時刻情報(atimematimeなど)まで含めてコピーできない。この事が問題なら 9pfs は使えない事となる。

Russ が 9pfuse で FUSE API を使わなかった理由の1つかも知れない。

その内に解決される可能性は高いのだが...

u9fs がマウントできる

Russ の 9pfuse は unix ホストの u9fs をマウントできないが1、9pfs だとマウントできる。
もっとも unix から unix ホストのマウントは、現在では sshfs で間に合うだろう。

注1: 可能かもしれないが、筆者はまだ成功していない。

いろいろな「9pfs」

ところで「9pfs」と言うのはいろいろあるらしい。
記事[1]のコードは Mischief のもの。(コードを見る限り、Mischief は几帳面だね...)
記事[2]から推測すると py9p プロジェクトの副産物としての 9pfs。これは、Saveliev と Mirtchovski による開発である。

前者では

Usage: 9pfs [-anU] [-A aname] [-p port] [-u user] service mtpt
で、これはクライアント仕様。

後者では

Usage: 9pfs [-dDw] [-c mode] [-p port] [-r root] [-a address] [user [domain]]
これはサーバー仕様。

また記事[3]によると、「9pfs」は 9P プロトコルの別名としても使われているらしい。

なお記事[4]には、9P の実装が多数紹介されている。(いつの間にか、こんなに...)

[1] 9pfs
https://github.com/mischief/9pfs

[2] 9pfs man page
https://www.mankier.com/1/9pfs

[3] Xen transport for 9pfs version 1
https://xenbits.xen.org/docs/unstable/misc/9pfs.html

[4] 9P Implementations
http://9p.cat-v.org/implementations

9PFUSE の古い記事 (参考程度に)

実験環境

クライアントは Mac のノートブック。僕は Mac のノートブックを2つ持っている。PowerBook と MacBook である。いずれも OSX 10.4 環境下で動いている。以下それらを各々 pbookmbook と呼ぶ。どちらで行っても動作に違いはない。そこで、ここでは pbook での実験のみを示す。

マウントするリモートホストは 3 つを試した。

pc
自宅のデスクトップの Plan 9 端末で、端末と言っても実際にはサーバと同様なサービスを行っている。認証サーバを持たずに、単体で動いている。Factotum と venti を備えている。
ar
大学の Plan 9 の CPU サーバー
pmac
自宅のデスクトップの Mac で u9fs が動いている。
太字で示したのはマシン名であり、以下この名前で説明する。

pbook のディレクトリ構成

ここでは Plan 9 端末風にディレクトリを構成する。メリットは
注意: X11 は intel Mac ではサポートされていない。また X11 のユーザーインターフェースは Mac ユーザにとっては使いやすいとは言えない。

逆にデメリットは、

事にある。最後に述べたデメリットり関しては、ノートパソコンであるから問題にはならない。

pc のマウント

実験した日には研究室にある認証サーバ hera は停電のためにダウンしていた。しかし pc は認証サーバーと関係なく動いているので問題はない。

pc に接続するためには、pc の factotum には次の内容が必要である。

key dom=pc proto=p9sk1 user=arisawa !password=xxxxxxxx
xxxxxxxx はパスワードである。

以下にマウントに至るまでの pbook で実行するコマンド手順を示す。

-bash$ mkdir /srv   # needs only once
-bash$ mkdir -p /n/pc  # needs only once
-bash$ mkdir -p /mnt/factotum  # needs only once
-bash$ NAMESPACE=/srv
-bash$ export NAMESPACE
-bash$ factotum
# it may be required to execute here (added 2016)
# -bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ 9fs pc

!adding key: role=client proto=p9sk1 dom=pc
user[arisawa]:
password:
!
-bash$ 9 mount /srv/pc /n/pc
kextload: /System/Library/Filesystems/fusefs.fs/Support/fusefs.kext loaded successfully
-bash$ ls /n/pc
386             NOTICE          cfg             lp              rc
68000           acme            cron            mail            sparc
68020           adm             dist            mips            sys
LICENSE         alpha           env             mnt             tmp
LICENSE.afpl    amd64           fd              n               update
LICENSE.gpl     arm             lib             power           usr
-bash$

ディレクトリ /srv/n/pc はあらかじめ作成しておく。また NAMESPACE の設定と export.profile で行うのが良いであろう。

9 コマンドは Plan9port のコマンド名が UNIX のコマンド名と衝突する場合に Plan9port のコマンドを実行してくれる。

factotum を実行すると /srv/factotum が生成される。"9fs pc" を実行すると /srv/pc が生成される。/srv に生成されたものはソケットである。

Plan 9 の 9fs はマウントまでやってくれるが、Plan9port の 9fs はやらない。9fs は rc スクリプトで内部で srv を実行している。また、Plan9port の mount も rc スクリプトで、ソースを見るに BSD 系の OS に対しては 9pfuse を実行している。

以下にマウントされた時の Mac の Finder を示す。

Finder に反映された MacFUSE

Factotum の ctl にアクセスする。

-bash$ mkdir -p /mnt/factotum     # needs only onece
-bash$ 9 mount /srv/factotum /mnt/factotum
-bash$ ls /mnt/factotum
confirm conv    ctl     log     needkey proto   rpc
-bash$ cat /mnt/factotum/ctl
key dom=pc proto=p9sk1 role=client user=arisawa !password?
-bash$

factotum にデータを追加するには

echo key 'dom=aichi-u.ac.jp proto=p9sk1 role=client user=arisawa !password=xxxxxxxx' >> /mnt/factotum/ctl
のように ">>" を使う必要がある。(Plan 9 の factotum の場合には ">" で構わない。)

削除するときにも同様である。

問題点

ls -l を実行してみると UNIX の限界がよく分かる。

-bash$ ls -l /n/pc
total 85
drwxrwxr-x   1 arisawa  arisawa      0 Jun 27 17:24 386
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 68000
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 68020
-r--r--r--   1 arisawa  arisawa  13006 Jul 13  2005 LICENSE
-rw-rw-r--   1 arisawa  arisawa  14333 Jun 29  2003 LICENSE.afpl
-rw-rw-r--   1 arisawa  arisawa  15081 Jun 26  2003 LICENSE.gpl
-r--r--r--   1 arisawa  arisawa     63 Apr 15  2002 NOTICE
drwxrwxr-x   1 arisawa  arisawa      0 Jan 31  2007 acme
...
オーナーやグループはどれも arisawa になっているが、本来は sys である。UNIX ではファイルシステム毎にファイルのユーザとグループを決める事ができないので、リモートファイルをマウントした時にローカルファイルシステムのユーザとグループで適当にマッピングする他ない。ここでは全て arisawa にマッピングされているのだ。その場合にはファイルに対する arisawa の本来のアクセス権を知る事ができない。

コマンドでファイルにアクセスする限り、実際にアクセスして拒否されれば知らせてくれる。しかし Mac の Finder を通じてマウスでクリックしていると状況が異なる。Finder は余計な親切をしているのだ。それがあだになって読み取れるはずのファイルが読み取れない事もある。(Finder は正しいメッセージを出していない!)

このような問題は UNIX と Plan 9 と言う異質な OS を結んだから発生したのではない。 UNIX 相互でも管理者ドメインが異なれば同じ問題が発生する。UNIX がネットワーク環境に適合しないと言われる根拠の一つになっている。

参考のために Plan 9 端末から u9fs を使って UNIX (Mac OSX) をマウントした場合の ls -l を示す

--rwxrwxrwx M 29 arisawa staff    6148 Apr 24 22:05 .DS_Store
d-rw------- M 29 root    ???       272 Aug 29 06:34 .Spotlight-V100
d--wx-wx-wx M 29 root    admin     170 Feb 23  2006 .Trashes
[中略]
d-rwxr-xr-x M 29 arisawa staff    1360 Jan 26  2003 システムフォルダ
d-rwxrwxr-x M 29 root    admin     340 Sep 13  2002 書類
d-rwxr-xr-x M 29 arisawa admin      68 Jan 26  2003 起動時に消去する項目
グループ名の欄の "???" は元は数字であった。この変更以外は本来のユーザ名とグループ名が正しく表示される。Plan 9 の場合にはマッピングの必要はないのである。

ar のマウント

ar は研究室に置かれている Plan 9 システムの CPU サーバである。ファイルサーバーの /lib/ndb/local で、ar の認証サーバーとして hera が指定されている。また ar の factotum は
key dom=aichi-u.ac.jp proto=p9sk1 user=arisawa !password=xxxxxxxx
である。(xxxxxxxx はパスワード)

ar の認証ドメインは aichi-u.ac.jp であるが、factotum には認証サーバーに関する情報が含まれていない。従って pbook から ar をマウントするには ar の認証サーバーが何であるかを知らせる必要がある。この事は $PLAN9/ndb/local で行える。僕のケースでは

authdom=aichi-u.ac.jp
	auth=hera.aichi-u.ac.jp
を追加した。これを追加すれば、マウントまでの手順は pc と同じである。
hera.aichi-u.ac.jp は NetInfo に登録しておかなくてはならない。

pmac のマウント

これは unix (like) から unix (like) へのマウントである。

pmac は自宅の PowerMac G4 で、ここでは u9fs が動いている。pmac は Plan 9 端末からはマウントできる。しかし不思議な事に pbook からは(pmac からも)マウントできない。
この問題は現在においても解決できない。9fans ではマウントできるとの情報もある。(2016/02/17)

-bash$ 9fs pmac
authdial: Connection refused
原因不明

取り消し

mount

マウント
9 mount /srv/ar /n/ar
の効果は unmount
9 unmount /n/ar
で取り消せる。

9fs

9fs ar
の効果を取り消すには次のようにする。
-bash$ ps
  PID  TT  STAT      TIME COMMAND
24157  p1  S      0:00.46 -bash
24276  p1  S      0:00.51 factotum
24278  p1  S      0:02.51 9pserve -u unix!/srv/factotum
24289  p1  S      0:40.18 9pserve -u -M 8192 -A  0 unix!/srv/ar
24306  p1  S      0:11.60 9pserve -u -M 8192 -A  0 unix!/srv/pc
24198  p2  S+     0:00.07 -bash
-bash$ kill 24289
-bash$ ls /srv
ar              factotum        pc
-bash$ rm /srv/ar
-bash$
Plan 9 の場合には /srv/ar だけを消せば良かったが、Plan9port ではプロセスも落とさなくてはならない。

factotum

factotum を取り消すには
-bash$ ps
  PID  TT  STAT      TIME COMMAND
24157  p1  S      0:00.53 -bash
24751  p1  S      0:00.01 factotum
24753  p1  S      0:00.01 9pserve -u unix!/srv/factotum
24198  p2  S+     0:00.07 -bash
-bash$ kill 24751
-bash$ rm /srv/factotum
-bash$

この後に

unmount /mnt/factotum
が必要かもしれない。

"9pserve -u unix!/srv/factotum" は factotum によって生成されたプロセスで factotum を落とせば自動的に落ちるが、/srv/factotum は削除しなくてはならない。

診断

以下に実験中に出会ったエラーについて解説と対処法を付ける。
なお、pc とか ar は実験当時に筆者が使用していたホスト名である。
また pmac は実験当時に僕が(Plan9port をインストールして)使っていた PowerBook の名称である。

実験では 9fs は Plan9port 付属のものをそのまま使用していた。譜1を使えは、もっとスムーズに行く可能性がある。

unknown host

bash$ 9fs pc

!adding key: role=client proto=p9sk1 dom=home
user[arisawa]:
password:
!
authdial: unknown host home
bash$
原因: pc 側の factotum の誤設定
dom=home となっていた。$PLAN9/ndb/local の設定と一致していることを確認する。

unable to find common key

-bash$ factotum
-bash$ 9fs ar
srv: authproxy: auth_proxy rpc: p9any client ask for keys: unable to find common key
-bash$
この問題は $PLAN9/ndb/local の設定を行う事で解決したはずである。

Result too large

-bash$ echo key 'dom=aichi-u.ac.jp proto=p9sk1 user=arisawa !password=xxxxxxxx'>/mnt/factotum/ctl
-bash: /mnt/factotum/ctl: Result too large
この問題は ">>" を使う事によって解決する。

can't mount on Darwin

-bash$ 9 mount /srv/pc /n/pc
can't mount on Darwin
-bash$
これは pmac から pc をマウントするときに出た。原因は pmac の Plan9port が古い事による。最新の版をダウンロードしてインストールすれば解決する。

Connection refused (1)

2016/02/17

このメッセージはマウントするときに発生する。例えば

-bash$ 9 mount /srv/hebe /n/hebe
9pfuse: dial /srv/hebe: connect /srv/hebe: Connection refused

原因は認証されないままマウントを試みたからだろうと思われる。

参考のために、実行すべきコマンドと、その結果として生成されるファイル("→" で示してある)を以下に示しておく。
"*" はそこに名前が存在することを意味する。また"#" より右はコメントである。

  1. factotum # → /srv/factotum
  2. 9 mount /srv/factotum /mnt/factotum # → /mnt/factotum/*
  3. 9fs HOST # → /srv/HOST
  4. 9 mount /srv/HOST /n/HOST # → /n/HOST/*
認証は 9fs で行われているので、/mnt/factotum/ctl が存在すれば、(このケースでは)
9fs hebe
を実行してから、再度マウントを試みる。

なお譜1だと "9fs HOST" でマウントまで進むはずである。

Connection refused (2)

2016/02/17

認証を求めようとして 9fs で次のメッセージに出会うことがある。

-bash$ 9fs nix
authdial: Connection refused

相手ホストは Linux で、こちらは Mac である。
今のところ筆者は unix 相互のマウントに成功したことがない。

注: Connection refused の発生要因として多いのは、閉じている port へのアクセス。(2017/06/13)

fid unknown or out of range

2016/02/17

-bash$ 9pfuse /srv/mmac /n/mmac
9pfuse: fsmount: fid unknown or out of range
-bash$

これは macbook から mac mini へのマウントで発生する。もっと一般的に言えば unix (like) から u9fs へのマウントで発生する。原因は認証が正しく行われていないからだろうと思えるが、「Connection refused」との違いが今のところ分からない。

mount point XXX is itself on a OSXFUSE volume

2016/03/03

既にマウントされている XXX にさらにマウントしようとした。

unmount XXX
で解決する。

評価

2017/05/21

9PFUSE はコマンドレベルで使う限り、現在のところ問題はない。

しかし Finder との関係では問題がある。見えることは見えるのだが、書き込みが発生する操作(複製とか Drag&Drop とか)はエラーになる。これが何から発生しているか今のところ分からない。Macの拡張属性の処理ではないかとは推測しているが証拠を持っていない。
sshfs は上手くやっているので研究したいと思う。

Mac 付属のテキストエディタ TextEdit.app や Xcode.app では、(拡張属性が邪魔をして)編集した結果を保存できない1
Plan9port の acme は OK である。

ところで最近の TextEdit.app は(僕にとっては非常に使いにくくなっている)

なお僕は edit コマンドを作って持っており、TextEdit.app で読み取る前に xattr を削除することとした。
関係するコードは次の通りである。(rc で書かれている)

xa=`{xattr $e}	# extended attribute
if(~ $xa ?*)
	xattr -d $xa $e
open -a $EDITOR $e || echo $usage
ここに、$e は編集の対象となっているファイルである。


注1: TextEdit.app はファイルの保存時に必ず拡張属性も合わせて保存する。不思議なことに、9pfuse でも 9pfs でも拡張属性の上書きができない。その場合には、TextEdit.app はファイルの上書き(つまり保存)を拒否するようだ。 従って 9pfuse や 9pfs を使って Plan9 ホストをマウントした場合には、エディタは acme 択一になろうか? (2017/06/13)

References