使用 inotify 监控 Linux 文件系统事件(2)
- UID
- 1066743
|
使用 inotify 监控 Linux 文件系统事件(2)
在简单应用程序中使用 inotify为演示 inotify 的使用,我将展示如何为文件系统事件构造一个监控任意目录(或单个文件)的示例程序。我将站在一个较高的层次上来展示 inotify 使文件系统监控变得多么容易。
Main 方法这个简单的示例向我们展示 inotify 在任意目录上设置监控是多么容易。稍后我们将看到主要的帮助器例程。您可以在本文的 一节获取这些例子中使用的示例代码。
清单 1. 在目录上设置监控1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| /* This program will take as argument a directory name and monitor it,
printing event notifications to the console.
*/
int main (int argc, char **argv)
{
/* This is the file descriptor for the inotify device */
int inotify_fd;
/* First we open the inotify dev entry */
inotify_fd = open_inotify_dev();
if (inotify_fd < 0)
{
return 0;
}
/* We will need a place to enqueue inotify events,
this is needed because if you do not read events
fast enough, you will miss them.
*/
queue_t q;
q = queue_create (128);
/* Watch the directory passed in as argument
Read on for why you might want to alter this for
more efficient inotify use in your app.
*/
watch_dir (inotify_fd, argv[1], ALL_MASK);
process_inotify_events (q, inotify_fd);
/* Finish up by destroying the queue, closing the fd,
and returning a proper code
*/
queue_destroy (q);
close_inotify_dev (inotify_fd);
return 0;
}
|
重要的帮助器方法以下是每个基于 inotify 的应用程序共同的最重要的帮助器例程:
- 为读取而打开 inotify 设备。
- 对从该设备读取的事件进行排队。
- 允许应用程序对事件通知进行有用处理的实际的每事件处理器。
我不会深入钻研事件排队的细节,因为我们能够使用一些策略来避免排队。提供的代码中就展示了一个这样的方法;更先进的多线程方法可以并且已经在其他地方实现。在那些实现中,读者线程简单地在 inotify 设备上执行 select(),然后将事件拷贝到一些线程共享的存储空间(或者一些像 Glib 的异步消息队列的东西),以后处理器线程会处理这里的事件。
清单 2. 打开 inotify 设备1
2
3
4
5
6
7
8
9
10
11
| /* This simply opens the inotify node in dev (read only) */
int open_inotify_dev ()
{
int fd;
fd = open("/dev/inotify", O_RDONLY);
if (fd < 0)
{
perror ("open(\"/dev/inotify\", O_RDONLY) = ");
}
return fd;
}
|
这对任何一个在 Linux 系统上进行过文件编程的人来说都应该是熟悉的。
清单 3. 实际的事件处理例程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| /* This method does the dirty work of determining what happened,
then allows us to act appropriately
*/
void handle_event (struct inotify_event *event)
{
/* If the event was associated with a filename, we will store it here */
char * cur_event_filename = NULL;
/* This is the watch descriptor the event occurred on */
int cur_event_wd = event->wd;
if (event->len)
{
cur_event_filename = event->filename;
}
printf("FILENAME=%s\n", cur_event_filename);
printf("\n");
/* Perform event dependent handler routines */
/* The mask is the magic that tells us what file operation occurred */
switch (event->mask)
{
/* File was accessed */
case IN_ACCESS:
printf("ACCESS EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was modified */
case IN_MODIFY:
printf("MODIFY EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File changed attributes */
case IN_ATTRIB:
printf("ATTRIB EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was closed */
case IN_CLOSE:
printf("CLOSE EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was opened */
case IN_OPEN:
printf("OPEN EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was moved from X */
case IN_MOVED_FROM:
printf("MOVE_FROM EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was moved to X */
case IN_MOVED_TO:
printf("MOVE_TO EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* Subdir was deleted */
case IN_DELETE_SUBDIR:
printf("DELETE_SUBDIR EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was deleted */
case IN_DELETE_FILE:
printf("DELETE_FILE EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* Subdir was created */
case IN_CREATE_SUBDIR:
printf("CREATE_SUBDIR EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* File was created */
case IN_CREATE_FILE:
printf("CREATE_FILE EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* Watched entry was deleted */
case IN_DELETE_SELF:
printf("DELETE_SELF EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* Backing FS was unmounted */
case IN_UNMOUNT:
printf("UNMOUNT EVENT OCCURRED: File \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
/* Too many FS events were received without reading them
some event notifications were potentially lost. */
case IN_Q_OVERFLOW:
printf("Warning: AN OVERFLOW EVENT OCCURRED: \n");
break;
case IN_IGNORED:
printf("IGNORED EVENT OCCURRED: \n");
break;
/* Some unknown message received */
default:
printf ("UNKNOWN EVENT OCCURRED for file \"%s\" on WD #%i\n",
cur_event_filename, cur_event_wd);
break;
}
}
|
在每一条 case 语句中,您可以随意执行任意已实现并且满足需要的方法。
至于性能监控,您可以确定哪些文件是最经常被读取的和它们打开的持续时间。这种监控非常方便,因为在某些情况下,如果文件在短时间内被应用程序重复地读取,它会将文件缓存在内存中而不用返回磁盘去读取,从而提高性能。
很容易举出一些执行有趣操作的特定于事件的处理器的例子。比如,如果您是在为底层文件系统实现一个元数据存储索引,您可能会寻找文件创建事件,不久还会在该文件上触发一个元数据挖掘操作。在安全环境中,如果文件被写入一个无人可以写入的目录,您会触发某些形式的系统警报。
请注意,inotify 支持许多非常细粒度的事件 —— 例如 CLOSE 与 CLOSE_WRITE。
本文中的代码所列举的许多事件,可能您并不希望在每次代码运行时都看到。实际上,只要可能,您可以并且应该只请求对您的应用程序有用的事件子集。出于测试目的,本文章提供的代码通过严格使用完整掩码(如可下载的示例代码[请参阅 ] 中 main 方法的第 51 行附近或者上面的 中的第 29 行所执行的)展示了许多事件。应用程序员通常想要有更多选择,而您则需要更特定的掩码来满足您的需要。这使您可以从上述的 handle_event() 方法中的 catch 语句删除不感兴趣的条目。 |
|
|
|
|
|