「このディレクトリって何のファイルシステム?」とか「マウントオプションは?」を確認するときに、手癖で mount
コマンドを実行してるけど、
$ mount
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=4096k,nr_inodes=118922,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,size=194516k,nr_inodes=819200,mode=755)
...
このコマンドはもう古いらしい。もうすこし正確にいうと、mount(8) の man によれば、「リスト表示機能は後方互換性のために残してる。よりロバストで出力をカスタマイズ可能な findmnt
を利用するのがおススメ。」されていた。そうなんだ…めちゃくちゃ mount 使ってるな。
Listing the mounts
The listing mode is maintained for backward compatibility only.
For more robust and customizable output use findmnt(8), especially in your scripts. Note that control characters in the
mountpoint name are replaced with '?'.
The following command lists all mounted filesystems (of type type):
mount [-l] [-t type]
The option -l adds labels to this listing. See below.
findmnt の特徴
findmnt なら、階層構造で見やすく表示できるし、
$ findmnt
TARGET SOURCE FSTYPE OPTIONS
/ /dev/xvda1 xfs rw,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota
├─/proc proc proc rw,nosuid,nodev,noexec,relatime
│ └─/proc/sys/fs/binfmt_misc systemd-1 autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=12945
├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime,seclabel
│ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/fs/cgroup cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate,memory_recursiveprot
...
指定したファイルやディレクトリの所属するマウントポイントを表示できるし、
$ findmnt --target /tmp/.font-unix/
TARGET SOURCE FSTYPE OPTIONS
/tmp tmpfs tmpfs rw,nosuid,nodev,seclabel,nr_inodes=1048576
出力をリアルなストレージデバイスに絞ることもできる。
$ findmnt --real
TARGET SOURCE FSTYPE OPTIONS
/ /dev/xvda1 xfs rw,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota
もちろん mount コマンドにあった、ファイルシステムによる絞り込みもある。
# findmnt -t tmpfs
TARGET SOURCE FSTYPE OPTIONS
/dev/shm tmpfs tmpfs rw,nosuid,nodev,seclabel
/run tmpfs tmpfs rw,nosuid,nodev,seclabel,size=194516k,nr_inodes=819200,mode=755
├─/run/user/1000 tmpfs tmpfs rw,nosuid,nodev,relatime,seclabel,size=97256k,nr_inodes=24314,mode=700,uid=1000,gid=1000
└─/run/netns tmpfs[/netns] tmpfs rw,nosuid,nodev,seclabel,size=194516k,nr_inodes=819200,mode=755
/tmp tmpfs tmpfs rw,nosuid,nodev,seclabel,nr_inodes=1048576
また出力を json フォーマットにもできる。
$ findmnt -J | jq
{
"filesystems": [
{
"target": "/",
"source": "/dev/xvda1",
"fstype": "xfs",
"options": "rw,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota",
"children": [
{
"target": "/proc",
"source": "proc",
"fstype": "proc",
"options": "rw,nosuid,nodev,noexec,relatime",
"children": [
{
...
そしてなぜか df コマンドっぽい出力を模倣するオプションもある(これは df でいいんじゃないかという気がするが)。
# findmnt --df
SOURCE FSTYPE SIZE USED AVAIL USE% TARGET
devtmpfs devtmpfs 4M 0 4M 0% /dev
tmpfs tmpfs 474.9M 0 474.9M 0% /dev/shm
tmpfs tmpfs 190M 2.8M 187.2M 1% /run
/dev/xvda1 xfs 7.9G 2.3G 5.7G 29% /
tmpfs tmpfs 474.9M 0 474.9M 0% /tmp
tmpfs tmpfs 95M 0 95M 0% /run/user/1000
追加パッケージは不要
「でも追加パッケージが必要なんでしょ…いいよそういうのは… mount で足りてるんだ。」と思ったそこのアナタ(自分含む)。Amazon Linux 2023 の場合、findmnt コマンドは mount コマンドと同じ util-linux-core
パッケージに入っていますので追加のインストールは不要です(アップストリームでも util-linux で開発されているので、たいていのディストリビューションでは同梱されているはずです)。
mount との差
じゃあ今後は findmnt 使おうかな…と思える人は素直で素晴らしい人ですが、自分はなるべく手癖で生きていたいし、なんならデータの加工は grep や awk 使うからべつにいいよと思ってしまう派なので、具体的に出力がどう違うのかを調べてみようかなと。(ついでに最近 bind マウントの確認は findmnt 使わないとダメだよ、と教えてもらったんですが、それがなぜなのか確認しようかなと)
コマンドで出力された情報はどちらも、デバイス名・マウントポイント・ファイルシステム種別・マウントオプションの 4 種類の情報から構成されており、階層化されている事以外は、パッと見では情報量は同じに見えます。
$ mount
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=4096k,nr_inodes=118922,mode=755)
securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
$ findmnt
TARGET SOURCE FSTYPE OPTIONS
/ /dev/xvda1 xfs rw,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota
├─/proc proc proc rw,nosuid,nodev,noexec,relatime
│ └─/proc/sys/fs/binfmt_misc systemd-1 autofs rw,relatime,fd=29,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=12945
├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime,seclabel
│ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/fs/cgroup cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate,memory_recursiveprot
そもそもこれらのマウント情報は、どちらのコマンドも /proc/self/mountinfo
から取得しているようです。
$ strace -ttf -e openat mount
...
00:13:10.322574 openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY|O_CLOEXEC) = 3
<コマンドの出力>
$ strace -ttf -e openat findmnt
...
00:32:46.673625 openat(AT_FDCWD, "/proc/self/mountinfo", O_RDONLY|O_CLOEXEC) = 3
<コマンドの出力>
では /proc/self/mountinfo
を見てみると、出力の元になっている情報が色々あります。
# cat /proc/self/mountinfo | head
19 59 0:18 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
20 59 0:19 / /sys rw,nosuid,nodev,noexec,relatime shared:2 - sysfs sysfs rw,seclabel
21 59 0:5 / /dev rw,nosuid shared:8 - devtmpfs devtmpfs rw,seclabel,size=4096k,nr_inodes=118922,mode=755
22 20 0:6 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:3 - securityfs securityfs rw
23 21 0:20 / /dev/shm rw,nosuid,nodev shared:9 - tmpfs tmpfs rw,seclabel
proc(5) の man に細かい定義があるので詳細は控えますが、以下の情報などが含まれているようです。
- マウント ID
- 親のマウント ID
- デバイスのメジャー番号:マイナー番号
- ファイルシステムから見たときのマウントするパス(バインドマウントなどで、ファイルシステムの一部パスをマウントすることがありえるので)
- マウントポイント
- マウントオプション
- オプションフィールド(sharedとか。よく分からん。)
- ファイルシステム種別
- マウントのソース(デバイス名など)
で findmnt コマンドと mount コマンドの違いとしては、やっぱり会社でアドバイス貰った通り、bind マウント時の挙動が違いそうです。
バックエンドがストレージのファイルシステムを適当にバインドマウントしてみると、
# mkdir -p /mnt/bind
# mount -o bind,ro /root/tmp /mnt/bind
# mount | grep -E "bind|xvda1 "
/dev/xvda1 on / type xfs (rw,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota)
/dev/xvda1 on /mnt/bind type xfs (ro,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota)
# findmnt | grep bind
└─/mnt/bind /dev/xvda1[/root/tmp] xfs ro,noatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,sunit=1024,swidth=1024,noquota
findmnt のほうは、バインドマウントされていることがわかります(/dev/xvda1[/root/tmp]
)が、mount は分かりません。まあこの例であれば、mount コマンドであっても、マウントのソース(/dev/xvda1
)が識別可能なので、同じストレージをマウントしてる->バインドマウントかもと気づけるかもしれませんが、バインド元のファイルパス(/root/tmp
)はわかりません。
しかしもっと困るのは、バックエンドがストレージのファイルシステムじゃない場合(tmpfs とか)です。この場合、マウントのソースが tmpfs になってしまい判別不可能なので、mount コマンドでは、バインドマウントされたことが全くわかりません。
# mount --bind /tmp/work /mnt/bind
# mount | grep bind
tmpfs on /mnt/bind type tmpfs (rw,nosuid,nodev,seclabel,nr_inodes=1048576)
# mount | grep bind
# findmnt | grep bind
└─/mnt/bind tmpfs[/work] tmpfs rw,nosuid,nodev,seclabel,nr_inodes=1048576
ということで、いまはコンテナ全盛時代であり、バインドマウント使いまくってる現状を考えると、日頃から mount じゃなくて findmnt 使っといたほうがいいんじゃないかと思ったという話でした。