自由度を高めるユーザースペースファイルシステム

以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にOSM 本誌に記載されたものとは異なる。誤字脱字等そのままである。

致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。

目次


======================================================================
Part3: 自由度を高めるユーザースペースファイルシステム
======================================================================

■
■ユーザスペースファイルシステムの意義
■

計算機上で扱うデータは最終的に全てハードディスク等の補助記憶装置に保存さ
れる。さらにいえば、ほとんどのデータは「ファイル」という収納単位に納めら
れる。一般のアプリケーションでも、基本的にはこの「ファイル」を対象にデー
タの読み書きを行なう。テキストエディタ、ワープロ、mp3プレーヤ、どれもファ
イルを処理対象とする基本機能を持っている。ただし音楽ファイルのようにネッ
トワークの先にあるものを楽しみたい、と思うこともある。もし、音楽再生ソフ
トがリモートファイル直接再生に対応していなかったとすると、

	* ブラウザなどを用いローカルディスクに保存してから再生する
	* HTTPやFTPに対応した再生ソフトを利用する

という異なるアプローチがある。当然後者の方が手間は減るのだが、元々使って
いるソフトより使い勝手が悪くなる場合もあるし、自分の環境ではそもそもその
ようなソフトが見付からない場合もある。

音楽再生に限らず、あるいはHTTP/FTPを利用するという点に限らず、手元のディ
スクにファイルはないが「2〜3回コマンドを叩けばそのファイルを手に入れられ
る」というような場合に、ファイルシステム側で自動的にそのファイルを手に入
れるようにしてくれれば、アプリケーションが個別に対応しなくても「どんな場
所にあるファイルでも」繋がってさえいればそのまま開くことができる。

いま現在使っている全てのアプリケーションで、ローカルディスク、圧縮ファイ
ル、ネットワーク先、等々様々なファイルを直接開けるようにしてくれる可能性
を持っているのが新機軸のファイルシステムである。

■
■FUSE
■

FUSE(Filesystem in Userspace)は、ユーザスペース(カーネル外)プログラムで
構成するファイルシステムを実装するためのAPIだ。これを利用することで、入
出力方法を定義するだけの比較的簡単なプログラムを作成するだけで、それが新
しいファイルシステムとして使えるようになる。FUSEプロジェクトのWebページ
http://fuse.sourceforge.net/
にもあるように、「Hello World!」という内容だけをもつファイルシステムなど
が容易に作成できる【註 ら】。

---[註 ら]------------------------------------------------------------
同名のソフトウェア FUSE - Free Unix Spectrum Emulator
http://fuse-emulator.sourceforge.net/
がある。このため、混乱を避けるためFreeBSD portsのように FUSEFS, fusefs
などと表記しているものがある。FUSE(FileSystem)の作者は、fuse-emulator の
作者をそれ以前に知っていたようだがFUSEのことは知らなかったようだ。このあ
たりFAQファイルに記述がある。
----------------------------------------------------------------------

FUSEは現在 Linux と FreeBSD で利用できる。

●FUSE+SSHFSのインストール(Linux)

まずLinuxでの導入方法を示そう。現在も発展中のプロジェクトであり、RPMなど
のバイナリパッケージがあるかどうかはディストリビューションによって大きく
異なるようだ。FedoraCore 5 では既にパッケージ化されているので、以下の手
順でインストールできる。

	# yum install fuse-sshfs

パッケージ化されていない場合はソースビルドする必要がある。
http://sourceforge.net/project/showfiles.php?group_id=121684&package_id=132802
から fuse-2.5.3.tar.gz を、
http://sourceforge.net/project/showfiles.php?group_id=121684&package_id=140425
から sshfs-fuse-1.6.tar.gz を取得しよう(より新しいものがあればそちらを)。

	% tar zxpf fuse-2.5.3.tar.gz
	% cd fuse-2.5.3
	% ./configure && make
	% sudo make install

これで /usr/local 配下にユーザコマンドとライブラリが、
/lib/modules/バージョン/kernel/fs/fuse にローダブルモジュールがインストー
ルされる。

	# modprobe fuse

で、fuseモジュールをロードする。

次にsshfsをインストールする。glib-2.0 の開発用パッケージが必要なのでもし
なければ事前にインストールする。

	# apt-get install glib2-devel

sshfs本体のコンパイルとインストールを行なう。

	% tar zxpf sshfs-fuse-1.6.tar.gz
	% cd sshfs-fuse-1.6
	% ./configure
	% LD_RUN_PATH=/usr/local/lib make
	% sudo make install

インストールに成功したら、カーネルモジュールを有効化しておく。

	% sudo modprobe fuse

●FUSE+SSHFSのインストール(FreeBSD)

FreeBSDでは既にport化されているのでそれを利用する手順を示す。

	# cd /usr/ports/sysutils/fusefs-sshfs
	# make install clean

依存関係によりfusefsもコンパイル後インストールされる。FUSEを有効化するた
めにカーネルローダブルモジュールをロードしておく。

	# kldload fuse

また、一般ユーザでのマウントを可能とするためsysctl変数を以下のように設定
する。

	# sysctl -w vfs.usermount=1

なお、vfs.usermountの変更をリブート後も有効にしたい場合は 
/etc/sysctl.conf に

	vfs.usermount=1

という1行を追加しておく。

●SSHFSによるファイル共有

別のマシン上にあるローカルファイルを共有する方法にはいろいろあるが、設定
の上でもっとも頭を悩ますのがセキュリティだろう。たとえばNFS(Network File
System)は、実績もありネットワーク透過性も高いためファイル共有の面では有利
だが、低速回線では使いづらいことやセキュリティ確保の問題などを考えると、安
全の確保された同一LANのマシンどうしでないと困難が伴う。

遠隔地でのファイル共有を行なうためには、これまでは事前にVPNなどで論理回線
的に安全性を確保する必要があったが、SSHそのものをファイルシステムのトラン
スポートに据えることで特段の設定をしなくてもよくなるため個人レベルでのファ
イル共有が非常にやりやすい。

fuse-sshfs を利用したリモートファイルシステムのマウントは非常に簡単だ。
リモートホストにsshログインできることを確認した上で

% sshfs [オプション] [ユーザ@]リモートホスト:パス マウントディレクトリ

のように起動するだけで、スーパーユーザになる必要もない。次の例は、クライ
アントホスト chibi の ~/oyahome ディレクトリに、ファイルサーバとなるホス
ト oya の、/home/taro ディレクトリをマウントすることを示したものである。

	% ssh oya hostname	(oyaにsshログインできることを確認)
	oya
	% sshfs oya:/home/taro ~/oyahome
	% ls ~/oyahome
	(ホスト oya の /home/taro の内容が出力される)

なお、FreeBSDの場合はsshfsコマンド起動時のコマンド検索パスに
mount_fusefs のあるディレクトリが登録されていないとエラーになる。portで
インストールした場合は /usr/local/sbin がそれにあたるので、あらかじめ
$PATHに足すか

	% env PATH=/usr/local/sbin:$PATH sshfs oya:/home/taro ~/oyahome
	  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

のように起動するとよいだろう。一度マウントしたディレクトリをアンマウント
するには
	% fusermount -u マウントポイント	(Linuxの場合)
	% umount マウントポイント		(FreeBSDの場合)

とする。
sshfsで指定できるオプション一覧を【表 い】に示す。


---[表 い]------------------------------------------------------------

★sshfsのオプション
    -o サブオプション      SSHFSサブオプション(下記)の指定
    -h   --help            ヘルプ出力
    -V   --version         バージョン出力

★SSHFS サブオプション(-oの直後に指定する)
    -p ポート番号          ssh接続のポート番号
    -C                     ssh接続時に圧縮を指定
    -1                     SSH-1プロトコルを利用
    -o reconnect           サーバに再接続
    -o sshfs_sync          同期書き込み
    -o no_readahead        同期読み込み(先読みしない)
    -o sshfs_debug         デバッグ情報を出力
    -o cache=YESNO         キャッシュするかを yes か no で指定(既定値はyes)
    -o cache_timeout=N     キャッシュのタイムアウトの秒指定(既定値は20)
    -o cache_X_timeout=N   stat、dir、linkのキャッシュタイムアウト指定
    -o workaround=rename   既存ファイルにmv(rename)したときにエラーとな
       			   ることを回避
    -o workaround=nodelay  ssh接続でtcp nodelayフラグをセット
    -o workaround=truncate 古いsftpサーバでファイルの切り詰め(truncate)
       			   ができなくなる問題を回避(※註 ろ)
    -o workaround=all      上記の回避策を全て有効化する
    -o workaround=none     上記の回避策を取らない
    -o idmap=none          uid gidの変換をしない(既定値)
    -o idmap=user          接続ユーザの uid のみuid変換をする(おすすめ)
    -o ssh_command=コマンド    ssh接続に利用するコマンドを指定する
    -o ssh_protocol=N      SSHプロトコルバージョン(既定値は 2)
    -o sftp_server=パス    sftpサーバプログラムのパス(既定値は sftp)
    -o directport=PORT     directly connect to PORT bypassing ssh
    -o transform_symlinks  サーバ側の絶対パスで張られたsymlinkのうち
       			   マウントポイント内で到達できるものを相対パスに変換
    -o SSHOPT=オプション   sshのオプションを自由に指定

★FUSE 共通オプション:
    -d   -o debug          デバッグモードで起動(-fも自動的にON)
    -f                     フォアグラウンドで動作
    -s                     マルチスレッド動作をしない

    -o allow_other         マウントしたユーザ以外のユーザにもアクセス許可
    -o allow_root          ローカルのスーパーユーザにもアクセスを
       			   許可する
    -o nonempty            マウントポイントディレクトリが空でなく
       			   てもマウントを許可する
    -o default_permissions カーネルによるファイル属性チェックを行なう
    -o fsname=名前         ファイルシステムの名前
    -o large_read          large read リクエストを使用する (Linux2.4のみ)
    -o max_read=N          readリクエストの最大値

    -o hard_remove         openされているファイルも直ちにunlinkする
    -o use_ino             ファイルシステムが返すinodeを使用する
    -o readdir_ino         readdirでd_inoを埋めるように努める
    -o direct_io           ダイレクトI/Oを使用する
    -o kernel_cache        open()のときにファイルキャッシュをクリアしな
       			   い。FUSEでマウントしたクライアント以外の場所
			   でのファイル変更がないことが保証できる場合のみ
			   用いること
    -o umask=M             ファイルのumask値を8進数Mに
    -o uid=N               ファイル所有者のuidをNに
    -o gid=N               ファイル所有者のgidをNに
    -o entry_timeout=T     ファイル名キャッシュのタイムアウトを
       			   T秒に(既定値1.0秒)
    -o negative_timeout=T  消去されたファイル名キャッシュのタイムアウト
       			   をT秒に(既定値0秒)
    -o attr_timeout=T      ファイル属性キャッシュのタイムアウトをT秒
       			   に(既定値1.0秒)
----------------------------------------------------------------------

---[註 ろ]------------------------------------------------------------
FreeBSD版 fusefs-sshfs ではtruncateがうまくいかないようだ。
----------------------------------------------------------------------

実際にsshfsを利用してマウントした様子を以下に示す。

【ファイルサーバ側(FreeBSD)】
----------------------------------------------------------------------ここから
lead% id
      ~~
uid=2020(yuuji) gid=20(staff) groups=20(staff), 0(wheel), 5(operator)
lead% ls -lFa /usr/home
      ~~~~~~~~~~~~~~~~~
total 1
drwxr-xr-x   4 root   wheel   512 Aug  8 11:51 ./
drwxr-xr-x  19 root   wheel   512 Jul 31 19:04 ../
drwxr-xr-x   2 taro   staff   512 Aug  8 11:51 taro/
drwxr-xr-x  11 yuuji  staff  1024 Aug  8 11:15 yuuji/
----------------------------------------------------------------------ここまで

(ユーザはyuuji、/usr/home にはtaroがあるが書き込めるのはyuuji/以下だけ)

【クライアント側(Linux)】
----------------------------------------------------------------------ここから
cx% id
    ~~
uid=2020(yuuji) gid=2020(yuuji) 所属グループ=2020(yuuji)

cx% mkdir leadhome
    ~~~~~~~~~~~~~~
cx% sshfs -o idmap=user lead:/usr/home leadhome
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cx% df -tfuse -h
    ~~~~~~~~~~~~
ファイルシステム    サイズ 使用中 空き 使用% マウント場所
sshfs#lead:/usr/home  7.5T     0  7.4T   0% /home/yuuji/leadhome

cx{yuuji}% ls -lFa leadhome
合計 13
drwxr-xr-x    1 root     root          512 Aug  8  2006 ./
drwxr-xr-x   15 yuuji    yuuji        1024 Aug  7 12:40 ../
drwxr-xr-x    1 2021     games         512 Aug  8  2006 taro/
drwxr-xr-x    1 yuuji    games        1024 Aug  8  2006 yuuji/
----------------------------------------------------------------------ここまで

taroディレクトリには書き込みできない。

----------------------------------------------------------------------ここから
cx% touch leadhome/taro/hoge
    ~~~~~~~~~~~~~~~~~~~~~~~~
touch: `leadhome/taro/hoge' を読み込み中です: 許可がありません
----------------------------------------------------------------------ここまで

自分のディレクトリには書ける。
----------------------------------------------------------------------ここから
cx% touch leadhome/yuuji/hoge
    ~~~~~~~~~~~~~~~~~~~~~~~~~
cx% ls -lF leadhome/yuuji/hoge
    ~~~~~~~~~~~~~~~~~~~~~~~~~~
-rw-r--r--    1 yuuji    games     0 Aug  7 12:59 leadhome/yuuji/hoge
----------------------------------------------------------------------ここまで

ローカルのシェルで操作できるので、ファイル名補完もばっちり。
----------------------------------------------------------------------ここから
cx% ls -lF leadhome/yuuji/m[TAB]
       ↓
cx% ls -lF leadhome/yuuji/make[Return]
drwxr-xr-x    1 yuuji    yuuji         512 May  1  2005 amd/
-rw-r--r--    1 yuuji    yuuji    27565669 Apr 27  2005 ports.tar.gz
----------------------------------------------------------------------ここまで

リモートディレクトリのファイルも普通のコマンドで読み書き可能。
----------------------------------------------------------------------ここから
cx% gtar vztf leadhome/yuuji/make/ports.tar.gz|head -2
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drwxrwxr-x archive/archive   0 2005-04-27 10:08:30 ports/
drwxrwxr-x archive/archive   0 2005-04-18 10:11:11 ports/Mk/

cx% cp ~/.zshrc leadhome/yuuji && echo Success
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sucess
----------------------------------------------------------------------ここまで



●FUSE-CURLFTPFS

FUSEを利用したユーザスペースファイルシステムとしてもうひとつ、CurlFtpFSを紹
介しておこう。Linuxの場合は

http://curlftpfs.sourceforge.net/
http://sourceforge.net/project/showfiles.php?group_id=160565


より最新版(執筆当時 curlftpfs-0.8)を入手し【註 は】、以下のようにコン
パイル&インストールを行なう【註 に】。

---[註 は]------------------------------------------------------------
現時点で Fedora Core 5 にもパッケージがないのでソースビルドする必要があ
るだろう。
----------------------------------------------------------------------

	% tar zxpf curlftpfs-0.8.tar.gz
	% ./configure && make
	% sudo make install

---[註 に]------------------------------------------------------------
コンパイルにはcurlの開発用パッケージ(バージョン7.15.2以降)が必要となる。
それより古いcurlが入っている場合は、たとえば以下のようにして新しいcurlに
入れ換える。

  # curl ftp.vinelinux.org:/pub/Vine/apt/unstable/SRPMS.plus/curl-7.15.3-0vl1.src.rpm
  # apt-get build-dep curl-7.15.3-0vl1.src.rpm
  # apt-get -s source curl-7.15.3-0vl1.src.rpm
  # apt-get install ~/rpm/RPMS/i386/curl-*
----------------------------------------------------------------------


FreeBSD の場合は /usr/ports/sshfs-curlftpfs で make install clean すれば
/usr/local/bin に curlftpfs コマンドがインストールされる。

●CurlFtpFSによる Anonymous FTP マウント

curlftpfsコマンドも、sshfsと同様ftp先のURLとマウントポイントを指定するこ
とでユーザ権限でのマウントができる。実際にRINGプロジェクトの Anonymous
FTP サーバのディレクトリをマウントした例を示そう。

----------------------------------------------------------------------ここから
cx% mkdir ~/ring
    ~~~~~~~~~~~~
cx% curlftpfs ftp://ftp.ring.gr.jp/pub ~/ring
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cx% ls -F ~/ring
    ~~~~~~~~~~~~
CPAN@  NetBSD/   X/        doc/    graphics/  linux/  misc/  pc/   text/
GNU/   OpenBSD/  XFree86/  elisp/  lang/      mac/    net/   pgp/

----------------------------------------------------------------------ここまで

●/etc/fuse.conf

FUSEでマウントするディレクトリに対するポリシの指定は /etc/fuse.conf に書
いておく。現状では以下の2つのオプションを書ける。

	mount_max = NNN
		一般ユーザがFUSEでマウントできる最大個数。デフォルトは1000。
	user_allow_other
		スーパーユーザ以外が allow_other または allow_root オプ
		ションを指定できるようにする。

●その他のFUSEベースファイルシステム

http://fuse.sourceforge.net/wiki/index.php/FileSystems
にはFUSEベースで利用できる様々なファイルシステムが書いてある。いくつか面
白そうなものをピックアップしてみた。

Fusedav
	WebDAVをファイルシステムに。

GmailFS
	Gmail(www.gmail.com)が誇る2GBという容量【註 む】を利用して、それ
	をファイルシステムにしてしまおうというもの。今回紹介しようと思っ
	たが、安定度に欠ける面があるのとPythonライブラリがBSDで動かない
	問題があったので紹介を見送った。話題性は豊かなのだが。

---[註 む]------------------------------------------------------------
今も少しずつ増えている。2006/8/15 現在2700MBを超えているようだ。
----------------------------------------------------------------------

CvsFS
	CVSのリポジトリをファイルシステムのように覗けるファイルシステム。

FunionFS: An UnionFS over FUSE
	
	FUSEをベースにしたUnionfsの実装。下記のものに比べ
	こちらの実装はインカーネルの
	Unionfsの実装に近いセマンティクスになっている。

unionfs-fuse
	もうひとつのUnionfs実装。昨日も必要最低限に絞り、
	非常にシンプルでコンパクトである。

■
■portalfs
■

4.4BSDで実装されたportalfsは、「ファイルのopen」をportalデーモンを介して
行なわせるものである。portalfs がマウントされたディレクトリ以下のパス名は、
あらかじめ指定したルールによって様々な変換【註 ほ】が行なわれ読み出すこと
ができる擬似的なファイルとして扱われる。これだけでは分かりづらいので例を
示そう。

---[註 ほ]------------------------------------------------------------
ソケットやパイプなど、ファイル記述子を返すものであればなんでもよく、それ
がportafls内の固定的なパス名でopenしたファイル記述子として扱うことがで
きる。
----------------------------------------------------------------------

たとえば、portalfsのデーモン用の変換ルールとして次の行を与える。

	#prefix		type	arg-prefix
	tcp/		tcp	tcp/

これは、マウントポイント直下で tcp/ というprefixで始まるパス名
のものを「tcp」というルールで処理することを指示してデーモンに渡すことを意
味する。このファイルが /etc/portal.conf という名前で保存されているなら

	# mkdir /p
	# mount_portalfs /etc/portal.conf /p	(FreeBSDの場合)
	# mount_portal /etc/portal.conf /p	(NetBSDの場合)

として、/p 以下にマウントする。こうすると、

	/p/tcp/<ホスト>/<ポート番号>

というパス名へのアクセスがその「ホスト」の<ポート番号>(tcp)へのアクセス
に変換される。たとえば、

	# head -1 /p/tcp/mailsv01.softbank.co.jp/25

のようにすると、mailsv01.softbank.co.jp の tcp 25番ポートにアクセスして
得られたSMTPグリーティングメッセージの最初の1行が返って来る。

変換されるオブジェクト一覧を【表 と】に示した。

【表 と】
---------+----------------------+----------------------------------------
ルール	 |/p 以下のパスの記法	|意味
---------+----------------------+----------------------------------------
fs	 |fs/PATH		|PATHに単純変換(chroot環境内に特定の
	 |			| ファイルアクセスを提供するために
	 |			| 利用できる)
	 |			| 
tcp      |tcp/ADDR/PORT 	|ADDRのPORT(tcp)へ接続して得られる
	 |			|出力を返す(FreeBSDのみ)
tcplisten|tcplisten/ADDR/PORT 	|ADDRのPORT(tcp)でlistenする(FreeBSDのみ)
pipe	 |pipe/CMD		|CMDというコマンドのパイプを作成する 
	 |			| (FreeBSDのみ)
	 |			| 
rfilter	 |rfilter/PATH		|PATHをあらかじめportal.confに登録した
	 |			| フィルタコマンドに通したものを返す
	 |			| (NetBSDのみ)
wfilter	 |wfilter/PATH		|あらかじめportal.confに登録した
	 |			| フィルタコマンドに通したものを
	 |			| PATHに書き込む(NetBSDのみ)
	 |			| 
---------+----------------------+----------------------------------------

このうちpipe(FreeBSD)とrfilter(NetBSD)を使うと内容が動的に変化するファイ
ルを作ることができる。Part4では、これを利用して独自の機能を持つファイルシ
ステムを作っていってみよう。


yuuji@example.org
Fingerprint16 = FF F9 FF CC E0 FE 5C F7 19 97 28 24 EC 5D 39 BA
HIROSE Yuuji - ASTROLOGY / BIKE / EPO / GUEST BOOK / YaTeX [Tweet]