Provided by: manpages-fr_4.21.0-2_all 

NOM
fanotify – Surveiller les événements des systèmes de fichiers
DESCRIPTION
L’interface de programmation fanotify permet la notification et l’interception des événements du système
de fichiers. La recherche de virus et la gestion de stockage hiérarchisé font partie des cas
d’utilisation. Dans l’interface originelle seul un ensemble limité d’événements était pris en charge. En
particulier, les événements de création, de suppression ou de déplacement n’étaient pas pris en charge.
La prise en charge de ces évènements a été ajoutée dans Linux 5.1. Consultez inotify(7) pour plus de
précisions sur l’interface qui ne notifiait pas ces évènements avant Linux 5.1.
La capacité de surveiller tous les objets d’un système de fichiers monté, la capacité de décider des
droits d’accès et la possibilité de lire ou modifier les fichiers avant qu’ils ne soient accédés par
d’autres applications font partie des capacités supplémentaires à celles de l’interface de programmation
inotify(7).
Les appels système suivants sont utilisés avec cette interface de programmation : fanotify_init(2),
fanotify_mark(2), read(2), write(2) et close(2).
fanotify_init(), fanotify_mark() et groupes de notification
L’appel système fanotify_init(2) crée et initialise un groupe de notifications fanotify et renvoie un
descripteur de fichier le référençant.
Un groupe de notifications fanotify est un objet interne au noyau qui contient une liste de fichiers,
répertoires et points de montage pour lesquels des événements seront créés.
Pour chaque entrée dans un groupe de notifications fanotify, deux masques binaires sont présents : le
masque mark et le masque ignore. Le masque mark définit les activités de fichier pour lesquelles un
événement doit être créé. Le masque ignore définit les activités pour lesquelles aucun événement ne doit
être créé. Avoir ces deux types de masque permet à un point de montage ou à un répertoire d’être marqué
pour recevoir des événements, tout en ignorant en même temps les événements pour des objets spécifiques
dans ce point de montage ou répertoire.
L’appel système fanotify_mark(2) ajoute un fichier, répertoire ou point de montage à un groupe de
notifications et indique les événements qui doivent être signalés (ou ignorés), ou supprime ou modifie
une telle entrée.
Le masque ignore peut servir pour un cache de fichier. Les événements intéressants pour un cache de
fichier sont la modification et la fermeture d’un fichier. Ainsi, le répertoire ou point de montage en
cache va être marqué pour recevoir ces événements. Après la réception du premier événement informant
qu’un fichier a été modifié, l’entrée correspondante du cache sera désactivée. Aucun autre événement de
modification pour ce fichier ne sera utile jusqu’à sa fermeture. Ainsi, l’événement de modification peut
être ajouté au masque ignore. Lors de la réception d’un événement de fermeture, l’événement de
modification peut être supprimé du masque ignore et l’entrée de cache de fichier peut être mise à jour.
Les entrées des groupes de notification fanotify font référence aux fichiers et répertoires à l’aide de
leur numéro d’inœud et aux montages à l’aide de leur identifiant de montage. Si les fichiers ou
répertoires sont renommés ou déplacés dans le même montage, les entrées correspondantes survivent. Si les
fichiers ou répertoires sont supprimés ou déplacés dans un autre montage ou si les montages sont
démontés, les entrées correspondantes sont supprimées.
La file d’événements
Comme les événements surviennent sur les objets de système de fichiers surveillés par un groupe de
notifications, le système fanotify génère les événements qui sont collectés dans une file. Ces événements
peuvent être lus (en utilisant read(2) ou similaire) à partir du descripteur de fichier fanotify renvoyé
par fanotify_init(2).
Deux types d’événements sont créés : les événements de notification et les événements de permission. Les
événements de notification sont surtout informatifs et ne nécessitent pas d’action à prendre par
l’application qui les reçoit à part pour la fermeture du descripteur de fichier valable passé dans
l’événement (voir ci-dessous). Les événements de permission sont des demandes à l’application qui les
reçoit pour décider si les droits d’accès à un fichier doivent être attribués. Pour ces événements, le
destinataire doit écrire une réponse qui décide d’attribuer l’accès ou non.
Un événement est supprimé de la file d’événements du groupe fanotify quand il a été lu. Les événements de
permission qui ont été lus sont gardés dans une liste interne du groupe fanotify jusqu’à ce qu’une
décision d’attribution de droits ait été prise en écrivant dans le descripteur de fichier fanotify ou que
le descripteur de fichier fanotify soit fermé.
Lecture d’événements fanotify
Appeler read(2) pour le descripteur de fichier renvoyé par fanotify_init(2) bloque (si l’attribut
FAN_NONBLOCK n’est pas indiqué dans l’appel de fanotify_init(2)) jusqu’à ce qu’un événement de fichier
survienne ou que l’appel soit interrompu par un signal (consultez signal(7)).
Après un read(2) réussi, le tampon de lecture contient une ou plus des structures suivantes :
struct fanotify_event_metadata {
__u32 event_len;
__u8 vers;
__u8 reserved;
__u16 metadata_len;
__aligned_u64 mask;
__s32 fd;
__s32 pid;
};
Information records are supplemental pieces of information that may be provided alongside the generic
fanotify_event_metadata structure. The flags passed to fanotify_init(2) have influence over the type of
information records that may be returned for an event. For example, if a notification group is
initialized with FAN_REPORT_FID or FAN_REPORT_DIR_FID, then event listeners should also expect to receive
a fanotify_event_info_fid structure alongside the fanotify_event_metadata structure, whereby file handles
are used to identify filesystem objects rather than file descriptors. Information records may also be
stacked, meaning that using the various FAN_REPORT_* flags in conjunction with one another is supported.
In such cases, multiple information records can be returned for an event alongside the generic
fanotify_event_metadata structure. For example, if a notification group is initialized with
FAN_REPORT_TARGET_FID and FAN_REPORT_PIDFD, then an event listener should expect to receive up to two
fanotify_event_info_fid information records and one fanotify_event_info_pidfd information record
alongside the generic fanotify_event_metadata structure. Importantly, fanotify provides no guarantee
around the ordering of information records when a notification group is initialized with a stacked based
configuration. Each information record has a nested structure of type fanotify_event_info_header. It is
imperative for event listeners to inspect the info_type field of this structure in order to determine the
type of information record that had been received for a given event.
In cases where an fanotify group identifies filesystem objects by file handles, event listeners should
also expect to receive one or more of the below information record objects alongside the generic
fanotify_event_metadata structure within the read buffer:
struct fanotify_event_info_fid {
struct fanotify_event_info_header hdr;
__kernel_fsid_t fsid;
unsigned char file_handle[0];
};
In cases where an fanotify group is initialized with FAN_REPORT_PIDFD, event listeners should expect to
receive the below information record object alongside the generic fanotify_event_metadata structure
within the read buffer:
struct fanotify_event_info_pidfd {
struct fanotify_event_info_header hdr;
__s32 pidfd;
};
In case of a FAN_FS_ERROR event, an additional information record describing the error that occurred is
returned alongside the generic fanotify_event_metadata structure within the read buffer. This structure
is defined as follows:
struct fanotify_event_info_error {
struct fanotify_event_info_header hdr;
__s32 error;
__u32 error_count;
};
All information records contain a nested structure of type fanotify_event_info_header. This structure
holds meta-information about the information record that may have been returned alongside the generic
fanotify_event_metadata structure. This structure is defined as follows:
struct fanotify_event_info_header {
__u8 info_type;
__u8 pad;
__u16 len;
};
Pour des raisons de performances, une grande taille de tampon (par exemple 4096 octets) est conseillée
pour que plusieurs événements puissent être récupérés en une seule lecture.
La valeur de retour de read(2) est le nombre d’octets placés dans le tampon, ou -1 en cas d’erreur (mais
consultez BOGUES).
Les champs de la structure fanotify_event_metadata sont les suivants.
event_len
C’est la taille des données pour l’événement actuel et la position du prochain événement dans le
tampon. À moins que le groupe identifie des objets du système de fichiers par des gestionnaires de
fichiers, la valeur d’event_len est toujours FAN_EVENT_METADATA_LEN. Pour un groupe qui identifie
les objets du système de fichiers par des gestionnaires de fichiers, event_len inclut aussi des
enregistrements d’identificateur de fichier de taille variable.
vers Ce champ contient un numéro de version pour la structure. Il doit être comparé à
FANOTIFY_METADATA_VERSION pour vérifier que les structures renvoyées pendant l’exécution
correspondent aux structures définies à la compilation. En cas d’erreur de correspondance,
l’application devrait arrêter d’essayer d’utiliser le descripteur de fichier fanotify.
reserved
Ce champ n’est pas utilisé.
metadata_len
C’est la taille de la structure. Le champ a été introduit pour faciliter l’implémentation
d’en-têtes facultatifs par type d’événement. Aucun en-tête facultatif n’existe dans
l’implémentation actuelle.
mask C’est un masque binaire décrivant l’événement (voir ci-dessous).
fd C’est un descripteur de fichier ouvert pour l’objet actuellement accédé ou FAN_NOFD si un
dépassement de file est survenu. Avec un groupe fanotify qui identifie les objets de système
d’exploitation par des gestionnaires de fichiers, les applications doivent escompter que cette
valeur soit FAN_NOFD pour chaque évènement qu’elles reçoivent. Le descripteur de fichier peut être
utilisé pour accéder au contenu du fichier ou répertoire surveillé. L’application qui lit est
responsable de la fermeture de ce descripteur de fichier.
Lors d’un appel de fanotify_init(2), l’appelant pourrait indiquer (à l’aide de l’argument
event_f_flags) plusieurs attributs d’état de fichier à définir dans la description de fichier
ouverte qui correspond à ce descripteur de fichier. De plus, l’attribut d’état de fichier
FMODE_NONOTIFY (interne au noyau) est défini dans la description de fichier ouverte. L’attribut
supprime la création d’événement fanotify. Ainsi, quand le destinataire de l’événement fanotify
accède au fichier ou répertoire notifié en utilisant ce descripteur de fichier, aucun événement
supplémentaire n’est créé.
pid Si l’attribut FAN_REPORT_TID était réglé dans fanotify_init(2), c’est l’identifiant (TID) du
thread qui a provoqué cet évènement. Sinon, c’est le PID du processus qui a provoqué cet
évènement.
Un programme écoutant les événements fanotify peut comparer ce PID au PID renvoyé par getpid(2) pour
déterminer si l’événement est provoqué par l’écoutant lui-même ou par un autre processus accédant au
fichier.
Le masque binaire mask indique les événements survenus pour un seul objet de système de fichiers.
Plusieurs bits pourraient être définis dans ce masque si plus d’un événement est survenu pour l’objet de
système de fichiers surveillé. En particulier, les événements consécutifs pour le même objet de système
de fichiers et originaires du même processus pourraient être fusionnés dans un seul événement, mais deux
événements de permission ne sont jamais fusionnés dans une entrée de file.
Les bits pouvant apparaître dans mask sont les suivants.
FAN_ACCESS
Un fichier ou un répertoire (mais consultez BOGUES) a été accédé (en lecture).
FAN_OPEN
Un fichier ou un répertoire a été ouvert.
FAN_OPEN_EXEC
Un fichier a été ouvert dans le but d’être exécuté. Consultez NOTES dans fanotify_mark(2) pour
plus de détails.
FAN_ATTRIB
Une métadonnée de fichier ou d’un répertoire a été modifiée.
FAN_CREATE
Un fichier enfant ou un répertoire a été créé dans le répertoire surveillé.
FAN_DELETE
Un fichier enfant ou un répertoire a été supprimé dans le répertoire surveillé.
FAN_DELETE_SELF
Un fichier ou un répertoire a été supprimé.
FAN_FS_ERROR
A filesystem error was detected.
FAN_RENAME
A file or directory has been moved to or from a watched parent directory.
FAN_MOVED_FROM
Un fichier ou un répertoire a été déplacé du répertoire surveillé.
FAN_MOVED_TO
Un fichier ou un répertoire a été déplacé du répertoire parent surveillé.
IN_MOVE_SELF
Un fichier ou un répertoire surveillé a été déplacé.
FAN_MODIFY
Un fichier a été modifié.
FAN_CLOSE_WRITE
Un fichier qui était ouvert en écriture (O_WRONLY ou O_RDWR) a été fermé.
FAN_CLOSE_NOWRITE
Un fichier ou un répertoire, qui était ouvert en lecture seule (O_RDONLY), a été fermé.
FAN_Q_OVERFLOW
The event queue exceeded the limit on number of events. This limit can be overridden by specifying
the FAN_UNLIMITED_QUEUE flag when calling fanotify_init(2).
FAN_ACCESS_PERM
Une application veut lire un fichier ou répertoire, par exemple en utilisant read(2) ou
readdir(2). Le lecteur doit écrire une réponse (telle que décrite ci-dessous) qui détermine si le
droit d’accès à l’objet de système de fichiers sera attribué.
FAN_OPEN_PERM
Une application veut ouvrir un fichier ou un répertoire. Le lecteur doit écrire une réponse qui
détermine si le droit d’ouvrir l’objet de système de fichiers sera attribué.
FAN_OPEN_PERM
Une application veut ouvrir un fichier pour une exécution. Le lecteur doit écrire une réponse qui
détermine si le droit d’ouvrir l’objet de système de fichiers sera attribué. Consultez NOTES dans
fanotify_mark(2) pour plus de détails.
Pour vérifier tous les événements fermés, le masque binaire suivant pourrait être utilisé :
FAN_CLOSE
Un fichier a été fermé. C’est un synonyme de :
FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE
Pour vérifier tous les événements de déplacement, le masque binaire suivant pourrait être utilisé :
FAN_MOVE
Un fichier ou un répertoire a été déplacé. C’est un synonyme de :
FAN_MOVED_FROM | FAN_MOVED_TO
Les bits suivants peuvent apparaître dans mask seulement conjointement avec d’autres bits de type
d’évènement :
FAN_ONDIR
Les évènements décrits dans le mask se sont déroulés dans un objet de répertoire. Le rapport
d’évènements dans des répertoires requiert le réglage de cet attribut dans le masque mark.
Consultez fanotify_mark(2) pour plus de détails. L’attribut FAN_ONDIR est rapporté dans un masque
d’évènement seulement si le groupe fanotify identifie les objets de système d’exploitation avec
des gestionnaires de fichiers.
Information records that are supplied alongside the generic fanotify_event_metadata structure will always
contain a nested structure of type fanotify_event_info_header. The fields of the
fanotify_event_info_header are as follows:
info_type
A unique integer value representing the type of information record object received for an event.
The value of this field can be set to one of the following: FAN_EVENT_INFO_TYPE_FID,
FAN_EVENT_INFO_TYPE_DFID, FAN_EVENT_INFO_TYPE_DFID_NAME, or FAN_EVENT_INFO_TYPE_PIDFD. The value
set for this field is dependent on the flags that have been supplied to fanotify_init(2). Refer to
the field details of each information record object type below to understand the different cases
in which the info_type values can be set.
pad This field is currently not used by any information record object type and therefore is set to
zero.
len The value of len is set to the size of the information record object, including the
fanotify_event_info_header. The total size of all additional information records is not expected
to be larger than (event_len - metadata_len).
Les champs de la structure fanotify_event_info_fid sont les suivants.
hdr This is a structure of type fanotify_event_info_header. For example, when an fanotify file
descriptor is created using FAN_REPORT_FID, a single information record is expected to be attached
to the event with info_type field value of FAN_EVENT_INFO_TYPE_FID. When an fanotify file
descriptor is created using the combination of FAN_REPORT_FID and FAN_REPORT_DIR_FID, there may be
two information records attached to the event: one with info_type field value of
FAN_EVENT_INFO_TYPE_DFID, identifying a parent directory object, and one with info_type field
value of FAN_EVENT_INFO_TYPE_FID, identifying a child object. Note that for the directory entry
modification events FAN_CREATE, FAN_DELETE, FAN_MOVE, and FAN_RENAME, an information record
identifying the created/deleted/moved child object is reported only if an fanotify group was
initialized with the flag FAN_REPORT_TARGET_FID.
fsid C’est un identifiant unique du système de fichiers contenant l’objet associé avec l’évènement.
C’est une structure de type __kernel_fsid_t et elle contient la même valeur que f_fsid lors de
l’appel statfs(2).
file_handle
This is a variable length structure of type struct file_handle. It is an opaque handle that
corresponds to a specified object on a filesystem as returned by name_to_handle_at(2). It can be
used to uniquely identify a file on a filesystem and can be passed as an argument to
open_by_handle_at(2). If the value of info_type field is FAN_EVENT_INFO_TYPE_DFID_NAME, the file
handle is followed by a null terminated string that identifies the created/deleted/moved directory
entry name. For other events such as FAN_OPEN, FAN_ATTRIB, FAN_DELETE_SELF, and FAN_MOVE_SELF, if
the value of info_type field is FAN_EVENT_INFO_TYPE_FID, the file_handle identifies the object
correlated to the event. If the value of info_type field is FAN_EVENT_INFO_TYPE_DFID, the
file_handle identifies the directory object correlated to the event or the parent directory of a
non-directory object correlated to the event. If the value of info_type field is
FAN_EVENT_INFO_TYPE_DFID_NAME, the file_handle identifies the same directory object that would be
reported with FAN_EVENT_INFO_TYPE_DFID and the file handle is followed by a null terminated string
that identifies the name of a directory entry in that directory, or '.' to identify the directory
object itself.
The fields of the fanotify_event_info_pidfd structure are as follows:
hdr This is a structure of type fanotify_event_info_header. When an fanotify group is initialized
using FAN_REPORT_PIDFD, the info_type field value of the fanotify_event_info_header is set to
FAN_EVENT_INFO_TYPE_PIDFD.
pidfd This is a process file descriptor that refers to the process responsible for generating the event.
The returned process file descriptor is no different from one which could be obtained manually if
pidfd_open(2) were to be called on fanotify_event_metadata.pid. In the instance that an error is
encountered during pidfd creation, one of two possible error types represented by a negative
integer value may be returned in this pidfd field. In cases where the process responsible for
generating the event has terminated prior to the event listener being able to read events from the
notification queue, FAN_NOPIDFD is returned. The pidfd creation for an event is only performed at
the time the events are read from the notification queue. All other possible pidfd creation
failures are represented by FAN_EPIDFD. Once the event listener has dealt with an event and the
pidfd is no longer required, the pidfd should be closed via close(2).
The fields of the fanotify_event_info_error structure are as follows:
hdr This is a structure of type fanotify_event_info_header. The info_type field is set to
FAN_EVENT_INFO_TYPE_ERROR.
error Identifies the type of error that occurred.
error_count
This is a counter of the number of errors suppressed since the last error was read.
Les macros suivantes sont fournies pour itérer sur un tampon contenant les métadonnées d’événement
fanotify renvoyées par read(2) à partir d’un descripteur de fichier fanotify.
FAN_EVENT_OK(meta, len)
Cette macro compare la taille restante len du tampon meta à la taille de la structure de
métadonnées et au champ event_len de la première structure de métadonnées du tampon.
FAN_EVENT_NEXT(meta, len)
Cette macro utilise la taille indiquée dans le champ event_len de la structure de métadonnées
pointée par meta pour calculer l’adresse de la prochaine structure de métadonnées qui suit meta.
len est le nombre d’octets de métadonnées qui restent actuellement dans le tampon. La macro
renvoie un pointeur vers la prochaine structure de métadonnées qui suit meta et réduit len du
nombre d’octets dans la structure de métadonnées qui a été sautée (c’est-à-dire qu’elle soustrait
meta->event_len de len).
De plus, il existe :
FAN_EVENT_METADATA_LEN
Cette macro renvoie la taille (en octet) de la structure fanotify_event_metadata. C’est la taille
minimale (et actuellement la seule taille) de métadonnées d’événements.
Surveiller un descripteur de fichier fanotify pour les événements
Quand un événement fanotify survient, le descripteur de fichier fanotify est indiqué comme lisible
lorsque passé à epoll(7), poll(2) ou select(2).
Traitement des événements de permission
Pour les événements de permission, l’application doit écrire (avec write(2)) une structure de la forme
suivante sur le descripteur de fichier fanotify :
struct fanotify_response {
__s32 fd;
__u32 response;
};
Les membres de cette structure sont les suivants :
fd C’est le descripteur de fichier de la structure fanotify_event_metadata.
response
Ce champ indique si les droits doivent être attribués ou non. Cette valeur doit être soit
FAN_ALLOW pour permettre l’opération de fichier, soit FAN_DENY pour refuser l’opération de
fichier.
Si l’accès est refusé, l’appel de l’application requérante recevra une erreur EPERM. De plus, si le
groupe de notifications a été créé avec l’attribut FAN_ENABLE_AUDIT, alors l’attribut FAN_AUDIT peut être
défini dans le champ response. Dans ce cas, le sous-système d’audit journalisera l’information à propos
de la décision d’accès aux journaux d’audit.
Monitoring filesystems for errors
A single FAN_FS_ERROR event is stored per filesystem at once. Extra error messages are suppressed and
accounted for in the error_count field of the existing FAN_FS_ERROR event record, but details about the
errors are lost.
Errors reported by FAN_FS_ERROR are generic errno values, but not all kinds of error types are reported
by all filesystems.
Errors not directly related to a file (i.e. super block corruption) are reported with an invalid
file_handle. For these errors, the file_handle will have the field handle_type set to FILEID_INVALID, and
the handle buffer size set to 0.
Fermeture du descripteur de fichier fanotify
Quand tous les descripteurs de fichier se référant au groupe de notifications fanotify sont fermés, le
groupe fanotify est libéré et ses ressources sont libérées pour être réutilisées par le noyau. Lors de
l’appel de close(2), les événements de permission restants seront définis à permis.
Interfaces /proc
Le fichier /proc/[pid]/fdinfo/[fd] contient des renseignements sur les marques fanotify pour le
descripteur de fichier fd du processus pid. Consultez proc(5) pour plus de précisions.
Since Linux 5.13, the following interfaces can be used to control the amount of kernel resources consumed
by fanotify:
/proc/sys/fs/fanotify/max_queued_events
The value in this file is used when an application calls fanotify_init(2) to set an upper limit on
the number of events that can be queued to the corresponding fanotify group. Events in excess of
this limit are dropped, but an FAN_Q_OVERFLOW event is always generated. Prior to Linux kernel
5.13, the hardcoded limit was 16384 events.
/proc/sys/fs/fanotify/max_user_group
This specifies an upper limit on the number of fanotify groups that can be created per real user
ID. Prior to Linux kernel 5.13, the hardcoded limit was 128 groups per user.
/proc/sys/fs/fanotify/max_user_marks
This specifies an upper limit on the number of fanotify marks that can be created per real user
ID. Prior to Linux kernel 5.13, the hardcoded limit was 8192 marks per group (not per user).
ERREURS
En plus des erreurs habituelles de read(2), les erreurs suivantes peuvent survenir lors de la lecture
d’un descripteur de fichier fanotify.
EINVAL Le tampon est trop petit pour contenir l’événement.
EMFILE La limite par processus du nombre de fichiers ouverts a été atteinte. Consultez la description de
RLIMIT_NOFILE dans getrlimit(2).
ENFILE La limite du nombre de fichiers ouverts sur le système a été atteinte. Consultez
/proc/sys/fs/file-max dans proc(5).
ETXTBSY
Cette erreur est renvoyée par read(2) si O_RDWR ou O_WRONLY ont été indiqués dans l’argument
event_f_flags lors de l’appel fanotify_init(2) et qu’un événement est survenu pour un fichier
surveillé actuellement en cours d’exécution.
En plus des erreurs habituelles de write(2), les erreurs suivantes peuvent survenir lors de l’écriture
sur un descripteur de fichier fanotify.
EINVAL Les droits d’accès fanotify ne sont pas activés dans la configuration du noyau ou la valeur de
response dans la structure de réponse n’est pas valable.
ENOENT Le descripteur de fichier fd dans la structure de réponse n’est pas valable. Cela pourrait
survenir quand une réponse pour l’événement de permission a déjà été écrite.
VERSIONS
The fanotify API was introduced in Linux 2.6.36 and enabled in Linux 2.6.37. Fdinfo support was added in
Linux 3.8.
STANDARDS
L’interface de programmation fanotify est spécifique à Linux.
NOTES
L’interface de programmation fanotify n’est disponible que si le noyau a été construit avec l’option de
configuration CONFIG_FANOTIFY activée. De plus, le traitement de permission fanotify n’est disponible que
si l’option de configuration CONFIG_FANOTIFY_ACCESS_PERMISSIONS est activée.
Limites et réserves
Fanotify ne signale que les événements déclenchés par un programme en espace utilisateur à l’aide d’une
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.
L'interface fanotify ne signale pas les accès ni les modifications de fichier qui pourraient survenir à
cause de mmap(2), msync(2) ou munmap(2).
Les événements pour répertoire ne sont créés que si le répertoire lui-même est ouvert, lu et fermé.
Ajouter, supprimer ou modifier les enfants d’un répertoire marqué ne crée pas d’événement pour le
répertoire surveillé lui-même.
La surveillance fanotify des répertoires n'est pas récursive : pour surveiller les sous-répertoires, des
marques supplémentaires doivent être créées. L’évènement FAN_CREATE peut être utilisé pour détecter quand
un sous-répertoire a été créé dans un répertoire marqué. Une marque supplémentaire doit être définie dans
le sous-répertoire nouvellement créé. Cette approche crée une situation de compétition, parce qu’elle
peut perdre les évènements qui se produisent dans le nouveau sous-répertoire avant qu’une marque soit
ajoutée dans ce sous-répertoire. La surveillance des montages offre la capacité de surveiller un arbre
entier de répertoires sans ce problème de chronologie. La surveillance de système de fichiers offre la
capacité de surveiller tout montage d’une instance de système de fichiers sans situation de compétition.
La file d'événements peut déborder. Dans ce cas, les événements sont perdus.
BOGUES
Avant Linux 3.19, fallocate(2) ne créait pas d'événement fanotify. Depuis Linux 3.19, les appels à
fallocate(2) créent des événements FAN_MODIFY.
Dans Linux 3.17, les bogues suivants existent :
- Dans Linux, un objet du système de fichiers pourrait être accessible par de multiples chemins. Par
exemple, une partie d'un système de fichiers pourrait être remontée avec l'option --bind de mount(8).
Un écoutant ayant marqué un montage ne sera notifié que des événements déclenchés pour un objet du
système de fichiers utilisant le même montage. Tout autre événement passera inaperçu.
- Quand un événement est créé, aucune vérification n’est effectuée pour voir si l’identifiant
utilisateur du processus recevant a le droit de lire ou écrire le fichier avant de passer un
descripteur de fichier pour ce fichier. Cela pose un risque de sécurité quand la capacité
CAP_SYS_ADMIN est définie pour un programme exécuté par les utilisateurs ordinaires.
- Si un appel de read(2) traite plusieurs événements de la file fanotify et qu’une erreur survient, la
valeur de retour sera la taille totale des événements copiés correctement dans le tampon d’espace
utilisateur avant que l’erreur ne survienne. La valeur de retour ne sera pas -1 et errno ne sera pas
définie. Ainsi, l’application lisant n’a aucun moyen de détecter l’erreur.
EXEMPLES
Les deux programmes ci-dessous montrent l’utilisation de l’API de fanotify.
Exemple de programme : fanotify_example.c
Le programme suivant montre l’utilisation de l’interface de programmation fanotify avec les informations
d’évènements d’objet passées sous la forme d’un descripteur de fichier. Il marque le point de montage
passé en argument de ligne de commande et attend les événements de type FAN_OPEN_PERM et FAN_CLOSE_WRITE.
Quand un événement de permission survient, une réponse FAN_ALLOW est donnée.
La sortie suivante de session d’interpréteur de commande montre un exemple de l’exécution de ce
programme. Cette session concerne l’édition du fichier /home/utilisateur/temp/notes. Avant d’ouvrir le
fichier, un événement FAN_OPEN_PERM est survenu. Après la fermeture du fichier, un événement
FAN_CLOSE_WRITE est survenu. L’exécution du programme se termine quand l’utilisateur appuie sur la touche
Entrée.
# ./fanotify_exemple /home
Appuyer sur la touche Entrée pour quitter.
En écoute d’événements.
FAN_OPEN_PERM : Fichier /home/utilisateur/temp/notes
FAN_CLOSE_WRITE : Fichier /home/utilisateur/temp/notes
Arrêt de l’écoute d’événements.
Source du programme : fanotify_example.c
#define _GNU_SOURCE /* Nécessaire pour obtenir la définition de O_LARGEFILE */
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/fanotify.h>
#include <unistd.h>
/* Read all available fanotify events from the file descriptor 'fd'. */
static void
handle_events(int fd)
{
const struct fanotify_event_metadata *metadata;
struct fanotify_event_metadata buf[200];
ssize_t len;
char path[PATH_MAX];
ssize_t path_len;
char procfd_path[PATH_MAX];
struct fanotify_response response;
/* Boucler tant que les événements peuvent être lus à partir du
descripteur de fichier fanotify */
for (;;) {
/* Lire certains événements */
len = read(fd, buf, sizeof(buf));
if (len == -1 && errno != EAGAIN) {
perror("read");
exit(EXIT_FAILURE);
}
/* Vérifier si la fin des données disponibles est atteinte */
if (len <= 0)
break;
/* Pointer vers le premier événement du tampon */
metadata = buf;
/* Boucler sur tous les événements du tampon */
while (FAN_EVENT_OK(metadata, len)) {
/* Vérifier que les structures au moment de l’exécution et
de la compilation correspondent */
if (metadata->vers != FANOTIFY_METADATA_VERSION) {
fprintf(stderr,
"Non correspondance de version de métadonnées fanotify.\n");
exit(EXIT_FAILURE);
}
/* metadata->fd contient soit FAN_NOFD, indiquant un
dépassement de file, soit un descripteur de fichier
(un entier positif).
Ici, le dépassement de file est simplement ignoré. */
if (metadata->fd >= 0) {
/* Traiter l’événement de permission d’ouverture */
if (metadata->mask & FAN_OPEN_PERM) {
printf("FAN_OPEN_PERM : ");
/* Permettre d’ouvrir le fichier */
response.fd = metadata->fd;
response.response = FAN_ALLOW;
write(fd, &response, sizeof(response));
}
/* Traiter l’événement de fermeture de fichier ouvert
en écriture */
if (metadata->mask & FAN_CLOSE_WRITE)
printf("FAN_CLOSE_WRITE : ");
/* Récupérer et afficher le chemin du fichier accédé */
snprintf(procfd_path, sizeof(procfd_path),
"/proc/self/fd/%d", metadata->fd);
path_len = readlink(procfd_path, path,
sizeof(path) - 1);
if (path_len == -1) {
perror("readlink");
exit(EXIT_FAILURE);
}
path[path_len] = '\0';
printf("File %s\n", path);
/* Fermer le descripteur de fichier de l’événement */
close(metadata->fd);
}
/* Avancer au prochain événement */
metadata = FAN_EVENT_NEXT(metadata, len);
}
}
}
int
main(int argc, char *argv[])
{
char buf;
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[2];
/* Vérifier qu’un point de montage est fourni */
if (argc != 2) {
fprintf(stderr, "Utilisation : %s MONTAGE\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 fanotify */
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
O_RDONLY | O_LARGEFILE);
if (fd == -1) {
perror("fanotify_init");
exit(EXIT_FAILURE);
}
/* Marquer le montage pour :
— les événements de permission avant d’ouvrir les fichiers
— les événements de notification après fermeture de descripteur
de fichier ouvert en écriture */
if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
argv[1]) == -1) {
perror("fanotify_mark");
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 fanotify */
fds[1].events = POLLIN;
/* Boucle en attente d’arrivée d’événements */
printf("En écoute d’événements.\n");
while (1) {
poll_num = poll(fds, nfds, -1);
if (poll_num == -1) {
if (errno == EINTR) /* Interrompu par un signal */
continue; /* Redémarrage de poll() */
perror("poll"); /* Erreur inattendue */
exit(EXIT_FAILURE);
}
if (poll_num > 0) {
if (fds[0].revents & POLLIN) {
/* Entrée de console disponible :
effacer 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 fanotify sont disponibles */
handle_events(fd);
}
}
}
printf("Arrêt de l’écoute d’événements.\n");
exit(EXIT_SUCCESS);
}
Exemple de programme : fanotify_fid.c
The second program is an example of fanotify being used with a group that identifies objects by file
handles. The program marks the filesystem object that is passed as a command-line argument and waits
until an event of type FAN_CREATE has occurred. The event mask indicates which type of filesystem object—
either a file or a directory—was created. Once all events have been read from the buffer and processed
accordingly, the program simply terminates.
Les sessions d’interpréteur de commande suivantes montrent deux invocations différentes avec des actions
différentes réalisées sur l’objet désiré.
La première session montre une marque placée sur /home/utilisateur. Cela est suivi par la création d’un
fichier normal, /home/utilisateur/fichiertest.txt. Cela aboutit à un évènement FAN_CREATE généré et
rapporté à l’objet de répertoire surveillé parent du fichier et à la création du nom de fichier.
L’exécution du programme se termine une fois que tous les évènements capturés du tampon ont été traités.
# ./fanotify_fid /home/user
Listening for events.
FAN_CREATE (file created):
Directory /home/user has been modified.
Entry 'testfile.txt' is not a subdirectory.
All events processed successfully. Program exiting.
$ touch /home/utilisateur/fichiertest.txt # Dans un autre terminal
La première session montre une marque placée sur /home/utilisateur. C’est suivi par la création d’un
répertoire, /home/utilisateur/réptest. Cette action spécifique aboutit à la génération d’un évènement
FAN_CREATE et est rapporté avec l’attribut FAN_ONDIR défini et avec la création du nom de répertoire.
# ./fanotify_fid /home/user
Listening for events.
FAN_CREATE | FAN_ONDIR (subdirectory created):
Directory /home/user has been modified.
Entry 'testdir' is a subdirectory.
All events processed successfully. Program exiting.
$ mkdir -p /home/utilisateur/réptest # Dans un autre terminal
Source du programme : fanotify_fid.c
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fanotify.h>
#include <unistd.h>
#define BUF_SIZE 256
int
main(int argc, char *argv[])
{
int fd, ret, event_fd, mount_fd;
ssize_t len, path_len;
char path[PATH_MAX];
char procfd_path[PATH_MAX];
char events_buf[BUF_SIZE];
struct file_handle *file_handle;
struct fanotify_event_metadata *metadata;
struct fanotify_event_info_fid *fid;
const char *file_name;
struct stat sb;
if (argc != 2) {
fprintf(stderr, "nb d’arguments de ligne de commande non valable.\n");
exit(EXIT_FAILURE);
}
mount_fd = open(argv[1], O_DIRECTORY | O_RDONLY);
if (mount_fd == -1) {
perror(argv[1]);
exit(EXIT_FAILURE);
}
/* Créer un descripteur de fichier avec FAN_REPORT_DFID_NAME sous
forme d’attribut de façon que le programme puisse recevoir des
évènements fid avec des noms de répertoire d’entrée */
fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME, 0);
if (fd == -1) {
perror("fanotify_init");
exit(EXIT_FAILURE);
}
/* Placer une marque sur un objet de système de fichiers
fourni dans argv[1]. */
ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR,
FAN_CREATE | FAN_ONDIR,
AT_FDCWD, argv[1]);
if (ret == -1) {
perror("fanotify_mark");
exit(EXIT_FAILURE);
}
printf("En écoute d’événements.\n");
/* Lire les évènements dans la file dans le tampon */
len = read(fd, events_buf, sizeof(events_buf));
if (len == -1 && errno != EAGAIN) {
perror("read");
exit(EXIT_FAILURE);
}
/* Traiter tous les événements du tampon */
for (metadata = (struct fanotify_event_metadata *) events_buf;
FAN_EVENT_OK(metadata, len);
metadata = FAN_EVENT_NEXT(metadata, len)) {
fid = (struct fanotify_event_info_fid *) (metadata + 1);
file_handle = (struct file_handle *) fid->handle;
/* Assurer que l’info d’évènement soit du type correct */
if (fid->hdr.info_type == FAN_EVENT_INFO_TYPE_FID ||
fid->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID) {
file_name = NULL;
} else if (fid->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
file_name = file_handle->f_handle +
file_handle->handle_bytes;
} else {
fprintf(stderr, "Type inattendu d’évènement reçu.\n");
exit(EXIT_FAILURE);
}
if (metadata->mask == FAN_CREATE)
printf("FAN_CREATE (file created):\n");
if (metadata->mask == (FAN_CREATE | FAN_ONDIR))
printf("FAN_CREATE | FAN_ONDIR (sous_répertoire créé) :\n");
/* metadata->fd is set to FAN_NOFD when the group identifies
objects by file handles. To obtain a file descriptor for
the file object corresponding to an event you can use the
struct file_handle that's provided within the
fanotify_event_info_fid in conjunction with the
open_by_handle_at(2) system call. A check for ESTALE is
done to accommodate for the situation where the file handle
for the object was deleted prior to this system call. */
event_fd = open_by_handle_at(mount_fd, file_handle, O_RDONLY);
if (event_fd == -1) {
if (errno == ESTALE) {
printf("Le gestionnaire de fichiers n’est plus valable, "
"le fichier a été supprimé\n");
continue;
} else {
perror("open_by_handle_at");
exit(EXIT_FAILURE);
}
}
snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
event_fd);
/* Retrouver et afficher le chemin de l’entrée modifiée */
path_len = readlink(procfd_path, path, sizeof(path) - 1);
if (path_len == -1) {
perror("readlink");
exit(EXIT_FAILURE);
}
path[path_len] = '\0';
printf("\tDirectory '%s' has been modified.\n", path);
if (file_name) {
ret = fstatat(event_fd, file_name, &sb, 0);
if (ret == -1) {
if (errno != ENOENT) {
perror("fstatat");
exit(EXIT_FAILURE);
}
printf("\tEntry '%s' does not exist.\n", file_name);
} else if ((sb.st_mode & S_IFMT) == S_IFDIR) {
printf("\tEntry '%s' is a subdirectory.\n", file_name);
} else {
printf("\tEntry '%s' is not a subdirectory.\n",
file_name);
}
}
/* Fermer le descripteur de fichier de l’événement */
close(event_fd);
}
printf("Tous les évènements traités avec succès, fin du programme.\n");
exit(EXIT_SUCCESS);
}
VOIR AUSSI
fanotify_init(2), fanotify_mark(2), inotify(7)
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> et Jean-Paul Guillonneau <guillonneau.jeanpaul@free.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.
Pages du manuel de Linux 6.03 5 février 2023 fanotify(7)