{
    "mode": "man",
    "parameter": "inotify",
    "section": "7",
    "url": "https://www.chedong.com/phpMan.php/man/inotify/7/json",
    "generated": "2026-06-12T13:14:42Z",
    "sections": {
        "NAME": {
            "content": "inotify - monitoring filesystem events\n",
            "subsections": []
        },
        "DESCRIPTION": {
            "content": "The  inotify  API provides a mechanism for monitoring filesystem events.  Inotify can be used\nto monitor individual files, or to monitor directories.  When a directory is monitored,  ino‐\ntify will return events for the directory itself, and for files inside the directory.\n\nThe following system calls are used with this API:\n\n*  inotifyinit(2) creates an inotify instance and returns a file descriptor referring to the\ninotify instance.  The more recent inotifyinit1(2) is like  inotifyinit(2),  but  has  a\nflags argument that provides access to some extra functionality.\n\n*  inotifyaddwatch(2)  manipulates  the  \"watch  list\" associated with an inotify instance.\nEach item (\"watch\") in the watch list specifies the pathname of a file or directory, along\nwith  some  set  of events that the kernel should monitor for the file referred to by that\npathname.  inotifyaddwatch(2) either creates a new watch item, or modifies  an  existing\nwatch.   Each  watch  has  a  unique  \"watch  descriptor\",  an  integer  returned  by ino‐‐\ntifyaddwatch(2) when the watch is created.\n\n*  When events occur for monitored files and directories, those events are made available  to\nthe application as structured data that can be read from the inotify file descriptor using\nread(2) (see below).\n\n*  inotifyrmwatch(2) removes an item from an inotify watch list.\n\n*  When all file descriptors referring  to  an  inotify  instance  have  been  closed  (using\nclose(2)),  the underlying object and its resources are freed for reuse by the kernel; all\nassociated watches are automatically freed.\n\nWith careful programming, an application can use inotify to efficiently monitor and cache the\nstate of a set of filesystem objects.  However, robust applications should allow for the fact\nthat bugs in the monitoring logic or races of the kind described below may  leave  the  cache\ninconsistent with the filesystem state.  It is probably wise to do some consistency checking,\nand rebuild the cache when inconsistencies are detected.\n",
            "subsections": [
                {
                    "name": "Reading events from an inotify file descriptor",
                    "content": "To determine what events have occurred, an application read(2)s from  the  inotify  file  de‐\nscriptor.   If  no  events  have  so far occurred, then, assuming a blocking file descriptor,\nread(2) will block until at least one event occurs (unless interrupted by a signal, in  which\ncase the call fails with the error EINTR; see signal(7)).\n\nEach successful read(2) returns a buffer containing one or more of the following structures:\n\nstruct inotifyevent {\nint      wd;       /* Watch descriptor */\nuint32t mask;     /* Mask describing event */\nuint32t cookie;   /* Unique cookie associating related\nevents (for rename(2)) */\nuint32t len;      /* Size of name field */\nchar     name[];   /* Optional null-terminated name */\n};\n\nwd  identifies the watch for which this event occurs.  It is one of the watch descriptors re‐\nturned by a previous call to inotifyaddwatch(2).\n\nmask contains bits that describe the event that occurred (see below).\n\ncookie is a unique integer that connects related events.  Currently, this is  used  only  for\nrename  events,  and  allows the resulting pair of INMOVEDFROM and INMOVEDTO events to be\nconnected by the application.  For all other event types, cookie is set to 0.\n\nThe name field is present only when an event is returned for a file inside a  watched  direc‐\ntory;  it identifies the filename within the watched directory.  This filename is null-termi‐\nnated, and may include further null bytes ('\\0') to align subsequent reads to a suitable  ad‐\ndress boundary.\n\nThe  len  field counts all of the bytes in name, including the null bytes; the length of each\ninotifyevent structure is thus sizeof(struct inotifyevent)+len.\n\nThe behavior when the buffer given to read(2) is too small to return  information  about  the\nnext  event depends on the kernel version: in kernels before 2.6.21, read(2) returns 0; since\nkernel 2.6.21, read(2) fails with the error EINVAL.  Specifying a buffer of size\n\nsizeof(struct inotifyevent) + NAMEMAX + 1\n\nwill be sufficient to read at least one event.\n"
                },
                {
                    "name": "inotify events",
                    "content": "The inotifyaddwatch(2) mask argument and the mask field of the inotifyevent structure  re‐\nturned  when  read(2)ing  an  inotify  file descriptor are both bit masks identifying inotify\nevents.  The following bits can be specified in mask when  calling  inotifyaddwatch(2)  and\nmay be returned in the mask field returned by read(2):\n\nINACCESS (+)\nFile was accessed (e.g., read(2), execve(2)).\n\nINATTRIB (*)\nMetadata changed—for example, permissions (e.g., chmod(2)), timestamps (e.g., uti‐‐\nmensat(2)), extended attributes (setxattr(2)), link  count  (since  Linux  2.6.25;\ne.g.,  for  the  target  of  link(2)  and for unlink(2)), and user/group ID (e.g.,\nchown(2)).\n\nINCLOSEWRITE (+)\nFile opened for writing was closed.\n\nINCLOSENOWRITE (*)\nFile or directory not opened for writing was closed.\n\nINCREATE (+)\nFile/directory created in watched  directory  (e.g.,  open(2)  OCREAT,  mkdir(2),\nlink(2), symlink(2), bind(2) on a UNIX domain socket).\n\nINDELETE (+)\nFile/directory deleted from watched directory.\n\nINDELETESELF\nWatched  file/directory  was itself deleted.  (This event also occurs if an object\nis moved to another filesystem, since mv(1) in effect copies the file to the other\nfilesystem  and  then  deletes  it from the original filesystem.)  In addition, an\nINIGNORED event will subsequently be generated for the watch descriptor.\n\nINMODIFY (+)\nFile was modified (e.g., write(2), truncate(2)).\n\nINMOVESELF\nWatched file/directory was itself moved.\n\nINMOVEDFROM (+)\nGenerated for the directory containing the old filename when a file is renamed.\n\nINMOVEDTO (+)\nGenerated for the directory containing the new filename when a file is renamed.\n\nINOPEN (*)\nFile or directory was opened.\n\nInotify monitoring is inode-based: when monitoring a file (but not when monitoring the direc‐\ntory  containing  a file), an event can be generated for activity on any link to the file (in\nthe same or a different directory).\n\nWhen monitoring a directory:\n\n*  the events marked above with an asterisk (*) can occur both for the directory  itself  and\nfor objects inside the directory; and\n\n*  the  events  marked  with a plus sign (+) occur only for objects inside the directory (not\nfor the directory itself).\n\nNote: when monitoring a directory, events are not generated for the files inside  the  direc‐\ntory  when the events are performed via a pathname (i.e., a link) that lies outside the moni‐\ntored directory.\n\nWhen events are generated for objects inside a watched directory, the name field in  the  re‐\nturned inotifyevent structure identifies the name of the file within the directory.\n\nThe  INALLEVENTS macro is defined as a bit mask of all of the above events.  This macro can\nbe used as the mask argument when calling inotifyaddwatch(2).\n\nTwo additional convenience macros are defined:\n\nINMOVE\nEquates to INMOVEDFROM | INMOVEDTO.\n\nINCLOSE\nEquates to INCLOSEWRITE | INCLOSENOWRITE.\n\nThe following further bits can be specified in mask when calling inotifyaddwatch(2):\n\nINDONTFOLLOW (since Linux 2.6.15)\nDon't dereference pathname if it is a symbolic link.\n\nINEXCLUNLINK (since Linux 2.6.36)\nBy default, when watching events on the children of a directory, events are gener‐\nated for children even after they have been unlinked from the directory.  This can\nresult in large numbers of uninteresting events for some  applications  (e.g.,  if\nwatching  /tmp,  in which many applications create temporary files whose names are\nimmediately unlinked).  Specifying INEXCLUNLINK changes the default behavior, so\nthat  events are not generated for children after they have been unlinked from the\nwatched directory.\n\nINMASKADD\nIf a watch instance already exists for  the  filesystem  object  corresponding  to\npathname,  add (OR) the events in mask to the watch mask (instead of replacing the\nmask); the error EINVAL results if INMASKCREATE is also specified.\n\nINONESHOT\nMonitor the filesystem object corresponding to pathname for one event, then remove\nfrom watch list.\n\nINONLYDIR (since Linux 2.6.15)\nWatch pathname only if it is a directory; the error ENOTDIR results if pathname is\nnot a directory.  Using this flag provides an application with a race-free way  of\nensuring that the monitored object is a directory.\n\nINMASKCREATE (since Linux 4.18)\nWatch  pathname  only  if it does not already have a watch associated with it; the\nerror EEXIST results if pathname is already being watched.\n\nUsing this flag provides an application with a way of ensuring that new watches do\nnot  modify existing ones.  This is useful because multiple paths may refer to the\nsame inode, and multiple calls to inotifyaddwatch(2) without this flag may clob‐\nber existing watch masks.\n\nThe following bits may be set in the mask field returned by read(2):\n\nINIGNORED\nWatch  was  removed  explicitly  (inotifyrmwatch(2))  or automatically (file was\ndeleted, or filesystem was unmounted).  See also BUGS.\n\nINISDIR\nSubject of this event is a directory.\n\nINQOVERFLOW\nEvent queue overflowed (wd is -1 for this event).\n\nINUNMOUNT\nFilesystem containing watched object was unmounted.  In  addition,  an  INIGNORED\nevent will subsequently be generated for the watch descriptor.\n"
                },
                {
                    "name": "Examples",
                    "content": "Suppose  an application is watching the directory dir and the file dir/myfile for all events.\nThe examples below show some events that will be generated for these two objects.\n\nfd = open(\"dir/myfile\", ORDWR);\nGenerates INOPEN events for both dir and dir/myfile.\n\nread(fd, buf, count);\nGenerates INACCESS events for both dir and dir/myfile.\n\nwrite(fd, buf, count);\nGenerates INMODIFY events for both dir and dir/myfile.\n\nfchmod(fd, mode);\nGenerates INATTRIB events for both dir and dir/myfile.\n\nclose(fd);\nGenerates INCLOSEWRITE events for both dir and dir/myfile.\n\nSuppose an application is watching the directories dir1 and dir2, and the  file  dir1/myfile.\nThe following examples show some events that may be generated.\n\nlink(\"dir1/myfile\", \"dir2/new\");\nGenerates an INATTRIB event for myfile and an INCREATE event for dir2.\n\nrename(\"dir1/myfile\", \"dir2/myfile\");\nGenerates  an  INMOVEDFROM event for dir1, an INMOVEDTO event for dir2, and an\nINMOVESELF event for myfile.  The INMOVEDFROM and INMOVEDTO events will have\nthe same cookie value.\n\nSuppose that dir1/xx and dir2/yy are (the only) links to the same file, and an application is\nwatching dir1, dir2, dir1/xx, and dir2/yy.  Executing the following calls in the order  given\nbelow will generate the following events:\n\nunlink(\"dir2/yy\");\nGenerates  an  INATTRIB  event  for  xx  (because  its link count changes) and an\nINDELETE event for dir2.\n\nunlink(\"dir1/xx\");\nGenerates  INATTRIB,  INDELETESELF,  and  INIGNORED  events  for  xx,  and  an\nINDELETE event for dir1.\n\nSuppose  an  application  is watching the directory dir and (the empty) directory dir/subdir.\nThe following examples show some events that may be generated.\n\nmkdir(\"dir/new\", mode);\nGenerates an INCREATE | INISDIR event for dir.\n\nrmdir(\"dir/subdir\");\nGenerates INDELETESELF and INIGNORED events for  subdir,  and  an  INDELETE  |\nINISDIR event for dir.\n"
                },
                {
                    "name": "/proc interfaces",
                    "content": "The  following  interfaces  can be used to limit the amount of kernel memory consumed by ino‐\ntify:\n\n/proc/sys/fs/inotify/maxqueuedevents\nThe value in this file is used when an application calls inotifyinit(2) to set an up‐\nper  limit on the number of events that can be queued to the corresponding inotify in‐\nstance.  Events in excess of this limit are dropped, but an INQOVERFLOW event is al‐\nways generated.\n\n/proc/sys/fs/inotify/maxuserinstances\nThis  specifies  an upper limit on the number of inotify instances that can be created\nper real user ID.\n\n/proc/sys/fs/inotify/maxuserwatches\nThis specifies an upper limit on the number of watches that can be  created  per  real\nuser ID.\n"
                }
            ]
        },
        "VERSIONS": {
            "content": "Inotify  was merged into the 2.6.13 Linux kernel.  The required library interfaces were added\nto glibc in version 2.4.  (INDONTFOLLOW, INMASKADD, and INONLYDIR were  added  in  glibc\nversion 2.5.)\n",
            "subsections": []
        },
        "CONFORMING TO": {
            "content": "The inotify API is Linux-specific.\n",
            "subsections": []
        },
        "NOTES": {
            "content": "Inotify  file  descriptors  can be monitored using select(2), poll(2), and epoll(7).  When an\nevent is available, the file descriptor indicates as readable.\n\nSince Linux 2.6.25, signal-driven I/O notification is available for inotify file descriptors;\nsee  the  discussion of FSETFL (for setting the OASYNC flag), FSETOWN, and FSETSIG in fc‐‐\nntl(2).  The siginfot structure (described in sigaction(2)) that is  passed  to  the  signal\nhandler  has  the  following  fields set: sifd is set to the inotify file descriptor number;\nsisigno is set to the signal number; sicode is  set  to  POLLIN;  and  POLLIN  is  set  in\nsiband.\n\nIf  successive  output  inotify  events produced on the inotify file descriptor are identical\n(same wd, mask, cookie, and name), then they are coalesced into a single event if  the  older\nevent  has  not  yet  been read (but see BUGS).  This reduces the amount of kernel memory re‐\nquired for the event queue, but also means that an application can't use inotify to  reliably\ncount file events.\n\nThe  events returned by reading from an inotify file descriptor form an ordered queue.  Thus,\nfor example, it is guaranteed that when renaming from one directory to another,  events  will\nbe produced in the correct order on the inotify file descriptor.\n\nThe  set  of  watch descriptors that is being monitored via an inotify file descriptor can be\nviewed via the entry for the inotify file descriptor in the process's /proc/[pid]/fdinfo  di‐\nrectory.  See proc(5) for further details.  The FIONREAD ioctl(2) returns the number of bytes\navailable to read from an inotify file descriptor.\n",
            "subsections": [
                {
                    "name": "Limitations and caveats",
                    "content": "The inotify API provides no information about the user or process that triggered the  inotify\nevent.   In particular, there is no easy way for a process that is monitoring events via ino‐\ntify to distinguish events that it triggers itself from those that  are  triggered  by  other\nprocesses.\n\nInotify  reports  only  events that a user-space program triggers through the filesystem API.\nAs a result, it does not catch remote events that occur on  network  filesystems.   (Applica‐\ntions  must  fall back to polling the filesystem to catch such events.)  Furthermore, various\npseudo-filesystems such as /proc, /sys, and /dev/pts are not monitorable with inotify.\n\nThe inotify API does not report file accesses and modifications that  may  occur  because  of\nmmap(2), msync(2), and munmap(2).\n\nThe  inotify  API identifies affected files by filename.  However, by the time an application\nprocesses an inotify event, the filename may already have been deleted or renamed.\n\nThe inotify API identifies events via watch descriptors.  It is the  application's  responsi‐\nbility  to  cache  a  mapping (if one is needed) between watch descriptors and pathnames.  Be\naware that directory renamings may affect multiple cached pathnames.\n\nInotify monitoring of directories is not recursive: to monitor subdirectories under a  direc‐\ntory,  additional watches must be created.  This can take a significant amount time for large\ndirectory trees.\n\nIf monitoring an entire directory subtree, and a new subdirectory is created in that tree  or\nan existing directory is renamed into that tree, be aware that by the time you create a watch\nfor the new subdirectory, new files (and subdirectories) may already exist inside the  subdi‐\nrectory.   Therefore, you may want to scan the contents of the subdirectory immediately after\nadding the watch (and, if desired, recursively add watches for  any  subdirectories  that  it\ncontains).\n\nNote  that the event queue can overflow.  In this case, events are lost.  Robust applications\nshould handle the possibility of lost events gracefully.  For example, it may be necessary to\nrebuild  part or all of the application cache.  (One simple, but possibly expensive, approach\nis to close the inotify file descriptor, empty the cache, create a new inotify file  descrip‐\ntor, and then re-create watches and cache entries for the objects to be monitored.)\n\nIf  a  filesystem  is  mounted on top of a monitored directory, no event is generated, and no\nevents are generated for objects immediately under the new mount point.  If the filesystem is\nsubsequently  unmounted,  events will subsequently be generated for the directory and the ob‐\njects it contains.\n"
                },
                {
                    "name": "Dealing with rename() events",
                    "content": "As noted above, the INMOVEDFROM and INMOVEDTO event pair that is generated  by  rename(2)\ncan  be  matched  up  via  their shared cookie value.  However, the task of matching has some\nchallenges.\n\nThese two events are usually consecutive in the event stream available when reading from  the\ninotify  file  descriptor.  However, this is not guaranteed.  If multiple processes are trig‐\ngering events for monitored objects, then (on rare occasions) an arbitrary  number  of  other\nevents  may  appear between the INMOVEDFROM and INMOVEDTO events.  Furthermore, it is not\nguaranteed that the event pair is atomically inserted into the queue: there may  be  a  brief\ninterval where the INMOVEDFROM has appeared, but the INMOVEDTO has not.\n\nMatching  up  the INMOVEDFROM and INMOVEDTO event pair generated by rename(2) is thus in‐\nherently racy.  (Don't forget that if an object is renamed outside of a monitored  directory,\nthere  may  not even be an INMOVEDTO event.)  Heuristic approaches (e.g., assume the events\nare always consecutive) can be used to ensure a match in most cases, but will inevitably miss\nsome  cases,  causing the application to perceive the INMOVEDFROM and INMOVEDTO events as\nbeing unrelated.  If watch descriptors are destroyed and re-created as a result,  then  those\nwatch  descriptors  will  be  inconsistent  with the watch descriptors in any pending events.\n(Re-creating the inotify file descriptor and rebuilding the cache may be useful to deal  with\nthis scenario.)\n\nApplications  should also allow for the possibility that the INMOVEDFROM event was the last\nevent that could fit in the buffer returned by the current call to read(2), and the  accompa‐\nnying  INMOVEDTO event might be fetched only on the next read(2), which should be done with\na (small) timeout to allow for the fact that insertion of the INMOVEDFROM-INMOVEDTO event\npair is not atomic, and also the possibility that there may not be any INMOVEDTO event.\n"
                }
            ]
        },
        "BUGS": {
            "content": "Before  Linux  3.19, fallocate(2) did not create any inotify events.  Since Linux 3.19, calls\nto fallocate(2) generate INMODIFY events.\n\nIn kernels before 2.6.16, the INONESHOT mask flag does not work.\n\nAs originally designed and implemented, the INONESHOT flag did not cause an INIGNORED event\nto be generated when the watch was dropped after one event.  However, as an unintended effect\nof other changes, since Linux 2.6.36, an INIGNORED event is generated in this case.\n\nBefore kernel 2.6.25, the kernel code that was  intended  to  coalesce  successive  identical\nevents  (i.e., the two most recent events could potentially be coalesced if the older had not\nyet been read) instead checked if the most recent event could be coalesced  with  the  oldest\nunread event.\n\nWhen a watch descriptor is removed by calling inotifyrmwatch(2) (or because a watch file is\ndeleted or the filesystem that contains it is unmounted), any pending unread events for  that\nwatch  descriptor  remain available to read.  As watch descriptors are subsequently allocated\nwith inotifyaddwatch(2), the kernel cycles through the range of possible watch  descriptors\n(0  to  INTMAX) incrementally.  When allocating a free watch descriptor, no check is made to\nsee whether that watch descriptor number has any pending unread events in the inotify  queue.\nThus,  it  can  happen that a watch descriptor is reallocated even when pending unread events\nexist for a previous incarnation of that watch descriptor number, with the  result  that  the\napplication  might then read those events and interpret them as belonging to the file associ‐\nated with the newly recycled watch descriptor.  In practice, the likelihood of  hitting  this\nbug  may  be extremely low, since it requires that an application cycle through INTMAX watch\ndescriptors, release a watch descriptor while leaving unread events for that watch descriptor\nin  the  queue,  and  then recycle that watch descriptor.  For this reason, and because there\nhave been no reports of the bug occurring in real-world applications, as of  Linux  3.15,  no\nkernel changes have yet been made to eliminate this possible bug.\n",
            "subsections": []
        },
        "EXAMPLES": {
            "content": "The  following  program  demonstrates the usage of the inotify API.  It marks the directories\npassed as a command-line arguments and waits for events of  type  INOPEN,  INCLOSENOWRITE,\nand INCLOSEWRITE.\n\nThe  following output was recorded while editing the file /home/user/temp/foo and listing di‐\nrectory /tmp.  Before the file and the directory were opened, INOPEN events occurred.  After\nthe  file  was  closed, an INCLOSEWRITE event occurred.  After the directory was closed, an\nINCLOSENOWRITE event occurred.  Execution of the program ended when the  user  pressed  the\nENTER key.\n",
            "subsections": [
                {
                    "name": "Example output",
                    "content": "$ ./a.out /tmp /home/user/temp\nPress enter key to terminate.\nListening for events.\nINOPEN: /home/user/temp/foo [file]\nINCLOSEWRITE: /home/user/temp/foo [file]\nINOPEN: /tmp/ [directory]\nINCLOSENOWRITE: /tmp/ [directory]\n\nListening for events stopped.\n"
                },
                {
                    "name": "Program source",
                    "content": "#include <errno.h>\n#include <poll.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/inotify.h>\n#include <unistd.h>\n#include <string.h>\n\n/* Read all available inotify events from the file descriptor 'fd'.\nwd is the table of watch descriptors for the directories in argv.\nargc is the length of wd and argv.\nargv is the list of watched directories.\nEntry 0 of wd and argv is unused. */\n\nstatic void\nhandleevents(int fd, int *wd, int argc, char* argv[])\n{\n/* Some systems cannot read integer variables if they are not\nproperly aligned. On other systems, incorrect alignment may\ndecrease performance. Hence, the buffer used for reading from\nthe inotify file descriptor should have the same alignment as\nstruct inotifyevent. */\n\nchar buf[4096]\nattribute ((aligned(alignof(struct inotifyevent))));\nconst struct inotifyevent *event;\nssizet len;\n\n/* Loop while events can be read from inotify file descriptor. */\n\nfor (;;) {\n\n/* Read some events. */\n\nlen = read(fd, buf, sizeof(buf));\nif (len == -1 && errno != EAGAIN) {\nperror(\"read\");\nexit(EXITFAILURE);\n}\n\n/* If the nonblocking read() found no events to read, then\nit returns -1 with errno set to EAGAIN. In that case,\nwe exit the loop. */\n\nif (len <= 0)\nbreak;\n\n/* Loop over all events in the buffer */\n\nfor (char *ptr = buf; ptr < buf + len;\nptr += sizeof(struct inotifyevent) + event->len) {\n\nevent = (const struct inotifyevent *) ptr;\n\n/* Print event type */\n\nif (event->mask & INOPEN)\nprintf(\"INOPEN: \");\nif (event->mask & INCLOSENOWRITE)\nprintf(\"INCLOSENOWRITE: \");\nif (event->mask & INCLOSEWRITE)\nprintf(\"INCLOSEWRITE: \");\n\n/* Print the name of the watched directory */\n\nfor (int i = 1; i < argc; ++i) {\nif (wd[i] == event->wd) {\nprintf(\"%s/\", argv[i]);\nbreak;\n}\n}\n\n/* Print the name of the file */\n\nif (event->len)\nprintf(\"%s\", event->name);\n\n/* Print type of filesystem object */\n\nif (event->mask & INISDIR)\nprintf(\" [directory]\\n\");\nelse\nprintf(\" [file]\\n\");\n}\n}\n}\n\nint\nmain(int argc, char* argv[])\n{\nchar buf;\nint fd, i, pollnum;\nint *wd;\nnfdst nfds;\nstruct pollfd fds[2];\n\nif (argc < 2) {\nprintf(\"Usage: %s PATH [PATH ...]\\n\", argv[0]);\nexit(EXITFAILURE);\n}\n\nprintf(\"Press ENTER key to terminate.\\n\");\n\n/* Create the file descriptor for accessing the inotify API */\n\nfd = inotifyinit1(INNONBLOCK);\nif (fd == -1) {\nperror(\"inotifyinit1\");\nexit(EXITFAILURE);\n}\n\n/* Allocate memory for watch descriptors */\n\nwd = calloc(argc, sizeof(int));\nif (wd == NULL) {\nperror(\"calloc\");\nexit(EXITFAILURE);\n}\n\n/* Mark directories for events\n- file was opened\n- file was closed */\n\nfor (i = 1; i < argc; i++) {\nwd[i] = inotifyaddwatch(fd, argv[i],\nINOPEN | INCLOSE);\nif (wd[i] == -1) {\nfprintf(stderr, \"Cannot watch '%s': %s\\n\",\nargv[i], strerror(errno));\nexit(EXITFAILURE);\n}\n}\n\n/* Prepare for polling */\n\nnfds = 2;\n\n/* Console input */\n\nfds[0].fd = STDINFILENO;\nfds[0].events = POLLIN;\n\n/* Inotify input */\n\nfds[1].fd = fd;\nfds[1].events = POLLIN;\n\n/* Wait for events and/or terminal input */\n\nprintf(\"Listening for events.\\n\");\nwhile (1) {\npollnum = poll(fds, nfds, -1);\nif (pollnum == -1) {\nif (errno == EINTR)\ncontinue;\nperror(\"poll\");\nexit(EXITFAILURE);\n}\n\nif (pollnum > 0) {\n\nif (fds[0].revents & POLLIN) {\n\n/* Console input is available. Empty stdin and quit */\n\nwhile (read(STDINFILENO, &buf, 1) > 0 && buf != '\\n')\ncontinue;\nbreak;\n}\n\nif (fds[1].revents & POLLIN) {\n\n/* Inotify events are available */\n\nhandleevents(fd, wd, argc, argv);\n}\n}\n}\n\nprintf(\"Listening for events stopped.\\n\");\n\n/* Close inotify file descriptor */\n\nclose(fd);\n\nfree(wd);\nexit(EXITSUCCESS);\n}\n"
                }
            ]
        },
        "SEE ALSO": {
            "content": "inotifywait(1), inotifywatch(1), inotifyaddwatch(2), inotifyinit(2), inotifyinit1(2), in‐‐\notifyrmwatch(2), read(2), stat(2), fanotify(7)\n\nDocumentation/filesystems/inotify.txt in the Linux kernel source tree\n",
            "subsections": []
        },
        "COLOPHON": {
            "content": "This page is part of release 5.10 of the Linux  man-pages  project.   A  description  of  the\nproject,  information about reporting bugs, and the latest version of this page, can be found\nat https://www.kernel.org/doc/man-pages/.\n\n\n\nLinux                                        2020-11-01                                   INOTIFY(7)",
            "subsections": []
        }
    },
    "summary": "inotify - monitoring filesystem events",
    "flags": [],
    "examples": [
        "The  following  program  demonstrates the usage of the inotify API.  It marks the directories",
        "passed as a command-line arguments and waits for events of  type  INOPEN,  INCLOSENOWRITE,",
        "and INCLOSEWRITE.",
        "The  following output was recorded while editing the file /home/user/temp/foo and listing di‐",
        "rectory /tmp.  Before the file and the directory were opened, INOPEN events occurred.  After",
        "the  file  was  closed, an INCLOSEWRITE event occurred.  After the directory was closed, an",
        "INCLOSENOWRITE event occurred.  Execution of the program ended when the  user  pressed  the",
        "ENTER key.",
        "$ ./a.out /tmp /home/user/temp",
        "Press enter key to terminate.",
        "Listening for events.",
        "INOPEN: /home/user/temp/foo [file]",
        "INCLOSEWRITE: /home/user/temp/foo [file]",
        "INOPEN: /tmp/ [directory]",
        "INCLOSENOWRITE: /tmp/ [directory]",
        "Listening for events stopped.",
        "#include <errno.h>",
        "#include <poll.h>",
        "#include <stdio.h>",
        "#include <stdlib.h>",
        "#include <sys/inotify.h>",
        "#include <unistd.h>",
        "#include <string.h>",
        "/* Read all available inotify events from the file descriptor 'fd'.",
        "wd is the table of watch descriptors for the directories in argv.",
        "argc is the length of wd and argv.",
        "argv is the list of watched directories.",
        "Entry 0 of wd and argv is unused. */",
        "static void",
        "handleevents(int fd, int *wd, int argc, char* argv[])",
        "/* Some systems cannot read integer variables if they are not",
        "properly aligned. On other systems, incorrect alignment may",
        "decrease performance. Hence, the buffer used for reading from",
        "the inotify file descriptor should have the same alignment as",
        "struct inotifyevent. */",
        "char buf[4096]",
        "attribute ((aligned(alignof(struct inotifyevent))));",
        "const struct inotifyevent *event;",
        "ssizet len;",
        "/* Loop while events can be read from inotify file descriptor. */",
        "for (;;) {",
        "/* Read some events. */",
        "len = read(fd, buf, sizeof(buf));",
        "if (len == -1 && errno != EAGAIN) {",
        "perror(\"read\");",
        "exit(EXITFAILURE);",
        "/* If the nonblocking read() found no events to read, then",
        "it returns -1 with errno set to EAGAIN. In that case,",
        "we exit the loop. */",
        "if (len <= 0)",
        "break;",
        "/* Loop over all events in the buffer */",
        "for (char *ptr = buf; ptr < buf + len;",
        "ptr += sizeof(struct inotifyevent) + event->len) {",
        "event = (const struct inotifyevent *) ptr;",
        "/* Print event type */",
        "if (event->mask & INOPEN)",
        "printf(\"INOPEN: \");",
        "if (event->mask & INCLOSENOWRITE)",
        "printf(\"INCLOSENOWRITE: \");",
        "if (event->mask & INCLOSEWRITE)",
        "printf(\"INCLOSEWRITE: \");",
        "/* Print the name of the watched directory */",
        "for (int i = 1; i < argc; ++i) {",
        "if (wd[i] == event->wd) {",
        "printf(\"%s/\", argv[i]);",
        "break;",
        "/* Print the name of the file */",
        "if (event->len)",
        "printf(\"%s\", event->name);",
        "/* Print type of filesystem object */",
        "if (event->mask & INISDIR)",
        "printf(\" [directory]\\n\");",
        "else",
        "printf(\" [file]\\n\");",
        "int",
        "main(int argc, char* argv[])",
        "char buf;",
        "int fd, i, pollnum;",
        "int *wd;",
        "nfdst nfds;",
        "struct pollfd fds[2];",
        "if (argc < 2) {",
        "printf(\"Usage: %s PATH [PATH ...]\\n\", argv[0]);",
        "exit(EXITFAILURE);",
        "printf(\"Press ENTER key to terminate.\\n\");",
        "/* Create the file descriptor for accessing the inotify API */",
        "fd = inotifyinit1(INNONBLOCK);",
        "if (fd == -1) {",
        "perror(\"inotifyinit1\");",
        "exit(EXITFAILURE);",
        "/* Allocate memory for watch descriptors */",
        "wd = calloc(argc, sizeof(int));",
        "if (wd == NULL) {",
        "perror(\"calloc\");",
        "exit(EXITFAILURE);",
        "/* Mark directories for events",
        "- file was opened",
        "- file was closed */",
        "for (i = 1; i < argc; i++) {",
        "wd[i] = inotifyaddwatch(fd, argv[i],",
        "INOPEN | INCLOSE);",
        "if (wd[i] == -1) {",
        "fprintf(stderr, \"Cannot watch '%s': %s\\n\",",
        "argv[i], strerror(errno));",
        "exit(EXITFAILURE);",
        "/* Prepare for polling */",
        "nfds = 2;",
        "/* Console input */",
        "fds[0].fd = STDINFILENO;",
        "fds[0].events = POLLIN;",
        "/* Inotify input */",
        "fds[1].fd = fd;",
        "fds[1].events = POLLIN;",
        "/* Wait for events and/or terminal input */",
        "printf(\"Listening for events.\\n\");",
        "while (1) {",
        "pollnum = poll(fds, nfds, -1);",
        "if (pollnum == -1) {",
        "if (errno == EINTR)",
        "continue;",
        "perror(\"poll\");",
        "exit(EXITFAILURE);",
        "if (pollnum > 0) {",
        "if (fds[0].revents & POLLIN) {",
        "/* Console input is available. Empty stdin and quit */",
        "while (read(STDINFILENO, &buf, 1) > 0 && buf != '\\n')",
        "continue;",
        "break;",
        "if (fds[1].revents & POLLIN) {",
        "/* Inotify events are available */",
        "handleevents(fd, wd, argc, argv);",
        "printf(\"Listening for events stopped.\\n\");",
        "/* Close inotify file descriptor */",
        "close(fd);",
        "free(wd);",
        "exit(EXITSUCCESS);"
    ],
    "see_also": [
        {
            "name": "inotifywait",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/inotifywait/1/json"
        },
        {
            "name": "inotifywatch",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/inotifywatch/1/json"
        },
        {
            "name": "inotifyaddwatch",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/inotifyaddwatch/2/json"
        },
        {
            "name": "inotifyinit",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/inotifyinit/2/json"
        },
        {
            "name": "inotifyinit1",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/inotifyinit1/2/json"
        },
        {
            "name": "otifyrmwatch",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/otifyrmwatch/2/json"
        },
        {
            "name": "read",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/read/2/json"
        },
        {
            "name": "stat",
            "section": "2",
            "url": "https://www.chedong.com/phpMan.php/man/stat/2/json"
        },
        {
            "name": "fanotify",
            "section": "7",
            "url": "https://www.chedong.com/phpMan.php/man/fanotify/7/json"
        }
    ]
}