$RodHat_/search
Syscall reference · Events

inotify_add_watch(2)

Watch a file or directory for filesystem events and read them off a file descriptor.

Since
Linux 2.6.13check your kernel →
glibc
glibc 2.4
System
Linux
Man page
inotify_add_watch(2)

Synopsis

#include <sys/inotify.h>

int inotify_init1(int flags);
int inotify_add_watch(int fd, const char *pathname, uint32_t mask);
int inotify_rm_watch(int fd, int wd);

Rod's take

inotify is the right answer for anything that was polling a file on a timer. Three syscalls and you have an fd that delivers events into epoll. The traps: watch IN_CLOSE_WRITE not IN_MODIFY (atomic-write tools rename, not modify-in-place), always check IN_Q_OVERFLOW or you miss events silently when under load, and max_user_watches defaults to 65536 which sounds like a lot until you watch a source tree. The name field is only populated on directory watches; for a single-file watch, ev->len is zero.

Flags and arguments that matter

NameWhat it does
IN_CLOSE_WRITEFile opened for writing was closed. Fires once per close; prefer this over IN_MODIFY for config-reload triggers.
IN_MOVED_TOFile was renamed into the watched directory. Required when the writer does an atomic temp-file-plus-rename.
IN_MODIFYFile content was modified. Fires on every write(2) call, not per-close. Noisy and wrong for watching targets of atomic renames.
IN_CREATEFile or directory was created inside a watched directory.
IN_DELETEFile or directory inside a watched directory was deleted.
IN_Q_OVERFLOWEvent queue overflowed; events were dropped. The kernel queues exactly one of these then discards until the queue drains. Always check for this flag or you have a silent failure mode.

Errors you will actually hit

errnoMeaning
ENOSPCThe per-user watch limit (/proc/sys/fs/inotify/max_user_watches) was reached. Raise the limit in /etc/sysctl.d/.
EACCESRead permission denied on the path.
ENOENTThe path does not exist. Watches on missing paths must be re-added after creation.

Example

#include <sys/inotify.h>
#include <unistd.h>

int fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
int wd = inotify_add_watch(fd, "/etc/app.conf",
                           IN_CLOSE_WRITE | IN_MOVED_TO);

char buf[4096]
    __attribute__((aligned(__alignof__(struct inotify_event))));
ssize_t n = read(fd, buf, sizeof(buf));
struct inotify_event *ev = (struct inotify_event *)buf;
if (ev->mask & IN_Q_OVERFLOW) {
    /* queue overflowed: events were dropped, resync state */
}

Trimmed from the full walkthrough in inotify_add_watch(2): filesystem events without the poll loop.

BSD equivalent

FreeBSD uses kqueue(2) + kevent(2) with EVFILT_VNODE. Watches are per-fd: open the file or directory, then register with kevent. NOTE_WRITE, NOTE_RENAME, NOTE_DELETE, and NOTE_ATTRIB are the main filter flags. Overflow is explicit and per-event rather than a single queue-full signal. More granular, fewer surprises.

The long version, from the console

Sources

  1. inotify(7), man7.org
  2. inotify_add_watch(2), man7.org

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.