LoginSignup
1
0

More than 1 year has passed since last update.

filemonでファイルの変更イベントを監視する

Posted at

NetBSD Advent Calendar 2021 6日目の記事です。
今日はファイルの変更を監視するfilemonの紹介をしようと思います。

filemon

filemonはファイルの変更イベントを監視するための疑似デバイスで、NetBSD-6以降でサポートされています。

マニュアルを参照すると、ファイルに対する以下のイベントを監視できます。

イベントタイプ 意味
C ディレクトリの変更(chdir(2))
D ファイルの削除(unlink(2))
E ファイルの実行(exec(3))
F プロセスのフォーク(fork(2), vfork(2))
L シンボリックリンクの操作(link(2), symlink(2))
M ファイル名の変更(rename(2))
R 読み込み専用でのファイルのオープン(open(2))
W 読み書きするファイルのオープン(open(2))
X プロセスの終了(exit(3))
V filemonのバージョン

filemonを試してみる

さて、このfilemonですが、マニュアルだけだとイマイチ使い方が分かりません。そこで、実際に filemon を動かして振る舞いを見てみます。

filemonの準備

filemon は疑似デバイスとして提供されており、カーネルコンフィグに以下を追記することで利用可能となります。

pseudo-device filemon

が、NetBSD-amd64の GENERIC カーネルには pseudo-device filemon は組み込まれておらず、カーネルモジュールとしてビルドしておく必要があります。

# cd /usr/src/sys/modules/filemon/
# make
...
# file filemon.kmod
filemon.kmod: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

あとは filemon.kmod をロードして準備完了です。 /dev/filemon は最初から存在しているようです(なので mknod は不要)。

filemonによるファイルイベントの監視

/dev/filemon を使う準備はできたので、実際にファイルイベントを監視してみます。filemonには /dev/filemon を用いたファイルイベント監視のサンプルコードがあるのですが、実はこのコードはそのままではビルドできない+ mkstemp("/tmp/filemon.XXXXXXX")SEGV してしまいます…(文字列リテラル "/tmp/filemon.XXXXXXX" は実行ファイルのread onlyな領域に配置されるため、 char temp_path[] = "/tmp/filemonXXXXXXXX"; みたいな感じでスタックorヒープ領域に文字列データを置く必要があるっぽい…)。

とはいえ、大まかな処理の流れは把握できるので、このコードを参考にサンプルコードを作成してみました。

さっそくサンプルを動かして振る舞いを見てみましょう。コードの挙動としては、 /dev/filemonopen() したのち、 fork() した子プロセスの側で ioctl(filemon_fd, FILEMON_SET_PID, &pid); でファイルイベントを監視したいプロセスのID(この場合は子プロセスID)を指定し、シェルを立ち上げるという流れになります。

発生したファイルイベントは、あらかじめ temp_fd = mkstemp(temp_path); で作成しておいたファイルに逐次記録される形になります。

# gcc -Wall -Werror -g -o filemon_sample filemon_sample.c
# ./filemon_sample
pid= 484
filemon= /tmp/filemondnp1bePE
# 

ここで cal コマンドを実行してみます。シェル上は普通にコマンドの実行結果が表示されます。

# cal
   December 2021
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

ファイルイベントを記録している /tmp/filemondnp1bePE を見ると、以下が出力されています。

F 893 752
E 752 /usr/bin/cal
R 752 /usr/lib/libterminfo.so.1
R 752 /usr/lib/libc.so.12
R 752 /etc/localtime
R 752 /usr/share/zoneinfo/posixrules
X 752 0

プロセスが fork() ( F )したのち、 cal が実行( E )され、 /usr/lib/libc.so.12 等が読み込み専用でオープンされ( R )、最後にプロセスが終了( X )したことが見て取れます。

この機能を応用すれば、特定のファイルが更新された場合の処理を(ポーリング等を行わない)小さな負荷で実現できそうです。

まとめ

filemonの機能を簡単なサンプルを踏まえて紹介してみました。
GENERIC カーネルに含まれていないのと、マニュアルのサンプルを少し修正する必要があるのが難点ですが、ファイルイベントの監視は応用範囲が広そうです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0