.\" -*- coding: UTF-8 -*- .\" Copyright (C) 2006, 2014 Michael Kerrisk .\" Copyright (C) 2014 Heinrich Schuchardt .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH inotify 7 "15 июня 2024 г." "Справочные страницы Linux 6.9.1" .SH ИМЯ inotify \- наблюдает за событиями файловой системы .SH ОПИСАНИЕ Программный интерфейс \fIinotify\fP предоставляет механизм для слежения за событиями в файловой системе. Его можно использовать для слежения за отдельными файлами или каталогами. При слежении за каталогами inotify возвращает события как для самого каталога, так и для файлов внутри каталога. .P В программный интерфейс входят следующие системные вызовы: .IP \[bu] 3 Вызов \fBinotify_init\fP(2) создаёт экземпляр inotify и возвращает файловый дескриптор, ссылающийся на экземпляр inotify. Более новый \fBinotify_init1\fP(2) подобен \fBinotify_init\fP(2), но имеет аргумент \fIflags\fP, который предоставляет доступ к некоторым дополнительным возможностям. .IP \[bu] Вызов \fBinotify_add_watch\fP(2) изменяет «список наблюдения», связанный с экземпляром inotify. Каждый элемент (сторожок (watch)) в списке задаёт путь к файлу или каталогу и некоторый набор событий, которые ядро должно отслеживать для файла, на который указывает этот путь. Вызов \fBinotify_add_watch\fP(2) или создаёт новый сторожок, или изменяет существующий. Каждый сторожок имеет уникальный «дескриптор сторожка» — целое число, возвращаемое \fBinotify_add_watch\fP(2) при создании сторожка. .IP \[bu] При возникновении событий с отслеживаемыми файлами и каталогами, эти события становятся доступны приложению в виде структурированных данных, которые можно прочитать из файлового дескриптора inotify с помощью \fBread\fP(2) (смотрите ниже). .IP \[bu] Вызов \fBinotify_rm_watch\fP(2) удаляет элемент из списка наблюдения inotify. .IP \[bu] При закрытии (с помощью \fBclose\fP(2)) файловых дескрипторов, ссылающихся на экземпляр inotify, этот объект и его ресурсы освобождаются для повторного использования ядром; все связанные сторожки освобождаются автоматически. .P При корректном программировании, приложение может эффективно использовать inotify для слежения и кэширования состояния набора объектов файловой системы. Однако, в тщательно проработанных приложениях нужно предполагать наличие ошибок в логике слежения или состязательности, описанных далее, которые могут приводить к рассогласованности кэша с состоянием файловой системы. Вероятно, лучше сделать некоторую проверку и перестроить кэш при обнаружении рассогласованности. .SS "Чтение событий из файлового дескриптора inotify" Чтобы определить, что события произошли, приложение должно прочитать (\fBread\fP(2)) файловый дескриптор inotify. Если событий не было, то предполагая, что это блокирующий файловый дескриптор, вызов \fBread\fP(2) заблокирует работу до возникновения, по крайней мере, одного события (если не будет прерван сигналом; в этом случае вызов завершается с ошибкой \fBEINTR\fP, смотрите \fBsignal\fP(7)). .P При успешном выполнении \fBread\fP(2) возвращает буфер с одной или более структурами следующего вида: .P .in +4n .EX .\" FIXME . The type of the 'wd' field should probably be "int32_t". .\" I submitted a patch to fix this. See the LKML thread .\" "[patch] Fix type errors in inotify interfaces", 18 Nov 2008 .\" glibc bug filed: https://www.sourceware.org/bugzilla/show_bug.cgi?id=7040 struct inotify_event { int wd; /* дескриптор наблюдаемого */ uint32_t mask; /* маска, описывающая событие */ uint32_t cookie; /* уникальный cookie, связывающий относящиеся друг к другу события (для rename(2)) */ uint32_t len; /* размер поля \fIname\fP */ char name[]; /* необязательное имя, завершающееся null */ }; .EE .in .P В \fIwd\fP указывается сторожок, к которому относится событие. Это один из дескрипторов сторожка, полученный из вызова \fBinotify_add_watch\fP(2). .P В \fImask\fP содержатся биты, описывающие возникшее событие (смотрите ниже). .P Значение \fIcookie\fP — это уникальное целое, которое объединяет связанные события. В настоящее время используется только для событий переименования и позволяет приложению объединить возвращаемые \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP в пару событий. Для остальных типов событий значение \fIcookie\fP равно 0. .P The \fIname\fP 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 (\[aq]\[rs]0\[aq]) to align subsequent reads to a suitable address boundary. .P Поле \fIlen\fP содержит количество всех байт в \fIname\fP, включая байты null; длина каждой структуры \fIinotify_event\fP равна \fIsizeof(struct inotify_event)+len\fP. .P The behavior when the buffer given to \fBread\fP(2) is too small to return information about the next event depends on the kernel version: before Linux 2.6.21, \fBread\fP(2) returns 0; since Linux 2.6.21, \fBread\fP(2) fails with the error \fBEINVAL\fP. Specifying a buffer of size .P .in +4n .EX sizeof(struct inotify_event) + NAME_MAX + 1 .EE .in .P будет достаточно для чтения, по крайней мере, одного события. .SS "События inotify" В аргументе \fBinotify_add_watch\fP(2) \fImask\fP и поле \fImask\fP структуры \fIinotify_event\fP, возвращаемых при чтении файлового дескриптора inotify, содержатся битовые маски, определяющие события inotify. Следующие биты могут быть заданы в \fImask\fP при вызове \fBinotify_add_watch\fP(2) и возвращены в поле \fImask\fP, возвращаемом \fBread\fP(2): .RS 4 .TP \fBIN_ACCESS\fP (+) Был произведён доступ к файлу (например, \fBread\fP(2), \fBexecve\fP(2)). .TP \fBIN_ATTRIB\fP (*) .\" FIXME . .\" Events do not occur for link count changes on a file inside a monitored .\" directory. This differs from other metadata changes for files inside .\" a monitored directory. Metadata changed\[em]for example, permissions (e.g., \fBchmod\fP(2)), timestamps (e.g., \fButimensat\fP(2)), extended attributes (\fBsetxattr\fP(2)), link count (since Linux 2.6.25; e.g., for the target of \fBlink\fP(2) and for \fBunlink\fP(2)), and user/group ID (e.g., \fBchown\fP(2)). .TP \fBIN_CLOSE_WRITE\fP (+) Файл, открытый для записи, был закрыт. .TP \fBIN_CLOSE_NOWRITE\fP (*) Файл или каталог, не открытый для записи, был закрыт. .TP \fBIN_CREATE\fP (+) В отслеживаемом каталоге был создан файл/каталог (например, \fBopen\fP(2) \fBO_CREAT\fP, \fBmkdir\fP(2), \fBlink\fP(2), \fBsymlink\fP(2), \fBbind\fP(2) для доменного сокета UNIX). .TP \fBIN_DELETE\fP (+) В отслеживаемом каталоге был удалён файл/каталог. .TP \fBIN_DELETE_SELF\fP Отслеживаемый файл/каталог был удалён (это событие также возникает, если объект перемещён в другую файловую систему, так как \fBmv\fP(1), фактически, копирует файл в другую файловую систему и удаляет его из исходной). Также затем будет создано событие \fBIN_IGNORED\fP для дескриптора сторожка. .TP \fBIN_MODIFY\fP (+) Файл был изменён (например, \fBwrite\fP(2), \fBtruncate\fP(2)). .TP \fBIN_MOVE_SELF\fP Отслеживаемый файл/каталог был перемещён. .TP \fBIN_MOVED_FROM\fP (+) При переименовании генерируется для каталога, содержащего старое имя файла. .TP \fBIN_MOVED_TO\fP (+) При переименовании генерируется для каталога, содержащего новое имя файла. .TP \fBIN_OPEN\fP (*) Файл или каталог был открыт. .RE .P Наблюдение inotify ведётся за inode: при наблюдении за файлом (но не когда наблюдение ведётся за каталогом, содержащим файл) событие может генерироваться при активности по любой ссылке на файл (находящейся в том же или в другом каталоге). .P При наблюдении за каталогом: .IP \[bu] 3 события, помеченные звёздочкой (*), могут возникать как для самого каталога, так и для файлов в каталоге; и .IP \[bu] события, помеченные знаком плюс (+), могут возникать только для объектов внутри каталога (но не самого каталога). .P \fIЗамечание\fP: при слежении за каталогом события не генерируются для файлов каталога, если событие возникает по пути (т. е., по ссылке), который находится вне отслеживаемого каталога. .P Когда события генерируются для объектов внутри отслеживаемого каталога, поле \fIname\fP, возвращаемое в структуре \fIinotify_event\fP, хранит имя файла внутри этого каталога. .P Макрос \fBIN_ALL_EVENTS\fP определён как битовая маска всех перечисленных выше событий. Данный макрос можно использовать в качестве аргумента \fImask\fP в вызове \fBinotify_add_watch\fP(2). .P Дополнительно, два удобных макроса: .RS 4 .TP \fBIN_MOVE\fP То же, что и \fBIN_MOVED_FROM | IN_MOVED_TO\fP. .TP \fBIN_CLOSE\fP То же, что и \fBIN_CLOSE_WRITE | IN_CLOSE_NOWRITE\fP. .RE .P Также, при вызове \fBinotify_add_watch\fP(2) в \fImask\fP могут быть указаны следующие биты: .RS 4 .TP \fBIN_DONT_FOLLOW\fP (начиная с Linux 2.6.15) Не разыменовывать \fIpathname\fP, если это символическая ссылка. .TP \fBIN_EXCL_UNLINK\fP (начиная с Linux 2.6.36) .\" commit 8c1934c8d70b22ca8333b216aec6c7d09fdbd6a6 По умолчанию, при слежении за событиями для потомков каталога, события генерируются для потомков даже после того, как они будут удалены из каталога. Это может привести к большому количеству ненужных для приложения событий (например, если следить за \fI/tmp\fP, в котором многие приложения создают и сразу удаляют временные файлы). Указание \fBIN_EXCL_UNLINK\fP изменяет поведение по умолчанию, и такие события не генерируются для потомков после удаления из отслеживаемого каталога. .TP \fBIN_MASK_ADD\fP Если экземпляр слежения уже существует для объекта файловой системы соответствующего \fIpathname\fP, то выполнять добавление (OR) событий в \fImask\fP к маске слежения (вместо замены маски); если также указан \fBIN_MASK_CREATE\fP, то возвращается ошибка \fBEINVAL\fP. .TP \fBIN_ONESHOT\fP Отслеживать объект файловой системы, соответствующий \fIpathname\fP до одного события, затем удалить объект из списка слежения. .TP \fBIN_ONLYDIR\fP (начиная с Linux 2.6.15) Следить за \fIpathname\fP, только если это каталог; если \fIpathname\fP не является каталогом, то возвращается ошибка \fBENOTDIR\fP. Этот флаг предоставляет приложению бессостязательный способ убедиться, что отслеживаемый объект — каталог. .TP \fBIN_MASK_CREATE\fP (начиная с Linux 4.18) Следить за \fIpathname\fP только, если за ним никто не следит; если уже выполняется слежение за \fIpathname\fP, то возвращается ошибка \fBEEXIST\fP. .IP С помощью этого флага приложение может быть уверено, что новые слежения не изменят существующих. Это полезно, так как несколько путей могут ссылаться на одну иноду, а несколько вызовов \fBinotify_add_watch\fP(2) без этого флага могут затереть существующие маски слежения. .RE .P Следующие биты могут быть установлены в поле \fImask\fP при возврате из \fBread\fP(2): .RS 4 .TP \fBIN_IGNORED\fP Слежение было снято явно (\fBinotify_rm_watch\fP(2)) или автоматически (файл был удалён или размонтирована файловая система). Также смотрите ДЕФЕКТЫ. .TP \fBIN_ISDIR\fP Объект этого события — каталог. .TP \fBIN_Q_OVERFLOW\fP Переполнена очередь событий (для этого события значение \fIwd\fP равно \-1). .TP \fBIN_UNMOUNT\fP Файловая система, содержащая отслеживаемый объект, была размонтирована. Также, будет сгенерировано событие \fBIN_IGNORED\fP для дескриптора сторожка. .RE .SS Примеры Предположим, приложение следит за всеми событиями для каталога \fIdir\fP и файла \fIdir/myfile\fP. В примере ниже показаны некоторые события, которые будут сгенерированы для этих двух объектов. .RS 4 .TP fd = open("dir/myfile", O_RDWR); Генерируется событие \fBIN_OPEN\fP и для \fIdir\fP, и для \fIdir/myfile\fP. .TP read(fd, buf, count); Генерируется событие \fBIN_ACCESS\fP и для \fIdir\fP, и для \fIdir/myfile\fP. .TP write(fd, buf, count); Генерируется событие \fBIN_MODIFY\fP и для \fIdir\fP, и для \fIdir/myfile\fP. .TP fchmod(fd, mode); Генерируется событие \fBIN_ATTRIB\fP и для \fIdir\fP, и для \fIdir/myfile\fP. .TP close(fd); Генерируется событие \fBIN_CLOSE_WRITE\fP и для \fIdir\fP, и для \fIdir/myfile\fP. .RE .P Предположим, приложение следит за всеми событиями для каталогов \fIdir1\fP и \fIdir2\fP и файла \fIdir1/myfile\fP. В примере ниже показаны некоторые события, которые могут быть сгенерированы. .RS 4 .TP link("dir1/myfile", "dir2/new"); Генерируется событие \fBIN_ATTRIB\fP для \fImyfile\fP и событие \fBIN_CREATE\fP для \fIdir2\fP. .TP rename("dir1/myfile", "dir2/myfile"); Генерируется событие \fBIN_MOVED_FROM\fP для \fIdir1\fP, событие \fBIN_MOVED_TO\fP для \fIdir2\fP и событие \fBIN_MOVE_SELF\fP для \fImyfile\fP. События \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP будут содержать одинаковое значение \fIcookie\fP. .RE .P Предположим, что \fIdir1/xx\fP и \fIdir2/yy\fP только ссылки на один файл и приложение следит за \fIdir1\fP, \fIdir2\fP, \fIdir1/xx\fP и \fIdir2/yy\fP. При выполнение следующих вызовов в порядке, указанном ниже, будут сгенерированы следующие события: .RS 4 .TP unlink("dir2/yy"); Генерируется событие \fBIN_ATTRIB\fP для \fIxx\fP (так как изменился его счётчик ссылок) и событие \fBIN_DELETE\fP для \fIdir2\fP. .TP unlink("dir1/xx"); Генерируется событие \fBIN_ATTRIB\fP, \fBIN_DELETE_SELF\fP и \fBIN_IGNORED\fP для \fIxx\fP и событие \fBIN_DELETE\fP для \fIdir1\fP. .RE .P Предположим, приложение следит за каталогом \fIdir\fP и пустым каталогом \fIdir/subdir\fP. В примере ниже показаны некоторые события, которые могут быть сгенерированы. .RS 4 .TP mkdir("dir/new", mode); Генерируется событие \fBIN_CREATE | IN_ISDIR\fP для \fIdir\fP. .TP rmdir("dir/subdir"); Генерируются события \fBIN_DELETE_SELF\fP и \fBIN_IGNORED\fP для \fIsubdir\fP и событие \fBIN_DELETE | IN_ISDIR\fP для \fIdir\fP. .RE .SS "Интерфейс /proc" Для ограничения потребления inotify памяти ядра, можно использовать следующие интерфейсы: .TP \fI/proc/sys/fs/inotify/max_queued_events\fP Значение в этом файле используется когда приложение вызывает \fBinotify_init\fP(2) для установки верхнего порога количества событий, которые могут поместиться в очередь соответствующего экземпляра inotify. События, превысившие это ограничение, отбрасываются, но событие \fBIN_Q_OVERFLOW\fP генерируется всегда. .TP \fI/proc/sys/fs/inotify/max_user_instances\fP В этом файле задаётся ограничение на количество экземпляров inotify, которые могут быть созданы для одного реального идентификатора пользователя. .TP \fI/proc/sys/fs/inotify/max_user_watches\fP В этом файле задаётся ограничение на количество сторожков, которые могут быть созданы для одного реального идентификатора пользователя. .SH СТАНДАРТЫ Linux. .SH ИСТОРИЯ Inotify was merged into Linux 2.6.13. The required library interfaces were added in glibc 2.4. (\fBIN_DONT_FOLLOW\fP, \fBIN_MASK_ADD\fP, and \fBIN_ONLYDIR\fP were added in glibc 2.5.) .SH ПРИМЕЧАНИЯ За файловыми дескрипторами inotify можно наблюдать с помощью \fBselect\fP(2), \fBpoll\fP(2), и \fBepoll\fP(7). Когда возникает событие, файловый дескриптор указывает на возможность чтения. .P Начиная с Linux 2.6.25, для файловых дескрипторов inotify стали доступны уведомления ввода\-вывода посредством сигналов; смотрите обсуждение \fBF_SETFL\fP (для установки флага \fBO_ASYNC\fP), \fBF_SETOWN\fP и \fBF_SETSIG\fP в \fBfcntl\fP(2). Структура \fIsiginfo_t\fP (описана в \fBsigaction\fP(2)), передаваемая обработчику сигнала, содержит следующие настройки полей: в \fIsi_fd\fP указывается номер файлового дескриптора inotify; в \fIsi_signo\fP указывается номер сигнала; в \fIsi_code\fP указывается \fBPOLL_IN\fP; в \fIsi_band\fP указывается \fBPOLLIN\fP. .P Если последующие события inotify, выводимые в файловый дескриптор inotify, одинаковы (содержат одинаковые значения \fIwd\fP, \fImask\fP, \fIcookie\fP и \fIname\fP), то они сливаются в одно событие, если самое старое событие ещё не прочитано (но смотрите ДЕФЕКТЫ). Это сокращает требуемое количество памяти ядра для очереди событий, но также означает, что приложение не может использовать inotify для надёжного подсчёта файловых событий. .P События, возвращаемые при чтении из файлового дескриптора inotify, формируют упорядоченную очередь. То есть, например, это гарантирует, что при переименовании одного каталога в другой, события в файловом дескрипторе inotify будут созданы в правильном порядке. .P 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 \fI/proc/\fPpid\fI/fdinfo\fP directory. See \fBproc\fP(5) for further details. The \fBFIONREAD\fP \fBioctl\fP(2) returns the number of bytes available to read from an inotify file descriptor. .SS "Ограничения и подводные камни" Программный интерфейс inotify не предоставляет информацию о пользователе или процессе, из\-за которого возникло событие. В частности, для процесса, отслеживающего события через inotify, нет простого способа определить, возникли события из\-за его действий или из\-за действий других процессов. .P Inotify сообщает только о событиях, которые возникли из\-за пользовательских программ, использовавших программный интерфейс файловой системы. То есть, не возникает событий для файловых систем, доступных по сети (приложения должны использовать старый метод опроса файловой системы для слежения за такими событиями). Кроме того, различные псевдо\-файловый системы, такие как \fI/proc\fP, \fI/sys\fP и \fI/dev/pts\fP, не отслеживаются через inotify. .P Программный интерфейс inotify не сообщает о доступе и изменениях, которые могут произойти из\-за \fBmmap\fP(2), \fBmsync\fP(2) и \fBmunmap\fP(2). .P Программный интерфейс inotify в качестве идентификаторов объектов использует имена файлов. Однако, в момент обработки приложением события inotify, имя файла может быть уже удалено или переименовано. .P Программный интерфейс inotify различает события по их дескрипторам сторожков. Приложение само должно кэшировать сопоставление (если нужно) дескрипторов сторожков и имён. Имейте в виду, что переименование каталога может повлиять на несколько кэшированных путей. .P Отслеживание каталогов через inotify ведётся не рекурсивно: чтобы отслеживать подкаталоги, нужно создать дополнительные сторожки. Это может занять много времени при большом дереве каталога. .P Если отслеживается полное дерево каталога и создаётся новый каталог в этом дереве или существующий каталог переименовывается в этом дереве, учтите, что на момент создания сторожка за новым подкаталогом, в подкаталоге могут уже существовать новые файлы (и подкаталоги). Поэтому вам может потребоваться сканировать содержимое подкаталога сразу после добавления сторожка (и, если нужно, рекурсивно добавить сторожки для всех подкаталогов, которые в нём есть). .P Заметим, что очередь событий может переполниться. В этом случае события теряются. Корректные приложения должны учитывать возможность пропажи событий. Например, может потребоваться перестроить часть или весь кэш приложения (один простой, но, возможно, затратный способ, это закрыть файловый дескриптор inotify, опустошить кэш, создать новый файловый дескриптор inotify и затем пересоздать сторожки и записи в кэше для отслеживаемых объектов). .P .\" Если файловая система смонтирована поверх отслеживаемого каталога, то событие не генерируются, а также не генерируются события для объектов, находящихся в новой точке монтирования на первом уровне. Если в дальнейшем файловая система отмонтируется, то события начнут генерироваться для каталога и содержащихся в нём объектов. .SS "Работа с событиями rename()" Как указывалось выше, из событий \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP, генерируемых \fBrename\fP(2), можно определить пару по их одинаковому значению cookie. Однако, с этой задачей есть несколько проблем. .P Эти два события, обычно, стоят друг за другом в потоке событий, если читать из файлового дескриптора inotify. Однако, это не гарантируется. Если несколько процессов создают события для отслеживаемых объектов, то (в редких случаях) произвольное количество других событий может появиться между событиями \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP. Кроме того, не гарантируется, что пара событий вставляется в очередь атомарно: может существовать короткий интервал, в котором \fBIN_MOVED_FROM\fP уже появилось, а \fBIN_MOVED_TO\fP ещё нет. .P Соответствие \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP паре событий, сгенерированных \fBrename\fP(2), по сути, просто (не забудьте, что если объект переименовывается вне отслеживаемого каталога, то может не быть даже события \fBIN_MOVED_TO\fP). Можно использовать эвристические предположения (например, что события всегда следуют друг за другом), что работает в большинстве случаев, но неминуемо не сработает в некоторых случаях, в которых приложение посчитает события \fBIN_MOVED_FROM\fP и \fBIN_MOVED_TO\fP несвязными. Если в результате дескрипторы сторожков будут уничтожены и пересозданы, то такие дескрипторы будут несогласованны с дескрипторами сторожков для любых ожидающих событий (пересоздание файлового дескриптора inotify и пересборка кэша может быть полезна в этом случае). .P Applications should also allow for the possibility that the \fBIN_MOVED_FROM\fP event was the last event that could fit in the buffer returned by the current call to \fBread\fP(2), and the accompanying \fBIN_MOVED_TO\fP event might be fetched only on the next \fBread\fP(2), which should be done with a (small) timeout to allow for the fact that insertion of the \fBIN_MOVED_FROM\fP+\fBIN_MOVED_TO\fP event pair is not atomic, and also the possibility that there may not be any \fBIN_MOVED_TO\fP event. .SH ОШИБКИ .\" commit 820c12d5d6c0890bc93dd63893924a13041fdc35 До Linux 3.19, \fBfallocate\fP(2) не создавал события inotify. Начиная с Linux 3.19, вызов \fBfallocate\fP(2) генерирует событие \fBIN_MODIFY\fP. .P .\" FIXME . kernel commit 611da04f7a31b2208e838be55a42c7a1310ae321 .\" implies that unmount events were buggy since Linux 2.6.11 to Linux 2.6.36 .\" Before Linux 2.6.16, the \fBIN_ONESHOT\fP \fImask\fP flag does not work. .P В первоначальной задумке и реализации флаг \fBIN_ONESHOT\fP не приводил к генерации события \fBIN_IGNORED\fP, если наблюдение отменялось после одного события. Однако, как непреднамеренный эффект других изменений, начиная с Linux 2.6.36, событие \fBIN_IGNORED\fP в этом случае генерируется. .P .\" commit 1c17d18e3775485bf1e0ce79575eb637a94494a2 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 \fIoldest\fP unread event. .P .\" FIXME . https://bugzilla.kernel.org/show_bug.cgi?id=77111 When a watch descriptor is removed by calling \fBinotify_rm_watch\fP(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 \fBinotify_add_watch\fP(2), the kernel cycles through the range of possible watch descriptors (1 to \fBINT_MAX\fP) 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 \fBINT_MAX\fP 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. .SH ПРИМЕРЫ 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 \fBIN_OPEN\fP, \fBIN_CLOSE_NOWRITE\fP, and \fBIN_CLOSE_WRITE\fP. .P Следующий вывод был записан при редактировании файла \fI/home/user/temp/foo\fP и просмотра каталога \fI/tmp\fP. Перед открытием файла и каталога произошли события \fBIN_OPEN\fP. После закрытия файла произошло событие \fBIN_CLOSE_WRITE\fP. После закрытия каталога произошло событие \fBIN_CLOSE_NOWRITE\fP. Выполнение программы закончилось после нажатия пользователем клавиши ENTER. .SS "Пример вывода" .in +4n .EX $ \fB./a.out /tmp /home/user/temp\fP 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. .EE .in .SS "Исходный код программы" \& .EX #include #include #include #include #include #include #include \& /* Read all available inotify events from the file descriptor \[aq]fd\[aq]. 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]\[rs]n"); else printf(" [file]\[rs]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 ...]\[rs]n", argv[0]); exit(EXIT_FAILURE); } \& printf("Press ENTER key to terminate.\[rs]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 \[aq]%s\[aq]: %s\[rs]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.\[rs]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 != \[aq]\[rs]n\[aq]) continue; break; } \& if (fds[1].revents & POLLIN) { \& /* Inotify events are available. */ \& handle_events(fd, wd, argc, argv); } } } \& printf("Listening for events stopped.\[rs]n"); \& /* Close inotify file descriptor. */ \& close(fd); \& free(wd); exit(EXIT_SUCCESS); } .EE .SH "СМОТРИТЕ ТАКЖЕ" \fBinotifywait\fP(1), \fBinotifywatch\fP(1), \fBinotify_add_watch\fP(2), \fBinotify_init\fP(2), \fBinotify_init1\fP(2), \fBinotify_rm_watch\fP(2), \fBread\fP(2), \fBstat\fP(2), \fBfanotify\fP(7) .P Файл \fIDocumentation/filesystems/inotify.txt\fP в дереве исходного кода ядра Linux .PP .SH ПЕРЕВОД Русский перевод этой страницы руководства разработал(и) Azamat Hackimov , Dmitriy S. Seregin , Yuri Kozlov и Иван Павлов . .PP Этот перевод является свободной программной документацией; он распространяется на условиях общедоступной лицензии GNU (GNU General Public License - GPL, .UR https://www.gnu.org/licenses/gpl-3.0.html .UE версии 3 или более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ. .PP Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите об этом разработчику(ам) по его(их) адресу(ам) электронной почты или по адресу .MT списка рассылки русских переводчиков .ME .