Linuxサーバを運用するにあたって、通常であれば余程のことが無い限り「/etc」フォルダ配下にあるような設定ファイルは変更しないものだ。
もし何かしら変更された場合、事前に変更を行うとわかっているものなのか、手違いでの変更なのか、それとも悪意のある第三者による変更なのか…どちらにしても、変更があると同時に認識をしたいと思うものだろう。そんな設定ファイルやフォルダの変更(ファイルが作成・削除されたり、ファイルの編集が行われたり)を監視するのが、『inotify』だ。

『inotify』は、Linux カーネル 2.6.13で組み込まれたファイルやディレクトリに対する監視機能。そのため、それ以前のカーネルを利用している場合は利用することが出来ないので注意。
…まぁ、2015年にもなってそんなに古いカーネルを使っているとは思えないので、基本的に大丈夫だと思うけど。

『inotify』自体はカーネルに最初から組み込まれているのだが、機能として利用するには専用の管理ツールである『inotify-tools』が必要になる。
まずは、このツールのインストールから始める事にしよう。

1.『inotify-tools』のインストール

まずは、管理ツールである『inotify-tools』をインストールする。

Debian/Ubuntuの場合

apt-get install inotify-tools

RHEL系の場合

yum install inotify-tools

これで、『inotify』の管理コマンドである「inotifywait」「inotifywatch」を実行できるようになった。

  • inotifywait … ファイル・ディレクトリを監視し、変動があった場合は通知を行う
  • inotifywatch … ファイル・ディレクトリへの変動を統計情報として収集・出力する

syslogへの出力など、ファイルの監視機能としては「inotifywait」コマンドの方が使うことが多いだろう。

2.inotifywaitコマンドの実行

それでは実際にinotifywaitコマンドを実行し、ファイルの動作を監視してみよう。
まず、inotifywaitコマンドの実行形式から。

inotifywait [オプション] ファイル(フォルダ)1 ファイル(フォルダ)2 ......

よく使われるオプションは以下。

  • -m(--monitor) … モニタリングモード(イベントが複数あっても監視を続行する)で実行する
  • -d(--deamon) … デーモン化して起動する。-oオプションとセットにする必要がある。
  • -r(--recursive) … フォルダを指定した場合、再帰的にその配下も監視する
  • --fromfile <監視対象一覧ファイル> … 指定したファイル名に記載されているPATHを監視する
  • -o(--outfile) ログ出力ファイル … 監視内容を外部ファイルにログとして出力する
  • --format … メッセージのフォーマットを定義する
  • --timefmt … メッセージの時刻に関するフォーマットを定義する

なお、-sオプションはinotifywaitでエラーが出た場合にsyslogに出力するというもので、syslogに出力内容を渡してくれる、というものではない。
syslogにログを出力させる場合は、loggerコマンドと組み合わせるなどの必要がある。

syslog形式で無くて良いならば、-dオプションでデーモン化して起動すると良いだろう。

検出出来るイベント内容については、以下のようになっている。

イベント名 イベント発生タイミング
ACCESS readなどでアクセスされた
MODIFY writeなどでファイル内容が変更された
ATTRIB アクセス件やタイムスタンプなどのメタデータが変更された
CLOSE_WRITE 書き込みモードでオープンされた後クローズされた
CLOSE_NOWRITE 読み込みモードオープンされた後クローズされた
CLOSE オープンモードに関わらずクローズされた
OPEN オープンされた
MOVED_TO 対象ディレクトリ内へ移動された
MOVED_FROM 対象ディレクトリ内から移動された
MOVE 対象自身が移動された
CREATE 対象ディレクトリ内で新規作成された
DELETE 対象ディレクトリ内で削除された
DELTELE_SELF 対象自身が削除された
UNMOUNT 対象を含むファイルシステムがアンマウントされた

それでは、まずはオプション無しで実際にファイルを監視してみよう。
オプション無しの場合、標準出力でファイルへの変更内容が表示されるため、片側のターミナルでコマンドを実行しておく。

inotifywait ./inotify_test

この状態で、echoコマンドを使用して「inotify_test」ファイルに追記書き込みを行ってみる。

上のgifを見てもらえればわかるかと思うが、ファイルへの変更と同時に右側のターミナルで表示していた「inotify_test」への監視にイベントが出力されている。
ただし、オプション無しでコマンドを実行した場合、イベント通知が行われるのは一度だけとなっている(そのため、最初のOPENしか記述されていない)。

複数のイベントを通知する場合は、「-m(--monitor)」オプションと組み合わせる必要がある。

出力のフォーマットを変更するには、「--format」オプションを利用するとよい。
「--format」で日時を含める場合、「--timefmt」オプションを利用して日時のフォーマットを指定する。日時フォーマットの形式については、strftimeに準拠する。

「--format」で設定できるフォーマット形式は以下。

  • %w … 監視対象である、イベントの発生したファイル名
  • %f … 監視対象である、イベントの発生したディレクトリ名
  • %e … イベント内容を表示する。(カンマ区切り有り)
  • %Xe … イベント内容を表示する。(カンマ区切り無し)
  • %T … イベント発生日時を出力する

出力フォーマットを指定して実行した例がこちら。
以下の例では、「/home/test」ディレクトリ配下のイベントを再帰的に全てモニタリングで検出し、かつフォーマットを[イベント発生日時 対象ディレクトリ(ファイル) イベント内容]としている。

test@ubuntu-server:~$ inotifywait -rm --format '%T %w%f %e' --timefmt '%F %T' /home/test/
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
2015-04-14 19:21:14 /home/test/test1234 CREATE,ISDIR
2015-04-14 19:21:14 /home/test/test1234 OPEN,ISDIR
2015-04-14 19:21:14 /home/test/test1234 CLOSE_NOWRITE,CLOSE,ISDIR
2015-04-14 19:21:28 /home/test/inotify_test1 MODIFY
2015-04-14 19:21:28 /home/test/inotify_test1 OPEN
2015-04-14 19:21:28 /home/test/inotify_test1 MODIFY
2015-04-14 19:21:28 /home/test/inotify_test1 CLOSE_WRITE,CLOSE

デーモン化して実行する場合は、以下のようにコマンドを実行する。
(フォーマット等の部分は好みで変更してもらいたい)

inotifywait -rd -o ログ出力先ファイル -s --format '%T %w%f %e' --timefmt '%F %T' 監視対象ディクトリ

なお、デーモンとして実行する場合、必ず-oオプション(アウトプット先)が必要になるので注意。その際、アウトプット先のファイルとして監視対象のディレクトリ配下を指定した場合、「Failed to open output file アウトプット先のファイル名」というエラーが返ってくる。

3.inotifywatchコマンドの実行

次に、「inotifywatch」コマンドを実行してみる。
以下のように、「-r」オプション付きで実行することで、対象のディレクトリ配下で発生した内容をサマリとして出力してくれる…のだが、集計結果が出力されるのがCtrl + Cでキャンセルした後となっている。

test@ubuntu-server:~$ inotifywatch -r /home/test
Establishing watches...
Finished establishing watches, now collecting statistics.
^Ctotal  access  modify  close_write  close_nowrite  open  filename
32     7       5       3            7              10    /home/test/

正直、あまり使い道がないような気がする…
inotifywaitのおまけのようなものと考えていいだろう。