1 .\" Copyright (C) 2013, Heinrich Schuchardt <xypron.glpk@gmx.de>
2 .\" and Copyright (C) 2014, Michael Kerrisk <mtk.manpages@gmail.com>
4 .\" %%%LICENSE_START(VERBATIM)
5 .\" Permission is granted to make and distribute verbatim copies of this
6 .\" manual provided the copyright notice and this permission notice are
7 .\" preserved on all copies.
9 .\" Permission is granted to copy and distribute modified versions of
10 .\" this manual under the conditions for verbatim copying, provided that
11 .\" the entire resulting derived work is distributed under the terms of
12 .\" a permission notice identical to this one.
14 .\" Since the Linux kernel and libraries are constantly changing, this
15 .\" manual page may be incorrect or out-of-date. The author(s) assume.
16 .\" no responsibility for errors or omissions, or for damages resulting.
17 .\" from the use of the information contained herein. The author(s) may.
18 .\" not have taken the same level of care in the production of this.
19 .\" manual, which is licensed free of charge, as they might when working.
22 .\" Formatted or processed versions of this manual, if unaccompanied by
23 .\" the source, must acknowledge the copyright and authors of this work.
25 .\"*******************************************************************
27 .\" This file was generated with po4a. Translate the source file.
29 .\"*******************************************************************
30 .TH FANOTIFY 7 2014\-12\-31 Linux "Linux Programmer's Manual"
32 fanotify \- ファイルシステムイベントを監視する
34 fanotify API はファイルシステムイベントの通知と横取り機能 (interception) を提供する。
35 ユースケースとしては、ウイルススキャンや階層型ストレージの管理などがある。 現在のところ、限定的なイベントのみがサポートされている。 特に、作成
36 (create)、削除 (delete)、移動 (move) イベントがサポートされていない (これらのイベントを通知する API の詳細については
37 \fBinotify\fP(7) を参照)。
39 \fBinotify\fP(7) API と比較して追加されている機能としては、 マウントされたファイルシステムの全オブジェクトを監視する機能、
40 アクセス許可の判定を行う機能、 他のアプリケーションによるアクセスの前にファイルを読み出したり変更したりする機能がある。
42 この API では以下のシステムコールを使用する: \fBfanotify_init\fP(2), \fBfanotify_mark\fP(2),
43 \fBread\fP(2), \fBwrite\fP(2), \fBclose\fP(2)。
44 .SS "fanotify_init(), fanotify_mark() と通知グループ"
45 \fBfanotify_init\fP(2) システムコールは fanotify 通知グループを作成、初期化し、
46 この通知グループを参照するファイルディスクリプターを返す。
48 fanotify 通知グループはカーネル内部のオブジェクトで、 イベントが作成されるファイル、 ディレクトリ、 マウントポイントのリストを保持する。
50 fanotify 通知グループの各エントリーには 2 つのビットマスクがある。 \fImark\fP マスクと \fIignore\fP マスクである。 mark
51 マスクはどのファイル操作についてイベントを作成するかを定義する。 ignore マスクはどの操作についてイベントを作成しないかを定義する。 これらの 2
52 種類のマスクがあることで、 マウントポイントやディレクトリに対してイベントの受信を mark しておきつつ、
53 同時にそのマウントポイントやディレクトリ配下の特定のオブジェクトに対するイベントを無視する、 といったことができる。
55 \fBfanotify_mark\fP(2) システムコールは、ファイル、ディレクトリ、マウントを通知グループに追加し、 どのイベントを報告 (もしくは無視)
56 するかを指定する。 また、このようなエントリーの削除、変更も行う。
58 ignore マスクの考えられる使用方法はファイルキャッシュに対してである。
59 ファイルキャッシュに関して興味のあるイベントは、ファイルの変更とファイルのクローズである。 それゆえ、
60 キャッシュされたディレクトリやマウントポイントは、 これらのイベントを受信するようにマークされる。
61 ファイルが変更されたという最初のイベントを受信した後は、 対応するキャッシュエントリーは無効化される。 そのファイルがクローズされるまでは、
62 このファイルに対する変更イベントは興味のない情報となる。 したがって、 変更イベントを ignore マスクに追加することができる。
63 クローズイベントを受信すると、 変更イベントを ignore イベントから削除し、 ファイルキャッシュエントリーを更新することができる。
65 fanotify 通知グループのエントリーは、 ファイルやディレクトリでは inode 番号経由で参照され、 マウントではマウント ID
66 経由で参照される。 ファイルやディレクトリの名前が変更されたり、移動されたりした場合も、 関連するエントリーはそのまま残る。
67 ファイルやディレクトリが削除されたり、マウントがアンマウントされたりした場合には、 対応するエントリーは削除される。
69 通知グループにより監視されているファイルシステムオブジェクトでイベントが発生すると、 fanotify システムはイベントを生成し、
70 そのイベントはキューにまとめられる。 これらのイベントは、 \fBfanotify_init\fP(2) が返した fanotify
71 ファイルディスクリプターから (\fBread\fP(2) などを使って) 読み出すことができる。
73 2 種類のイベントが生成される。 \fInotification\fP (通知) イベントと \fIpermission\fP (アクセス許可) イベントである。
74 通知イベントは単なる情報通知であり、 イベントで渡されたファイルディスクリプターをクローズする場合 (下記参照) を除き、
75 受信したアプリケーションでアクションを取る必要はない。 アクセス許可イベントは、
76 受信したアプリケーションがファイルアクセスの許可を承認するかを判定する必要がある。 この場合、
77 受信者はアクセスが許可されたか否かを決定する応答を書き込まなければならない。
79 イベントは、 読み出されると、 fanotify グループのイベントキューから削除される。 読み出されたアクセス許可イベントは、 fanotify
80 ファイルディスクリプターにアクセス許可の判定が書き込まれるか、 fanotify ファイルディスクリプターがクローズされるまで、 fanotify
82 .SS "fanotify イベントの読み出し"
83 \fBfanotify_init\fP(2) が返したファイルディスクリプターに対する \fBread\fP(2) を呼び出しは、
84 (\fBfanotify_init\fP(2) の呼び出しでフラグ \fBFAN_NONBLOCK\fP を指定しなかった場合)
85 ファイルイベントが起こるか、呼び出しがシグナルによって割り込まれる (\fBsignal\fP(7) 参照) まで停止する。
87 \fBread\fP(2) が成功すると、読み出しバッファーには以下の構造体が 1 つ以上格納される。
91 struct fanotify_event_metadata {
103 性能上の理由から、複数のイベントを一度の \fBread\fP(2) で取得できるように大きめのバッファーサイズ (例えば 4096 バイト)
106 \fBread\fP(2) の返り値はバッファーに格納されたバイト数である。 エラーの場合は \-1 が返される (ただし、バグも参照)。
108 \fIfanotify_event_metadata\fP 構造体のフィールドは以下のとおりである。
111 これは、 このイベントのデータ長であり、バッファー内の次のイベントへのオフセットである。 現在の実装では、 \fIevent_len\fP の値は常に
112 \fBFAN_EVENT_METADATA_LEN\fP である。 しかしながら、 API は将来可変長の構造体を返すことができるように設計されている。
115 このフィールドには構造体のバージョン番号が入る。 実行時に返された構造体がコンパイル時の構造体と一致しているかを検査するには、 この値を
116 \fBFANOTIFY_METADATA_VERSION\fP を比較すること。 一致しない場合、 アプリケーションはその fanotify
117 ファイルディスクリプターを使用するのを諦めるべきである。
123 この構造体の長さである。 このフィールドは、 イベント種別単位のオプションヘッダーの実装を扱うために導入された。
124 現在の実装ではこのようなオプションヘッダーは存在しない。
127 イベントを示すビットマスクである (下記参照)
130 これはアクセスされたオブジェクトに対するオープンされたファイルディスクリプターである。 または、キューのオーバーフローが発生した場合には
131 \fBFAN_NOFD\fP が入る。 ファイルディスクリプターは監視対象のファイルやディレクトリの内容にアクセスするのに使用できる。
132 読み出したアプリケーションは責任を持ってこのファイルディスクリプターをクローズしなければならない。
134 \fBfanotify_init\fP(2) を呼び出す際、
135 呼び出し元はこのファイルディスクリプターに対応するオープンファイル記述にセットされた様々なファイル状態フラグを (\fIevent_f_flags\fP
136 引き数を使って) 指定することができる。 さらに、 (カーネル内部の) \fBFMODE_NONOTIFY\fP
137 ファイル状態フラグがオープンファイル記述にセットされる。 このフラグは fanotify イベントの生成を抑制する。 したがって、 fanotify
138 イベントの受信者がこのファイルディスクリプターを使って通知されたファイルやディレクトリにアクセスした際に、 これ以上イベントが作成されなくなる。
141 これはイベントが発生する原因となったプロセス ID である。 fanotify イベントを監視しているプログラムは、 この PID を
142 \fBgetpid\fP(2) が返す PID と比較することで、 イベントが監視しているプログラム自身から発生したかどうか、
143 別のプロセスによるファイルアクセスにより発生したか、を判定できる。
145 \fImask\fP のビットマスクは、1 つのファイルシステムオブジェクトに対してどのイベントが発生したかを示す。
146 監視対象のファイルシステムオブジェクトに複数のイベントが発生した場合は、 このマスクに複数のビットがセットされることがある。 特に、
147 同じファイルシステムオブジェクトに対する連続するイベントが同じプロセスから生成された場合には、 一つのイベントにまとめられることがある。 例外として、
148 2 つのアクセス許可イベントが一つのキューエントリーにまとめられることは決してない。
150 \fImask\fP でセットされている可能性のあるビットは以下のとおりである。
153 ファイルやディレクトリがアクセスされた (読み出しが行われた) (ただし、「バグ」の節も参照)。
161 \fBFAN_CLOSE_WRITE\fP
162 書き込み用 (\fBO_WRONLY\fP か \fBO_RDWR\fP) にオープンされたファイルがクローズされた。
164 \fBFAN_CLOSE_NOWRITE\fP
165 読み出し用 (\fBO_RDONLY\fP) にオープンされたファイルがクローズされた。
168 イベントキューが 16384 エントリーの上限を超過した。 この上限は \fBfanotify_init\fP(2) 呼び出し時に
169 \fBFAN_UNLIMITED_QUEUE\fP フラグを指定することで上書きできる。
171 \fBFAN_ACCESS_PERM\fP
172 アプリケーションが例えば \fBread\fP(2) や \fBreaddir\fP(2) などを使ってファイルやディレクトリを読み出そうとした。
173 このイベントを読み出したプログラムは、 そのファイルシステムオブジェクトへのアクセス許可を承認するかを判定し (下記で説明するとおり)
177 アプリケーションがファイルやディレクトリをオープンしようとした。 このイベントを読み出したプログラムは、
178 そのファイルシステムオブジェクトのオープンを承認するかを判定し (下記で説明するとおり) 応答を書き込まなければならない。
180 クローズイベントを確認するために以下のビットマスクを使うことができる。
183 ファイルがクローズされた。 以下の同義語である。
185 FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE
187 fanotify ファイルディスクリプターからの \fBread\fP(2) が返した fanotify
188 イベントメタデータを含むバッファーに対して繰り返しを行うため、 以下のマクロが提供されている。
190 \fBFAN_EVENT_OK(meta, len)\fP
191 このマクロは、 バッファー \fImeta\fP の残りの長さ \fIlen\fP を、 メタデータ構造体の長さとバッファーの最初のメタデータ構造体の
192 \fIevent_len\fP フィールドと比較して検査する。
194 \fBFAN_EVENT_NEXT(meta, len)\fP
195 このマクロは、 \fImeta\fP が指すメタデータ構造体の \fIevent_len\fP フィールドで示された長さを使って、 \fImeta\fP
196 の次のメタデータ構造体のアドレスを計算する。 \fIlen\fP はバッファーに現在残っているメタデータのバイト数である。 このマクロは \fImeta\fP
197 の次のメタデータ構造体へのポインターを返し、 スキップされたメタデータ構造体のバイト数だけ \fIlen\fP を減算する (つまり、 \fIlen\fP から
198 \fImeta\->event_len\fP を引き算する)。
202 \fBFAN_EVENT_METADATA_LEN\fP
204 このマクロは \fIfanotify_event_metadata\fP 構造体の (バイト単位の) サイズを返す。
205 返される値はイベントメタデータの最小値である (現在のところ、これが唯一のサイズである)。
206 .SS "fanotify ファイルディスクリプターのイベントを監視する"
207 fanotify イベントが発生すると、 \fBepoll\fP(7), \fBpoll\fP(2), \fBselect\fP(2) に fanotify
208 ファイルディスクリプターが渡された場合には、そのファイルディスクリプターが読み出し可能であると通知される。
210 アクセス許可イベントでは、 アプリケーションは以下の形式の構造体を fanotify ファイルディスクリプターに \fBwrite\fP(2)
215 struct fanotify_response {
222 この構造体のフィールドは以下のとおりである。
225 このフィールドは \fIfanotify_event_metadata\fP 構造体で返されたファイルディスクリプターである。
228 このフィールドはアクセス許可を承認するかどうかを示す。 値は、このファイル操作を許可する \fBFAN_ALLOW\fP か、 このファイル操作を拒否する
229 \fBFAN_DENY\fP のいずれかでなければならない。
231 アクセスを拒否した場合、 アクセスを要求したアプリケーションは \fBEPERM\fP エラーを受け取ることになる。
232 .SS "fanotify ファイルディスクリプターのクローズ"
234 fanotify 通知グループを参照するすべてのファイルディスクリプターがクローズされると、 fanotify グループは解放され、
235 カーネルが再利用できるようにそのリソースは解放される。 \fBclose\fP(2) の際に、 処理中であったアクセス許可イベントには許可が設定される。
236 .SS /proc/[pid]/fdinfo
237 ファイル \fI/proc/[pid]/fdinfo/[fd]\fP には、 プロセス \fIpid\fP のファイルディスクリプター \fIfd\fP の
238 fanotify マークに関する情報が格納される。 詳細はカーネルのソースファイル
239 \fIDocumentation/filesystems/proc.txt\fP を参照。
241 通常の \fBread\fP(2) のエラーに加え、 fanotify ファイルディスクリプターから読み出しを行った際に以下のエラーが発生することがある。
244 バッファーがイベントを保持するには小さすぎる。
247 オープンしたファイル数のプロセス毎の上限に達した。 \fBgetrlimit\fP(2) の \fBRLIMIT_NOFILE\fP の説明を参照。
250 オープンされたファイル数のシステム全体の上限に達した。 \fBproc\fP(5) の \fI/proc/sys/fs/file\-max\fP を参照。
253 \fBfanotify_init\fP(2) の呼び出し時に \fBO_RDWR\fP か \fBO_WRONLY\fP が \fIevent_f_flags\fP
254 引き数に指定されており、 現在実行中の監視対象のファイルに対してイベントが発生した際に、 このエラーが \fBread\fP(2) から返される。
256 通常の \fBwrite\fP(2) のエラーに加え、 fanotify ファイルディスクリプターに書き込みを行った際に以下のエラーが発生することがある。
259 fanotify アクセス許可がカーネルの設定で有効になっていない。 応答構造体の \fIresponse\fP 値が無効である。
262 応答構造体のファイルディスクリプター \fIfd\fP が無効である。 このエラーはアクセス許可イベントに対する応答がすでに書き込まれている際に発生する。
264 fanotify API は Linux カーネルのバージョン 2.6.36 で導入され、 バージョン 2.6.37 で有効にされた。 fdinfo
265 のサポートはバージョン 3.8 で追加された。
267 fanotify API は Linux 独自のものである。
269 fanotify API が利用できるのは、 カーネルが \fBCONFIG_FANOTIFY\fP 設定オプションを有効にして作成されている場合だけである。
270 また、 fanotify アクセス許可の処理が利用できるのは \fBCONFIG_FANOTIFY_ACCESS_PERMISSIONS\fP
271 設定オプションが有効になっている場合だけである。
273 fanotify が報告するのはユーザー空間プログラムがファイルシステム API 経由で行ったイベントだけである。 その結果、 fanotify
274 ではネットワークファイルシステム上で発生したリモートイベントは捕捉できない。
276 inotify API は \fBmmap\fP(2), \fBmsync\fP(2), \fBmunmap\fP(2)
277 により起こったファイルのアクセスと変更を報告しない。
279 ディレクトリのイベントは、ディレクトリ自身がオープン、読み出し、クローズされた場合にしか作成されない。
280 マークされたディレクトリでの子要素の追加、削除、変更では、監視対象のディレクトリ自身へのイベントは作成されない。
282 fanotify のディレクトリの監視は再帰的ではない。 ディレクトリ内のサブディレクトリを監視するには、
283 追加で監視用のマークを作成しなければならない。 (ただし、 fanotify API
284 では、サブディレクトリが監視対象としてマークされているディレクトリに作成された際に検出する手段は提供されていない点に注意すること。)
285 マウントの監視を使うことで、 ディレクトリツリー全体を監視することができる。
287 ベントキューはオーバーフローすることがある。 この場合、 イベントは失われる。
289 Linux 3.17 時点では、 以下のバグが存在する。
291 Linux では、ファイルシステムオブジェクトは複数のパスでアクセス可能である。 例えば、 ファイルシステムの一部は \fBmount\fP(8) の
292 \fI\-\-bind\fP オプションを使って再マウントされることがある。 マークされたマウントの監視者は、
293 同じマウントを使ったファイルオブジェクトについてのみイベント通知を受ける。 それ以外のイベントは通知されない。
295 \fBfallocate\fP(2) の呼び出しでは fanotify イベントが作成されない。
297 .\" FIXME . A patch was proposed.
298 イベントが生成された際に、 そのファイルのファイルディスクリプターを渡す前に、 イベントを受信するプロセスのユーザー ID
299 がそのファイルに対する読み出し/書き込み許可があるかの確認は行われない。 非特権ユーザーによって実行されたプログラムに \fBCAP_SYS_ADMIN\fP
300 ケーパビリティーがセットされている場合には、 このことはセキュリティーリスクとなる。
302 \fBread\fP(2) の呼び出しが fanotify キューから複数のイベントを処理している際に、 エラーが発生した場合、
303 返り値はエラーが発生する前までにユーザー空間バッファーに正常にコピーされたイベントの合計長となる。 返り値は \-1 にならず、 \fIerrno\fP
304 もセットされない。 したがって、 読み出しを行うアプリケーションではエラーを検出する方法はない。
306 以下のプログラムは fanotify API の使用法を示すものである。 コマンドライン引き数で渡されたマウントポイントを監視し、 種別が
307 \fBFAN_PERM_OPEN\fP と \fBFAN_CLOSE_WRITE\fP のイベントを待つ。 アクセス許可イベントが発生には、
308 \fBFAN_ALLOW\fP 応答を返す。
310 以下の出力例はファイル \fI/home/user/temp/notes\fP を編集した際に記録されたものである。 ファイルをオープンする前に
311 \fBFAN_OPEN_PERM\fP イベントが発生している。 ファイルをクローズした後に \fBFAN_CLOSE_WRITE\fP イベントが発生している。
312 エンターキーをユーザーが押すと、 このプログラムの実行は終了する。
316 # ./fanotify_example /home
317 Press enter key to terminate.
318 Listening for events.
319 FAN_OPEN_PERM: File /home/user/temp/notes
320 FAN_CLOSE_WRITE: File /home/user/temp/notes
322 Listening for events stopped.
327 #define _GNU_SOURCE /* O_LARGEFILE の定義を得るために必要 */
334 #include <sys/fanotify.h>
337 /* ファイルディスクリプター 'fd' から読み出しできる全 fanotify イベントを読み出す */
340 handle_events(int fd)
342 const struct fanotify_event_metadata *metadata;
343 struct fanotify_event_metadata buf[200];
347 char procfd_path[PATH_MAX];
348 struct fanotify_response response;
350 /* fanotify ファイルディスクリプターからイベントが読み出せる間はループする */
356 len = read(fd, (void *) &buf, sizeof(buf));
357 if (len == \-1 && errno != EAGAIN) {
362 /* 読み出せるデータの最後に達しているかチェックする */
367 /* バッファーの最初のイベントを参照する */
371 /* バッファー内の全イベントを処理する */
373 while (FAN_EVENT_OK(metadata, len)) {
375 /* 実行時とコンパイル時の構造体が一致するか確認する */
377 if (metadata\->vers != FANOTIFY_METADATA_VERSION) {
379 "Mismatch of fanotify metadata version.\en");
383 /* metadata\->fd には、キューのオーバーフローを示す FAN_NOFD か、
384 ファイルディスクリプター (負でない整数) のいずれかが入っている。
385 ここではキューのオーバーフローは無視している。 */
387 if (metadata\->fd >= 0) {
389 /* オープン許可イベントを処理する */
391 if (metadata\->mask & FAN_OPEN_PERM) {
392 printf("FAN_OPEN_PERM: ");
396 response.fd = metadata\->fd;
397 response.response = FAN_ALLOW;
399 sizeof(struct fanotify_response));
402 /* 書き込み可能ファイルのクローズイベントを処理する */
404 if (metadata\->mask & FAN_CLOSE_WRITE)
405 printf("FAN_CLOSE_WRITE: ");
407 /* アクセスされたファイルのパス名を取得し表示する */
409 snprintf(procfd_path, sizeof(procfd_path),
410 "/proc/self/fd/%d", metadata\->fd);
411 path_len = readlink(procfd_path, path,
413 if (path_len == \-1) {
418 path[path_len] = '\e0';
419 printf("File %s\en", path);
421 /* イベントのファイルディスクリプターをクローズする */
423 close(metadata\->fd);
428 metadata = FAN_EVENT_NEXT(metadata, len);
434 main(int argc, char *argv[])
439 struct pollfd fds[2];
441 /* マウントポイントが指定されたか確認する */
444 fprintf(stderr, "Usage: %s MOUNT\en", argv[0]);
448 printf("Press enter key to terminate.\en");
450 /* fanotify API にアクセスするためのファイルディスクリプターを作成する */
452 fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
453 O_RDONLY | O_LARGEFILE);
455 perror("fanotify_init");
459 /* 指定されたマウントに対して以下を監視するようにマークを付ける:
460 \- ファイルのオープン前のアクセス許可イベント
461 \- 書き込み可能なファイルディスクリプターのクローズ後の
464 if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
465 FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
467 perror("fanotify_mark");
477 fds[0].fd = STDIN_FILENO;
478 fds[0].events = POLLIN;
483 fds[1].events = POLLIN;
487 printf("Listening for events.\en");
490 poll_num = poll(fds, nfds, \-1);
491 if (poll_num == \-1) {
492 if (errno == EINTR) /* シグナルに割り込まれた場合 */
493 continue; /* poll() を再開する */
495 perror("poll"); /* 予期しないエラー */
500 if (fds[0].revents & POLLIN) {
502 /* コンソールからの入力がある場合: 空の標準入力であれば終了 */
504 while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\en')
509 if (fds[1].revents & POLLIN) {
511 /* fanotify イベントがある場合 */
518 printf("Listening for events stopped.\en");
524 \fBfanotify_init\fP(2), \fBfanotify_mark\fP(2), \fBinotify\fP(7)
526 この man ページは Linux \fIman\-pages\fP プロジェクトのリリース 3.77 の一部
527 である。プロジェクトの説明とバグ報告に関する情報は
528 http://www.kernel.org/doc/man\-pages/ に書かれている。