首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

使用 inotify 监控 Linux 文件系统事件(2)

使用 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 语句删除不感兴趣的条目。
返回列表