inotify监控Linux文件系统的必备利器

现代C++封装inotify与select实现高效文件监控方案 文件系统监控是Linux开发中的常见需求,传统轮询方案实时性差且资源消耗大。inotify作为内核提供的事件驱动机制,能够高效监控文件变化并即时通知应用。结合I/O多路复用技术如select,可以实现单线程同时监控多个文件描述符,构建非阻塞的异步事件处理模型。这种方案在现代C++工程实践中,通过RAII机制和类型安全封装,将底层系统调用转化为安全易用的高级抽象,广泛应用于日志分析、配置热重载等场景。本文深入探讨了如何利用select与inotify实现一套符合现代C++设计哲学的文件监控组件,涵盖核心封装、 阅读详情
http://os.51cto.com/art/201005/199023.htm 

文件系统事件监控对于从文件管理器到安全工具等多种程序来说都是必要的。对于如何整理和控制Linux文件系统中的事件在实际的使用中有很多方式,inotify是比较常用的一种方法。在本文中你会学习到如何使用inotify以及他的一些相关知识。

AD:


    本文主要向大家介绍了如何使用inotify控制Linux文件系统中的事件。在具体的学习之前我们先来看看什么是inotify以及他的历史简介。我们还会向大家介绍inotify的具体应用情况以及使中遇到问题的解决方案。

    inotify 介绍

    文件系统事件监控对于从文件管理器到安全工具等多种程序来说都是必要的。自 2.6.13 版本内核开始,Linux 就提供 inotify 功能,这允许监控程序打开一个独立文件描述符,并针对一系列特定的事件来监控一个或多个文件或者目录,例如打开、关闭、移动/重命名、 删除、创建或者改变属性。在以后的版本中还提供更多增强功能,因此在依赖这些特性之前请先检查系统的内核版本。

    在本文中,您将学会如何在简单的监控程序当中使用 inotify 函数。下载样例代码 并在系统当中进行编译,来为后面的研究做准备。

    历史简介

    在 inotify 之前有 dnotify 。不幸的是,dnotify 有局限性,无法满足用户的需求, inotify 的优势如下:

    Inotify 采用简单的文件描述符,而 dnotify 需要为每个受监控的目录打开一个文件描述符。 这使得同时监控多个目录成本很高,而且还会遇到每进程文件描述符限制问题。

    inotify 所采用的文件描述符通过系统调用获得,并且没有相关的设备或文件。对于 dnotify ,文件描述符与目录关系固定,避免了相关设备未被加载的问题,这是可移动媒体的典型问题。对于 inotify ,如果受监控文件或目录所在的文件系统未被加载, 则会产生一个事件,然后该监控会被自动移除。

    Inotify 能够监控文件或目录。Dnotify 监控目录, 因此程序员必须保持 stat 结构或者等效的数据结构,来反映目录当中被监控的文件, 然后在一个事件发生时,将其与当前状态进行对比,来知晓目录当中的条目发生了什么情况。

    如前面所述,inotify 采用文件描述符,允许程序员采用标准 select 或者 poll 函数来对事件进行监控。 这允许高效的多重 I/O 或者与 Glib 的 mainloop 集成。相比之下,dnotify 采用信号, 这使得程序员感到难度更大或者不够流畅。 在 2.6.25 版本内核中,inotify 也增加了 Signal-drive I.O 通告功能。

    用于 inotify 的 API

    Inotify 提供简单的 API ,采用最小的文件描述符并允许细粒度监控。与 inotify 的通信通过系统调用实现。

    inotify_init

    是用于创建 inotify 实例的系统调用,并返回一个指向该实例的文件描述符。

    inotify_init1

    与 inotify_init 相似,并带有附加标志。如果这些标志没有指定,将采用与 inotify_init 相同的值。

    inotify_add_watch

    增加对文件或目录的监控并指定需要监控哪些事件。 标志用于控制是否将事件加入到已有的监控当中,是否只有路径代表一个目录才进行监控, 是否需要追踪符号链接,是否进行一次性监控,当首次出现事件后就停止监控。

    inotify_rm_watch

    从监控列表中移除监控项目。

    read

    读取包含一个或多个事件信息的缓存。

    close

    关闭文件描述符,并移除所有在该描述符上的监控。 当关于某一实例的文件描述符都关闭以后, 资源和下层的对象都将释放,来供内核再次使用。

    因此,典型的监控程序要进行如下操作:

    利用 inotify_init 打开文件描述符;

    增加一个或多个监控;

    等待事件;

    处理事件,然后返回并等待更多事件;

    当没有活跃的监控时或者基于某些信号的指示,关闭文件描述符,清空,然后退出。

    在下一部分中,您将看到可以监控的事件,以及它们如何在简单程序当中运行。最后您将看到如何进行事件监控。

    通告

    当应用程序读取一个通告时,事件的顺序也被读取到缓存中。事件在一个变长结构体中被返回,见清单 1 。如果数据占满了缓存,可能需要对最后一个条目进行局部事件信息或者局部名处理。

    清单 1. 用于 inotify 的事件结构体

       
    1. struct inotify_event  
    2. {  
    3. int wd; /* Watch descriptor. */  
    4. uint32_t mask; /* Watch mask. */  
    5. uint32_t cookie; /* Cookie to synchronize two events. */  
    6. uint32_t len; /* Length (including NULs) of name. */  
    7. char name __flexarr; /* Name. */  
    8. }; 

    注意,只有当监控对象是一个目录并且事件与目录内部相关项目有关,而与目录本身无关时,才提供 name 字段。 如果 IN_MOVED_FROM 事件与相应的 IN_MOVED_TO 事件都与被监控的项目有关,cookie 就可用于将两者关联起来。 事件类型在掩码字段中返回,并伴随着能够被内核设置的标志。 例如,如果事件与目录有关,则标志 IN_ISDIR 将由内核设置。

    能够监控的事件

    有几种事件能够被监控。有一些,比如 IN_DELETE_SELF 只应用到正在被监控的项目,然而另一些比如 IN_ATTRIB 或者 IN_OPEN 可以应用到监控过的项目, 或者如果该项目是目录,则可以应用到其所包含的目录或文件。

    IN_ACCESS

    被监控项目或者被监控目录当中的条目被访问过。例如,一个打开的文件被读取。

    IN_MODIFY

    被监控项目或者被监控目录当中的条目被修改过。例如,一个打开的文件被修改。

    IN_ATTRIB

    被监控项目或者被监控目录当中条目的元数据被修改过。例如,时间戳或者许可被修改。

    IN_CLOSE_WRITE

    一个打开的,等待写入的文件或目录被关闭。

    IN_CLOSE_NOWRITE

    一个以只读方式打开的文件或目录被关闭。

    IN_CLOSE

    是可以很便捷地对前面提到的两个关闭事件(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)进行逻辑或操作的掩码。

    IN_OPEN

    文件或目录被打开。

    IN_MOVED_FROM

    被监控项目或者被监控目录当中的条目被移出监控区域。该事件还包含一个 cookie 来实现 IN_MOVED_FROM 与 IN_MOVED_TO 的关联。

    IN_MOVED_TO

    文件或目录被移入监控区域。该事件包含一个针对 IN_MOVED_FROM 的 cookie 。如果文件或目录只是被重命名,将能看到这两个事件,如果它只是被移入或移出非监控区域,将只能看到一个事件。 如果移动或重命名一个被监控项目,监控将继续进行。参见下面的 IN_MOVE-SELF 。

    IN_MOVE

    是可以很便捷地对前面提到的两个移动事件(IN_MOVED_FROM | IN_MOVED_TO)进行逻辑或操作的掩码。

    IN_CREATE

    在被监控目录当中创建了子目录或文件。

    IN_DELETE

    被监控目录当中有子目录或文件被删除。

    IN_DELETE_SELF

    被监控项目本身被删除。监控被终止并收到一个 IN_IGNORED 事件。

    IN_MOVE_SELF

    监控项目本身被移动。

    除了事件标志以外,还可以在 inotify 头文件(/usr/include/sys/inotify.h)中找到其他几个标志。 例如,如果只想监控第一个事件,可以在增加监控时设置 IN_ONESHOT 标志。

    inotify 简单应用

    这里的简单应用遵循以上的通用逻辑。 我们使用一个信号处理程序来监控 ctrl-c(SIGINT)并且 重置一个标志(keep_running)使应用了解终止操作。 真实的 inotify 调用在 utility 例程当中完成。注意, 我们还创建了一个队列,这样能够将事件从 inotify 底层对象中清除,留着稍后处理。在真实的应用当中,您可能希望用其他(具有更高优先级)的线程来完成这一操作。 这里的列举的应用程序,只是为了对一般原理进行举例说明。我们采用了一个简单的事件链表, 队列中的每一条目都包含原始事件加上用于存储指向队列中下一事件指针的空间。

    主程序

    清单 2 中展示了信号处理程序和主程序。在本例当中,对所有在命令行中出现过的文件或目录进行监控, 并利用事件掩码 IN_ALL_EVENTS 来监控每一对象的所有事件。 在真实的应用程序中,您可能只希望追踪文件与目录的创建或删除事件,因此您可以掩去打开、关闭以及属性改变事件。 如果您对文件或目录的重命名和移动不感兴趣,您也可以掩去各种移动事件。关于更多细节,参见 inotify 帮助信息。

    清单 2. inotify-test.c 的简单主程序

       
    1. /* Signal handler that simply resets a flag to cause termination */  
    2. void signal_handler (int signum)  
    3. {  
    4. keep_running = 0;  
    5. }  
    6. int main (int argc, char **argv)  
    7. {  
    8. /* This is the file descriptor for the inotify watch */  
    9. int inotify_fd;  
    10. keep_running = 1;  
    11. /* Set a ctrl-c signal handler */  
    12. if (signal (SIGINT, signal_handler) == SIG_IGN)  
    13. {  
    14. /* Reset to SIG_IGN (ignore) if that was the prior state */  
    15. signal (SIGINT, SIG_IGN);  
    16. }  
    17. /* First we open the inotify dev entry */  
    18. inotify_fd = open_inotify_fd ();  
    19. if (inotify_fd > 0)  
    20. {  
    21. /* We will need a place to enqueue inotify events,  
    22. this is needed because if you do not read events  
    23. fast enough, you will miss them. This queue is   
    24. probably too small if you are monitoring something  
    25. like a directory with a lot of files and the directory   
    26. is deleted.  
    27. */  
    28. queue_t q;  
    29. q = queue_create (128);  
    30. /* This is the watch descriptor returned for each item we are   
    31. watching. A real application might keep these for some use   
    32. in the application. This sample only makes sure that none of  
    33. the watch descriptors is less than 0.  
    34. */  
    35. int wd;  
    36. /* Watch all events (IN_ALL_EVENTS) for the directories and   
    37. files passed in as arguments.  
    38. Read the article for why you might want to alter this for   
    39. more efficient inotify use in your app.   
    40. */  
    41. int index;  
    42. wd = 0;  
    43. printf("\n");  
    44. for (index = 1; (index < argc) && (wd >= 0); index++)   
    45. {  
    46. wd = watch_dir (inotify_fd, argv[index], IN_ALL_EVENTS);  
    47. }  
    48. if (wd > 0)   
    49. {  
    50. /* Wait for events and process them until a   
    51. termination condition is detected  
    52. */  
    53. process_inotify_events (q, inotify_fd);  
    54. }  
    55. printf ("\nTerminating\n");  
    56. /* Finish up by closing the fd, destroying the queue,  
    57. and returning a proper code  
    58. */  
    59. close_inotify_fd (inotify_fd);  
    60. queue_destroy (q);  
    61. }  
    62. return 0;  
    63. } 

    利用 inotify_init 打开文件描述符

    清单 3 展示了用于创建 inotify 实例的简单应用函数,并为其获得一个文件描述符。文件描述符返回给了调用者。 如果出现错误,返回值将为负。

    清单 3. 使用 inotify_init

       
    1. /* Create an inotify instance and open a file descriptor  
    2. to access it */  
    3. int open_inotify_fd ()  
    4. {  
    5. int fd;  
    6. watched_items = 0;  
    7. fd = inotify_init ();  
    8. if (fd < 0)  
    9. {  
    10. perror ("inotify_init () = ");  
    11. }  
    12. return fd;  
    13. } 

    利用 inotify_add_watch 来增加监控

    有了用于 inotify 实例的文件描述符之后,就需要增加一个或多个监控。 可以使用掩码来设置想要监控的事件。在本例当中,采用掩码 IN_ALL_EVENTS,来监控全部的有效事件。

    清单 4. 使用 inotify_add_watch

       
    1. int watch_dir (int fd, const char *dirname, unsigned long mask)  
    2. {  
    3. int wd;  
    4. wd = inotify_add_watch (fd, dirname, mask);  
    5. if (wd < 0)  
    6. {  
    7. printf ("Cannot add watch for \"%s\" with event mask %lX", dirname,  
    8. mask);  
    9. fflush (stdout);  
    10. perror (" ");  
    11. }  
    12. else  
    13. {  
    14. watched_items++;  
    15. printf ("Watching %s WD=%d\n", dirname, wd);  
    16. printf ("Watching = %d items\n", watched_items);   
    17. }  
    18. return wd;  
    19. } 

     

    事件处理循环

    现在我们已经设置了一些监控,接下来就要等待事件。如果还存在监控,并且 keep_running 标志没有被信号处理程序重置,则循环会一直进行。循环进程等待事件的发生,对有效事件进行排队,并在返回等待状态之前并处理队列。 在真实应用程序当中,可能会采用一个线程将事件放入队列,而采用另一个线程处理它们,清单 5 展示了该循环。

    清单 5. 事件处理循环

       
    1. int process_inotify_events (queue_t q, int fd)  
    2. {  
    3. while (keep_running && (watched_items > 0))  
    4. {  
    5. if (event_check (fd) > 0)  
    6. {  
    7. int r;  
    8. r = read_events (q, fd);  
    9. if (r < 0)  
    10. {  
    11. break;  
    12. }  
    13. else  
    14. {  
    15. handle_events (q);  
    16. }  
    17. }  
    18. }  
    19. return 0;  
    20. } 

    等待事件

    在本程序中,循环会不停地进行下去,直至发生被监控事件或者收到了中断信号。清单 6 展示了相关代码。

    清单 6. 等待事件或中断

       
    1. int event_check (int fd)  
    2. {  
    3. fd_set rfds;  
    4. FD_ZERO (&rfds);  
    5. FD_SET (fd, &rfds);  
    6. /* Wait until an event happens or we get interrupted   
    7. by a signal that we catch */  
    8. return select (FD_SETSIZE, &rfds, NULL, NULL, NULL);  
    9. } 

    读取事件

    当事件发生时,程序会依照缓存区的大小来读取尽量多的事件,然后把这些事件放入队列等待事件处理程序来处理。 样例代码对于事件量大于 16.384-byte 之类的问题不作处理。 想处理这类问题,需要在缓存末端处理局部事件。当前对名字长度所做的限制没有问题,但是优秀的防御式编程会检查名字,来确保不会出现缓存区溢出。

    清单 7. 读取事件并排队

       
    1. int read_events (queue_t q, int fd)  
    2. {  
    3. char buffer[16384];  
    4. size_t buffer_i;  
    5. struct inotify_event *pevent;  
    6. queue_entry_t event;  
    7. ssize_t r;  
    8. size_t event_size, q_event_size;-  
    9. int count = 0;  
    10. r = read (fd, buffer, 16384);  
    11. if (r <= 0)  
    12. return r;  
    13. buffer_i = 0;  
    14. while (buffer_i < r)  
    15. {  
    16. /* Parse events and queue them. */  
    17. pevent = (struct inotify_event *) &buffer[buffer_i];  
    18. event_size = offsetof (struct inotify_event, name) + pevent-> len;  
    19. q_event_size = offsetof (struct queue_entry, inot_ev.name) +   
    20. pevent->len;  
    21. event = malloc (q_event_size);  
    22. memmove (&(event->inot_ev), pevent, event_size);  
    23. queue_enqueue (event, q);  
    24. buffer_i += event_size;  
    25. count++;  
    26. }  
    27. printf ("\n%d events queued\n", count);  
    28. return count;  
    29. } 

    处理事件

    最终,需要对事件做处理。本例中的应用程序不处理事件,只报告发生了哪些事件。如果事件结构体中有一个名字出现, 程序将报告其是目录还是文件。在发生移动操作时,还会报告与移动或重命名事件相关的 cookie 信息。 清单 8 展示了部分代码,包括对一些事件的处理。参见 下载 部分可获得全部代码。

    清单 8. 处理事件

       
    1. void handle_event (queue_entry_t event)  
    2. {  
    3. /* If the event was associated with a filename, we will  store it here */  
    4. char *cur_event_filename = NULL;  
    5. char *cur_event_file_or_dir = NULL;  
    6. /* This is the watch descriptor the event occurred on */  
    7. int cur_event_wd = event->inot_ev.wd;  
    8. int cur_event_cookie = event->inot_ev.cookie;  
    9. unsigned long flags;  
    10. if (event->inot_ev.len)  
    11. {  
    12. cur_event_filename = event->inot_ev.name;  
    13. }  
    14. if ( event->inot_ev.mask & IN_ISDIR )  
    15. {  
    16. cur_event_file_or_dir = "Dir";  
    17. }  
    18. else   
    19. {  
    20. cur_event_file_or_dir = "File";  
    21. }  
    22. flags = event->inot_ev.mask &   
    23. ~(IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED );  
    24. /* Perform event dependent handler routines */  
    25. /* The mask is the magic that tells us what file operation  occurred */  
    26. switch (event->inot_ev.mask &   
    27. (IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED))  
    28. {  
    29. /* File was accessed */  
    30. case IN_ACCESS:  
    31. printf ("ACCESS: %s \"%s\" on WD #%i\n",  
    32. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    33. break;  
    34. /* File was modified */  
    35. case IN_MODIFY:  
    36. printf ("MODIFY: %s \"%s\" on WD #%i\n",  
    37. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    38. break;  
    39. /* File changed attributes */  
    40. case IN_ATTRIB:  
    41. printf ("ATTRIB: %s \"%s\" on WD #%i\n",  
    42. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    43. break;  
    44. /* File open for writing was closed */  
    45. case IN_CLOSE_WRITE:  
    46. printf ("CLOSE_WRITE: %s \"%s\" on WD #%i\n",  
    47. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    48. break;  
    49. /* File open read-only was closed */  
    50. case IN_CLOSE_NOWRITE:  
    51. printf ("CLOSE_NOWRITE: %s \"%s\" on WD #%i\n",  
    52. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    53. break;  
    54. /* File was opened */  
    55. case IN_OPEN:  
    56. printf ("OPEN: %s \"%s\" on WD #%i\n",  
    57. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
    58. break;  
    59. /* File was moved from X */  
    60. case IN_MOVED_FROM:  
    61. printf ("MOVED_FROM: %s \"%s\" on WD #%i. Cookie=%d\n",  
    62. cur_event_file_or_dir, cur_event_filename, cur_event_wd,   
    63. cur_event_cookie);  
    64. break;  
    65. .  
    66. . (other cases)  
    67. .  
    68. /* Watch was removed explicitly by inotify_rm_watch or  automatically  
    69. because file was deleted, or file system was unmounted. */  
    70. case IN_IGNORED:  
    71. watched_items--;  
    72. printf ("IGNORED: WD #%d\n", cur_event_wd);  
    73. printf("Watching = %d items\n",watched_items);   
    74. break;  
    75. /* Some unknown message received */  
    76. default:  
    77. printf ("UNKNOWN EVENT \"%X\" OCCURRED for file \"%s\" on WD #%i\n",  
    78. event->inot_ev.mask, cur_event_filename, cur_event_wd);  
    79. break;  
    80. }  
    81. /* If any flags were set other than IN_ISDIR, report the flags */  
    82. if (flags & (~IN_ISDIR))  
    83. {  
    84. flags = event->inot_ev.mask;  
    85. printf ("Flags=%lX\n", flags);  
    86. }  
    87. } 

    该例子用来举例说明 inotify 如何工作以及能够监控哪些事件。 您的实际需求将决定对哪些事件进行监控以及如何处理这些事件。

    用法举例

    在这部分当中,我们创建一个简单的两级目录结构,目录中有一个文件, 然后运行简单程序来举例说明 inotify 所能监控的一些事件。 我们将在一个终端会话中启动 inotify 样例程序, 但是因为他是在后台运行的(利用 &)因此程序的输出与我们输入的命令会交替出现。 应该在一个终端窗口运行该程序,而在其他窗口输入命令。清单 9 展示了简单文件结构和空文件的创建,以及最初启动该简单程序时的输出。

    清单 9. 创建样例环境

       
    1. ian@attic4:~/inotify-sample$ mkdir -p dir1/dir2  
    2. ian@attic4:~/inotify-sample$ touch dir1/dir2/file1  
    3. ian@attic4:~/inotify-sample$ ./inotify_test dir1/  dir1/dir2/ dir1/dir2/file1&  
    4. [2] 8733  
    5. ian@attic4:~/inotify-sample$   
    6. Watching dir1/ WD=1 
    7. Watching = 1 items  
    8. Watching dir1/dir2/ WD=2 
    9. Watching = 2 items  
    10. Watching dir1/dir2/file1 WD=3 
    11. Watching = 3 items  
    12. ian@attic4:~/inotify-sample$  

    在清单 10 当中,展示了列举 dir2 内容时的输出。 第一个事件报告与 dir1 有关,显示出有些东西,名字叫做 dir2 ,在与监控描述符 1 相关的被监控目录当中被打开了。 第二个条目与监控描述符 2 有关,显示出被监控项目(在本例中为 dir2 )被打开了。如果正在监控目录树中的多个项目, 可能会经常遇到这种双重输出。

    清单 10. 列出 dir2 的内容

       
    1. ian@attic4:~/inotify-sample$ ls dir1/dir2  
    2. file1  
    3. 4 events queued  
    4. OPEN: Dir "dir2" on WD #1  
    5. OPEN: Dir "(null)" on WD #2  
    6. CLOSE_NOWRITE: Dir "dir2" on WD #1  
    7. CLOSE_NOWRITE: Dir "(null)" on WD #2 

    在清单 11 当中,在 file1 中加入一些文字。需要再次强调对于文件以及该文件所在目录的双重打开,关闭,和修改事件。还要注意不是全部事件都会被立刻读取。排队例程被调用了3次,每次有两个事件。如果再次运行该程序,并且每次操作相同,您未必会再次遇到这一特别情况。

    清单 11. 在 file1 中加入一些文字

       
    1. ian@attic4:~/inotify-sample$ echo "Some text" >> dir1/dir2/file1  
    2. 2 events queued  
    3. OPEN: File "file1" on WD #2  
    4. OPEN: File "(null)" on WD #3  
    5. 2 events queued  
    6. MODIFY: File "file1" on WD #2  
    7. MODIFY: File "(null)" on WD #3  
    8. 2 events queued  
    9. CLOSE_WRITE: File "file1" on WD #2  
    10. CLOSE_WRITE: File "(null)" on WD #3 

    在清单 12 当中,改变 file1 的属性。我们再次得到有关被监控项目以及其所在目录的双重输出。

    清单 12. 改变文件属性

       
    1. ian@attic4:~/inotify-sample$ chmod a+w dir1/dir2/file1  
    2. 2 events queued  
    3. ATTRIB: File "file1" on WD #2  
    4. ATTRIB: File "(null)" on WD #3 

    现在将文件 file1 移动到上一级目录 dir1 当中。在清单 13 中显示了输出结果。 这次没有双重条目。我们实际上得到了 3 个条目,每个目录一个,文件本身一个。 注意 cookie (569) 允许将 MOVED-FROM 事件与 MOVED_TO 事件关联起来。

    清单 13. 将文件 file1 移入 dir1

       
    1. ian@attic4:~/inotify-sample$ mv dir1/dir2/file1 dir1  
    2. 3 events queued  
    3. MOVED_FROM: File "file1" on WD #2. Cookie=569 
    4. MOVED_TO: File "file1" on WD #1. Cookie=569 
    5. MOVE_SELF: File "(null)" on WD #3 

    现在创建一个 file1 到 file2 的硬链接。由于到 inode 的链接数量变了,我们得到针对 file1 的 ATTRIB 事件,还得到一个针对 file2 的 CREATE 事件。

    清单 14. 创建硬链接

       
    1. ian@attic4:~/inotify-sample$ ln dir1/file1 dir1/file2  
    2. 2 events queued  
    3. ATTRIB: File "(null)" on WD #3  
    4. CREATE: File "file2" on WD #1 

    现在将文件 file1 移入当前目录,将其重命名为 file3 。当前目录没有被监控,因此不存在与 MOVED_FROM 事件相关联的 MOVED_TO 事件。

    清单 15. 将 file1 移入不受监控的目录当中

       
    1. ian@attic4:~/inotify-sample$ mv dir1/file1 ./file3  
    2. 2 events queued  
    3. MOVED_FROM: File "file1" on WD #1. Cookie=572 
    4. MOVE_SELF: File "(null)" on WD #3 

    此时,dir2 是空的,因此可以移动它。注意我们得到一个关于监控描述符 2 的 IGNORED 事件,可见我们只在监控两个项目。

    清单 16. 移动 dir2

       
    1. ian@attic4:~/inotify-sample$ rmdir dir1/dir2  
    2. 3 events queued  
    3. DELETE: Dir "dir2" on WD #1  
    4. DELETE_SELF: File "(null)" on WD #2  
    5. IGNORED: WD #2  
    6. Watching = 2 items 

    移动文件 file3。注意这次我们没有得到 IGNORED 事件。为什么呢?为什么得到了关于 file 3 的 ATTRIB 事件(就是原来的 dir1/dir2/file1)?

    清单 17. 删除 file3

       
    1. ian@attic4:~/inotify-sample$ rm file3  
    2. 1 events queued  
    3. ATTRIB: File "(null)" on WD #3 

    记住我们创建了 file1 到 file2 的硬链接。清单 17 显示我们还在通过监控描述符 3 来监控 file2,尽管最开始不存在文件 2!

    清单 18. 仍对 file2 进行监控!

       
    1. ian@attic4:~/inotify-sample$ touch dir1/file2  
    2. 6 events queued  
    3. OPEN: File "file2" on WD #1  
    4. OPEN: File "(null)" on WD #3  
    5. ATTRIB: File "file2" on WD #1  
    6. ATTRIB: File "(null)" on WD #3  
    7. CLOSE_WRITE: File "file2" on WD #1  
    8. CLOSE_WRITE: File "(null)" on WD #3 

    现在删除 dir1 来监控事件级联,因为程序它不监控任何事,它结束了自己。

    清单 19. 删除 dir1

       
    1. ian@attic4:~/inotify-sample$ rm -rf dir1  
    2. 8 events queued  
    3. OPEN: Dir "(null)" on WD #1  
    4. ATTRIB: File "(null)" on WD #3  
    5. DELETE_SELF: File "(null)" on WD #3  
    6. IGNORED: WD #3  
    7. Watching = 1 items  
    8. DELETE: File "file2" on WD #1  
    9. CLOSE_NOWRITE: Dir "(null)" on WD #1  
    10. DELETE_SELF: File "(null)" on WD #1  
    11. IGNORED: WD #1  
    12. Watching = 0 items  
    13. Terminating 

    inotify 的使用情况

    可将 inotify 用于多种目标。下面列举一些可能的情况:

    性能监控

    您可能想确定应用程序打开最频繁的文件是哪个。如果发现一个小文件被频繁打开与关闭, 您可能会考虑采用内存版,或者改变应用程序来采取其他方式共享该数据。

    元信息

    您可能想记录文件的附加信息,例如起始创建时间,或者最后改变该文件的用户 id 。

    安全

    您可能会因为安全原因,需要对特定文件或目录的所有访问进行监控。

    我们的样例代码监控所有事件并进行报告。实际上,您可能想依据您的需要,来查看这些事件的特定子集。您可能想监控不同被监控项目的不同事件。例如,您可能想监控文件的打开与关闭事件,但对于目录只想监控创建与删除事件。在任何可能的时候,您可以监控您所感兴趣的最小事件集。

    结束语

    在应用到性能监控,程序调试,以及自动化等领域时,inotify 是功能强大,高级粒度机制的 Linux 文件系统监控工具。利用本文提供的样例代码,您可以开始编写用来实时记录文件系统事件并最小化性能开销的应用程序。

     

    Linux进程监控利器pspy:原理、部署与实战应用 进程监控是Linux系统管理和安全分析的基础技术,通过实时捕获进程活动来保障系统稳定性与安全性。传统工具如top和ps存在监控盲区,而基于inotify/fanotify机制的pspy工具能有效发现短生命周期进程和隐藏活动,特别适合排查定时任务异常、挖矿木马等安全事件。作为开源监控工具,pspy提供预编译二进制版本,解决了老旧系统环境依赖问题,支持容器化部署和进程树分析。在安全运维实践中,结合auditd和网络抓包工具,可构建完整的异常行为监控体系,典型应用包括入侵检测、性能优化等场景。 阅读详情

    相关推荐

    fsmon:跨平台文件系统监控工具实战指南

    fsmon。

    weixin_42583683的博客 689

    使用inotify监视Linux文件变化

    #include #include #include #include enum { ACTION_NULL_WD, ACTION_ADD_WD, ACTION_DEL_WD, }; int main(int argc, const char **argv) { int err = 0; if (!inotifytools_initialize()) {

    superbfly的专栏 3478

    yolo自动化项目实例解析(九) 导航

    比如我们经常使用的导航,说白了就是寻找两点之间最近的路径,也就是所谓的寻路,我们需要想办法让程序知道他要去哪里,路径包含(起点、轨迹、路径)

    默子昂 1998

    Linux inotify特性以及遍历方式监控所有子目录

    Linux inotify特性以及遍历方式监控所有子目录 首先,转载一段关于inotify的介绍: 它是一个内核用于通知用户空间程序文件系统变化的机制。 众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如 hotplug、udev 和 inotify 就是这种需求催生的。Hotplug 是一种内核向用户态应用通

    a66920164的博客 2261

    华为无线AP+AC(ensp)

    VLAN 100--192.168.100.0/24为AP的管理IP地址VLAN10--192.168.10.0/24为无线用户获取的IP地址在DHCP Server(LSW3)上查看地址分配情况。

    abcdlalal的博客 1万+

    创龙 瑞芯微 RK3588 国产2.4GHz八核 工业开发板—ISP图像处理开发案例

    创龙科技研发的 TL3588-EVM 评估板具备强大视频处理能力,可满足多场景视频开发需求。为助力开发者快速上手,本文整理 7 个实用视频开发案例,涵盖从采集到显示的全流程,详细说明各案例的硬件连接、参数配置与代码解析,帮助开发者高效实现评估板视频相关功能开发与调试。

    创龙,嵌入式一体化解决方案商 209

    inotify -- Linux 2.6 内核中的文件系统变化通知机制

    一、 引言 众所周知,Linux 桌面系统与 MAC 或 Windows 相比有许多不如人意的地方,为了改善这种状况,开源社区提出用户态需要内核提供一些机制,以便用户态能够及时地得知内核或底层硬件设备发生了什么,从而能够更好地管理设备,给用户提供更好的服务,如 hotplu

    512

    一文读懂 CST 时/频域求解器

    本文系统介绍了CST Studio Suite中的关键网格技术——六面体网格、四面体网格以及TLM求解器专用的八叉树非均匀网格技术。重点阐述了六面体网格的三项核心技术:理想边界拟合(PBA)技术可精确处理曲面边界,薄片技术(TST)能高效模拟薄层结构,自适应八叉树网格实现计算资源最优分配。同时详细对比了六面体网格与四面体网格的特点及适用场景,前者适用于系统级EMC/EMI分析等时域问题,后者擅长处理复杂曲面和异质材料的频域问题。

    一只豌豆象的博客 467

    使用 inotify 监控 Linux 文件系统事件

    使用 inotify 监控 Linux 文件系统事件<br />  <br />Inotify 是文件系统事件监控机制,计划包含在即将发布的 Linux 内核中作为dnotify 的有效替代。dnotify 是较早内核支持的文件监控机制。Inotify一种强大的、细粒度的、异步的机制,它满足各种各样的文件监控需要,不仅限于安全和性能。下面让我们一起学习如何安装 inotify 和如何构建一个示例用户空间应用程序来响应文件系统事件。<br />文件系统事件监控对于从文件管理器到安全工具的各种程序都是必要的,但

    qianfengwanyi的专栏 480

    【RT-DETR有效改进】手把手带你调参RT-DETR,1:1复现官方版本实验环境

    本文是带大家进行调参,利用ultralytics仓库1:1复现RT-DETR官方实验环境,从而在后期发表论文 的时候省去一些不必要的麻烦,例如被审稿人提出质疑,本文的调参内容均有依据,根据RT-DETR官方Github上发布的版本进行设置本文的调参以ResNet18为例,其余的何其的调参基本一致。RT-DETR剑指论文专栏,持续复现各种顶会内容——论文收割机RT-DETR。

    Snu77的博客 9939

    计算机视觉教程2-3:图解双线性插值算法&最近邻插值算法

    提出此算法的背景是基于图片的缩放,在图片缩放的过程中,实质上就是将原图像像素矩阵像素值,填到目标图像像素矩阵中,目标图像像素矩阵可能比原图像像素矩阵大(图片放大),也可能小(图片缩小)。我们假设图片的宽(WidthWidthWidth)和高(HeightHeightHeight)是按同比例缩放的,那么 srcXsrcWidth=dstXdstWidth\frac{srcX}{srcWidth}= \frac{dstX}{dstWidth}srcWidthsrcX​=dstWidthdstX​ ...

    FRIGIDWINTER的博客 7286

    linux inotify设备文件,inotify监控Linux文件系统的必备利器(1)

    inotify监控Linux文件系统的必备利器(1)本文主要向大家介绍了如何使用inotify控制Linux文件系统中的事件。在具体的学习之前我们先来看看什么是inotify以及他的历史简介。我们还会向大家介绍inotify的具体应用情况以及使中遇到问题的解决方案。inotify 介绍文件系统事件监控对于从文件管理器到安全工具等多种程序来说都是必要的。自 2.6.13 版本内核开始,Linux 就...

    weixin_39767645的博客 195

    手把手教你学Simulink——四开关 Buck‑Boost(FSBB)变换器的无缝模式切换仿真

    本文详细介绍了四开关Buck-Boost(FSBB)变换器的Simulink仿真方法,重点解决模式切换时的直通风险和输出电压波动问题。通过统一电压PI控制、迟滞比较模式仲裁(Buck/Boost/Pass-Through)和200ns死区设计,实现了Vin从26V到22V变化时Vout稳定在12V±0.15V。关键步骤包括:搭建功率级电路、Stateflow模式判断、PI控制器输出占空比映射(Buck模式D≈Vo/Vin,Boost模式D≈1-Vo/Vin),以及带死区的PWM信号分配。仿真验证了切换过程中

    MHD0815的博客 116

    Linux文件系统监控利器:5个实战场景掌握inotify-tools

    为什么需要实时监控文件系统变化?在当今的运维和开发环境中,文件系统的动态变化监控已成为自动化部署、安全审计和实时数据处理的关键需求。inotify-tools正是为解决这一需求而生的强大工具集,它基于Linux内核的inotify机制,为shell脚本提供了简单易用的文件监控接口。 ## 场景驱动:5个实际应用案例 ### 1. 网站安全监控与入侵检测 当您的Web服务器目录发生未经授权的文

    gitblog_00401的博客 843

    VS Code下载安装与使用教程

    VSCode下载安装与使用教程

    weixin_46713695的博客 4万+

    Statistics and Machine Learning Toolbox

    Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

    Linux inotify:实时感知文件变动的利器

    在 Linux 世界中,如果需要实时监控文件或目录的变化,**inotify** 几乎是最简单、最灵活的官方方案。通过 inotify,程序可以第一时间知道文件被创建、删除、修改等操作,尤其在日志监控、配置热加载等场景下,能带来非常便捷的效果。

    探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 2364

    OV9734 DATASHEET,完整规格书

    OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

    推荐开源项目:node-inotify——高效监控Linux文件系统事件的利器

    推荐开源项目:node-inotify——高效监控Linux文件系统事件的利器 项目介绍 node-inotify 是一个基于 Node.js 的库,它封装了GNU/Linux系统的内核功能inotify,提供了强大的文件系统事件监控能力。通过该库,开发者能够轻松地实时监听并响应文件或目录的各种变动,如访问、修改、创建、删除等事件。无论你是构建文件同步工具、版本控制系统还是自动化部署脚本,node...

    gitblog_00277的博客 850

    复分析 阿尔福斯(Ahlfors) 第三版答案 英文

    答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

    C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

    基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

    os-tutorial文件系统监控:inotify实现终极指南

    想要了解如何从零开始构建操作系统吗?os-tutorial项目为你提供了一个完美的学习平台!这个开源项目详细展示了如何从boot sector开始,逐步构建一个完整的操作系统。文件系统监控是操作系统中至关重要的功能,而inotify机制正是实现这一功能的利器。🎯 ## 什么是inotify文件系统监控? inotify是Linux内核提供的一种高效的文件系统事件监控机制。它允许应用程序监控文

    gitblog_00751的博客 859

    incron:实时文件系统事件监控的利器

    incron:实时文件系统事件监控的利器 在现代软件开发和自动化运维中,能够实时响应文件系统变化的需求日益常见。incron 正是这样一款强大的工具,它将文件系统事件的实时监控与传统的 cron 任务的定时执行相结合,为开发者提供了一个高效、灵活的事件驱动框架。 项目介绍 incron(inotify cron)系统由一个守护进程(incrond)和一个表操作工具组成。与传统的 cron 不同,i...

    gitblog_00820的博客 997

    终极指南:如何使用inotify-tools高效监控文件系统变化

    inotify-tools是一个提供简单接口来监控文件系统变化的库和命令行程序集,它能够帮助用户高效地追踪文件和目录的各种事件。 ## 一、inotifywait:文件变化监控利器 ### 1.1 功能简介 inotifywait通过Linux的inotify接口高效等待文件变化,非常适合在shell脚本中使用。它既可以在事件发生时退出,也能持续执行并输出发生的事件。 ### 1.2 基本用

    gitblog_00080的博客 589

    【亲测免费】 探索go-fsevents:Golang下的文件系统监控利器

    探索go-fsevents:Golang下的文件系统监控利器 在追求高效开发和即时响应的今天,监控文件系统的变动成为了不可或缺的一项技能。为此,我们挖掘到了一个充满潜力的开源工具——go-fsevents,它是专为Golang设计的文件系统事件观察者。本文将带你深入了解这一强大工具,探讨其技术特性,应用场景,并揭秘它为何值得一试。 项目介绍 go-fsevents是一个基于Golang构建的递归文...

    gitblog_00018的博客 677

    终极文件监控指南:用inotify与fswatch打造实时响应系统

    在现代软件开发和系统管理中,实时监控文件变化并快速响应已成为提升效率的关键环节。无论是自动化部署流程、日志分析还是开发环境热重载,文件监控工具都扮演着不可或缺的角色。本文将为你介绍两款强大的命令行文件监控工具——inotify和fswatch,帮助你构建高效、可靠的实时响应系统。 ## 为什么需要专业的文件监控工具? 传统的文件轮询方式不仅占用大量系统资源,还存在响应延迟的问题。专业的文件监控

    gitblog_00360的博客 640

    一文读懂onedrived-dev工作原理:inotify监控与OneDrive API交互详解

    onedrived-dev是一款专为Linux系统设计的Microsoft OneDrive客户端,采用Python3开发,能够实现本地目录与远程OneDrive存储的高效同步。本文将深入解析其核心工作原理,包括基于inotify的本地文件监控机制和与OneDrive API的交互流程,帮助新手用户理解这款工具如何实现双向数据同步。 ## 核心工作流程:本地监控与云端交互的完美协作 onedr

    gitblog_00406的博客 797

    如何使用 nix 库实现高效系统监控:inotify、timerfd、signalfd 实战指南

    nix 是一个为 Rust 开发者提供友好系统调用绑定的开源库,专注于 *nix 系统 API 的安全封装与便捷使用。本文将通过实战案例,详细介绍如何利用 nix 库中的 inotify、timerfd 和 signalfd 组件构建高效的系统监控解决方案,帮助开发者轻松实现文件变化追踪、精准定时任务和可靠信号处理。 ## 一、文件系统监控利器:inotify 实战 inotify 是 Lin

    gitblog_00660的博客 868
    上一篇: 如何使用inotify_init,inotify_add_watch,inotify_rm_watch,read编写监控程序
    下一篇: 使用trap/tee命令/调试钩子调试Shell脚本
    gracioushe
    博客等级 码龄25年 62粉丝 98原创
    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    个

    红包个数最小为10个

    元

    红包金额最低5元

    当前余额3.43元 前往充值 >
    需支付:10.00元
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付元
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值