Provided by: manpages-ja_0.5.0.0.20221215+dfsg-1_all bug

名前

       inotify - ファイルシステムイベントを監視する

説明

       inotify  API  はファイルシステムイベントを監視するための機構を提供する。  inotify は個々の
       ファイルやディレクトリを監視するのに使える。 ディレクトリを監視する場合、inotify  はディレ
       クトリ自身と ディレクトリ内のファイルのイベントを返す。

       この API では以下のシステムコールが使用される。

       *  inotify_init(2)  は inotify インスタンスを作成し、inotify インスタンスを参照する ファイ
          ルディスクリプターを返す。 より新しい inotify_init1(2)   も  inotify_init(2)   と同様だ
          が、 こちらにはいくつかの追加の機能を利用するための flags 引数がある。

       *  inotify_add_watch(2)   は  inotify  インスタンスに関連づけられた「監視対象 (watch) リス
          ト」を操作する。 監視対象リストの各アイテム ("watch") は、 ファイルまたはディレクトリの
          パス名と、  そのパス名で参照されるファイルに対して カーネルが監視する複数のイベントの集
          合を指定する。 inotify_add_watch(2)  は新しい監視アイテムの作成や既存の監視対象の変更が
          できる。  各監視対象は一意の「監視対象ディスクリプター」を持つ。 これは監視対象を作成し
          たときに inotify_add_watch(2)  から返される整数である。

       *  監視しているファイルやディレクトリでイベントが起こると、   それらのイベントはアプリケー
          ションから  inotify ファイルディスクリプターから read(2) を使って構造化データとして読み
          出すことができる (下記参照)。

       *  inotify_rm_watch(2)  は inotify の監視対象リストからアイテムを削除する。

       *  inotify インスタンスを指している 全てのファイルディスクリプターが  (close(2)  を使って)
          クローズされた場合、  その下層にあるオブジェクトとそのリソースは、 カーネルで再利用する
          ために解放される。 関連が切られた監視対象は自動的に解放される。

       注意深くプログラミングすることで、 アプリケーションは inotify を使ってファイルシステムオブ
       ジェクトの集合の状態を効率的に監視しキャッシュしておくことができる。  しかしながら、ロバス
       トなアプリケーションでは、監視ロジックのバグや以下に説明があるような種類の競合条件により
       ファイルシステムの状態とキャッシュが一致しない状態になることがあるという事実も考慮に入れて
       おくべきである。  おそらく何らかの一貫性のチェックを行い、不一致が検出された場合にはキャッ
       シュを再構築するのが懸命だろう。

   inotify ファイルディスクリプターからのイベントの読み出し
       どのようなイベントが起こっていたかを知るには、 アプリケーションで inotify ファイルディスク
       リプターを   read(2)    すればよい。   これまでに何もイベントが起こっていない場合、   停止
       (blocking)  モードのファイルディスクリプターであれば、 少なくとも 1 つのイベントが起こるま
       で read(2)   は停止する  (シグナルにより割り込まれなかった場合。  シグナルによる割り込みが
       あった場合、呼び出しはエラー EINTR で失敗する。 signal(7)  参照)。

       read(2)  が成功すると、以下の構造体を 1 つ以上含むバッファーが返される:

           struct inotify_event {
               int      wd;       /* 監視対象ディスクリプター */
               uint32_t mask;     /* イベントを示すマスク */
               uint32_t cookie;   /* 関連するイベント群を関連づける
                                     一意なクッキー (rename(2) 用) */
               uint32_t len;      /* 'name' フィールドのサイズ */
               char     name[];   /* ヌルで終端された任意の名前 */
           };

       wd はイベント発生の監視対象を指定する。 これは、前もって行われた inotify_add_watch(2) 呼び
       出しで返された監視対象ディスクリプターのうちの 1 つである。

       mask には発生したイベント (下記参照) を記述するためのビットが含まれる。

       cookie    は関連するイベントを関連づけるための一意な整数である。    現在のところ、この値は
       rename イベントに対してのみ使われており、 結果のペアである IN_MOVED_FROMIN_MOVED_TO イ
       ベントを アプリケーションで関連づけることができる。 他のイベント種別の場合には、 cookie は
       0 に設定する。

       name フィールドは監視しているディレクトリ内のファイルに対して イベントが返される場合のため
       にだけ存在する。  監視するディレクトリ内のファイル名を表す。  このファイル名はヌルで終端さ
       れ、 その後の読み込みで適切なアドレス境界に調整するために、 さらにヌルバイト ('\0') が含ま
       れる場合もある。

       len フィールドはヌルバイトを含む name の全てのバイト数を表す。 よって、 inotify_event 構造
       体のサイズは sizeof(struct inotify_event)+len である。

       read(2)   に渡されたバッファーが小さすぎて次のイベントに関する情報を返せ  ない場合の動作は
       カーネルのバージョンにより異なる。 2.6.21 より前のカー ネルでは、 read(2)  は  0  を返す。
       2.6.21 以降のカーネルでは、 read(2) はエラー EINVAL で失敗する。 バッファーサイズとして

           sizeof(struct inotify_event) + NAME_MAX + 1

       を指定すれば、少なくとも 1 イベントで読み出しを行うには十分である。

   inotify イベント
       inotify_add_watch(2)   の mask 引数と、inotify ファイル構造体を read(2) したときに返される
       inotify_event 構造体の mask フィールドは、ともに inotify イベントを識別するための ビットマ
       スクである。  以下のビットが  inotify_add_watch(2)   を呼ぶときの  mask に指定可能であり、
       read(2)  で返される mask フィールドで返される:

           IN_ACCESS (+)
                  (read(2), execve(2) などで) ファイルがアクセスされた。

           IN_ATTRIB (*)
                  メタデータが変更された。 メタデータとは、例えば、アクセス許可  (chmod(2))、タイ
                  ムスタンプ  (utimensat(2) など)、拡張属性 (setxattr(2))、 リンクカウント (Linux
                  2.6.25  以降;  link(2)  のリンク先や  unlink(2)   など)、ユーザー/グループ   ID
                  (chown(2) など) などである。

           IN_CLOSE_WRITE (+)
                  書き込みのためにオープンされたファイルがクローズされた。

           IN_CLOSE_NOWRITE (*)
                  書き込み用としてはオープンされていないファイルやディレクトリがクローズされた。

           IN_CREATE (+)
                  監視対象ディレクトリ内でファイルやディレクトリが作成された  (open(2)   O_CREAT,
                  mkdir(2), link(2), symlink(2), UNIX ドメインソケットに対する bind(2) など)。

           IN_DELETE (+)
                  監視対象ディレクトリ内でファイルやディレクトリが削除された。

           IN_DELETE_SELF
                  監視対象のファイルやディレクトリ自身が削除あれた。  (このイベントはオブジェクト
                  が別のファイルシステムに移動された場合にも発生する。 mv(1) は実際には別のファイ
                  ルシステムにファイルをコピーした後、元のファイルシステムからそのファイルを削除
                  するからである。) また、 結果的に監視ディスクリプターに対して IN_IGNORED イベン
                  トも生成される。

           IN_MODIFY (+)
                  ファイルが変更された (write(2), truncate(2) など)。

           IN_MOVE_SELF
                  監視対象のディレクトリまたはファイル自身が移動された。

           IN_MOVED_FROM (+)
                  ファイル名の変更を行った際に変更前のファイル名が含まれるディレクトリに対して生
                  成される。

           IN_MOVED_TO (+)
                  ファイル名の変更を行った際に新しいファイル名が含まれるディレクトリに対して生成
                  される。

           IN_OPEN (*)
                  ファイルやディレクトリがオープンされた。

       Inotify monitoring is inode-based: when monitoring a file (but  not  when  monitoring  the
       directory  containing  a  file), an event can be generated for activity on any link to the
       file (in the same or a different directory).

       ディレクトリを監視する場合:

       *  上記でアスタリスク (*) が付いたイベントは、  ディレクトリ自身とディレクトリ内のオブジェ
          クトのどちらに対しても発生する。

       *  上記でプラス記号  (+) が付いたイベントは、 ディレクトリ内のオブジェクトに対してのみ発生
          する (ディレクトリ自身に対しては発生しない)。

       Note: when monitoring a directory, events are not  generated  for  the  files  inside  the
       directory  when  the events are performed via a pathname (i.e., a link)  that lies outside
       the monitored directory.

       監視対象のディレクトリ内のオブジェクトに対してイベントが発生した場合、 inotify_event  構造
       体で返される name フィールドは、ディレクトリ内のファイル名を表す。

       IN_ALL_EVENTS       マクロは上記のイベント全てのマスクとして定義される。      このマクロは
       inotify_add_watch(2) を呼び出すときの mask 引数として使える。

       以下の 2 つの便利なマクロが定義されている。

           IN_MOVE
                  IN_MOVED_FROM | IN_MOVED_TO と等価。

           IN_CLOSE
                  IN_CLOSE_WRITE | IN_CLOSE_NOWRITE と等価。

       その他にも以下のビットを inotify_add_watch(2)  を呼ぶときの mask に指定できる:

           IN_DONT_FOLLOW (Linux 2.6.15 以降)
                  pathname がシンボリックリンクである場合に辿らない。 (Linux 2.6.15 以降)

           IN_EXCL_UNLINK (Linux 2.6.36 以降)
                  デフォルトでは、あるディレクトリの子ファイルに関するイベントを監視 (watch) した
                  際、ディレクトリからその子ファイルが削除   (unlink)  された場合であってもその子
                  ファイルに対してイベントが生成される。このことは、アプリケーションによってはあ
                  まり興味のないイベントが大量に発生することにつながる (例えば、/tmp を監視してい
                  る場合、たくさんのアプリケーションが、すぐにその名前が削除される一時ファイルを
                  そのディレクトリに作成する)。 IN_EXCL_UNLINK を指定するとこのデフォルトの動作を
                  変更でき、監視対象のディレクトリから子ファイルが削除された後に子ファイルに関す
                  るイベントが生成されなくなる。

           IN_MASK_ADD
                  If  a  watch instance already exists for the filesystem object corresponding to
                  pathname, add (OR) the events in mask to the watch mask (instead  of  replacing
                  the mask); the error EINVAL results if IN_MASK_CREATE is also specified.

           IN_ONESHOT
                  pathname  に対応するファイルシステムオブジェクトを  1  イベントについてだけ監視
                  し、 イベントが発生したら監視対象リストから削除する。

           IN_ONLYDIR (Linux 2.6.15 以降)
                  Watch pathname only if it is a directory; the error ENOTDIR results if pathname
                  is  not  a directory.  Using this flag provides an application with a race-free
                  way of ensuring that the monitored object is a directory.

           IN_MASK_CREATE (Linux 4.18 以降)
                  Watch pathname only if it does not already have a watch associated with it; the
                  error EEXIST results if pathname is already being watched.

                  Using this flag provides an application with a way of ensuring that new watches
                  do not modify existing ones.  This is useful because multiple paths  may  refer
                  to the same inode, and multiple calls to inotify_add_watch(2) without this flag
                  may clobber existing watch masks.

       以下のビットが read(2)  で返される mask フィールドに設定される:

           IN_IGNORED
                  監視対象が (inotify_rm_watch(2) により) 明示的に 削除された。もしくは (ファイル
                  の削除、またはファイル  システムのアンマウントにより)  自動的に削除された。「バ
                  グ」も参照のこと。

           IN_ISDIR
                  このイベントの対象がディレクトリである。

           IN_Q_OVERFLOW
                  イベントキューが溢れた (このイベントの場合、wd は -1 である)。

           IN_UNMOUNT
                  監視対象オブジェクトを含むファイルシステムがアンマウントされた。さらに、この監
                  視対象ディスクリプターに対して IN_IGNORED イベントが生成される。

   
       アプリケーションがディレクトリ  dir とファイル dir/myfile のすべてのイベントを監視している
       とする。 以下に、これらの 2 つのオブジェクトに対して生成されるイベントの例を示す。

           fd = open("dir/myfile", O_RDWR);
                  dirdir/myfile の両方に対して IN_OPEN イベントが生成される。

           read(fd, buf, count);
                  dirdir/myfile の両方に対して IN_ACCESS イベントが生成される

           write(fd, buf, count);
                  dirdir/myfile の両方に対して IN_MODIFY イベントが生成される

           fchmod(fd, mode);
                  dirdir/myfile の両方に対して IN_ATTRIB イベントが生成される

           close(fd);
                  dirdir/myfile の両方に対して IN_CLOSE_WRITE イベントが生成される

       アプリケーションがディレクトリ dir1dir2、およびファイル dir1/myfile を監視しているとす
       る。 以下に生成されるイベントの例を示す。

           link("dir1/myfile", "dir2/new");
                  myfile に対して IN_ATTRIB イベントが生成され、 dir2 に対して IN_CREATE イベント
                  が生成される。

           rename("dir1/myfile", "dir2/myfile");
                  dir1 に対してイベント IN_MOVED_FROM が、 dir2 に対してイベント IN_MOVED_TO が、
                  myfile     に対してイベント    IN_MOVE_SELF    が生成される。この際    イベント
                  IN_MOVED_FROMIN_MOVED_TO は同じ cookie 値を持つ。

       dir1/xxdir2/yy は同じファイルを参照するリンクで (他のリンクはないものとする)、  アプリ
       ケーションは  dir1, dir2, dir1/xx, dir2/yy を監視しているものとする。 以下に示す順序で下記
       の呼び出しを実行すると、以下のイベントが生成される。

           unlink("dir2/yy");
                  xx に対して IN_ATTRIB イベントが生成され (リンク数が変化したため)、 dir2 に対し
                  て IN_DELETE イベントが生成される。

           unlink("dir1/xx");
                  xx  に対してイベント IN_ATTRIB, IN_DELETE_SELF, IN_IGNORED が生成され、 dir1 に
                  対して IN_DELETE イベントが生成される。

       アプリケーションがディレクトリ dir と (空の) ディレクトリ dir/subdir  を監視しているものと
       する。 以下に生成されるイベントの例を示す。

           mkdir("dir/new", mode);
                  dir に対して IN_CREATE | IN_ISDIR イベントが生成される。

           rmdir("dir/subdir");
                  subdir  に対してイベント IN_DELETE_SELFIN_IGNORED が生成され、 dir に対して
                  IN_DELETE | IN_ISDIR イベントが生成される。

   /proc インターフェース
       以下のインターフェースは、inotify で消費される  カーネルメモリーの総量を制限するのに使用で
       きる:

       /proc/sys/fs/inotify/max_queued_events
              このファイルの値は、アプリケーションが    inotify_init(2)    を呼び出すときに使用さ
              れ、対応する inotify インスタンスについて  キューに入れられるイベントの数の上限を設
              定する。  この制限を超えたイベントは破棄されるが、 IN_Q_OVERFLOW イベントが常に生成
              される。

       /proc/sys/fs/inotify/max_user_instances
              1 つの実ユーザー ID に対して生成できる inotify インスタンスの数の上限を指定する。

       /proc/sys/fs/inotify/max_user_watches
              作成可能な監視対象の数の実 UID 単位の上限を指定する。

バージョン

       inotify は 2.6.13 の Linux カーネルに組込まれた。 これに必要なライブラリのインターフェース
       は、 glibc のバージョン 2.4 に追加された (IN_DONT_FOLLOW, IN_MASK_ADD, IN_ONLYDIR は glibc
       バージョン 2.5 で追加された)。

準拠

       inotify API は Linux 独自のものである。

注意

       inotify ファイルディスクリプターは select(2), poll(2), epoll(7)  を使って監視できる。 イベ
       ントがある場合、ファイルディスクリプターは読み込み可能と通知する。

       Linux  2.6.25 以降では、シグナル駆動 (signal-driven) I/O の通知が inotify ファイルディスク
       リプターについて利用可能である。 fcntl(2)  に書かれている (O_ASYNC フラグを設定するための)
       F_SETFL, F_SETOWN, F_SETSIG の議論を参照のこと。 シグナルハンドラーに渡される siginfo_t 構
       造体は、以下のフィールドが設定される (siginfo_tsigaction(2)  で説明されている)。 si_fd
       には  inotify  ファイルディスクリプター番号が、 si_signo にはシグナル番号が、 si_code には
       POLL_IN が、 si_band には POLLIN が設定される。

       inotify ファイルディスクリプターに対して 連続して生成される出力 inotify イベントが同一の場
       合 (wd, mask, cookie, name が等しい場合)、 前のイベントがまだ読み込まれていなければ、 連続
       するイベントが 1 つのイベントにまとめられる (ただし「バグ」の節も参照のこと)。  これにより
       イベントキューに必要なカーネルメモリー量が減るが、  これはまたアプリケーションがファイルイ
       ベント数を信頼性を持って数えるのに inotify を使用できないということでもある。

       inotify ファイルディスクリプターの読み込みで返されるイベントは、  順序付けられたキューにな
       る。  従って、たとえば、あるディレクトリの名前を別の名前に変更した場合、  inotify ファイル
       ディスクリプターについての正しい順番で イベントが生成されることが保証される。

       The set of watch descriptors that is being monitored via an inotify file descriptor can be
       viewed  via  the entry for the inotify file descriptor in the process's /proc/[pid]/fdinfo
       directory.  See proc(5)  for further details.  The FIONREAD ioctl(2)  returns  the  number
       of bytes available to read from an inotify file descriptor.

   制限と警告
       inotify API では、inotify イベントが発生するきっかけとなったユーザーやプロセスに関する情報
       は提供されない。とりわけ、inotify 経由でイベントを監視しているプロセスが、自分自身がきっか
       けとなったイベントと他のプロセスがきっかけとなったイベントを区別する簡単な手段はない。

       inotify  は、ファイルシステム API 経由でユーザー空間プログラムがきっかけとなったイベントだ
       けを報告する。 結果として、 inotify はネットワークファイルシステムで発生したリモートのイベ
       ントを捉えることはできない (このようなイベントを捉えるにはアプリケーションはファイルシステ
       ムをポーリングする必要がある)。 さらに、 /proc, /sys, /dev/pts  といったいくつかの疑似ファ
       イルシステムは inotify で監視することができない。

       inotify API は mmap(2), msync(2), munmap(2) により起こったファイルのアクセスと変更を報告し
       ない。

       inotify API では影響が受けるファイルをファイル名で特定する。  しかしながら、アプリケーショ
       ンが inotify イベントを処理する時点では、 そのファイル名がすでに削除されたり変更されたりし
       ている可能性がある。

       inotify API では監視対象ディスクリプターを通してイベントが区別される。 (必要であれば) 監視
       対象ディスクリプターとパス名のマッピングをキャッシュしておくのはアプリケーションの役目であ
       る。  ディレクトリの名前変更の場合、キャッシュしている複数のパス名に影響がある点に注意する
       こと。

       inotify  によるディレクトリの監視は再帰的に行われない: あるディレクトリ以下の サブディレク
       トリを監視する場合、 監視対象を追加で作成しなければならない。 大きなディレクトリツリーの場
       合には、この作業にかなり時間がかかることがある。

       ディレクトリツリー全体を監視していて、    そのツリー内に新しいサブディレクトリが作成される
       か、 既存のディレクトリが名前が変更されそのツリー内に移動した場合、 新しいサブディレクトリ
       に対する watch を作成するまでに、 新しいファイル (やサブディレクトリ) がそのサブディレクト
       リ内にすでに作成されている場合がある点に注意すること。 したがって、watch  を追加した直後に
       サブディレクトリの内容をスキャンしたいと思う場合もあるだろう (必要ならそのサブディレクトリ
       内のサブディレクトリに対する watch も再帰的に追加することもあるだろう)。

       イベントキューはオーバーフローする場合があることに注意すること。  この場合、イベントは失な
       われる。 ロバスト性が求められるアプリケーションでは、 イベントが失なわれる可能性も含めて適
       切に処理を行うべきである。  例えば、アプリケーション内のキャッシュの一部分または全てを再構
       築する必要があるかもしれない。  (単純だが、おそらくコストがかかる方法は、 inotify ファイル
       ディスクリプターをクローズし、 キャッシュを空にし、  新しい  inotify  ファイルディスクリプ
       ターを作成し、  監視しているオブジェクトの監視対象ディスクリプターとキャッシュエントリーの
       再作成を行う方法である。)

       If a filesystem is mounted on top of a monitored directory, no event is generated, and  no
       events are generated for objects immediately under the new mount point.  If the filesystem
       is subsequently unmounted, events will subsequently be generated for the directory and the
       objects it contains.

   rename() イベントの取り扱い
       上述の通り、  rename(2) により生成される IN_MOVED_FROMIN_MOVED_TO イベントの組は、共有
       される cookie 値によって対応を取ることができる。  しかし、対応を取る場合にはいくつか難しい
       点がある。

       これらの 2 つのイベントは、 inotify ファイルディスクリプターから読み出しを行った場合に、通
       常はイベントストリーム内で連続している。    しかしながら、連続していることは保証されていな
       い。  複数のプロセスが監視対象オブジェクトでイベントを発生させた場合、 (めったに起こらない
       ことだが) イベント IN_MOVED_FROMIN_MOVED_TO の間に任意の数の他のイベントがはさまる可能
       性がある。    さらに、対となるイベントがアトミックにキューに挿入されることも保証されていな
       い。 IN_MOVED_FROM が現れたが IN_MOVED_TO は現れていないという短い期間がありえるということ
       だ。

       したがって、  rename(2) により生成された IN_MOVED_FROMIN_MOVED_TO のイベントの組の対応
       を取るのは本質的に難しいことである (監視対象のディレクトリの外へオブジェクトの rename が行
       われた場合には IN_MOVED_TO イベントは存在しさえしないことを忘れてはならない)。 (イベントは
       常に連続しているとの仮定を置くといった) 発見的な方法を使うと、ほとんどの場合でイベントの組
       をうまく見つけることができるが、 いくつかの場合に見逃すことが避けられず、 アプリケーション
       が IN_MOVED_FROMIN_MOVED_TO  イベントが無関係だとみなしてしまう可能性がある。  結果的
       に、監視対象ディスクリプターが破棄され再作成された場合、これらの監視対象ディスクリプター
       は、処理待ちイベントの監視対象ディスクリプターと一貫性のないものになってしまう    (inotify
       ファイルディスクリプターの再作成とキャッシュの再構成はこの状況に対処するのに有用な方法なの
       だが)。

       また、アプリケーションは、 IN_MOVED_FROM イベントが今行った  read(2)  の呼び出しで返された
       バッファーのちょうど一番最後のイベントで、 IN_MOVED_TO イベントは次の read(2) を行わないと
       取得できない可能性も考慮に入れる必要がある。 2 つ目の read(2) は (短い) タイムアウトで行う
       べきである。 これは、 IN_MOVED_FROM-IN_MOVED_TO のイベントペアのキューへの挿入はアトミック
       ではなく、 また IN_MOVED_TO イベントが全く発生しない可能性もあるという事実を考慮に入れてお
       く必要があるからである。

バグ

       Before  Linux  3.19,  fallocate(2)   did not create any inotify events.  Since Linux 3.19,
       calls to fallocate(2)  generate IN_MODIFY events.

       2.6.16 以前のカーネルでは IN_ONESHOT mask フラグが働かない。

       元々は設計/実装時の意図通り、 イベントが一つ発生し watch が削除された際に IN_ONESHOT  フラ
       グでは IN_IGNORED イベントが発生しなかった。 しかし、 別の変更での意図していなかった影響に
       より、 Linux 2.6.36 以降では、 この場合に IN_IGNORED イベントが生成される。

       カーネル  2.6.25  より前では、  連続する同一のイベントを一つにまとめることを意図したコード
       (古い方のイベントがまだ読み込まれていない場合に、  最新の 2 つのイベントを一つにまとめられ
       る可能性がある) が、  最新のイベントが「最も古い」読み込まれていないイベントとまとめられる
       か をチェックするようになっていた。

       inotify_rm_watch(2) の呼び出しにより監視対象ディスクリプターが削除された場合 (なお、監視対
       象ファイルの削除や監視対象ファイルが含まれるファイルシステムのアンマウントによっても監視対
       象ディスクリプターは削除される)、 この監視対象ディスクリプター関連の処理待ちの未読み出しイ
       ベントは、 読み出し可能なままとなる。 監視対象ディスクリプターは  inotify_add_watch(2)  に
       よって後で割り当てられるため、  カーネルは利用可能な監視対象ディスクリプターの範囲 (0 から
       INT_MAX)  から昇順にサイクリックに割り当てを行う。未使用の監視対象ディスクリプターを割り当
       てる際、 その監視対象ディスクリプター番号に inotify キューで処理待ちの未読み出しイベントが
       あるかの確認は行われない。 したがって、監視対象ディスクリプターが再割り当てされた際に、 そ
       の監視対象ディスクリプターの一つ前の使用時に発生した処理待ちの未読み出しイベントが存在する
       ということが起こりうる。  その結果、アプリケーションはこれらのイベントを読み出す可能性があ
       り、  これらのイベントが新しく再利用された監視対象ディスクリプターに関連付けられたファイル
       に属するものかを解釈する必要が出て来る。  実際のところ、このバグを踏む可能性は極めて低い。
       それは、このバグを踏むためには、アプリケーションが  INT_MAX 個の監視対象ディスクリプターが
       一周させて、 キューに未読み出しイベントが残っている監視対象ディスクリプターを解放し、 その
       監視対象ディスクリプターを再利用する必要があるからである。  この理由と、実世界のアプリケー
       ションで発生したというバグ報告がないことから、 Linux 3.15 時点では、この計算上は起こりうる
       バグを取り除くためのカーネルの変更は行われていない。

       以下のプログラムは  inotify  API の使用例を示したものである。 コマンドライン引数で渡された
       ディレクトリに印を付け、 タイプが IN_OPEN, IN_CLOSE_NOWRITE IN_CLOSE_WRITE  のイベントを待
       つ。

       以下は、  ファイル /home/user/temp/foo を編集し、 ディレクトリ /tmp の一覧表示を行った場合
       の出力である。 対象のファイルとディレクトリがオープンされる前に、イベント IN_OPEN が発生し
       ている。 対象ファイルがクローズされた後にイベント IN_CLOSE_WRITE が発生している。 対象ディ
       レクトリがクローズされた後にイベント IN_CLOSE_NOWRITE  が発生している。  ユーザーが  ENTER
       キーを押すると、プログラムの実行は終了する。

   出力例
           $ ./a.out /tmp /home/user/temp
           Press enter key to terminate.
           Listening for events.
           IN_OPEN: /home/user/temp/foo [file]
           IN_CLOSE_WRITE: /home/user/temp/foo [file]
           IN_OPEN: /tmp/ [directory]
           IN_CLOSE_NOWRITE: /tmp/ [directory]

           Listening for events stopped.

   プログラムソース

       #include <errno.h>
       #include <poll.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/inotify.h>
       #include <unistd.h>
       #include <string.h>

       /* Read all available inotify events from the file descriptor 'fd'.
          wd is the table of watch descriptors for the directories in argv.
          argc is the length of wd and argv.
          argv is the list of watched directories.
          Entry 0 of wd and argv is unused. */

       static void
       handle_events(int fd, int *wd, int argc, char* argv[])
       {
           /* Some systems cannot read integer variables if they are not
              properly aligned. On other systems, incorrect alignment may
              decrease performance. Hence, the buffer used for reading from
              the inotify file descriptor should have the same alignment as
              struct inotify_event. */

           char buf[4096]
               __attribute__ ((aligned(__alignof__(struct inotify_event))));
           const struct inotify_event *event;
           ssize_t len;

           /* Loop while events can be read from inotify file descriptor. */

           for (;;) {

               /* Read some events. */

               len = read(fd, buf, sizeof(buf));
               if (len == -1 && errno != EAGAIN) {
                   perror("read");
                   exit(EXIT_FAILURE);
               }

               /* If the nonblocking read() found no events to read, then
                  it returns -1 with errno set to EAGAIN. In that case,
                  we exit the loop. */

               if (len <= 0)
                   break;

               /* バッファー内の全イベントを処理する */

               for (char *ptr = buf; ptr < buf + len;
                       ptr += sizeof(struct inotify_event) + event->len) {

                   event = (const struct inotify_event *) ptr;

                   /* Print event type */

                   if (event->mask & IN_OPEN)
                       printf("IN_OPEN: ");
                   if (event->mask & IN_CLOSE_NOWRITE)
                       printf("IN_CLOSE_NOWRITE: ");
                   if (event->mask & IN_CLOSE_WRITE)
                       printf("IN_CLOSE_WRITE: ");

                   /* Print the name of the watched directory */

                   for (int i = 1; i < argc; ++i) {
                       if (wd[i] == event->wd) {
                           printf("%s/", argv[i]);
                           break;
                       }
                   }

                   /* Print the name of the file */

                   if (event->len)
                       printf("%s", event->name);

                   /* Print type of filesystem object */

                   if (event->mask & IN_ISDIR)
                       printf(" [directory]\n");
                   else
                       printf(" [file]\n");
               }
           }
       }

       int
       main(int argc, char* argv[])
       {
           char buf;
           int fd, i, poll_num;
           int *wd;
           nfds_t nfds;
           struct pollfd fds[2];

           if (argc < 2) {
               printf("Usage: %s PATH [PATH ...]\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           printf("Press ENTER key to terminate.\n");

           /* Create the file descriptor for accessing the inotify API */

           fd = inotify_init1(IN_NONBLOCK);
           if (fd == -1) {
               perror("inotify_init1");
               exit(EXIT_FAILURE);
           }

           /* Allocate memory for watch descriptors */

           wd = calloc(argc, sizeof(int));
           if (wd == NULL) {
               perror("calloc");
               exit(EXIT_FAILURE);
           }

           /* Mark directories for events
              - file was opened
              - file was closed */

           for (i = 1; i < argc; i++) {
               wd[i] = inotify_add_watch(fd, argv[i],
                                         IN_OPEN | IN_CLOSE);
               if (wd[i] == -1) {
                   fprintf(stderr, "Cannot watch '%s': %s\n",
                           argv[i], strerror(errno));
                   exit(EXIT_FAILURE);
               }
           }

           /* ポーリングの準備 */

           nfds = 2;

           /* コンソールの入力 */

           fds[0].fd = STDIN_FILENO;
           fds[0].events = POLLIN;

           /* Inotify input */

           fds[1].fd = fd;
           fds[1].events = POLLIN;

           /* Wait for events and/or terminal input */

           printf("Listening for events.\n");
           while (1) {
               poll_num = poll(fds, nfds, -1);
               if (poll_num == -1) {
                   if (errno == EINTR)
                       continue;
                   perror("poll");
                   exit(EXIT_FAILURE);
               }

               if (poll_num > 0) {

                   if (fds[0].revents & POLLIN) {

                       /* Console input is available. Empty stdin and quit */

                       while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
                           continue;
                       break;
                   }

                   if (fds[1].revents & POLLIN) {

                       /* Inotify events are available */

                       handle_events(fd, wd, argc, argv);
                   }
               }
           }

           printf("Listening for events stopped.\n");

           /* Close inotify file descriptor */

           close(fd);

           free(wd);
           exit(EXIT_SUCCESS);
       }

関連項目

       inotifywait(1),  inotifywatch(1), inotify_add_watch(2), inotify_init(2), inotify_init1(2),
       inotify_rm_watch(2), read(2), stat(2), fanotify(7)

       Linux カーネルソース内の Documentation/filesystems/inotify.txt

この文書について

       この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの
       説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。