inotify(7) Miscellaneous Information Manual inotify(7) NOM inotify - Surveiller les evenements des systemes de fichiers DESCRIPTION L'API inotify fournit un mecanisme pour surveiller les evenements au niveau des systemes de fichiers. Inotify peut etre utilise pour surveiller des fichiers individuels ou des repertoires. Quand un repertoire est surveille, inotify va signaler des evenements pour le repertoire lui-meme et pour les fichiers de ce repertoire. Les appels systeme suivants sont utilises avec cette interface de programmation : - inotify_init(2) cree une instance inotify et renvoie un descripteur de fichier se referant a cette instance inotify. L'appel systeme plus recent inotify_init1(2) est comme inotify_init(2), mais a un argument flags qui fournit un acces a des fonctionnalites supplementaires. - inotify_add_watch(2) manipule la << liste de surveillance >> associee a une instance inotify. Chaque element (<< watch >>) de la liste de surveillance indique le chemin d'un fichier ou d'un repertoire, avec un ensemble d'evenements que le noyau doit surveiller pour le fichier indique par ce chemin. inotify_add_watch(2) cree un nouvel element de surveillance ou modifie un element existant. Chaque element a un unique << descripteur de surveillance >>, un entier renvoye par inotify_add_watch(2) lorsque cet element est cree. - Quand les evenements ont lieu pour des fichiers et repertoires surveilles, ces evenements sont rendus disponibles a l'application comme des donnees structurees qui peuvent etre lues depuis le descripteur de fichier inotify en utilisant read(2) (voir plus bas). - inotify_rm_watch(2) retire un element d'une liste de surveillance inotify. - Quand tous les descripteurs de fichier se referant a une instance inotify ont ete fermes (en utilisant close(2)), l'objet sous-jacent et ses ressources sont liberes pour etre reutilises par le noyau ; tous les elements de surveillance associes sont automatiquement liberes. Avec une programmation prudente, une application peut utiliser inotify pour surveiller et mettre en cache efficacement l'etat d'un ensemble d'objets de systeme de fichiers. Cependant, les applications robustes devraient prendre en compte que des bogues dans la logique de surveillance ou des situations de competition du type decrit ci-dessous pourraient laisser le cache incoherent avec l'etat du systeme de fichiers. Realiser des verifications de coherence et reconstruire le cache en cas de detection d'incoherences serait sans doute sage. Lecture d'evenements d'un descripteur de fichier inotify Pour determiner quels evenements ont eu lieu, une application va lire avec read(2) le descripteur de fichier inotify. Si aucun evenement n'a eu lieu, alors, en supposant qu'il s'agisse d'un descripteur de fichier bloquant, read(2) se bloquera jusqu'a ce qu'au moins un evenement ait lieu (a moins qu'elle ne soit interrompue par un signal, auquel cas l'appel echouera avec l'erreur EINTR ; consultez signal(7)). Chaque lecture (avec read(2)) reussie renvoie un tampon contenant une ou plusieurs des structures suivantes : struct inotify_event { int wd; /* Descripteur de surveillance */ uint32_t mask; /* Masque decrivant l'evenement */ uint32_t cookie; /* Cookie unique d'association des evenements (pour rename(2)) */ uint32_t len; /* Taille du champ name */ char name[]; /* Nom optionnel termine par un nul */ }; wd identifie l'element de surveillance pour lequel cet evenement a lieu. Il s'agit de l'un des descripteurs de surveillance renvoyes par un precedent appel a inotify_add_watch(2). mask contient des bits qui decrivent l'evenement qui a eu lieu (voir ci-dessous). cookie est un entier unique qui relie les evenements. Ce n'est actuellement utilise que pour les evenements de renommage, et permet a la paire d'evenements IN_MOVED_FROM et IN_MOVED_TO en resultant d'etre associee par l'application. Pour tous les autres types d'evenements, cookie est mis a 0. Le champ name n'est present que lorsqu'un evenement est renvoye pour un fichier au sein d'un repertoire surveille. Il identifie le chemin du fichier dans le repertoire surveille. Ce chemin est termine par un caractere NULL et peut inclure d'autres octets nuls (<< \0 >>) pour ajuster des lectures successives a une limite d'adressage convenable. Le champ len compte tous les octets de name, incluant les caracteres nuls. La longueur de chaque structure inotify_event vaut donc sizeof(structinotify_event)+len. Le comportement, lorsque le tampon donne a read(2) est trop petit pour renvoyer l'information sur le prochain evenement, depend de la version du noyau : avant Linux 2.6.21, read(2) renvoie 0 ; depuis Linux 2.6.21, read(2) echoue avec l'erreur EINVAL. Indiquer un tampon de taille sizeof(struct inotify_event) + NAME_MAX + 1 est suffisant pour lire au moins un evenement. Evenements inotify L'argument mask passe a inotify_add_watch(2) et le champ mask de la structure inotify_event renvoyes lors de la lecture avec read(2) d'un descripteur de fichier inotify sont tous deux des masques binaires identifiant les evenements inotify. Les bits suivants peuvent etre definis dans l'argument mask lors de l'appel a inotify_add_watch(2) et peuvent etre renvoyes dans le champ mask renvoye par read(2). IN_ACCESS (+) Acces au fichier (par exemple read(2), execve(2)). IN_ATTRIB (*) Modification des metadonnees, par exemple, les permissions (par exemple chmod(2)), les horodatages (par exemple utimensat(2)), les attributs etendus (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 ecriture ferme. IN_CLOSE_NOWRITE (*) Fichier ou repertoire non ouverts en ecriture fermes. IN_CREATE (+) Fichier ou repertoire crees dans le repertoire surveille (par exemple open(2) O_CREAT, mkdir(2), link(2), symlink(2), bind(2) sur un socket de domaine UNIX). IN_DELETE (+) Fichier ou repertoire supprimes dans le repertoire surveille. IN_DELETE_SELF Fichier ou repertoire surveilles supprimes (cet evenement se produit egalement si un objet est deplace vers un autre systeme de fichiers, puisque mv(1) copie effectivement le fichier vers l'autre systeme de fichiers puis le supprime du systeme de fichiers d'origine). De plus, un evenement IN_IGNORED sera ensuite genere pour le descripteur de surveillance. IN_MODIFY (+) Fichier modifie (par exemple write(2), truncate(2)). IN_MOVE_SELF Fichier ou repertoire surveilles deplaces. IN_MOVED_FROM (+) Genere pour le repertoire contenant l'ancien nom quand un fichier est renomme. IN_MOVED_TO (+) Genere pour le repertoire contenant le nouveau nom quand un fichier est renomme. IN_OPEN (*) Fichier ou repertoire ouvert. La surveillance par Inotify est basee sur les inodes : lorsqu'un fichier est surveille (mais pas lors de la surveillance d'un repertoire contenant un fichier), un evenement peut etre cree sur tout lien vers le fichier (dans le meme repertoire ou dans un repertoire different). Lors de la surveillance d'un repertoire : - les evenements marques precedemment par un asterisque (*) peuvent avoir lieu a la fois pour le repertoire et pour les objets a l'interieur du repertoire ; - les evenements marques par un signe plus (+) n'ont lieu que pour les objets a l'interieur du repertoire (et non pour le repertoire lui-meme). Note : lorsqu'un repertoire est surveille, les evenements ne sont pas crees pour les fichiers contenus dans le repertoire quand des evenements sont executes avec un nom de chemin (par exemple, un lien) qui se trouve hors du repertoire surveille. Lorsque les evenements sont crees pour les objets dans un repertoire surveille, le champ name dans la structure inotify_event renvoyee identifie le nom du fichier dans ce repertoire. La macro IN_ALL_EVENTS est definie comme un masque binaire de tous les evenements decrits ci-dessus. Cette macro peut etre utilisee comme l'argument mask lors de l'appel a inotify_add_watch(2). Deux macros supplementaires de convenance sont definies : IN_MOVE Equivalent a IN_MOVED_FROM | IN_MOVED_TO. IN_CLOSE Equivalent a IN_CLOSE_WRITE | IN_CLOSE_NOWRITE. Les bits supplementaires suivants peuvent etre indiques dans l'argument mask lors de l'appel a inotify_add_watch(2) : IN_DONT_FOLLOW (depuis Linux 2.6.15) Ne pas dereferencer chemin s'il s'agit d'un lien symbolique. IN_EXCL_UNLINK (depuis Linux 2.6.36) Par defaut, lors de la surveillance d'evenements sur les entrees d'un repertoire, des evenements sont crees pour ces entrees meme apres leur suppression du repertoire. De nombreux evenements ininteressants pour certaines applications peuvent ainsi etre crees (par exemple, lors de la surveillance de /tmp, ou de nombreuses applications creent des fichiers temporaires donc les noms sont immediatement supprimes). Indiquer IN_EXCL_UNLINK modifie le comportement par defaut, de telle sorte qu'aucun evenement n'est cree pour ces entrees apres leur suppression du repertoire surveille. IN_MASK_ADD Si une instance de surveillance existe deja pour l'objet de systeme de fichiers correspondant a chemin, ajouter (avec un OU binaire) les evenements de mask au masque de surveillance (au lieu de remplacer le masque) ; il resulte une erreur EINVAL si IN_MASK_CREATE est aussi specifie. IN_ONESHOT Surveiller l'objet de systeme de fichiers correspondant a chemin jusqu'au premier evenement, puis le supprimer de la liste de surveillance. IN_ONLYDIR (depuis Linux 2.6.15) Surveiller chemin seulement s'il s'agit d'un repertoire ; il resulte une erreur ENOTDIR si chemin n'est pas un repertoire. Utiliser cet attribut fournit a une application un moyen sans probleme de concurrence de s'assurer qu'un objet surveille est un repertoire. IN_MASK_CREATE (depuis Linux 4.18) Surveiller chemin seulement s'il n'y a pas deja une surveillance qui lui est associee ; il resulte une erreur EEXIST si chemin est deja surveille. Utiliser cet attribut fournit a une application un moyen de s'assurer que de nouveaux elements de surveillance ne modifient pas ceux qui existent deja. C'est utile parce que plusieurs chemins peuvent faire reference au meme inoeud et plusieurs appels a inotify_add_watch(2) sans cet attribut peuvent ecraser des masques de surveillance existants. Les bits suivants peuvent avoir ete definis dans le champ mask renvoye par read(2) : IN_IGNORED Le surveillant a ete retire explicitement (inotify_rm_watch(2)) ou automatiquement (le fichier a ete efface, ou le systeme de fichiers a ete demonte). Consultez egalement BOGUES. IN_ISDIR Le sujet de cet evenement est un repertoire. IN_Q_OVERFLOW Queue des evenements surchargee (wd vaut alors -1). IN_UNMOUNT Le systeme de fichiers contenant l'objet surveille a ete demonte. De plus, un evenement IN_IGNORED sera ensuite genere pour le descripteur de surveillance. Exemples Soit une application surveillant le repertoire rep et le fichier rep/monfichier pour tous les evenements. Les exemples ci-dessous montrent quelques evenements qui seront generes pour ces deux objets. fd = open("rep/monfichier", O_RDWR); Genere des evenements IN_OPEN a la fois pour rep et rep/monfichier. read(fd, buf, count); Genere des evenements IN_ACCESS a la fois pour rep et rep/monfichier. write(fd, buf, count); Genere des evenements IN_MODIFY a la fois pour rep et rep/monfichier. fchmod(fd, mode); Genere des evenements IN_ATTRIB a la fois pour rep et rep/monfichier. close(fd); Genere des evenements IN_CLOSE_WRITE a la fois pour rep et rep/monfichier. Soit une application surveillant les repertoires rep1 et rep2, et le fichier rep1/monfichier. Les exemples suivants montrent quelques evenements qui pourraient etre generes. link("rep1/monfichier", "rep2/nouveau"); Genere un evenement IN_ATTRIB pour monfichier et un evenement IN_CREATE pour rep2. rename("rep1/monfichier", "rep2/monfichier"); Genere un evenement IN_MOVED_FROM pour dir1, un evenement IN_MOVED_TO pour rep2 et un evenement IN_MOVE_SELF pour monfichier. Les evenements IN_MOVED_FROM et IN_MOVED_TO auront la meme valeur cookie. Soient rep1/xx et rep2/yy les (seuls) liens vers le meme ficher, et une application surveillant rep1, rep2, rep1/xx et rep2/yy. L'execution des appels suivants dans l'ordre donne ci-dessous generera les evenements suivants : unlink("rep2/yy"); Genere un evenement IN_ATTRIB pour xx (a cause du changement de son compteur de liens) et un evenement IN_DELETE pour rep2. unlink("rep1/xx"); Genere des evenements IN_ATTRIB, IN_DELETE_SELF et IN_IGNORED pour xx et un evenement IN_DELETE pour rep1. Soit une application surveillant le repertoire rep et le repertoire (vide) rep/sousrep. Les exemples suivants montrent quelques evenements qui pourraient etre generes. mkdir("rep/nouveau", mode); Genere un evenement IN_CREATE | IN_ISDIR pour rep. rmdir("rep/sousrep"); Genere des evenements IN_DELETE_SELF et IN_IGNORED pour sousrep et un evenement IN_DELETE | IN_ISDIR pour rep. /proc interfaces Les interfaces suivantes peuvent etre utilisees pour limiter la quantite de memoire du noyau utilisee par inotify : /proc/sys/fs/inotify/max_queued_events La valeur dans ce fichier est utilisee lorsqu'une application appelle inotify_init(2) pour definir la limite maximale du nombre des evenements qui peuvent entrer dans la file d'attente de l'instance inotify correspondante. Les evenements au-dela de cette limite sont annules, mais un evenement IN_Q_OVERFLOW est systematiquement genere. /proc/sys/fs/inotify/max_user_instances Cela indique la limite maximale du nombre d'instances inotify qui peuvent etre creees par identifiant utilisateur reel. /proc/sys/fs/inotify/max_user_watches Cela indique la limite maximale du nombre de << watch >> qui peuvent etre crees par identifiant utilisateur reel. STANDARDS Linux. HISTORIQUE Inotify a ete inclus dans Linux 2.6.13. Les interfaces bibliotheque necessaires ont ete ajoutees dans la glibc 2.4 (IN_DONT_FOLLOW, IN_MASK_ADD et IN_ONLYDIR ont ete ajoutees dans la glibc 2.5). NOTES Les descripteurs de fichier inotify peuvent etre surveilles en utilisant select(2), poll(2) et epoll(7). Lorsqu'un evenement est disponible, le descripteur de fichier indique qu'il est accessible en lecture. Depuis Linux 2.6.25, il est possible d'etre notifie par des signaux pour des entrees-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 (decrite dans sigaction(2)) qui est passee au gestionnaire de signal a les champs suivants definis : si_fd est defini avec le numero de descripteur de fichiers inotify ; si_signo est defini avec le numero du signal ; si_code est defini avec POLL_IN ; et si_band est defini avec POLLIN. Si deux evenements inotify de sortie successifs produits sur le descripteur de fichier inotify sont identiques (wd, mask, cookie, et name identiques), alors ils sont fusionnes en un seul evenement si l'evenement le plus ancien n'a toujours pas ete lu (mais consultez la section BOGUES). Cela permet de reduire la quantite de memoire en espace noyau necessaire a la file d'evenements, mais signifie egalement qu'une application ne peut utiliser inotify pour compter de maniere fiable les evenements lies a un fichier. Les evenements renvoyes lors de la lecture d'un descripteur de fichier inotify forment une file ordonnee. Ainsi, par exemple, il est garanti que lors du renommage d'un repertoire, les evenements seront produits dans l'ordre convenable sur le descripteur de fichier inotify. L'ensemble des descripteurs surveilles grace a un descripteur de fichier inotify peut etre vu dans l'entree du descripteur de fichier inotify dans le repertoire /proc/pid/fdinfo du processus. Consultez proc(5) pour de plus amples details. FIONREAD ioctl(2) renvoie le nombre d'octets disponibles a la lecture dans un descripteur de fichier inotify. Limites et reserves L'interface inotify ne fournit aucun renseignement sur l'utilisateur ou le processus qui a declenche l'evenement inotify. En particulier, un processus en train de surveiller des evenements a l'aide d'inotify ne dispose d'aucun moyen facile pour distinguer les evenements qu'il declenche lui-meme de ceux qui ont ete declenches par d'autres processus. Inotify ne signale que les evenements declenches par un programme en espace utilisateur a l'aide de l'interface de programmation de systeme de fichiers. Par consequent, elle n'intercepte pas les evenements qui surviennent sur les systemes de fichiers en reseau (les applications doivent avoir recours a la scrutation (polling) pour intercepter ce type d'evenements). De plus, divers pseudo-systemes de fichiers comme /proc, /sys et /dev/pts ne sont pas surveillables avec inotify. L'interface inotify ne signale pas les acces ni les modifications de fichier qui pourraient survenir a cause de mmap(2), msync(2) ou munmap(2). L'interface inotify identifie les fichiers affectes par leur nom. Cependant, au moment ou l'application traite un evenement inotify, ce nom de fichier peut avoir deja ete supprime ou renomme. L'interface inotify identifie les evenements a l'aide de descripteurs de surveillance. L'application est responsable de mettre en cache une correspondance (si necessaire) entre les descripteurs de fichier et les chemins. Soyez vigilants aux renommages de repertoire qui pourraient affecter plusieurs chemins en cache. La surveillance inotify des repertoires n'est pas recursive : pour surveiller les sous-repertoires, des elements de surveillance supplementaires doivent etre crees. Cela peut etre assez long pour les repertoires contenant une grande arborescence. Si la surveillance concerne une arborescence dans son integralite, et si un nouveau sous-repertoire est cree dans ce repertoire ou si un repertoire existant est renomme dans cette arborescence, soyez conscient qu'au moment ou vous creez un element de surveillance pour le nouveau sous-repertoire, de nouveaux fichiers (et sous-repertoires) peuvent deja exister dans le sous-repertoire. Ainsi, vous devriez analyser le contenu du sous-repertoire immediatement apres avoir ajoute l'element de surveillance (et, si necessaire, ajouter des elements de surveillance pour tous les sous-repertoires qu'il contient). Remarquez que la file d'evenements peut deborder. Dans ce cas, des evenements sont perdus. Les applications robustes devraient gerer correctement la possibilite de perdre des evenements. Par exemple, la reconstruction de tout ou partie du cache de l'application pourrait etre necessaire (une approche simple, mais eventuellement couteuse, est de fermer le descripteur de fichier inotify, vider le cache, creer un nouveau descripteur de fichier inotify et recreer les elements de surveillance et les entrees du cache pour les objets a surveiller). Si un systeme de fichiers est monte par dessus un repertoire surveille, aucun evenement n'est genere, pas plus que pour les objets se trouvant directement sous le nouveau point de montage. Si le systeme de fichiers est par la suite demonte, les evenements seront crees pour le repertoire et les objets qu'il contient. Traitement des evenements rename() Comme note precedemment, la paire d'evenements IN_MOVED_FROM et IN_MOVED_TO generee par rename(2) peut etre assemblee a l'aide de la valeur de cookie partage. Cependant, la tache d'assemblage peut poser quelques problemes. Ces deux evenements sont normalement consecutifs dans le flux d'evenements disponibles lors de la lecture depuis le descripteur de fichiers inotify. Cependant, ce n'est pas garanti. Si plusieurs processus declenchent des evenements pour des objets surveilles, alors (rarement) un nombre arbitraire d'autres evenements pourrait apparaitre entre les evenements IN_MOVED_FROM et IN_MOVED_TO. De plus, il n'est pas garanti que la paire d'evenements soit inseree de facon 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'evenements IN_MOVED_FROM et IN_MOVED_TO generes par rename(2) pose donc intrinsequement un risque de situation de competition (n'oubliez pas que si un objet est renomme en dehors d'un repertoire surveille, un evenement IN_MOVED_TO pourrait ne meme pas etre envoye). Des approches heuristiques (par exemple supposer que les evenements sont toujours consecutifs) permettent d'assurer un assemblage dans la plupart des cas, mais manqueront forcement certains cas, forcant l'application a percevoir les evenements IN_MOVED_FROM et IN_MOVED_TO comme independants. Si les descripteurs de surveillance sont detruits et recrees par consequent, alors ces descripteurs de surveillance seront incoherents avec les descripteurs de surveillance dans tous les evenements en attente (la recreation du descripteur de fichier inotify et la reconstruction du cache pourrait etre utile dans ce cas). Les applications devraient aussi considerer la possibilite que l'evenement IN_MOVED_FROM soit le dernier evenement ayant pu entrer dans le tampon renvoye pour l'appel actuel de read(2) et l'evenement IN_MOVED_TO accompagnant pourrait n'etre recupere que lors de l'appel read(2) suivant, ce qui devrait etre fait avec un (leger) delai pour permettre que l'insertion de la paire d'evenements IN_MOVED_FROM+IN_MOVED_TO ne soit pas atomique et aussi qu'il n'y ait pas d'evenement IN_MOVED_TO. BOGUES Avant Linux 3.19, fallocate(2) ne creait pas d'evenements inotify. Depuis Linux 3.19, les appels a fallocate(2) creent des evenements IN_MODIFY. Avant Linux 2.6.16, l'attribut IN_ONESHOT de mask ne fonctionne pas. Tel que concu et implemente a l'origine, l'attribut IN_ONESHOT ne forcait pas a generer un appel IN_IGNORED lorsque la surveillance etait supprimee apres un evenement. Cependant, en consequence involontaire d'autres modifications, depuis Linux 2.6.36, un evenement IN_IGNORED est genere dans ce cas. Avant Linux 2.6.25, le code du noyau qui etait cense regrouper deux evenements successifs (c'est-a-dire que les deux evenements les plus recents pouvaient etre fusionnes si le plus ancien des deux n'avait toujours pas ete lu) verifiait a la place si l'evenement le plus recent pouvait etre fusionne a l'evenement non lu le plus ancien. Quand un descripteur de surveillance est supprime en appelant inotify_rm_watch(2) (ou parce qu'un fichier de surveillance est supprime ou que le systeme de fichiers qui le contient est demonte), tous les evenements non lus en attente pour ce descripteur de fichier restent disponibles en lecture. Comme les descripteurs de surveillance sont ensuite alloues avec inotify_add_watch(2), le noyau boucle sur l'intervalle des descripteurs de surveillance possibles (1 a INT_MAX) de facon incrementielle. Lors de l'allocation d'un descripteur de surveillance libre, aucune verification n'est effectuee pour voir si ce numero de descripteur de surveillance a des evenements non lus en attente dans la file inotify. Ainsi, un descripteur de surveillance pourrait etre realloue meme quand des evenements non lus en attente existent pour une incarnation precedente de ce numero de descripteur de surveillance, avec comme resultat que l'application pourrait alors lire ces evenements et les interpreter comme appartenant au fichier associe au descripteur de surveillance nouvellement recycle. En pratique, la probabilite d'etre victime de ce bogue devrait etre extremement basse, puisqu'il necessite qu'une application boucle sur INT_MAX descripteurs de surveillance, relache un descripteur de surveillance tout en laissant des evenements 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 a propos de reelles applications, dans Linux 3.15, aucune modification de noyau n'a encore ete faite pour eliminer ce bogue eventuel. EXEMPLES Le programme suivant montre l'utilisation de l'interface de programmation inotify. Il marque les repertoires passes en arguments de ligne de commande et attend les evenements de type IN_OPEN, IN_CLOSE_NOWRITE et IN_CLOSE_WRITE. La sortie suivante a ete enregistree lors de la modification du fichier /home/utilisateur/temp/toto et de l'affichage du contenu du repertoire /tmp. Avant d'ouvrir le fichier et le repertoire, un evenement IN_OPEN est survenu. Apres la fermeture du fichier, un evenement IN_CLOSE_WRITE est survenu. Apres la fermeture du repertoire, un evenement IN_CLOSE_NOWRITE est survenu. L'execution du programme s'est terminee quand l'utilisateur a appuye sur la touche Entree. Sortie de l'exemple $ ./a.out /tmp /home/utilisateur/temp Appuyer sur la touche Entree pour quitter. En ecoute d'evenements. IN_OPEN : /home/utilisateur/temp/toto [fichier] IN_CLOSE_WRITE : /home/utilisateur/temp/toto [fichier] IN_OPEN : /tmp/ [repertoire] IN_CLOSE_NOWRITE : /tmp/ [repertoire] Arret de l'ecoute d'evenements. Source du programme #include #include #include #include #include #include #include /* Lire tous les evenements inotify disponibles a partir du descripteur de fichier << fd >>. wd est le tableau des descripteurs de surveillance pour les repertoires en argv. argc est la taille de wd et argv. argv est la liste des repertoires surveilles. L'entree 0 de wd et argv n'est pas utilisee. */ static void handle_events(int fd, int *wd, int argc, char* argv[]) { /* Certains systemes ne peuvent pas lire de variables entieres si elles ne sont pas alignees correctement. Sur d'autres systemes, un alignement incorrect pourrait diminuer les performances. Par consequent, le tampon utilise pour lire le descripteur de fichier inotify devrait avoir le meme 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 evenements peuvent etre lus a partir du descripteur de fichier inotify */ for (;;) { /* Lire certains evenements. */ len = read(fd, buf, sizeof(buf)); if (len == -1 && errno != EAGAIN) { perror("read"); exit(EXIT_FAILURE); } /* Si le read() non bloquant n'a pas trouve d'evenement a lire, il renvoie -1 avec errno defini a EAGAIN. Dans ce cas, on sort de la boucle. */ if (len <= 0) break; /* Boucler sur tous les evenements 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'evenement. */ 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 repertoire surveille. */ 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 systeme de fichiers. */ if (event->mask & IN_ISDIR) printf(" [repertoire]\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 Entree pour quitter.\n"); /* Creer le descripteur de fichier pour acceder a l'interface de programmation inotify. */ fd = inotify_init1(IN_NONBLOCK); if (fd == -1) { perror("inotify_init1"); exit(EXIT_FAILURE); } /* Allouer la memoire pour les descripteurs de surveillance. */ wd = calloc(argc, sizeof(int)); if (wd == NULL) { perror("calloc"); exit(EXIT_FAILURE); } /* Marquer les repertoires pour les evenements : - un fichier a ete ouvert ; - un fichier a ete ferme 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); } } /* Preparer pour la scrutation (polling). */ nfds = 2; fds[0].fd = STDIN_FILENO; /* Entree de console */ fds[0].events = POLLIN; fds[1].fd = fd; /* Entree d'inotify */ fds[1].events = POLLIN; /* Attendre les evenements ou une entree du terminal. */ printf("En ecoute d'evenements.\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) { /* Entree de console disponible. Vider l'entree standard et quitter. */ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n') continue; break; } if (fds[1].revents & POLLIN) { /* Des evenements inotify sont disponibles. */ handle_events(fd, wd, argc, argv); } } } printf("Arret de l'ecoute d'evenements.\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 francaise de cette page de manuel a ete creee par Christophe Blaess , Stephan Rafin , Thierry Vignaud , Francois Micaux, Alain Portal , Jean-Philippe Guerard , Jean-Luc Coulon (f5ibh) , Julien Cristau , Thomas Huriaux , Nicolas Francois , Florentin Duneau , Simon Paillard , Denis Barbier , David Prevot , Thomas Vincent et Jean- Pierre Giraud Cette traduction est une documentation libre ; veuillez vous reporter a la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITE LEGALE. Si vous decouvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message a . Pages du manuel de Linux 6.06 31 octobre 2023 inotify(7)