inotify

INOTIFY(7)                Manuel du programmeur Linux               INOTIFY(7)



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és 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 par rapport au répertoire surveillé. Ce chemin est
       terminé par un caractère nul 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 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 non ouvert en écriture fermé.

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

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

       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
                  Si une instance de surveillance existe déjà  pour lâobjet
                  de système de fichiers correspondant à pathname, ajouter
                  (avec un OU binaire) les événements de mask au masque de
                  surveillance (au lieu de remplacer le masque).

           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)
                  Ne surveiller pathname que si c'est un répertoire.

       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.

   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 « watches » qui
              peuvent être créées par identifiant utilisateur réel.

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

CONFORMITÃ
       Lâinterface de programmation inotify est spécifique à  Linux.

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'ioctl(2) FIONREAD renvoie le nombre d'octets disponibles pour la
       lecture d'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 pseudosystè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).

   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és 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.

       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.

BOGUES
       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 recycler 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.

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

   Exemple de sortie
           $ ./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>

       /* 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 et 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;
           int i;
           ssize_t len;
           char *ptr;

           /* 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 (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 (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 à été ouvert ;
              - un fichier à é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 »\n", argv[i]);
                   perror("inotify_add_watch");
                   exit(EXIT_FAILURE);
               }
           }

           /* Préparer pour la scrutation (polling) */

           nfds = 2;

           /* Entrée de console */

           fds[0].fd = STDIN_FILENO;
           fds[0].events = POLLIN;

           /* Entrée dânotify */

           fds[1].fd = fd;
           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

COLOPHON
       Cette page fait partie de la publication 3.70 du projet man-pages
       Linux. Une description du projet et des instructions pour signaler des
       anomalies peuvent être trouvées à l'adresse
       http://www.kernel.org/doc/man-pages/.

TRADUCTION
       Depuis 2010, cette traduction est maintenue à l'aide de l'outil po4a
       <http://po4a.alioth.debian.org/> par l'équipe de traduction
       francophone au sein du projet perkamon
       <http://perkamon.alioth.debian.org/>.

       Christophe Blaess <http://www.blaess.fr/christophe/> (1996-2003), Alain
       Portal <http://manpagesfr.free.fr/> (2003-2006).  Julien Cristau et
       l'équipe francophone de traduction de Debian (2006-2009).

       Veuillez signaler toute erreur de traduction en écrivant Ã
       <perkamon-fr@traduc.org>.

       Vous pouvez toujours avoir accès à la version anglaise de ce document
       en utilisant la commande « LC_ALL=C man <section> <page_de_man> ».



Linux                           8 juillet 2014                      INOTIFY(7)