3

I want to monitor USB-Keys on my system. I know they are always mounted in /media so I use inotify to monitor /media. Some USB Keys create a folder (e.g. sda) when plugged which stays until they are unplugged, some create a folder (e.g. sda), delete it imediately and create a new one (e.g. sda1). That's due to the partitions on the key.

However, sometimes inotify catches only the events for creation and deletion of the first folder, but misses the creation of the second. When I manually check /media, the second folder exists, but it was never notified by inotify.

This happens very rarely and when it happens, it's always at the first plug of a device after reboot.

#include <sys/inotify.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 32 events */
#define BUF_LEN        (32 * (EVENT_SIZE + 16))

int main(int argc, char **argv) {
    int fd,wd,len,i;
    char buf[BUF_LEN];
    struct inotify_event *event;
    fd_set watch_set;

    fd = inotify_init();
    if (fd < 0) {
        perror("init failed");
        exit(EXIT_FAILURE);
    }

    wd = inotify_add_watch(fd,"/media",IN_ALL_EVENTS);
    if (wd < 0) {
        perror("add watch failed");
        exit(EXIT_FAILURE);
    }

    /* put the file descriptor to the watch list for select() */
    FD_ZERO(&watch_set);
    FD_SET(fd,&watch_set);

    while(1) {
        select(fd+1,&watch_set,NULL,NULL,NULL);
        len = read(fd,buf,BUF_LEN);
        i=0;
        while(i < len) {

            event = (struct inotify_event *) &buf[i];

            if ((event->mask & IN_CREATE) != 0) {
                printf ("%s created\n",event->name);
            }
            else if ((event->mask & IN_DELETE) != 0) {
                printf ("%s deleted\n",event->name);
            }
            else {
                printf ("wd=%d mask=0x%X cookie=%u len=%u name=%s\n",
                                event->wd, event->mask,
                                event->cookie, event->len, event->name);
            }

            i += EVENT_SIZE + event->len;

        }

    }

}

Any ideas what's going wrong?

bad
  • 63
  • 1
  • 5
  • Can it be related to http://stackoverflow.com/questions/15350369/how-to-use-inotify-in-c that is `/media` is removed and a new `/media` is created for which no new `inotify_add_watch` is done? – Bryan Olivier Apr 04 '13 at 10:01
  • Only subfolders of /media are created and deleted. Although an event has been missed, the next one is catched again. So the watch is still running. – bad Apr 04 '13 at 10:53

3 Answers3

6

The subfolder problem with inotify is well known and easily reproduced:

  1. Start inotifywait watching an empty tmp directory:

    inotifywait -e create -m -r --format '%:e %f' ./tmp

  2. In another shell enter:

    mkdir tmp/0 tmp/0/0 tmp/0/0/0 tmp/0/0/0/0

  3. You will most likely only get a notification for the first subdirectory.

    CREATE:ISDIR 0

The distinct possibility of losing events (particularly subdirectory creation events) between the time a directory is created, your app gets notified, and a new inotify watch is added, makes recursive monitoring too unreliable. The only safe option is to scan contents of newly created directories.

From the inotify doc under Limitations and caveats:

If monitoring an entire directory subtree, and a new subdirectory is created in that tree, be aware that by the time you create a watch for the new subdirectory, new files may already have been created in the subdirectory. Therefore, you may want to scan the contents of the subdirectory immediately after adding the watch.

Peter Krnjevic
  • 1,070
  • 15
  • 20
  • Looking more closely at bad's problem, he's only concerned with one directory level, so the above won't apply. – Peter Krnjevic Jul 11 '13 at 07:43
  • However, digging a bit deeper, this may not be what bad wants: fd = inotify_init(); If using select, this should probably be: fd = inotify_init1(IN_NONBLOCK); With select, subdirectory events are received immediately, rather than buffered. – Peter Krnjevic Jul 11 '13 at 08:09
  • As you mentioned, subdirectories were not what bodered me, I was only interested in events on one directory level. However, in the meanwhile I found that this is a known issue of inotify (see my answer) – bad Jul 12 '13 at 07:47
3

In the meanwhile I found that this is a known issue of inotify. If two events appear virtually at the same time, inotify only catches one of them. My solution: I don't use inotify anymore, but took libudev instead to monitor the devices plugged to the machine...

bad
  • 63
  • 1
  • 5
2
  1. You can use inotifywait command (from the inotify-tools package) to monitor the /media directory, in order to check whether the inotify events which interest you do occur.
    reference:
    http://www.noah.org/wiki/Inotify,_FAM,_Gamin#Examples_with_inotify-tools

  2. If inotify does miss events, the reason might be:
    Inotify does report some but not all events in sysfs and procfs.
    (Well, I can not say for sure. Just my guess.)

Reference:
http://en.wikipedia.org/wiki/Inotify#Limitations
http://en.wikipedia.org/wiki/Sysfs
http://en.wikipedia.org/wiki/Procfs

zeekvfu
  • 3,344
  • 1
  • 22
  • 19