Man page - inotify(7)

Packages contains this manual

Available languages:

en fr ja ru

Manual

inotify

NOM
DESCRIPTION
Lecture d’évĂ©nements d’un descripteur de fichier inotify
ÉvĂ©nements inotify
Exemples
/proc interfaces
STANDARDS
HISTORIQUE
NOTES
Limites et réserves
Traitement des événements rename()
BOGUES
EXEMPLES
Sortie de l’exemple
Source du programme
VOIR AUSSI
TRADUCTION

NOM

inotify - Surveiller les événements des systÚmes de fichiers

DESCRIPTION

L’API inotify 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 :

-

inotify_init (2) crĂ©e une instance inotify et renvoie un descripteur de fichier se rĂ©fĂ©rant Ă  cette instance inotify. L’appel systĂšme plus rĂ©cent inotify_init1 (2) est comme inotify_init (2), mais a un argument flags qui fournit un accĂšs Ă  des fonctionnalitĂ©s supplĂ©mentaires.

-

inotify_add_watch (2) manipule la « liste de surveillance » associĂ©e Ă  une instance inotify. Chaque Ă©lĂ©ment (« watch ») de la liste de surveillance indique le chemin d’un fichier ou d’un rĂ©pertoire, avec un ensemble d’évĂ©nements que le noyau doit surveiller pour le fichier indiquĂ© par ce chemin. inotify_add_watch (2) crĂ©e un nouvel Ă©lĂ©ment de surveillance ou modifie un Ă©lĂ©ment existant. Chaque Ă©lĂ©ment a un unique « descripteur de surveillance », un entier renvoyĂ© par inotify_add_watch (2) lorsque cet Ă©lĂ©ment est créé.

-

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).

-

inotify_rm_watch (2) retire un Ă©lĂ©ment d’une liste de surveillance inotify.

-

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.

Lecture d’évĂ©nements d’un descripteur de fichier inotify

Pour dĂ©terminer quels Ă©vĂ©nements ont eu lieu, une application va lire avec read (2) le descripteur de fichier inotify. Si aucun Ă©vĂ©nement n’a eu lieu, alors, en supposant qu’il s’agisse d’un descripteur de fichier bloquant, read (2) se bloquera jusqu’à ce qu’au moins un Ă©vĂ©nement ait lieu (Ă  moins qu’elle ne soit interrompue par un signal, auquel cas l’appel Ă©chouera avec l’erreur EINTR ; consultez signal (7)).

Chaque lecture (avec read (2)) réussie renvoie un tampon contenant une ou plusieurs des structures suivantes :

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 */
};

wd 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).

mask 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.

Le champ name n’est prĂ©sent que lorsqu’un Ă©vĂ©nement est renvoyĂ© pour un fichier au sein d’un rĂ©pertoire surveillĂ©. Il identifie le chemin du fichier dans le rĂ©pertoire surveillĂ©. Ce chemin est terminĂ© par un caractĂšre NULL et peut inclure d’autres octets nuls (« \0 ») pour ajuster des lectures successives Ă  une limite d’adressage convenable.

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 .

Le 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 Linux 2.6.21, read (2) renvoie 0 ; depuis Linux 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 un 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 chemin 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

Si une instance de surveillance existe dĂ©jĂ  pour l’objet de systĂšme de fichiers correspondant Ă  chemin , ajouter (avec un OU binaire) les Ă©vĂ©nements de mask au masque de surveillance (au lieu de remplacer le masque) ; il rĂ©sulte une erreur EINVAL si IN_MASK_CREATE est aussi spĂ©cifiĂ©.

IN_ONESHOT

Surveiller l’objet de systĂšme de fichiers correspondant Ă  chemin jusqu’au premier Ă©vĂ©nement, puis le supprimer de la liste de surveillance.

IN_ONLYDIR (depuis Linux 2.6.15)

Surveiller chemin seulement s’il s’agit d’un rĂ©pertoire ; il rĂ©sulte une erreur ENOTDIR si chemin n’est pas un rĂ©pertoire. Utiliser cet attribut fournit Ă  une application un moyen sans problĂšme de concurrence de s’assurer qu’un objet surveillĂ© est un rĂ©pertoire.

IN_MASK_CREATE (depuis Linux 4.18)

Surveiller chemin seulement s’il n’y a pas dĂ©jĂ  une surveillance qui lui est associĂ©e ; il rĂ©sulte une erreur EEXIST si chemin est dĂ©jĂ  surveillĂ©.

Utiliser cet attribut fournit Ă  une application un moyen de s’assurer que de nouveaux Ă©lĂ©ments de surveillance ne modifient pas ceux qui existent dĂ©jĂ . C’est utile parce que plusieurs chemins peuvent faire rĂ©fĂ©rence au mĂȘme inƓud et plusieurs appels Ă  inotify_add_watch (2) sans cet attribut peuvent Ă©craser des masques de surveillance existants.

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.

fd = 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 .

/proc interfaces

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.

STANDARDS

Linux.

HISTORIQUE

Inotify a été inclus dans Linux 2.6.13. Les interfaces bibliothÚque nécessaires ont été ajoutées dans la glibc 2.4 ( IN_DONT_FOLLOW , IN_MASK_ADD et IN_ONLYDIR ont été ajoutées dans la glibc 2.5).

NOTES

Les descripteurs de fichier inotify peuvent ĂȘtre surveillĂ©s en utilisant select (2), poll (2) et epoll (7). Lorsqu’un Ă©vĂ©nement est disponible, le descripteur de fichier indique qu’il est accessible en lecture.

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.

Les Ă©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).

Les 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 .

BOGUES

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 .

Avant Linux 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 Linux 2.6.25, le code du noyau qui Ă©tait censĂ© 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 (1 Ă  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.

EXEMPLES

Le programme suivant montre l’utilisation de l’interface de programmation inotify. Il marque les rĂ©pertoires passĂ©s en arguments de ligne de commande et attend les Ă©vĂ©nements de type IN_OPEN , IN_CLOSE_NOWRITE et IN_CLOSE_WRITE .

La sortie suivante a Ă©tĂ© enregistrĂ©e lors de la modification du fichier /home/utilisateur/temp/toto et de l’affichage du contenu du rĂ©pertoire /tmp . Avant d’ouvrir le fichier et le rĂ©pertoire, un Ă©vĂ©nement IN_OPEN est survenu. AprĂšs la fermeture du fichier, un Ă©vĂ©nement IN_CLOSE_WRITE est survenu. AprĂšs la fermeture du rĂ©pertoire, un Ă©vĂ©nement IN_CLOSE_NOWRITE est survenu. L’exĂ©cution du programme s’est terminĂ©e quand l’utilisateur a appuyĂ© sur la touche EntrĂ©e.

Sortie de l’exemple

$ ./a.out /tmp /home/utilisateur/temp
Appuyer sur la touche Entrée pour quitter.
En Ă©coute d’évĂ©nements.
IN_OPEN : /home/utilisateur/temp/toto [fichier]
IN_CLOSE_WRITE : /home/utilisateur/temp/toto [fichier]
IN_OPEN : /tmp/ [répertoire]
IN_CLOSE_NOWRITE : /tmp/ [répertoire]
ArrĂȘt de l’écoute d’évĂ©nements.

Source du programme

#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <string.h>
/* Lire tous les événements inotify disponibles à partir du
descripteur de fichier « fd ».
wd est le tableau des descripteurs de surveillance pour
les répertoires en argv.
argc est la taille de wd et argv.
argv est la liste des répertoires surveillés.
L’entrĂ©e 0 de wd et argv n’est pas utilisĂ©e. */
static void
handle_events(int fd, int *wd, int argc, char* argv[])
{
/* Certains systĂšmes ne peuvent pas lire de variables entiĂšres
si elles ne sont pas alignĂ©es correctement. Sur d’autres
systĂšmes, un alignement incorrect pourrait diminuer les
performances. Par conséquent, le tampon utilisé pour lire
le descripteur de fichier inotify devrait avoir le mĂȘme
alignement que struct inotify_event. */
char buf[4096]
__attribute__ ((aligned(__alignof__(struct inotify_event))));
const struct inotify_event *event;
ssize_t len;
/* Boucler tant que les Ă©vĂ©nements peuvent ĂȘtre lus Ă  partir du
descripteur de fichier inotify */
for (;;) {
/* Lire certains événements. */
len = read(fd, buf, sizeof(buf));
if (len == -1 && errno != EAGAIN) {
perror("read");
exit(EXIT_FAILURE);
}
/* Si le read() non bloquant n’a pas trouvĂ© d’évĂ©nement Ă 
lire, il renvoie -1 avec errno défini à EAGAIN. Dans ce
cas, on sort de la boucle. */
if (len <= 0)
break;
/* Boucler sur tous les événements du tampon. */
for (char *ptr = buf; ptr < buf + len;
ptr += sizeof(struct inotify_event) + event->len) {
event = (const struct inotify_event *) ptr;
/* Afficher le type d’évĂ©nement. */
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: ");
/* Afficher le nom du répertoire surveillé. */
for (size_t i = 1; i < argc; ++i) {
if (wd[i] == event->wd) {
printf("%s/", argv[i]);
break;
}
}
/* Afficher le nom du fichier. */
if (event->len)
printf("%s", event->name);
/* Afficher le type d’objet de systùme de fichiers. */
if (event->mask & IN_ISDIR)
printf(" [répertoire]\n");
else
printf(" [fichier]\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(""Utilisation : %s CHEMIN [CHEMIN ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("Appuyer sur la touche Entrée pour quitter.\n");
/* CrĂ©er le descripteur de fichier pour accĂ©der Ă  l’interface de
programmation inotify. */
fd = inotify_init1(IN_NONBLOCK);
if (fd == -1) {
perror("inotify_init1");
exit(EXIT_FAILURE);
}
/* Allouer la mémoire pour les descripteurs de surveillance. */
wd = calloc(argc, sizeof(int));
if (wd == NULL) {
perror("calloc");
exit(EXIT_FAILURE);
}
/* Marquer les répertoires pour les événements :
- un fichier a été ouvert ;
- un fichier a été fermé
for (i = 1; i < argc; i++) {
wd[i] = inotify_add_watch(fd, argv[i],
IN_OPEN | IN_CLOSE);
if (wd[i] == -1) {
fprintf(stderr, "Impossible de surveiller « %s » : %s\n",
argv[i], strerror(errno));
exit(EXIT_FAILURE);
}
}
/* Préparer pour la scrutation (polling). */
nfds = 2;
fds[0].fd = STDIN_FILENO; /* Entrée de console */
fds[0].events = POLLIN;
fds[1].fd = fd; /* EntrĂ©e d’inotify */
fds[1].events = POLLIN;
/* Attendre les événements ou une entrée du terminal. */
printf("En Ă©coute d’évĂ©nements.\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) {
/* Entrée de console disponible.
Vider l’entrĂ©e standard et quitter. */
while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
continue;
break;
}
if (fds[1].revents & POLLIN) {
/* Des événements inotify sont disponibles. */
handle_events(fd, wd, argc, argv);
}
}
}
printf("ArrĂȘt de l’écoute d’évĂ©nements.\n");
/* Fermer le descripteur de fichier inotify. */
close(fd);
free(wd);
exit(EXIT_SUCCESS);
}

VOIR AUSSI

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 dans les sources du noyau Linux

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@laposte.net>, Thierry Vignaud <tvignaud@mandriva.com>, François Micaux, Alain Portal <aportal@univ-montp2.fr>, Jean-Philippe Guérard <fevrier@tigreraye.org>, Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>, Julien Cristau <jcristau@debian.org>, Thomas Huriaux <thomas.huriaux@gmail.com>, Nicolas François <nicolas.francois@centraliens.net>, Florentin Duneau <fduneau@gmail.com>, Simon Paillard <simon.paillard@resel.enst-bretagne.fr>, Denis Barbier <barbier@debian.org>, David Prévot <david@tilapin.org>, Thomas Vincent <tvincent@debian.org> et Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>

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@lists.debian.org .