fournit un mécanisme pour surveiller
les événements au niveau des systèmes
de fichiers. Inotify peut être utilisé pour
surveiller des fichiers individuels ou des
répertoires. Quand un répertoire est
surveillé, inotify va signaler des
événements pour le répertoire
lui-même et pour les fichiers de ce
répertoire.
Les appels
système suivants sont utilisés avec cette
interface de programmation :
Quand les événements ont lieu pour des
fichiers et répertoires surveillés, ces
événements sont rendus disponibles à
l’application comme des données
structurées qui peuvent être lues depuis le
descripteur de fichier inotify en utilisant
read(2)
(voir plus bas).
Quand tous les descripteurs de fichier se
référant à une instance inotify ont
été fermés (en utilisant
close(2)
), l’objet sous-jacent et ses
ressources sont libérés pour être
réutilisés par le noyau ; tous les
éléments de surveillance associés sont
automatiquement libérés.
Avec une
programmation prudente, une application peut utiliser
inotify pour surveiller et mettre en cache efficacement
l’état d’un ensemble d’objets de
système de fichiers. Cependant, les applications
robustes devraient prendre en compte que des bogues dans la
logique de surveillance ou des situations de
compétition du type décrit ci-dessous
pourraient laisser le cache incohérent avec
l’état du système de fichiers.
Réaliser des vérifications de cohérence
et reconstruire le cache en cas de détection
d’incohérences serait sans doute sage.
struct inotify_event {
int wd; /* Descripteur de surveillance */
uint32_t mask; /* Masque décrivant l’événement */
uint32_t cookie; /* Cookie unique d’association des
événements (pour rename(2)) */
uint32_t len; /* Taille du champ name */
char name[]; /* Nom optionnel terminé par un nul */
identifie l’élément de surveillance pour
lequel cet événement a lieu. Il s’agit
de l’un des descripteurs de surveillance
renvoyés par un précédent appel
à inotify_add_watch(2).
contient des bits qui décrivent
l’événement qui a eu lieu (voir
ci-dessous).
cookie
est un entier unique qui relie les événements.
Ce n’est actuellement utilisé que pour les
événements de renommage, et permet à la
paire d’événements IN_MOVED_FROM
et IN_MOVED_TO en résultant d’être
associée par l’application. Pour tous les
autres types d’événements, cookie
est mis à 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.
Le champ
len compte tous les octets de name, incluant
les caractères nuls. La longueur de chaque structure
inotify_event vaut donc
sizeof(structinotify_event)+len.
comportement, lorsque le tampon donné à
read(2) est trop petit pour renvoyer
l’information sur le prochain événement,
dépend de la version du noyau : avant 2.6.21,
read(2) renvoie 0 ; depuis le noyau 2.6.21,
read(2) échoue avec l’erreur
EINVAL. Indiquer un tampon de taille
sizeof(struct
inotify_event) + NAME_MAX + 1
est suffisant
pour lire au moins un événement.
Événements
inotify
L’argument mask passé à
inotify_add_watch(2) et le champ mask de la
structure inotify_event renvoyés lors de la
lecture avec read(2) d’un descripteur de
fichier inotify sont tous deux des masques binaires
identifiant les événements inotify. Les bits
suivants peuvent être définis dans
l’argument mask lors de l’appel à
inotify_add_watch(2) et peuvent être
renvoyés dans le champ mask renvoyé par
read(2).
IN_ACCESS (+)
Accès au fichier (par
exemple read(2), execve(2)).
IN_ATTRIB (*)
Modification des
métadonnées, par exemple, les permissions (par
exemple chmod(2)), les horodatages (par exemple
utimensat(2)), les attributs étendus
(setxattr(2)), le compteur de liens (depuis
Linux 2.6.25 ; par exemple pour la cible de
link(2) et unlink(2)) et les UID ou GID (par
exemple chown(2)).
IN_CLOSE_WRITE (+)
Fichier ouvert en
écriture fermé.
IN_CLOSE_NOWRITE (*)
Fichier ou répertoire
non ouverts en écriture fermés.
IN_CREATE (+)
Fichier ou répertoire
créés dans le répertoire
surveillé (par exemple open(2) O_CREAT,
mkdir(2), link(2), symlink(2),
bind(2) sur une socket de domaine UNIX).
IN_DELETE (+)
Fichier ou répertoire
supprimés dans le répertoire
surveillé.
IN_DELETE_SELF
Fichier ou répertoire
surveillés supprimés (cet
événement se produit également si un
objet est déplacé vers un autre système
de fichiers, puisque mv(1) copie effectivement le
fichier vers l’autre système de fichiers puis
le supprime du système de fichiers d’origine).
De plus, un événement IN_IGNORED sera
ensuite généré pour le descripteur de
surveillance.
IN_MODIFY (+)
Fichier modifié (par
exemple write(2), truncate(2)).
IN_MOVE_SELF
Fichier ou répertoire
surveillés déplacés.
IN_MOVED_FROM (+)
Généré
pour le répertoire contenant l’ancien nom quand
un fichier est renommé.
IN_MOVED_TO (+)
Généré
pour le répertoire contenant le nouveau nom quand un
fichier est renommé.
IN_OPEN (*)
Fichier ou répertoire
ouvert.
La surveillance
par Inotify est basée sur les inodes :
lorsqu’un fichier est surveillé (mais pas lors
de la surveillance d’un répertoire contenant un
fichier), un événement peut être
créé sur tout lien vers le fichier (dans le
même répertoire ou dans un répertoire
différent).
Lors de la
surveillance d’un répertoire :
les événements marqués
précédemment par un astérisque (*)
peuvent avoir lieu à la fois pour le
répertoire et pour les objets à
l’intérieur du répertoire ;
les événements marqués par un signe
plus (+) n’ont lieu que pour les objets à
l’intérieur du répertoire (et non pour
le répertoire lui-même).
Note :
lorsqu’un répertoire est surveillé, les
événements ne sont pas créés
pour les fichiers contenus dans le répertoire quand
des événements sont exécutés
avec un nom de chemin (par exemple, un lien) qui se trouve
hors du répertoire surveillé.
Lorsque les
événements sont créés pour les
objets dans un répertoire surveillé, le champ
name dans la structure inotify_event
renvoyée identifie le nom du fichier dans ce
répertoire.
La macro
IN_ALL_EVENTS est définie comme un masque
binaire de tous les événements décrits
ci-dessus. Cette macro peut être utilisée comme
l’argument mask lors de l’appel à
inotify_add_watch(2).
Deux macros
supplémentaires de convenance sont
définies :
IN_MOVE
Équivalent à
IN_MOVED_FROM | IN_MOVED_TO.
IN_CLOSE
Équivalent à
IN_CLOSE_WRITE | IN_CLOSE_NOWRITE.
Les bits
supplémentaires suivants peuvent être
indiqués dans l’argument mask lors de
l’appel à
inotify_add_watch(2) :
IN_DONT_FOLLOW (depuis
Linux 2.6.15)
Ne pas
déréférencer pathname s’il
s’agit d’un lien symbolique.
IN_EXCL_UNLINK (depuis
Linux 2.6.36)
Par défaut, lors de la
surveillance d’événements sur les
entrées d’un répertoire, des
événements sont créés pour ces
entrées même après leur suppression du
répertoire. De nombreux événements
inintéressants pour certaines applications peuvent
ainsi être créés (par exemple, lors de
la surveillance de /tmp, où de nombreuses
applications créent des fichiers temporaires donc les
noms sont immédiatement supprimés). Indiquer
IN_EXCL_UNLINK modifie le comportement par
défaut, de telle sorte qu’aucun
événement n’est créé pour
ces entrées après leur suppression du
répertoire surveillé.
IN_MASK_ADD
If a watch instance already
exists for the filesystem object corresponding to
pathname, add (OR) the events in mask to the
watch mask (instead of replacing the mask); the error
EINVAL results if IN_MASK_CREATE is also
specified.
IN_ONESHOT
Surveiller l’objet de
système de fichiers correspondant à
pathname jusqu’au premier
événement, puis le supprimer de la liste de
surveillance.
IN_ONLYDIR (depuis
Linux 2.6.15)
Watch pathname only if
it is a directory; the error ENOTDIR results if
pathname is not a directory. Using this flag provides
an application with a race-free way of ensuring that the
monitored object is a directory.
IN_MASK_CREATE (since
Linux 4.18)
Watch pathname only if
it does not already have a watch associated with it; the
error EEXIST results if pathname is already
being watched.
Using this flag
provides an application with a way of ensuring that new
watches do not modify existing ones. This is useful because
multiple paths may refer to the same inode, and multiple
calls to inotify_add_watch(2) without this flag may
clobber existing watch masks.
Les bits
suivants peuvent avoir été définis dans
le champ mask renvoyé par
read(2) :
IN_IGNORED
Le surveillant a
été retiré explicitement
(inotify_rm_watch(2)) ou automatiquement (le fichier
a été effacé, ou le système de
fichiers a été démonté).
Consultez également BOGUES.
IN_ISDIR
Le sujet de cet
événement est un répertoire.
IN_Q_OVERFLOW
Queue des
événements surchargée (wd vaut
alors -1).
IN_UNMOUNT
Le système de fichiers
contenant l’objet surveillé a été
démonté. De plus, un événement
IN_IGNORED sera ensuite généré
pour le descripteur de surveillance.
Exemples
Soit une application surveillant le répertoire
rép et le fichier rép/monfichier
pour tous les événements. Les exemples
ci-dessous montrent quelques événements qui
seront générés pour ces deux
objets.
open("rép/monfichier", O_RDWR);
Génère des
événements IN_OPEN à la fois
pour rép et rép/monfichier.
read(fd, buf, count);
Génère des
événements IN_ACCESS à la fois
pour rép et rép/monfichier.
write(fd, buf, count);
Génère des
événements IN_MODIFY à la fois
pour rép et rép/monfichier.
fchmod(fd, mode);
Génère des
événements IN_ATTRIB à la fois
pour rép et rép/monfichier.
close(fd);
Génère des
événements IN_CLOSE_WRITE à la
fois pour rép et
rép/monfichier.
Soit une
application surveillant les répertoires
rép1 et rép2, et le fichier
rép1/monfichier. Les exemples suivants
montrent quelques événements qui pourraient
être générés.
link("rép1/monfichier",
"rép2/nouveau");
Génère un
événement IN_ATTRIB pour
monfichier et un événement
IN_CREATE pour rép2.
rename("rép1/monfichier",
"rép2/monfichier");
Génère un
événement IN_MOVED_FROM pour
dir1, un événement IN_MOVED_TO
pour rép2 et un événement
IN_MOVE_SELF pour monfichier. Les
événements IN_MOVED_FROM et
IN_MOVED_TO auront la même valeur
cookie.
Soient
rép1/xx et rép2/yy les (seuls)
liens vers le même ficher, et une application
surveillant rép1, rép2,
rép1/xx et rép2/yy.
L’exécution des appels suivants dans
l’ordre donné ci-dessous générera
les événements suivants :
unlink("rép2/yy");
Génère un
événement IN_ATTRIB pour xx
(à cause du changement de son compteur de liens) et
un événement IN_DELETE pour
rép2.
unlink("rép1/xx");
Génère des
événements IN_ATTRIB,
IN_DELETE_SELF et IN_IGNORED pour xx et
un événement IN_DELETE pour
rép1.
Soit une
application surveillant le répertoire
rép et le répertoire (vide)
rép/sousrép. Les exemples suivants
montrent quelques événements qui pourraient
être générés.
mkdir("rép/nouveau",
mode);
Génère un
événement IN_CREATE | IN_ISDIR pour
rép.
rmdir("rép/sousrép");
Génère des
événements IN_DELETE_SELF et
IN_IGNORED pour sousrép et un
événement IN_DELETE | IN_ISDIR pour
rép.
Interfaces
/proc
Les interfaces suivantes peuvent être utilisées
pour limiter la quantité de mémoire du noyau
utilisée par inotify :
/proc/sys/fs/inotify/max_queued_events
La valeur dans ce fichier est
utilisée lorsqu’une application appelle
inotify_init(2) pour définir la limite
maximale du nombre des événements qui peuvent
entrer dans la file d’attente de l’instance
inotify correspondante. Les événements
au-delà de cette limite sont annulés, mais un
événement IN_Q_OVERFLOW est
systématiquement généré.
/proc/sys/fs/inotify/max_user_instances
Cela indique la limite maximale
du nombre d’instances inotify qui peuvent être
créées par identifiant utilisateur
réel.
/proc/sys/fs/inotify/max_user_watches
Cela indique la limite maximale
du nombre de « watch » qui peuvent
être créés par identifiant utilisateur
réel.
Depuis
Linux 2.6.25, il est possible d’être
notifié par des signaux pour des
entrées-sorties des descripteurs de fichier
inotify ; consultez la discussion de F_SETFL
(pour la configuration de l’attribut O_ASYNC),
F_SETOWN, et F_SETSIG dans fcntl(2). La
structure siginfo_t (décrite dans
sigaction(2)) qui est passée au gestionnaire
de signal a les champs suivants définis :
si_fd est défini avec le numéro de
descripteur de fichiers inotify ; si_signo est
défini avec le numéro du signal ;
si_code est défini avec POLL_IN ;
et si_band est défini avec POLLIN.
Si deux
événements inotify de sortie successifs
produits sur le descripteur de fichier inotify sont
identiques (wd, mask, cookie, et
name identiques), alors ils sont fusionnés en
un seul événement si
l’événement le plus ancien n’a
toujours pas été lu (mais consultez la section
BOGUES). Cela permet de réduire la quantité de
mémoire en espace noyau nécessaire à la
file d’événements, mais signifie
également qu’une application ne peut utiliser
inotify pour compter de manière fiable les
événements liés à un
fichier.
événements renvoyés lors de la lecture
d’un descripteur de fichier inotify forment une file
ordonnée. Ainsi, par exemple, il est garanti que lors
du renommage d’un répertoire, les
événements seront produits dans l’ordre
convenable sur le descripteur de fichier inotify.
L’ensemble
des descripteurs surveillés grâce à un
descripteur de fichier inotify peut être vu dans
l’entrée du descripteur de fichier inotify dans
le répertoire /proc/[pid]/fdinfo du processus.
Consultez proc(5) pour de plus amples détails.
FIONREAD ioctl(2) renvoie le nombre d’octets
disponibles à la lecture dans un descripteur de
fichier inotify.
Limites et
réserves
L’interface inotify ne fournit aucun renseignement sur
l’utilisateur ou le processus qui a
déclenché l’événement
inotify. En particulier, un processus en train de surveiller
des événements à l’aide
d’inotify ne dispose d’aucun moyen facile pour
distinguer les événements qu’il
déclenche lui-même de ceux qui ont
été déclenchés par
d’autres processus.
Inotify ne
signale que les événements
déclenchés par un programme en espace
utilisateur à l’aide de l’interface de
programmation de système de fichiers. Par
conséquent, elle n’intercepte pas les
événements qui surviennent sur les
systèmes de fichiers en réseau (les
applications doivent avoir recours à la scrutation
(polling) pour intercepter ce type
d’événements). De plus, divers
pseudo-systèmes de fichiers comme /proc,
/sys et /dev/pts ne sont pas surveillables
avec inotify.
L’interface
inotify ne signale pas les accès ni les modifications
de fichier qui pourraient survenir à cause de
mmap(2), msync(2) ou munmap(2).
L’interface
inotify identifie les fichiers affectés par leur nom.
Cependant, au moment où l’application traite un
événement inotify, ce nom de fichier peut
avoir déjà été supprimé
ou renommé.
L’interface
inotify identifie les événements à
l’aide de descripteurs de surveillance.
L’application est responsable de mettre en cache une
correspondance (si nécessaire) entre les descripteurs
de fichier et les chemins. Soyez vigilants aux renommages de
répertoire qui pourraient affecter plusieurs chemins
en cache.
La surveillance
inotify des répertoires n’est pas
récursive : pour surveiller les
sous-répertoires, des éléments de
surveillance supplémentaires doivent être
créés. Cela peut être assez long pour
les répertoires contenant une grande
arborescence.
Si la
surveillance concerne une arborescence dans son
intégralité, et si un nouveau
sous-répertoire est créé dans ce
répertoire ou si un répertoire existant est
renommé dans cette arborescence, soyez conscient
qu’au moment où vous créez un
élément de surveillance pour le nouveau
sous-répertoire, de nouveaux fichiers (et
sous-répertoires) peuvent déjà exister
dans le sous-répertoire. Ainsi, vous devriez analyser
le contenu du sous-répertoire immédiatement
après avoir ajouté
l’élément de surveillance (et, si
nécessaire, ajouter des éléments de
surveillance pour tous les sous-répertoires
qu’il contient).
Remarquez que
la file d’événements peut
déborder. Dans ce cas, des événements
sont perdus. Les applications robustes devraient
gérer correctement la possibilité de perdre
des événements. Par exemple, la reconstruction
de tout ou partie du cache de l’application pourrait
être nécessaire (une approche simple, mais
éventuellement coûteuse, est de fermer le
descripteur de fichier inotify, vider le cache, créer
un nouveau descripteur de fichier inotify et recréer
les éléments de surveillance et les
entrées du cache pour les objets à
surveiller).
Si un
système de fichiers est monté par dessus un
répertoire surveillé, aucun
événement n’est
généré, pas plus que pour les objets se
trouvant directement sous le nouveau point de montage. Si le
système de fichiers est par la suite
démonté, les événements seront
créés pour le répertoire et les objets
qu’il contient.
Traitement
des événements rename()
Comme noté précédemment, la paire
d’événements IN_MOVED_FROM et
IN_MOVED_TO générée par
rename(2) peut être assemblée à
l’aide de la valeur de cookie partagé.
Cependant, la tâche d’assemblage peut poser
quelques problèmes.
Ces deux
événements sont normalement consécutifs
dans le flux d’événements disponibles
lors de la lecture depuis le descripteur de fichiers
inotify. Cependant, ce n’est pas garanti. Si plusieurs
processus déclenchent des événements
pour des objets surveillés, alors (rarement) un
nombre arbitraire d’autres événements
pourrait apparaître entre les événements
IN_MOVED_FROM et IN_MOVED_TO. De plus, il
n’est pas garanti que la paire
d’événements soit insérée
de façon atomique dans la file : il pourrait y
avoir un bref intervalle au cours duquel
IN_MOVED_FROM est apparu, mais pas
IN_MOVED_TO.
L’assemblage
de la paire d’événements
IN_MOVED_FROM et IN_MOVED_TO
générés par rename(2) pose donc
intrinsèquement un risque de situation de
compétition (n’oubliez pas que si un objet est
renommé en dehors d’un répertoire
surveillé, un événement
IN_MOVED_TO pourrait ne même pas être
envoyé). Des approches heuristiques (par exemple
supposer que les événements sont toujours
consécutifs) permettent d’assurer un assemblage
dans la plupart des cas, mais manqueront forcément
certains cas, forçant l’application à
percevoir les événements IN_MOVED_FROM
et IN_MOVED_TO comme indépendants. Si les
descripteurs de surveillance sont détruits et
recréés par conséquent, alors ces
descripteurs de surveillance seront incohérents avec
les descripteurs de surveillance dans tous les
événements en attente (la recréation du
descripteur de fichier inotify et la reconstruction du cache
pourrait être utile dans ce cas).
applications devraient aussi considérer la
possibilité que l’événement
IN_MOVED_FROM soit le dernier événement
ayant pu entrer dans le tampon renvoyé pour
l’appel actuel de read(2) et
l’événement IN_MOVED_TO
accompagnant pourrait n’être
récupéré que lors de l’appel
read(2) suivant, ce qui devrait être fait avec
un (léger) délai pour permettre que
l’insertion de la paire
d’événements
IN_MOVED_FROM-IN_MOVED_TO ne soit pas atomique
et aussi qu’il n’y ait pas
d’événement IN_MOVED_TO.
Avant
Linux 3.19, fallocate(2) ne créait pas
d’événements inotify. Depuis
Linux 3.19, les appels à fallocate(2)
créent des événements
IN_MODIFY.
Dans les noyaux
antérieurs à 2.6.16, l’attribut
IN_ONESHOT de mask ne fonctionne pas.
Tel que
conçu et implémenté à
l’origine, l’attribut IN_ONESHOT ne
forçait pas à générer un appel
IN_IGNORED lorsque la surveillance était
supprimée après un événement.
Cependant, en conséquence involontaire d’autres
modifications, depuis Linux 2.6.36, un
événement IN_IGNORED est
généré dans ce cas.
Avant le
noyau 2.6.25, le code du noyau qui était
sensé regrouper deux événements
successifs (c’est-à-dire que les deux
événements les plus récents pouvaient
être fusionnés si le plus ancien des deux
n’avait toujours pas été lu)
vérifiait à la place si
l’événement le plus récent
pouvait être fusionné à
l’événement non lu le plus
ancien.
Quand un
descripteur de surveillance est supprimé en appelant
inotify_rm_watch(2) (ou parce qu’un fichier de
surveillance est supprimé ou que le système de
fichiers qui le contient est démonté), tous
les événements non lus en attente pour ce
descripteur de fichier restent disponibles en lecture. Comme
les descripteurs de surveillance sont ensuite alloués
avec inotify_add_watch(2), le noyau boucle sur
l’intervalle des descripteurs de surveillance
possibles (O à INT_MAX) de façon
incrémentielle. Lors de l’allocation d’un
descripteur de surveillance libre, aucune
vérification n’est effectuée pour voir
si ce numéro de descripteur de surveillance a des
événements non lus en attente dans la file
inotify. Ainsi, un descripteur de surveillance pourrait
être réalloué même quand des
événements non lus en attente existent pour
une incarnation précédente de ce numéro
de descripteur de surveillance, avec comme résultat
que l’application pourrait alors lire ces
événements et les interpréter comme
appartenant au fichier associé au descripteur de
surveillance nouvellement recyclé. En pratique, la
probabilité d’être victime de ce bogue
devrait être extrêmement basse, puisqu’il
nécessite qu’une application boucle sur
INT_MAX descripteurs de surveillance,
relâche un descripteur de surveillance tout en
laissant des événements non lus pour ce
descripteur de fichier dans la file et ensuite recycle ce
descripteur de surveillance. Pour cette raison, et parce
qu’il n’y a eu aucun rapports de bogue à
propos de réelles applications, dans Linux 3.15,
aucune modification de noyau n’a encore
été faite pour éliminer ce bogue
éventuel.
COLOPHON
Cette page fait
partie de la publication 5.07 du projet
man-pages Linux. Une description du projet et des
instructions pour signaler des anomalies et la
dernière version de cette page, peuvent être
trouvées à l’adresse
https://www.kernel.org/doc/man-pages/.
TRADUCTION
La traduction
française de cette page de manuel a été
créée par Christophe Blaess
<https://www.blaess.fr/christophe/>, Stéphan
Rafin <stephan.rafin [AT] laposte.net>, Thierry Vignaud
<tvignaud [AT] mandriva.com>, François Micaux, Alain
Portal <aportal [AT] univ-montp2.fr>, Jean-Philippe
Guérard <fevrier [AT] tigreraye.org>, Jean-Luc
Coulon (f5ibh) <jean-luc.coulon [AT] wanadoo.fr>, Julien
Cristau <jcristau [AT] debian.org>, Thomas Huriaux
<thomas.huriaux [AT] gmail.com>, Nicolas François
<nicolas.francois [AT] centraliens.net>, Florentin Duneau
<fduneau [AT] gmail.com>, Simon Paillard
<simon.paillard [AT] resel.fr>, Denis Barbier
<barbier [AT] debian.org> et David Prévot
<david [AT] tilapin.org>
Cette
traduction est une documentation libre ; veuillez vous
reporter à la GNU General Public License
version 3 concernant les conditions de copie et de
distribution. Il n’y a aucune RESPONSABILITÉ
LÉGALE.
Si vous
découvrez un bogue dans la traduction de cette page
de manuel, veuillez envoyer un message à
<debian-l10n-french [AT] lists.org>.