inotify(7) Miscellaneous Information Manual inotify(7) inotify - inotify . . inotify , . : o inotify_init(2) inotify , inotify. inotify_init1(2) inotify_init(2), flags, . o inotify_add_watch(2) << >>, inotify. ( (watch)) , , . inotify_add_watch(2) , . << >> -- , inotify_add_watch(2) . o , , inotify read(2) ( ). o inotify_rm_watch(2) inotify. o ( close(2)) , inotify, ; . , inotify . , , , . , . inotify , , (read(2)) inotify. , , , read(2) , , ( ; EINTR, signal(7)). read(2) : struct inotify_event { int wd; /* */ uint32_t mask; /* , */ uint32_t cookie; /* cookie, ( rename(2)) */ uint32_t len; /* name */ char name[]; /* , null */ }; wd , . , inotify_add_watch(2). mask , ( ). cookie -- , . IN_MOVED_FROM IN_MOVED_TO . cookie 0. The name field is present only when an event is returned for a file inside a watched directory; it identifies the filename within the watched directory. This filename is null-terminated, and may include further null bytes ('\0') to align subsequent reads to a suitable address boundary. len name, null; inotify_event sizeof(struct inotify_event)+len. The behavior when the buffer given to read(2) is too small to return information about the next event depends on the kernel version: before Linux 2.6.21, read(2) returns 0; since Linux 2.6.21, read(2) fails with the error EINVAL. Specifying a buffer of size sizeof(struct inotify_event) + NAME_MAX + 1 , , . inotify inotify_add_watch(2) mask mask inotify_event, inotify, , inotify. mask inotify_add_watch(2) mask, read(2): IN_ACCESS (+) (, read(2), execve(2)). IN_ATTRIB (*) Metadata changed--for example, permissions (e.g., chmod(2)), timestamps (e.g., utimensat(2)), extended attributes (setxattr(2)), link count (since Linux 2.6.25; e.g., for the target of link(2) and for unlink(2)), and user/group ID (e.g., chown(2)). IN_CLOSE_WRITE (+) , , . IN_CLOSE_NOWRITE (*) , , . IN_CREATE (+) / (, open(2) O_CREAT, mkdir(2), link(2), symlink(2), bind(2) UNIX). IN_DELETE (+) /. IN_DELETE_SELF / ( , , mv(1), , ). IN_IGNORED . IN_MODIFY (+) (, write(2), truncate(2)). IN_MOVE_SELF / . IN_MOVED_FROM (+) , . IN_MOVED_TO (+) , . IN_OPEN (*) . inotify inode: ( , ) ( ). : o , (*), , ; o , (+), ( ). : , (. ., ), . , name, inotify_event, . IN_ALL_EVENTS . mask inotify_add_watch(2). , : IN_MOVE , IN_MOVED_FROM | IN_MOVED_TO. IN_CLOSE , IN_CLOSE_WRITE | IN_CLOSE_NOWRITE. , inotify_add_watch(2) mask : IN_DONT_FOLLOW ( Linux 2.6.15) pathname, . IN_EXCL_UNLINK ( Linux 2.6.36) , , , . (, /tmp, ). IN_EXCL_UNLINK , . IN_MASK_ADD pathname, (OR) mask ( ); IN_MASK_CREATE, EINVAL. IN_ONESHOT , pathname , . IN_ONLYDIR ( Linux 2.6.15) pathname, ; pathname , ENOTDIR. , -- . IN_MASK_CREATE ( Linux 4.18) pathname , ; pathname, EEXIST. , . , , inotify_add_watch(2) . mask read(2): IN_IGNORED (inotify_rm_watch(2)) ( ). . IN_ISDIR -- . IN_Q_OVERFLOW ( wd -1). IN_UNMOUNT , , . , IN_IGNORED . , dir dir/myfile. , . fd = open("dir/myfile", O_RDWR); IN_OPEN dir, dir/myfile. read(fd, buf, count); IN_ACCESS dir, dir/myfile. write(fd, buf, count); IN_MODIFY dir, dir/myfile. fchmod(fd, mode); IN_ATTRIB dir, dir/myfile. close(fd); IN_CLOSE_WRITE dir, dir/myfile. , dir1 dir2 dir1/myfile. , . link("dir1/myfile", "dir2/new"); IN_ATTRIB myfile IN_CREATE dir2. rename("dir1/myfile", "dir2/myfile"); IN_MOVED_FROM dir1, IN_MOVED_TO dir2 IN_MOVE_SELF myfile. IN_MOVED_FROM IN_MOVED_TO cookie. , dir1/xx dir2/yy dir1, dir2, dir1/xx dir2/yy. , , : unlink("dir2/yy"); IN_ATTRIB xx ( ) IN_DELETE dir2. unlink("dir1/xx"); IN_ATTRIB, IN_DELETE_SELF IN_IGNORED xx IN_DELETE dir1. , dir dir/subdir. , . mkdir("dir/new", mode); IN_CREATE | IN_ISDIR dir. rmdir("dir/subdir"); IN_DELETE_SELF IN_IGNORED subdir IN_DELETE | IN_ISDIR dir. /proc inotify , : /proc/sys/fs/inotify/max_queued_events inotify_init(2) , inotify. , , , IN_Q_OVERFLOW . /proc/sys/fs/inotify/max_user_instances inotify, . /proc/sys/fs/inotify/max_user_watches , . Linux. Inotify was merged into Linux 2.6.13. The required library interfaces were added in glibc 2.4. (IN_DONT_FOLLOW, IN_MASK_ADD, and IN_ONLYDIR were added in glibc 2.5.) inotify select(2), poll(2), epoll(7). , . Linux 2.6.25, inotify - ; F_SETFL ( O_ASYNC), F_SETOWN F_SETSIG fcntl(2). siginfo_t ( sigaction(2)), , : si_fd inotify; si_signo ; si_code POLL_IN; si_band POLLIN. inotify, inotify, ( wd, mask, cookie name), , ( ). , , inotify . , inotify, . , , , , inotify . The set of watch descriptors that is being monitored via an inotify file descriptor can be viewed via the entry for the inotify file descriptor in the process's /proc/pid/fdinfo directory. See proc(5) for further details. The FIONREAD ioctl(2) returns the number of bytes available to read from an inotify file descriptor. inotify , - . , , inotify, , - - . Inotify , - , . , , ( ). , - , /proc, /sys /dev/pts, inotify. inotify , - mmap(2), msync(2) munmap(2). inotify . , inotify, . inotify . ( ) . , . inotify : , . . , , , ( ). (, , , ). , . . . , ( , , , , inotify, , inotify ). , , , . , . rename() , IN_MOVED_FROM IN_MOVED_TO, rename(2), cookie. , . , , , inotify. , . , ( ) IN_MOVED_FROM IN_MOVED_TO. , , : , IN_MOVED_FROM , IN_MOVED_TO . IN_MOVED_FROM IN_MOVED_TO , rename(2), , ( , , IN_MOVED_TO). (, ), , , IN_MOVED_FROM IN_MOVED_TO . , ( inotify ). Applications should also allow for the possibility that the IN_MOVED_FROM event was the last event that could fit in the buffer returned by the current call to read(2), and the accompanying IN_MOVED_TO event might be fetched only on the next read(2), which should be done with a (small) timeout to allow for the fact that insertion of the IN_MOVED_FROM+IN_MOVED_TO event pair is not atomic, and also the possibility that there may not be any IN_MOVED_TO event. Linux 3.19, fallocate(2) inotify. Linux 3.19, fallocate(2) IN_MODIFY. Before Linux 2.6.16, the IN_ONESHOT mask flag does not work. IN_ONESHOT IN_IGNORED, . , , Linux 2.6.36, IN_IGNORED . Before Linux 2.6.25, the kernel code that was intended to coalesce successive identical events (i.e., the two most recent events could potentially be coalesced if the older had not yet been read) instead checked if the most recent event could be coalesced with the oldest unread event. When a watch descriptor is removed by calling inotify_rm_watch(2) (or because a watch file is deleted or the filesystem that contains it is unmounted), any pending unread events for that watch descriptor remain available to read. As watch descriptors are subsequently allocated with inotify_add_watch(2), the kernel cycles through the range of possible watch descriptors (1 to INT_MAX) incrementally. When allocating a free watch descriptor, no check is made to see whether that watch descriptor number has any pending unread events in the inotify queue. Thus, it can happen that a watch descriptor is reallocated even when pending unread events exist for a previous incarnation of that watch descriptor number, with the result that the application might then read those events and interpret them as belonging to the file associated with the newly recycled watch descriptor. In practice, the likelihood of hitting this bug may be extremely low, since it requires that an application cycle through INT_MAX watch descriptors, release a watch descriptor while leaving unread events for that watch descriptor in the queue, and then recycle that watch descriptor. For this reason, and because there have been no reports of the bug occurring in real-world applications, as of Linux 3.15, no kernel changes have yet been made to eliminate this possible bug. 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 IN_OPEN, IN_CLOSE_NOWRITE, and IN_CLOSE_WRITE. /home/user/temp/foo /tmp. IN_OPEN. IN_CLOSE_WRITE. IN_CLOSE_NOWRITE. ENTER. $ ./a.out /tmp /home/user/temp Press enter key to terminate. Listening for events. IN_OPEN: /home/user/temp/foo [file] IN_CLOSE_WRITE: /home/user/temp/foo [file] IN_OPEN: /tmp/ [directory] IN_CLOSE_NOWRITE: /tmp/ [directory] Listening for events stopped. #include #include #include #include #include #include #include /* 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 handle_events(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 inotify_event. */ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *event; ssize_t 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(EXIT_FAILURE); } /* 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 inotify_event) + event->len) { event = (const struct inotify_event *) ptr; /* Print event type. */ if (event->mask & IN_OPEN) printf("IN_OPEN: "); if (event->mask & IN_CLOSE_NOWRITE) printf("IN_CLOSE_NOWRITE: "); if (event->mask & IN_CLOSE_WRITE) printf("IN_CLOSE_WRITE: "); /* Print the name of the watched directory. */ for (size_t 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 & IN_ISDIR) printf(" [directory]\n"); else printf(" [file]\n"); } } } int main(int argc, char* argv[]) { char buf; int fd, i, poll_num; int *wd; nfds_t nfds; struct pollfd fds[2]; if (argc < 2) { printf("Usage: %s PATH [PATH ...]\n", argv[0]); exit(EXIT_FAILURE); } printf("Press ENTER key to terminate.\n"); /* Create the file descriptor for accessing the inotify API. */ fd = inotify_init1(IN_NONBLOCK); if (fd == -1) { perror("inotify_init1"); exit(EXIT_FAILURE); } /* Allocate memory for watch descriptors. */ wd = calloc(argc, sizeof(int)); if (wd == NULL) { perror("calloc"); exit(EXIT_FAILURE); } /* Mark directories for events - file was opened - file was closed */ for (i = 1; i < argc; i++) { wd[i] = inotify_add_watch(fd, argv[i], IN_OPEN | IN_CLOSE); if (wd[i] == -1) { fprintf(stderr, "Cannot watch '%s': %s\n", argv[i], strerror(errno)); exit(EXIT_FAILURE); } } /* Prepare for polling. */ nfds = 2; fds[0].fd = STDIN_FILENO; /* Console input */ fds[0].events = POLLIN; fds[1].fd = fd; /* Inotify input */ fds[1].events = POLLIN; /* Wait for events and/or terminal input. */ printf("Listening for events.\n"); while (1) { poll_num = poll(fds, nfds, -1); if (poll_num == -1) { if (errno == EINTR) continue; perror("poll"); exit(EXIT_FAILURE); } if (poll_num > 0) { if (fds[0].revents & POLLIN) { /* Console input is available. Empty stdin and quit. */ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n') continue; break; } if (fds[1].revents & POLLIN) { /* Inotify events are available. */ handle_events(fd, wd, argc, argv); } } } printf("Listening for events stopped.\n"); /* Close inotify file descriptor. */ close(fd); free(wd); exit(EXIT_SUCCESS); } inotifywait(1), inotifywatch(1), inotify_add_watch(2), inotify_init(2), inotify_init1(2), inotify_rm_watch(2), read(2), stat(2), fanotify(7) Documentation/filesystems/inotify.txt Linux () Azamat Hackimov , Dmitriy S. Seregin , Yuri Kozlov ; GNU (GNU General Public License - GPL, 3 ) , - . - , , () () () <>. Linux 6.9.1 15 2024 . inotify(7)