Unengineered Weblog

PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND

Linux でファイルがどのファイルシステムにあるのか調べるのは簡単ではなかった

GNU/Linux で df の挙動を見てみよう。引数に(デバイスファイルではなく、普通の)ファイル名を渡すと、それが保存してあるファイルシステムを探してきて、デバイスファイルやマウントポイントなどそのファイルシステムの情報を表示する。

$ df Makefile
Filesystem      1K-blocks       Used  Available Use% Mounted on
/dev/sda1       477514616  106381680  346803108  24%  /

実はこの挙動「ファイルが保存されてあるファイルシステムを返す」をするシステムコールは無い。 df はマウントしているファイルシステムの一覧がある /etc/mtab から探しているのである。

/etc/mtab は次のようなファイルだ

sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
...
/dev/sdb2 / ext4 rw,relatime 0 0
/dev/sda1 /home/ ext4 rw,relatime 0 0
...

マウントしているファイルシステムが一行ごとに書いてある。一行には左からスペース区切りで、ファイルシステムの名前(デバイスファイル)、マウントしてあるディレクトリ(マウントポイント)、あとは細かい情報(いまからの説明に関係がないので端折る)が書いてある。 ちなみに文法は /etc/fstab と同じである。

それでは df がどのようにファイルシステムを探しているのか見てみよう。 GNU のコードを読むのは大変なので、 busybox のコードを読んでみよう。まさにファイルがどのファイルシステムにあるのか調べる関数 find_mount_point という関数がある。これはファイル名を渡すと、それがあるファイルシステムの情報を構造体 のポインタ struct mntent* を返す。この構造体は /etc/mtab の一行をパースしただけである。

github.com

アルゴリズムを端折って説明すると、ファイルの stat から得られるデバイス ID (st_dev) と一致するマウントポイントのディレクトリを /etc/mtab から一行一行読んで探し、そこからファイルシステムを特定している。

なんて泥臭いんだ! 「ファイルが保存されてあるファイルシステムを探す」ためのシステムコールがあると思っていた僕は面食らってしまった。タイトルどおり簡単ではなかった。まあ難しくもないが。

ちなみに macOS では statfs システムコールを使えば一発でわかる。