fixedpoint.jp - inotify watches itself




inotify watches itself

inotify(7) は Linux 2.6.13 以降で利用できるファイルシステムの監視用 API です。扱いやすくいろいろな用途に使えそうな気のきいたもので、コマンドラインツール inotify-tools などの応用があります。

仕組みとしては、まず inotify インスタンスを初期化し、次に監視対象のパスと通知してほしいイベントの2つをこのインスタンスに登録することで監視が始まります。このインスタンスはファイルディスクリプタで実現されています。それを read(2) することでイベントを待ちます。

そこで気になったのは「このディスクリプタを表す proc ファイルシステムのパスを監視させたらどうなるか」ということでした。以下のようなコードを用意して実験です:

ino.c
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>

#include <sys/inotify.h>

int
main()
{
	int ino, watch, len, x;
	char path[128];
	struct inotify_event *e;

	if ( (ino = inotify_init()) < 0) {
		perror(NULL);
		return 1;
	}
	sprintf(path, "/proc/self/fd/%d", ino);
	if ( (watch = inotify_add_watch(ino, path, IN_ALL_EVENTS)) < 0) {
		perror(NULL);
		return 2;
	}
	len = sizeof(struct inotify_event) + strlen(path) + 1;
	e = (struct inotify_event *)malloc(len);
	if (!e) {
		perror(NULL);
		return 3;
	}
	if ( (x = fork()) < 0) {
		perror(NULL);
		return 4;
	} else if (x == 0) { /* child */
		chmod(path, 0);
		_Exit(0);
	} else { /* parent */
		int status;
		ssize_t s;

		wait(&status);
	retry:
		s = read(ino, e, len);
		if (s < 0) {
			perror(NULL);
			_Exit(4);
		}
		printf("%d\n", x);
		goto retry;
	}
	free(e);
	return 0;
}

コンパイルし実行:

$ uname -mrsv
Linux 2.6.26-1-686 #1 SMP Mon Dec 15 18:15:07 UTC 2008 i686
$ gcc -Wall -W -o ino ino.c 
$ ./ino 
Permission denied
$ echo $?
2
$ 

どうも権限に従って inotify_add_watch(2) の呼び出しでエラーになっているようです。それならということで root 権限で実行すると:

$ sudo ./ino
13517
13517
13517
13517
13517
(snip)
13517
13517
13517
13517
13517
^C
$ 

見事に自分自身に対する read(2) で無限ループに陥ってしまいました!


© 2006-2010 Takeshi Abe