はじめに
ファイルやディレクトリの変更をリアルタイムで監視したい場面は多い。
例えば、Webサーバーのコンテンツが改ざんされていないか、設定ファイルが変更されたか、などを即座に検知したい場合である。
iwatchは、Linuxカーネルのinotify機能を利用してファイルシステムの変更をリアルタイムで監視し、変更があった際にメール通知やコマンド実行を行うツールである。
今回は、iwatchを使ってファイルシステムの監視を試してみる。
環境
Ubuntu 24.04 LTS
iwatch 0.2.2iwatchとは
iwatchは、Linuxカーネルのinotify機能をラップしたPerlスクリプトで、ファイルやディレクトリの変更をリアルタイムで監視するツール。
できること
- ファイル/ディレクトリの作成、変更、削除などをリアルタイムで検知できる
- 変更を検知した際にメール通知を送信できる
- 変更を検知した際に任意のコマンドを実行できる
- 再帰的なディレクトリ監視に対応している
- 除外パターン(例外)を指定できる
- XMLベースの設定ファイルでデーモンとして動作できる
- HIDS(ホストベース侵入検知システム)や整合性チェッカーとして利用できる
インストール
sudo apt install iwatchログ
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
crack-common gyp libcares2 libgl1-amber-dri libglapi-mesa libjs-async libjs-events libjs-inherits
libjs-is-typedarray libjs-prettify libjs-regenerate libjs-source-map libjs-sprintf-js
libjs-typedarray-to-buffer libllvm17t64 liblttng-ust-common1t64 liblttng-ust-ctl5t64 liblttng-ust1t64
libnotify-bin libqt5x11extras5 libre2-10 libssl-dev libuv1-dev libxcb-damage0 mesa-utils-bin node-abbrev
node-ampproject-remapping node-ansi-regex node-ansi-styles node-aproba node-are-we-there-yet node-arrify
node-async node-async-each node-auto-bind node-babel-plugin-add-module-exports node-babel7-runtime
node-balanced-match node-base64-js node-binary-extensions node-brace-expansion node-busboy
node-camelcase node-caniuse-lite node-chownr node-chrome-trace-event node-ci-info node-cjs-module-lexer
node-cli-boxes node-cli-cursor node-clone node-collection-visit node-color-convert node-color-name
node-colors node-commander node-commondir node-concat-stream node-console-control-strings
node-convert-source-map node-core-js node-core-js-pure node-core-util-is node-data-uri-to-buffer
node-decompress-response node-deep-is node-defaults node-define-property node-delegates node-depd
node-diff node-electron-to-chromium node-encoding node-end-of-stream node-err-code node-error-ex
node-es-module-lexer node-escape-string-regexp node-eslint-utils node-eslint-visitor-keys node-esquery
node-estraverse node-esutils node-events node-fancy-log node-fast-deep-equal node-fast-levenshtein
node-fetch node-find-up node-flatted node-foreground-child node-fs-readdir-recursive
node-fs-write-stream-atomic node-fs.realpath node-function-bind node-get-caller-file node-get-stream
node-get-value node-glob node-globals node-got node-graceful-fs node-growl node-has-flag
node-has-unicode node-has-value node-has-values node-hosted-git-info node-iconv-lite node-ieee754
node-iferr node-imurmurhash node-indent-string node-inflight node-inherits node-ini node-interpret
node-ip node-ip-regex node-is-arrayish node-is-binary-path node-is-buffer node-is-descriptor
node-is-extglob node-is-path-cwd node-is-plain-obj node-is-plain-object node-is-stream
node-is-typedarray node-is-windows node-isarray node-isexe node-isobject node-js-tokens node-json-buffer
node-json-parse-better-errors node-json-schema node-json-schema-traverse node-json-stable-stringify
node-jsonify node-jsonparse node-kind-of node-levn node-loader-runner node-locate-path
node-lodash-packages node-lowercase-keys node-lru-cache node-map-visit node-memfs node-merge-stream
node-mimic-response node-minimatch node-minimist node-minipass node-mute-stream node-n3 node-negotiator
node-npm-run-path node-object-inspect node-object-visit node-once node-optimist node-optionator
node-osenv node-p-cancelable node-p-limit node-p-locate node-p-map node-pascalcase node-path-dirname
node-path-exists node-path-is-absolute node-path-is-inside node-path-type node-pify node-pkg-dir
node-postcss-value-parser node-prelude-ls node-process-nextick-args node-promise-inflight
node-promise-retry node-promzard node-prr node-pump node-punycode node-quick-lru node-randombytes
node-read node-readable-stream node-rechoir node-regenerator-runtime node-regenerator-transform
node-regexpp node-regjsgen node-repeat-string node-require-directory node-require-from-string
node-resolve node-resolve-cwd node-resolve-from node-restore-cursor node-resumer node-retry
node-run-queue node-safe-buffer node-serialize-javascript node-set-blocking node-set-immediate-shim
node-shebang-command node-shebang-regex node-shell-quote node-signal-exit node-slash node-slice-ansi
node-source-list-map node-source-map node-spdx-correct node-spdx-exceptions node-spdx-expression-parse
node-spdx-license-ids node-sprintf-js node-ssri node-stack-utils node-string-decoder node-strip-bom
node-supports-color node-tapable node-terser node-text-table node-through node-time-stamp
node-to-fast-properties node-tslib node-type-check node-typedarray node-typedarray-to-buffer node-undici
node-unicode-canonical-property-names-ecmascript node-unicode-match-property-value-ecmascript
node-unicode-property-aliases-ecmascript node-unset-value node-uri-js node-util-deprecate node-uuid
node-v8flags node-validate-npm-package-license node-wcwidth.js node-webpack-sources node-wordwrap
node-wrappy node-write-file-atomic node-xtend node-y18n node-yallist node-yaml nodejs-doc xbitmaps
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
cpio libcommon-sense-perl libevent-perl liblinux-inotify2-perl libmail-sendmail-perl libnsl2
libsys-hostname-long-perl libxml-libxml-perl libxml-namespacesupport-perl libxml-sax-base-perl
libxml-sax-expat-perl libxml-sax-perl libxml-simpleobject-libxml-perl postfix
Suggested packages:
libarchive-dev sendxmpp yowsup-cli libxml-sax-expatxs-perl mail-reader postfix-cdb postfix-doc
postfix-ldap postfix-lmdb postfix-mta-sts-resolver postfix-mysql postfix-pcre postfix-pgsql
postfix-sqlite procmail sasl2-bin | dovecot-common ufw
The following NEW packages will be installed:
cpio iwatch libcommon-sense-perl libevent-perl liblinux-inotify2-perl libmail-sendmail-perl libnsl2
libsys-hostname-long-perl libxml-libxml-perl libxml-namespacesupport-perl libxml-sax-base-perl
libxml-sax-expat-perl libxml-sax-perl libxml-simpleobject-libxml-perl postfix
0 upgraded, 15 newly installed, 0 to remove and 1 not upgraded.
Need to get 2129 kB of archives.
After this operation, 6741 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://archive.ubuntu.com/ubuntu noble/main amd64 cpio amd64 2.15+dfsg-1ubuntu2 [82.7 kB]
Get:2 http://archive.ubuntu.com/ubuntu noble/main amd64 libnsl2 amd64 1.3.0-3build3 [41.4 kB]
Get:3 http://archive.ubuntu.com/ubuntu noble/main amd64 postfix amd64 3.8.6-1build2 [1254 kB]
Get:4 http://archive.ubuntu.com/ubuntu noble/universe amd64 libevent-perl amd64 1.28-2build3 [250 kB]
Get:5 http://archive.ubuntu.com/ubuntu noble/main amd64 libcommon-sense-perl amd64 3.75-3build3 [20.4 kB]
Get:6 http://archive.ubuntu.com/ubuntu noble/universe amd64 liblinux-inotify2-perl amd64 1:2.3-2build3 [18.2 kB]
Get:7 http://archive.ubuntu.com/ubuntu noble/main amd64 libsys-hostname-long-perl all 1.5-3 [10.6 kB]
Get:8 http://archive.ubuntu.com/ubuntu noble/main amd64 libmail-sendmail-perl all 0.80-3 [21.7 kB]
Get:9 http://archive.ubuntu.com/ubuntu noble/main amd64 libxml-namespacesupport-perl all 1.12-2 [13.5 kB]
Get:10 http://archive.ubuntu.com/ubuntu noble/main amd64 libxml-sax-base-perl all 1.09-3 [18.9 kB]
Get:11 http://archive.ubuntu.com/ubuntu noble/main amd64 libxml-sax-perl all 1.02+dfsg-3 [57.0 kB]
Get:12 http://archive.ubuntu.com/ubuntu noble/main amd64 libxml-libxml-perl amd64 2.0207+dfsg+really+2.0134-1build4 [304 kB]
Get:13 http://archive.ubuntu.com/ubuntu noble/universe amd64 libxml-simpleobject-libxml-perl all 0.53-4 [8984 B]
Get:14 http://archive.ubuntu.com/ubuntu noble/universe amd64 iwatch all 0.2.2-10 [18.3 kB]
Get:15 http://archive.ubuntu.com/ubuntu noble/main amd64 libxml-sax-expat-perl all 0.51-2 [8644 B]
Fetched 2129 kB in 3s (695 kB/s)
Preconfiguring packages ...
Selecting previously unselected package cpio.
(Reading database ... 116862 files and directories currently installed.)
Preparing to unpack .../00-cpio_2.15+dfsg-1ubuntu2_amd64.deb ...
Unpacking cpio (2.15+dfsg-1ubuntu2) ...
Selecting previously unselected package libnsl2:amd64.
Preparing to unpack .../01-libnsl2_1.3.0-3build3_amd64.deb ...
Unpacking libnsl2:amd64 (1.3.0-3build3) ...
Selecting previously unselected package postfix.
Preparing to unpack .../02-postfix_3.8.6-1build2_amd64.deb ...
Unpacking postfix (3.8.6-1build2) ...
Selecting previously unselected package libevent-perl.
Preparing to unpack .../03-libevent-perl_1.28-2build3_amd64.deb ...
Unpacking libevent-perl (1.28-2build3) ...
Selecting previously unselected package libcommon-sense-perl:amd64.
Preparing to unpack .../04-libcommon-sense-perl_3.75-3build3_amd64.deb ...
Unpacking libcommon-sense-perl:amd64 (3.75-3build3) ...
Selecting previously unselected package liblinux-inotify2-perl.
Preparing to unpack .../05-liblinux-inotify2-perl_1%3a2.3-2build3_amd64.deb ...
Unpacking liblinux-inotify2-perl (1:2.3-2build3) ...
Selecting previously unselected package libsys-hostname-long-perl.
Preparing to unpack .../06-libsys-hostname-long-perl_1.5-3_all.deb ...
Unpacking libsys-hostname-long-perl (1.5-3) ...
Selecting previously unselected package libmail-sendmail-perl.
Preparing to unpack .../07-libmail-sendmail-perl_0.80-3_all.deb ...
Unpacking libmail-sendmail-perl (0.80-3) ...
Selecting previously unselected package libxml-namespacesupport-perl.
Preparing to unpack .../08-libxml-namespacesupport-perl_1.12-2_all.deb ...
Unpacking libxml-namespacesupport-perl (1.12-2) ...
Selecting previously unselected package libxml-sax-base-perl.
Preparing to unpack .../09-libxml-sax-base-perl_1.09-3_all.deb ...
Unpacking libxml-sax-base-perl (1.09-3) ...
Selecting previously unselected package libxml-sax-perl.
Preparing to unpack .../10-libxml-sax-perl_1.02+dfsg-3_all.deb ...
Unpacking libxml-sax-perl (1.02+dfsg-3) ...
Selecting previously unselected package libxml-libxml-perl.
Preparing to unpack .../11-libxml-libxml-perl_2.0207+dfsg+really+2.0134-1build4_amd64.deb ...
Unpacking libxml-libxml-perl (2.0207+dfsg+really+2.0134-1build4) ...
Selecting previously unselected package libxml-simpleobject-libxml-perl.
Preparing to unpack .../12-libxml-simpleobject-libxml-perl_0.53-4_all.deb ...
Unpacking libxml-simpleobject-libxml-perl (0.53-4) ...
Selecting previously unselected package iwatch.
Preparing to unpack .../13-iwatch_0.2.2-10_all.deb ...
Unpacking iwatch (0.2.2-10) ...
Selecting previously unselected package libxml-sax-expat-perl.
Preparing to unpack .../14-libxml-sax-expat-perl_0.51-2_all.deb ...
Unpacking libxml-sax-expat-perl (0.51-2) ...
Setting up cpio (2.15+dfsg-1ubuntu2) ...
update-alternatives: using /usr/bin/mt-gnu to provide /usr/bin/mt (mt) in auto mode
Setting up libevent-perl (1.28-2build3) ...
Setting up libcommon-sense-perl:amd64 (3.75-3build3) ...
Setting up liblinux-inotify2-perl (1:2.3-2build3) ...
Setting up libxml-namespacesupport-perl (1.12-2) ...
Setting up libxml-sax-base-perl (1.09-3) ...
Setting up libnsl2:amd64 (1.3.0-3build3) ...
Setting up libsys-hostname-long-perl (1.5-3) ...
Setting up libxml-sax-perl (1.02+dfsg-3) ...
update-perl-sax-parsers: Registering Perl SAX parser XML::SAX::PurePerl with priority 10...
update-perl-sax-parsers: Updating overall Perl SAX parser modules info file...
Creating config file /etc/perl/XML/SAX/ParserDetails.ini with new version
Setting up libmail-sendmail-perl (0.80-3) ...
Setting up libxml-libxml-perl (2.0207+dfsg+really+2.0134-1build4) ...
update-perl-sax-parsers: Registering Perl SAX parser XML::LibXML::SAX::Parser with priority 50...
update-perl-sax-parsers: Registering Perl SAX parser XML::LibXML::SAX with priority 50...
update-perl-sax-parsers: Updating overall Perl SAX parser modules info file...
Replacing config file /etc/perl/XML/SAX/ParserDetails.ini with new version
Setting up libxml-sax-expat-perl (0.51-2) ...
update-perl-sax-parsers: Registering Perl SAX parser XML::SAX::Expat with priority 50...
update-perl-sax-parsers: Updating overall Perl SAX parser modules info file...
Replacing config file /etc/perl/XML/SAX/ParserDetails.ini with new version
Setting up postfix (3.8.6-1build2) ...
info: Selecting GID from range 100 to 999 ...
info: Adding group `postfix' (GID 123) ...
info: Selecting UID from range 100 to 999 ...
info: Adding system user `postfix' (UID 115) ...
info: Adding new user `postfix' (UID 115) with group `postfix' ...
info: Not creating home directory `/var/spool/postfix'.
Creating /etc/postfix/dynamicmaps.cf
info: Selecting GID from range 100 to 999 ...
info: Adding group `postdrop' (GID 124) ...
/etc/aliases does not exist, creating it.
Postfix (main.cf) was not set up. Start with
cp /usr/share/postfix/main.cf.debian /etc/postfix/main.cf
. If you need to make changes, edit /etc/postfix/main.cf (and others) as
needed. To view Postfix configuration values, see postconf(1).
After modifying main.cf, be sure to run 'systemctl reload postfix'.
Created symlink /etc/systemd/system/multi-user.target.wants/postfix.service → /usr/lib/systemd/system/postfix.service.
Setting up libxml-simpleobject-libxml-perl (0.53-4) ...
Setting up iwatch (0.2.2-10) ...
Created symlink /etc/systemd/system/multi-user.target.wants/iwatch.service → /usr/lib/systemd/system/iwatch.service.
Processing triggers for libc-bin (2.39-0ubuntu8.6) ...
Processing triggers for rsyslog (8.2312.0-3ubuntu9.1) ...
Processing triggers for man-db (2.12.0-4build2) ...使い方
iwatchには2つの動作モードがある
- コマンドラインモード(フォアグラウンド): 単純な監視をすぐに開始
- デーモンモード(バックグラウンド): XML設定ファイルを使用して複数の監視を実行
コマンドラインモード
使用方法
# /tmpディレクトリを監視(デフォルトイベント)
iwatch /tmp
# 再帰的に監視
iwatch -r /var/www
# メール通知を有効にして監視も可能とのこと
iwatch -r -m root@localhost /etcオプション
| オプション | 説明 |
|---|---|
-r | 再帰的にディレクトリを監視 |
-m <email> | 変更をメール通知する宛先 |
-e <events> | 監視するイベントを指定(カンマ区切り) |
-c <command> | 変更時に実行するコマンド |
-x <path> | 除外するパス |
-X <regex> | 除外する正規表現パターン |
-t <filter> | ファイル名のフィルタ(正規表現) |
-s on|off | syslogへの記録を有効/無効 |
-v | 詳細表示 |
監視できるイベントについて
| イベント | 説明 |
|---|---|
access | ファイル/ディレクトリがアクセスされた |
modify | ファイルの内容が変更された |
attrib | ファイル/ディレクトリの属性が変更された |
close_write | 書き込み可能モードで開かれたファイルがクローズされた |
close_nowrite | 読み取り専用モードで開かれたファイルがクローズされた |
open | ファイル/ディレクトリが開かれた |
create | 監視中のディレクトリ内でファイル/ディレクトリが作成された |
delete | 監視中のディレクトリ内でファイル/ディレクトリが削除された |
move | 監視中のディレクトリ内でファイル/ディレクトリが移動された |
delete_self | 監視中のファイル/ディレクトリ自体が削除された |
move_self | 監視中のファイル/ディレクトリ自体が移動された |
default | close_write, create, delete, move, delete_self, move_self |
all_events | すべてのイベント |
使ってみる
例1: ディレクトリの変更を監視
iwatch /tmp/tmpディレクトリでファイルの作成、変更、削除などが発生すると、標準出力に通知される。
ログ
[11/Nov/2025 20:39:13] IN_CREATE /tmp/p10k-instant-prompt-output-kbushi-65724
[11/Nov/2025 20:39:13] IN_CLOSE_WRITE /tmp/p10k-instant-prompt-output-kbushi-65724
[11/Nov/2025 20:39:13] * /tmp/p10k-instant-prompt-output-kbushi-65724 is closed
[11/Nov/2025 20:39:13] IN_CREATE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock
[11/Nov/2025 20:39:13] IN_CLOSE_WRITE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock
[11/Nov/2025 20:39:13] * /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock is closed
[11/Nov/2025 20:39:13] IN_CREATE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.fifo
[11/Nov/2025 20:39:14] IN_DELETE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.fifo
[11/Nov/2025 20:39:14] * /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.fifo is deleted
[11/Nov/2025 20:39:14] IN_CREATE /tmp/p10k.worker.1002.65724.1762861154.fifo
[11/Nov/2025 20:39:14] IN_DELETE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock
[11/Nov/2025 20:39:14] * /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock is deleted
[11/Nov/2025 20:39:14] IN_CLOSE_WRITE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock
[11/Nov/2025 20:39:14] IN_DELETE /tmp/p10k.worker.1002.65724.1762861154.fifo
[11/Nov/2025 20:39:14] * /tmp/p10k.worker.1002.65724.1762861154.fifo is deleted
[11/Nov/2025 20:39:14] IN_CLOSE_WRITE /tmp/p10k-instant-prompt-output-kbushi-65724
[11/Nov/2025 20:39:14] * /tmp/p10k-instant-prompt-output-kbushi-65724 is closed
[11/Nov/2025 20:39:14] IN_DELETE /tmp/p10k-instant-prompt-output-kbushi-65724
[11/Nov/2025 20:39:14] * /tmp/p10k-instant-prompt-output-kbushi-65724 is deleted
[11/Nov/2025 20:39:17] IN_CREATE /tmp/aaa
[11/Nov/2025 20:39:17] IN_CLOSE_WRITE /tmp/aaa
[11/Nov/2025 20:39:17] * /tmp/aaa is closed
[11/Nov/2025 20:39:17] IN_CLOSE_WRITE /tmp/gitstatus.POWERLEVEL9K.1002.65724.1762861153.1.lock例2: /var/wwwを再帰的に監視する
iwatch -r /var/wwwログ
[11/Nov/2025 20:40:40] IN_CREATE /var/www/aaa
[11/Nov/2025 20:40:40] IN_CLOSE_WRITE /var/www/aaa
[11/Nov/2025 20:40:40] * /var/www/aaa is closed例3: /etcを再帰的に監視してメール通知 (未実施)
iwatch -r -e access,create -m root@localhost -x /etc/mail /etc/etcディレクトリを再帰的に監視accessとcreateイベントのみ監視/etc/mailディレクトリは除外- 変更があれば
root@localhostにメール通知
コマンド内で使用できる変数
| 変数 | 説明 |
|---|---|
%f | 変更されたファイルのフルパス |
%e | イベント名(例: IN_CLOSE_WRITE) |
%F | moved_toイベント時の元のファイル名 |
%p | プログラム名(常にiWatch) |
%v | バージョン番号 |
%c | イベントクッキー番号 |
例4: .svnディレクトリを除外して監視
iwatch -r -X '.svn' ~/projects~/projectsを再帰的に監視するが、.svnディレクトリは除外する。-Xオプションは正規表現で除外パターンを指定できる。
例5: 特定のファイルのみ監視(フィルタ使用)
iwatch -r -t 'shadow|passwd' -m root@localhost /etc/etc配下で、ファイル名がshadowまたはpasswdにマッチするファイルのみ監視する。
デーモンモードでの使用
設定ファイル /etc/iwatch/iwatch.xml を作成して、デーモンとして実行する。
<?xml version="1.0" ?>
<!DOCTYPE config SYSTEM "/etc/iwatch/iwatch.dtd" >
<config>
<guard email="admin@localhost" name="iWatch"/>
<watchlist>
<title>Web Server Monitoring</title>
<contactpoint email="webmaster@localhost" name="WebMaster"/>
<path type="recursive">/var/www/html</path>
<path type="exception">/var/www/html/cache</path>
</watchlist>
</config>デーモンとして起動
sudo iwatch -d -f /etc/iwatch/iwatch.xml主なオプション:
| オプション | 説明 |
|---|---|
-d | デーモンとして実行 |
-f <config> | 設定ファイルを指定(デフォルト: /etc/iwatch/iwatch.xml) |
-p <pidfile> | PIDファイルのパス(デフォルト: /var/run/iwatch.pid) |
参考
iwatch - Ubuntu Packages
https://launchpad.net/ubuntu/+source/iwatchiwatch man page
https://manpages.ubuntu.com/manpages/jammy/man1/iwatch.1.htmlinotify(7) - Linux manual page
https://man7.org/linux/man-pages/man7/inotify.7.html
おわりに
iwatchは、Linuxのinotify機能を活用してファイルシステムの変更をリアルタイムで監視できるツールであった。
コマンドラインモードで手軽に監視を開始できるだけでなく、XML設定ファイルを使ったデーモンモードで複雑な監視システムも構築できた。
Webサーバーの改ざん検知、設定ファイルの変更監視など、セキュリティ用途に活用できそうだった。
似たコマンドにwatchがあるが、watchは定期的にコマンドを実行して結果を表示するツールであり、iwatchはファイルシステムの変更をリアルタイムで検知するツールである点で異なる。