inotify监控Linux文件系统的必备利器(3)
时间:2010-08-26 来源:mydear
事件处理循环
现在我们已经设置了一些监控,接下来就要等待事件。如果还存在监控,并且 keep_running 标志没有被信号处理程序重置,则循环会一直进行。循环进程等待事件的发生,对有效事件进行排队,并在返回等待状态之前并处理队列。 在真实应用程序当中,可能会采用一个线程将事件放入队列,而采用另一个线程处理它们,清单 5 展示了该循环。
清单 5. 事件处理循环
- int process_inotify_events (queue_t q, int fd)
- {
- while (keep_running && (watched_items > 0))
- {
- if (event_check (fd) > 0)
- {
- int r;
- r = read_events (q, fd);
- if (r < 0)
- {
- break;
- }
- else
- {
- handle_events (q);
- }
- }
- }
- return 0;
- }
等待事件
在本程序中,循环会不停地进行下去,直至发生被监控事件或者收到了中断信号。清单 6 展示了相关代码。
清单 6. 等待事件或中断
- int event_check (int fd)
- {
- fd_set rfds;
- FD_ZERO (&rfds);
- FD_SET (fd, &rfds);
- /* Wait until an event happens or we get interrupted
- by a signal that we catch */
- return select (FD_SETSIZE, &rfds, NULL, NULL, NULL);
- }
读取事件
当事件发生时,程序会依照缓存区的大小来读取尽量多的事件,然后把这些事件放入队列等待事件处理程序来处理。 样例代码对于事件量大于 16.384-byte 之类的问题不作处理。 想处理这类问题,需要在缓存末端处理局部事件。当前对名字长度所做的限制没有问题,但是优秀的防御式编程会检查名字,来确保不会出现缓存区溢出。
清单 7. 读取事件并排队
- int read_events (queue_t q, int fd)
- {
- char buffer[16384];
- size_t buffer_i;
- struct inotify_event *pevent;
- queue_entry_t event;
- ssize_t r;
- size_t event_size, q_event_size;-
- int count = 0;
- r = read (fd, buffer, 16384);
- if (r <= 0)
- return r;
- buffer_i = 0;
- while (buffer_i < r)
- {
- /* Parse events and queue them. */
- pevent = (struct inotify_event *) &buffer[buffer_i];
- event_size = offsetof (struct inotify_event, name) + pevent->len;
- q_event_size = offsetof (struct queue_entry, inot_ev.name) +
- pevent->len;
- event = malloc (q_event_size);
- memmove (&(event->inot_ev), pevent, event_size);
- queue_enqueue (event, q);
- buffer_i += event_size;
- count++;
- }
- printf ("n%d events queuedn", count);
- return count;
- }
处理事件
最终,需要对事件做处理。本例中的应用程序不处理事件,只报告发生了哪些事件。如果事件结构体中有一个名字出现, 程序将报告其是目录还是文件。在发生移动操作时,还会报告与移动或重命名事件相关的 cookie 信息。 清单 8 展示了部分代码,包括对一些事件的处理。参见 下载 部分可获得全部代码。
清单 8. 处理事件
- void handle_event (queue_entry_t event)
- {
-
/* If the event was associated with a filename, we will
store it here */ - char *cur_event_filename = NULL;
- char *cur_event_file_or_dir = NULL;
- /* This is the watch descriptor the event occurred on */
- int cur_event_wd = event->inot_ev.wd;
- int cur_event_cookie = event->inot_ev.cookie;
- unsigned long flags;
- if (event->inot_ev.len)
- {
- cur_event_filename = event->inot_ev.name;
- }
- if ( event->inot_ev.mask & IN_ISDIR )
- {
- cur_event_file_or_dir = "Dir";
- }
- else
- {
- cur_event_file_or_dir = "File";
- }
- flags = event->inot_ev.mask &
- ~(IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED );
- /* Perform event dependent handler routines */
-
/* The mask is the magic that tells us what file operation
occurred */ - switch (event->inot_ev.mask &
- (IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED))
- {
- /* File was accessed */
- case IN_ACCESS:
- printf ("ACCESS: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File was modified */
- case IN_MODIFY:
- printf ("MODIFY: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File changed attributes */
- case IN_ATTRIB:
- printf ("ATTRIB: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File open for writing was closed */
- case IN_CLOSE_WRITE:
- printf ("CLOSE_WRITE: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File open read-only was closed */
- case IN_CLOSE_NOWRITE:
- printf ("CLOSE_NOWRITE: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File was opened */
- case IN_OPEN:
- printf ("OPEN: %s "%s" on WD #%in",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd);
- break;
- /* File was moved from X */
- case IN_MOVED_FROM:
- printf ("MOVED_FROM: %s "%s" on WD #%i. Cookie=%dn",
- cur_event_file_or_dir, cur_event_filename, cur_event_wd,
- cur_event_cookie);
- break;
- .
- . (other cases)
- .
-
/* Watch was removed explicitly by inotify_rm_watch or
automatically - because file was deleted, or file system was unmounted. */
- case IN_IGNORED:
- watched_items--;
- printf ("IGNORED: WD #%dn", cur_event_wd);
- printf("Watching = %d itemsn",watched_items);
- break;
- /* Some unknown message received */
- default:
- printf ("UNKNOWN EVENT "%X" OCCURRED for file "%s" on WD #%in",
- event->inot_ev.mask, cur_event_filename, cur_event_wd);
- break;
- }
- /* If any flags were set other than IN_ISDIR, report the flags */
- if (flags & (~IN_ISDIR))
- {
- flags = event->inot_ev.mask;
- printf ("Flags=%lXn", flags);
- }
- }
相关阅读 更多 +