Monitoring File Events

The key steps in the use of the inotify API are as follows:

  1. The application uses inotify_init to create an inotify instance.
  2. The application informs the kernel about which files are of interest by using inotify_add_watch to add items to the watch list of the inotify instance.
  3. In order to obtain event notifications, the application performs read operations on the inotify file descriptor.
  4. When the application has finished monitoring, it closes the inotify file descriptor.

inotify API

The inotify_init creates a new inotify instance

1
2
3
#include <sys/notify.h>

int inotify_init(void); // returns file descriptor on success, or -1 on error

The inotify_add_watch either adds a new watch to or modifies an existing watch item in the watch list for the inotify instance referred to by the file descriptor fd.

1
2
3
#include <sys/notify.h>

int inotify_add_watch(int fd, const char* pathname, uint32_t mask);

The inotify_rm_watch removes the watch item specified by wd from the inotify instance referred to by the file descriptor fd.

1
2
3
#include <sys/notify.h>

int inotify_rm_watch(int fd, uint32_t wd);

inotify 事件

Bit value In Out Description
IN_ACCESS . . File was accessed(read)
IN_ATTRIB . . File metadata changed
IN_CLOSE_WRITE . . File opened for writing was closed
IN_CLOSE_NOWRITE . . File opened for read-only was closed
IN_CREATE . . File/directory created inside watched directory
IN_DELETE . . File/directory deleted from within watched directory
IN_DELETE_SELF . . Watched file/directory was itself deleted
IN_MODIFY . . File was modified
IN_MOVE_SELF . . Watched file/directory was itself moved
IN_MOVED_FROM . . File moved out of watched directory
IN_MOVED_TO . . File moved into watched directory
IN_OPEN . . File was opened
IN_ALL_EVENTS . Shorthand for all of the above input events
IN_MOVE . Shorthand for IN_MOVED_FORM, IN_MOVED_TO
IN_CLOSE . Shorthand for IN_CLOSE_WRITE, IN_CLOSE_NOWRITE
IN_DONT_FOLLOW . Don’t dereference symbolic link
IN_MASK_ADD . Add events to current watch mask for pathname
IN_ONESHOT . Monitor pathname for just one event
IN_ONLYDIR . Fail if pathname is not a directory
IN_IGNORED . Watch was removed by application or by kernel
IN_ISDIR . Filename returned in name is a directory
IN_Q_OVERFLOW . Overflow on event queue
IN_UNMOUNT . File system containing object was unmounted

读取 inotify 事件

1
2
3
4
5
6
7
struct inotify_event {
    int wd; // watch descriptor on which event occurred
    uint32_t mask; // bits describing event that occurred
    uint32_t cookie; // cookie for related events
    uint32_t len; // size of the name field
    char name[]; // optional null-terminated filename
};
  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
100
101
102
#include <sys/inotify.h>
#include <limits.h>
#include "tlpi_hdr.h"

static void /* Display information from inotify_event structure */ displayInotifyEvent(struct inotify_event *i)
{
    printf("    wd =%2d; ", i->wd);
    if (i->cookie > 0)
        printf("cookie =%4d; ", i->cookie);

    printf("mask = ");
    if (i->mask & IN_ACCESS)
        printf("IN_ACCESS ");
    if (i->mask & IN_ATTRIB)
        printf("IN_ATTRIB ");
    if (i->mask & IN_CLOSE_NOWRITE)
        printf("IN_CLOSE_NOWRITE ");
    if (i->mask & IN_CLOSE_WRITE)
        printf("IN_CLOSE_WRITE ");
    if (i->mask & IN_CREATE)
        printf("IN_CREATE ");
    if (i->mask & IN_DELETE)
        printf("IN_DELETE ");
    if (i->mask & IN_DELETE_SELF)
        printf("IN_DELETE_SELF ");
    if (i->mask & IN_IGNORED)
        printf("IN_IGNORED ");
    if (i->mask & IN_ISDIR)
        printf("IN_ISDIR ");
    if (i->mask & IN_MODIFY)
        printf("IN_MODIFY ");
    if (i->mask & IN_MOVE_SELF)
        printf("IN_MOVE_SELF ");
    if (i->mask & IN_MOVED_FROM)
        printf("IN_MOVED_FROM ");
    if (i->mask & IN_MOVED_TO)
        printf("IN_MOVED_TO ");
    if (i->mask & IN_OPEN)
        printf("IN_OPEN ");
    if (i->mask & IN_Q_OVERFLOW)
        printf("IN_Q_OVERFLOW ");
    if (i->mask & IN_UNMOUNT)
        printf("IN_UNMOUNT ");
    printf("\n");

    if (i->len > 0)
        printf("        name = %s\n", i->name);
}

#define BUF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1))

int main(int argc, char *argv[])
{
    int inotifyFd, wd, j;
    char buf[BUF_LEN] __attribute__((aligned(8)));
    ssize_t numRead;
    char *p;
    struct inotify_event *event;

    if (argc < 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s pathname...\n", argv[0]);

    inotifyFd = inotify_init(); /* Create inotify instance */
    if (inotifyFd == -1)
        errExit("inotify_init");

    /* For each command-line argument, add a watch for all events */

    for (j = 1; j < argc; j++)
    {
        wd = inotify_add_watch(inotifyFd, argv[j], IN_ALL_EVENTS);
        if (wd == -1)
            errExit("inotify_add_watch");

        printf("Watching %s using wd %d\n", argv[j], wd);
    }

    for (;;)
    { /* Read events forever */
        numRead = read(inotifyFd, buf, BUF_LEN);
        if (numRead == 0)
            fatal("read() from inotify fd returned 0!");

        if (numRead == -1)
            errExit("read");

        /*FIXME: should use %zd here, and remove (long) cast */
        printf("Read %ld bytes from inotify fd\n", (long)numRead);

        /* Process all of the events in buffer returned by read() */

        for (p = buf; p < buf + numRead;)
        {
            event = (struct inotify_event *)p;
            displayInotifyEvent(event);

            p += sizeof(struct inotify_event) + event->len;
        }
    }

    exit(EXIT_SUCCESS);
}

队列限制和/proc文件

Queuing inotify events requires kernel memory. The superuser can configure limits via three files in the directory /proc/sys/fs/inotify

  • max_queued_events -> 16384
  • max_user_instances -> 128
  • max_user_watches -> 8192
Licensed under CC BY-NC-SA 4.0
Get Things Done
Built with Hugo
Theme Stack designed by Jimmy