This is a short introduction to using the inofity api in linux to detect file system modifications for specific files. Which can be useful for a number of reasons. The particular reason why I wrote the example program here was to reload parts of apache when python scripts were being modified while doing some web development. the problem being that apache + django caches the python files.

The example here is simple. It will take a file list to monitor and will then execute a command when one of thoose files are modified. Though it also shows a simple example of how to use the inofity api in linux.

To start with you will need to get a suitable file descriptor by calling inotify_init and then setup the files you would like to monitor you can do this by using the function inotify_add_watch with the correct arguments to be notified when files changes. See below for the first half of the program. Note that the program expects the file list to be passed on the command line.

int main(int argc, char **argv) {
    int fdnotify = -1;
    int i;

    fdnotify = inotify_init();
    if (fdnotify < 0) {
        fprintf(stderr, "inotify_init failed: %s\n", strerror(errno));
        exit(-1);
    }

    for(i = 2;i<argc;i++) {
        int wd = inotify_add_watch(fdnotify, argv[i], IN_MODIFY);
        if (wd < 0) {
            fprintf(stderr, "inotify_add_watch failed: %s\n", strerror(errno));
        }
    }
}

Once the initial list has been completed you just need to wait for a notification which is done by reading from the file descriptor with the inotify_event data structure and just keep reading from that file descriptor in a loop.

while(1) {
    char buffer[4096];
    struct inotify_event *event = NULL;
    int exec = 0;

    int len = read(fdnotify, buffer, sizeof(buffer));
    if (len < 0) {
        fprintf(stderr, "read: %s\n", strerror(errno));
        exit(-1);
    }

    event = (struct inotify_event *) buffer;
    while(event != NULL) {
        if ( (event->mask & IN_MODIFY) && event->len > 0) {
            printf("File Modified: %s\n", event->name);
            exec = 1;
        } else {
            printf("Unknown Mask 0x%.8x\n", event->mask);
        }

        /* Move to next struct */
        len -= sizeof(*event) + event->len;
        if (len > 0)
            event = ((void *) event) + sizeof(event) + event->len;
        else
            event = NULL;
    }

    if (exec)
        system(argv[1]);
}

And that is really it. Note that I wanted to ignore most of the file notification events before running the external script so that it would only execute the script once. It can also serve other nice purposes eg it can be used to auto rebuild a c project on the file by using it like this "./inotify make `find . -type f -name '*.[ch]'" which will run make any time any of the .c, .h files change. the program has 100's of useful ways to be used for being able to trigger shell scripts from file system events.





Last Modified: 19 February 2017

Releated Posts


2017-03-01 - Shooting yourself in the head with threads
2013-02-16 - C - Some simple examples of using strcat
2012-11-03 - C - How to override malloc / free
2012-09-22 - Linux Programming - Using inotify for detecting file modifications
2012-08-09 - C++ - Check an IP Address is in a IP Mask
2012-06-16 - CPP - Using gperf
2012-04-05 - Using gdb to debug a core file
2012-03-15 - C - Is the stdin a tty
2012-03-13 - C - Converting from char / string to int using atoi
2012-03-08 - C - UDP Socket example
2012-02-20 - C - Get home dir location in linux
2012-02-17 - C - IP address validation
2012-02-15 - C - Get current ip address of an interface
2012-02-10 - Using asprintf instead of sprintf or snprintf
2012-01-31 - C - Example of how to overwrite argv
2012-01-30 - C - The string reverse
2012-01-27 - C - Palindrome
2012-01-26 - C - Example of using popen
2011-12-28 - C - gethostbyname example
2011-12-11 - C - Linux get mac address from interface