man fcntl (Appels systèmes) - Manipuler un descripteur de fichier.

NOM

fcntl - Manipuler un descripteur de fichier.

SYNOPSIS

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);

DESCRIPTION

fcntl permet de se livrer à diverses opérations sur le descripteur de fichier fd. L'opération en question est déterminée par la valeur de l'argument cmd.

Manipulation de Close-on-exec

F_DUPFD
Trouve le plus petit numéro de descripteur libre supérieur ou égal à arg et le transforme en copie de fd. Ceci est différent de dup(2) qui utilise exactement le descripteur transmis. Le nouveau et l'ancien descripteurs deviennent interchangeables. Ils partagent les verrous, l'indicateur de position et les attributs. Si par exemple la tête de lecture/écriture est déplacée en utilisant lseek sur l'un des deux descripteurs, la position sera aussi modifiée pour l'autre. Les deux descripteurs ne partagent toutefois pas l'attribut Close-on-exec. L'attribut Close-on-exec de la copie est désactivé, ce qui signifie qu'il ne sera pas fermé lors d'un exec(). En cas de réussite, le nouveau descripteur est renvoyé.
F_GETFD
Retourne la valeur de l'attribut Close-on-exec. Si le bit FD_CLOEXEC est 0, le fichier restera ouvert même au travers d'un exec, autrement il sera fermé.
F_SETFD
Positionne l'attribut Close-on-Exec avec la valeur précisée par le bit FD_CLOEXEC de arg.

Attribut d'état du fichier

Un descripteur de fichier dispose de certains attributs, initialisés par open(2) et eventuellement modifiés par fcnt(2). Les attributs sont partagés entre les copies (obtenues avec dup(2), fork(2), etc.) du même descripteur de fichier. Les attributs et leurs sémantiques sont décrits dans la page open(2).

F_GETFL
Renvoie l'attribut d'état du descripteur.
F_SETFL
Positionne les nouveaux attributs pour le descripteur de fichier à la valeur indiquée par arg. Les bits restants (mode d'accès, attributs de création) de arg sont ignorés. Sous Linux, cette commande ne peut changer que O_APPEND, O_NONBLOCK, O_ASYNC, et O_DIRECT.

Verrouillages coopératifs

F_GETLK, F_SETLK et F_SETLKW servent à gérer les verrouillages d'enregistrements (de segments ou de régions de fichiers). Le troisième argument lock est un pointeur sur une structure qui a au moins les champs suivants (dans un ordre non spécifié).

struct flock {
    ...
    short l_type;    /* Type de verrouillage : F_RDLCK,
                        F_WRLCK, F_UNLCK */
    short l_whence;  /* Interprétation de l_start:
                        SEEK_SET, SEEK_CUR, SEEK_END */
    off_t l_start;   /* Décalage de début du verrouillage */
    off_t l_len;     /* Nombre d'octets du verrouillage */
    pid_t l_pid;     /* PID du processus bloquant notre verrou
                        (F_GETLK seulement) */
    ...
};

Les champs l_whence, l_start, et l_len de cette structure indiquent l'intervalle à verrouiller. l_start est le décalage de début du verrouillage et s'interprète par rapport : au début du fichier (si l_whence vaut SEEK_SET) ; à la position actuelle dans le fichier (si l_whence vaut SEEK_CUR) ; ou la fin du fichier (si l_whence vaut SEEK_END). Dans les deux derniers cas, l_start peut être un nombe négatif, à condition de ne pas indiquer une position avant le début du fichier. l_len est un entier non-négatif (mais voir les NOTES plus bas) indiquant le nombre d'octets à verrouiller. On peut verrouiller des octets après la fin du fichier, mais pas avant son début. Fournir un 0 dans l_len a un sens particulier : verrouiller tous les octets de la position indiquée par l_whence et l_start jusqu'à la fin du fichier, quelque soit sa taille.

Le champ l_type peut servir à placer un verrou en lecture (F_RDLCK) ou en écriture (F_WDLCK) sur un fichier. Un nombre quelconque de processus peuvent tenir un verrou en lecture (partagé), sur une région d'un fichier, mais un seul peut avoir un verrou en écriture (exclusif). Un verrou en écriture exclut tous les autres verrous, aussi bien en lecture qu'en écriture. Un processus donné ne peut tenir qu'un seul verrou sur une région d'un fichier, si un nouveau verrou y est appliqué, alors le verrou précédent est converti suivant le nouveau type. Ceci peut entraîner le découpage, la réduction ou l'extension du verrou existant si le nombre d'octets du nouveau verrou ne coïncide pas exactement avec celui de l'ancien.

F_SETLK
Acquérir (si l_type vaut F_RDLCK ou F_WRLCK) ou libérer (si l_type vaut F_UNLCK) le verrou sur les octets indiqués par les champs l_whence, l_start, et l_len de lock. Si un conflit avec un verrou tenu par un autre processus existe, cet appel renvoie -1 et positionne errno aux valeurs EACCES ou EAGAIN.
F_SETLKW
Comme F_SETLK, mais attend la libération du verrou au lieu de retourner une erreur. Si un signal à intercepter est reçu pendant l'attente, l'appel est interrompu et renverra immédiatement (après retour du gestionnaire de signaux) la valeur -1. errno sera remplie avec la valeur EINTR.
F_GETLK
En entrée dans cette routine, lock décrit un verrou que nous aimerions placer sur le fichier. Si le verrouillage est possible, fcntl() ne le fait pas, mais renvoie F_UNLCK dans le champ l_type de lock et laisse les autres champs de la structure inchangés. Si un ou plusieurs verrouillages incompatibles empêchaient l'action, alors fcntl() renvoie des informations sur l'un de ces verrous dans les champs l_type, l_whence, l_start, et l_len de lock et remplit l_pid avec le PID du processus tenant le verrou.

Pour pouvoir placer un verrou en lecture, fd doit être ouvert au moins en lecture. Pour placer un verrou en écriture, fd doit être ouvert en écriture. Pour placer les deux types de verrous, il faut une ouverture en lecture-écriture.

Outre la suppression par un F_UNLCK explicite, les verrous sont automatiquement libérés lorsque le processus se termine, ou s'il ferme l'un des descripteurs se référant au fichier sur lequel le verrou est placé. C'est dangereux : cela signifie qu'un processus peut perdre un verrou sur un fichier comme /etc/passwd ou /etc/mtab si, pour une raison quelconque, une fonction de bibliothèque décide de l'ouvrir puis de le refermer.

Les verrouillages d'enregistrements ne sont pas hérités par les enfants lors d'un fork(2), mais sont préservés au cours d'un execve(2).

À cause des buffers gérés par la bibliothèque stdio(3), l'utilisation des verrous d'enregistrements avec les routines de celle-ci est déconseillé. Utilisez plutôt read(2) et write(2).

Verrouillage obligatoire

(NON-POSIX) Les verrouillages d'enregistrements ci-dessus peuvent être coopératifs ou impératifs (coopératifs par défaut). Pour utiliser des verrous impératifs, ce type de verrouillage doit être activé sur le système de fichiers contenant le fichier à verrouiller (en utilisant l'option « -o mand » de mount(8)) et validé pour le fichier lui-même (en désactivant la permission d'exécution du groupe et en activant le bit de permission Set-GID).

Les verrouillages coopératifs ne fonctionnent qu'entre processus qui les utilisent. Les verrouillages impératifs fonctionnent avec tous les processus.

Gestion des signaux

F_GETOWN, F_SETOWN, F_GETSIG et F_SETSIG servent à gérer les signaux de disponibilité d'entrée-sortie :

F_GETOWN
obtient le PID ou l'ID du groupe de processus qui reçoit les signaux SIGIO et SIGURG pour les événements concernant le descripteur de fichier fd. Les groupes de processus sont renvoyés sous forme de valeurs négatives.
F_SETOWN
fixe le PID ou l'ID du groupe de processus qui recevront les signaux SIGIO et SIGURG pour les événements concernant le descripteur fd. Les groupes de processus sont formulés en tant que valeurs négatives. (F_SETSIG peut servir à indiquer un autre signal que SIGIO).

Si vous fixez l'attribut O_ASYNC sur un descripteur de fichier (soit en utilisant ce drapeau lors de l'appel à open(2), soit en utilisant la commande F_SETFL de fcntl(2)), un signal SIGIO est envoyé dès que l'entrée ou la sortie sont possibles sur ce descripteur. Le processus, ou le groupe de processus, susceptibles de recevoir le signal peut être indiqué avec la commande F_SETOWN de la fonction fcntl. Si le descripteur est une socket, ceci permet également la réception de signaux SIGURG lorsque des données hors-bande arrivent sur la socket. (SIGURG est émis dans toutes les situations où l'appel select(2) aurait indiqué que la socket est dans une « situation exceptionnelle »). Si le descripteur de fichier correspond à un terminal, le signal SIGIO est envoyé au groupe de processus en avant-plan sur ce terminal.

F_GETSIG
Renvoie le numéro du signal émis lorsque l'entrée ou la sortie deviennent possibles. Une valeur nulle signifie l'émission de SIGIO. Toute autre valeur (y compris SIGIO) précise le signal émis, et des informations supplémentaires seront disponibles pour le gestionnaire s'il est installé avec SA_SIGINFO.
F_SETSIG
Indique le signal à émettre lorsque l'entrée ou la sortie deviennent possibles. Une valeur nulle signifie l'émission de SIGIO. Toute autre valeur (y compris SIGIO) précise le signal à émettre, et des informations supplémentaires seront disponibles pour le gestionnaire s'il est installé avec SA_SIGINFO. En utilisant F_SETDIG avec une valeur non-nulle, et en configurant SA_SIGINFO pour le gestionnaire (voir sigaction(2)), des informations supplémentaires sur les événements d'entrées-sorties sont fournies au gestionnaire à travers une structure siginfo_t. Si le champ si_code indique que la source est SI_SIGIO, le champ si_fd fournit le descripteur du fichier concerné par l'événement. Sinon il n'y a pas d'indication du descripteur en attente, et il faut utiliser le mécanisme habituel (select(2), poll(2), read(2) avec O_NONBLOCK configuré etc.) pour déterminer quels descripteurs sont disponibles pour les entrées-sorties. En sélectionnant un signal temps réel POSIX.1b (valeur >= SIGRTMIN), de multiples événements d'entrées-sorties peuvent être mémorisés avec le même numéro. Des informations supplémentaires sont disponibles, comme ci-dessus, si SA_SIGINFO est configuré pour le gestionnaire.

En utilisant ces mécanismes, un programme peut implémenter des entrées-sorties totalement asynchrones, la plupart du temps sans avoir besoin d'invoquer select(2) ou poll(2).

L'utilisation de O_ASYNC, F_GETOWN, est spécifique BSD et Linux. F_GETSIG et F_SETSIG sont spécifiques à Linux. POSIX disposent d'entrées-sorties asynchrones et de la structure aio_sigevent pour effectuer la même chose. Ceci est également disponible sous Linux dans la bibliothèque GNU C (Glibc).

Baux

F_SETLEASE et F_GETLEASE (depuis Linux 2.4) servent respectivement à établir et consulter le paramétrage du bail dont le processus appelant dispose sur le fichier indiqué par fd. (Ndt : je traduis « lease » par « bail », faute de terme plus techique.) Le bail sur un fichier fournit un mécanisme par lequel un processus détenteur du bail est averti (par délivrance d'un signal) lorsqu'un autre processus (le « casseur de bail ») essaye d'appeler open(2) ou truncate(2) sur ce fichier.

F_SETLEASE
Fixe ou supprime un bail de fichier en fonction de la valeur fournie dans l'entier arg :
F_RDLCK
Prendre un bail en lecture. Le processus sera prévenu lorsqu'un autre processus ouvrira le fichier en écriture ou le tronquera.
F_WRLCK
Prendre un bail en écriture. Le processus sera prévenu lorsqu'un autre processus ouvrira le fichier (en lecture ou écriture) ou le tronquera. Un bail en écriture ne peut être pris sur le fichier que si aucun autre processus ne l'a actuellement ouvert.
F_UNLCK
Supprimer le bail sur un fichier.

Un processus ne peut prendre qu'un seul type de bail sur un fichier.

Les baux ne peuvent être pris que sur des fichiers normaux. Un processus non-privilégié ne peut prendre un bail que sur un fichier dont l'UID correspond au FS-UID du processus.

F_GETLEASE
Indique le type de bail possédé sur le fichier indiqué par fd en renvoyant F_RDLCK, F_WRLCK, ou F_UNLCK, pour signifiquer respectivement que le processus appelant a un bail en lecture, écriture, ou pas de bail sur le fichier. (Le troisième argument de fcntl(2) est omis).

Lorsqu'un processus (le « casseur de bail » appelle open(2) ou truncate(2) en conflit avec un bail établi par F_SETLEASE, l'appel-système est bloqué par le noyau, sauf si l'attribut O_NONBLOCK est indiqué avec open(2), auquel cas l'appel-système revient tout de suite avec l'erreur EWOULDBLOCK. Le noyau avertit le processus tenant le bail par l'envoi d'un signal (SIGIO par défaut). Le tenant du bail doit répondre à ce signal en effectuant tout le nettoyage nécessaire pour que le fichier soit accessible par un autre processus (par ex. en vidant des buffers internes) et en supprimant ou déclassant son bail. Un bail est supprimé en appelant la commande F_SETLEASE avec arg valant F_UNLCK. Si on tient un bail en écriture sur le fichier et que le casseur de bail ouvre le fichier en lecture, cela est suffisant pour déclasser le bail en un bail en lecture. Cela est effectué en appelant la commande F_SETLEASE avec arg valant F_RDLCK.

Si le détenteur du bail n'arrive pas à le déclasser ou le supprimer avant le nombre de secondes indiqué dans /proc/sys/fs/lease-break-time alors le noyau supprimera ou déclassera de force le bail du processus qui le tient.

Dès que le bail a été, de gré ou de force, résilié ou déclassé et en supposant que le casseur de bail n'a pas débloqué son appel-système, le noyau permet à ce dernier de se dérouler.

Le signal de notification par défaut pour le tenant du bail est SIGIO, mais on peut le modifier avec la commande F_SETSIG de la fonction fcntl (2). Si une commande F_SETSIG est réalisée (même pour SIGIO), et si le gestionnaire de signal est installé avec SA_SIGINFO, alors il recevra une structure siginfo_t en second argument, et le champ si_fd contiendra le descripteur de fichier du bail où il y a eu une tentative d'accès par un autre processus. (Ceci sert si le processus tient des bails sur plusieurs fichiers.)

Notification de modification de fichier et de répertoire

F_NOTIFY
(Nouveauté Linux 2.4) Fournit un avertissement lorsque le répertoire correspondant à fd ou l'un des fichiers qu'il contient est modifié. Les évènements à notifier sont précisés dans arg, sous forme de masque regroupant par un OU binaire zéro, une ou plusieurs des constantes suivantes :

l l ---- lB l. Bit Description (événement dans le répertoire) DN_ACCESS Accès à un fichier (read, pread, readv) DN_MODIFY Modification d'un fichier (write, pwrite, writev, truncate, ftruncate) DN_CREATE Création d'un fichier (open, creat, mknod, mkdir, link, symlink, rename) DN_DELETE Suppression d'un fichier (unlink, renommage dans un autre répertoire, rmdir) DN_RENAME Un fichier a été renommé dans le même répertoire (rename) DN_ATTRIB Les attributs d'un fichier ont été modifiés (chown, chmod, utime[s]) (Afin d'obtenir ces définitions, la macro _GNU_SOURCE_ doit être définie avant l'inclusion de <fcntl.h>.) Les notifications de répertoire sont habituellement uniques, et l'application doit ré-enregistrer une demande pour les notifications ultérieures. Inversement, si DN_MULTISHOT est incluse dans arg, les notifications resteront en effet jusqu'à une demande explicite de suppression. Une série de F_NOTIFY sont cumulés, les événements décrits dans arg étant ajoutés à l'ensemble des évènements déjà surveillés. Pour supprimer les notifications de tous les événements, il faut invoquer F_NOTIFY avec arg valant 0. La notification se produit par l'occurrence d'un signal. Le signal par défaut est SIGIO, mais on peut le changer avec la commande F_SETSIG de fcntl(). Dans ce cas, le gestionnaire de signal reçoit une structure siginfo_t en second argument (si le gestionnaire a été installé avec SA_SIGINFO) dont le champ si_fd contient le descripteur du fichier qui a déclenché la notification (utile pour superviser plusieurs répertoires). En outre, avec DN_MULTISHOT, un signal temps-réel POSIX.1b devrait être utilisé pour la notification pour pouvoir empiler les notifications successives.

VALEUR RENVOYÉE

La valeur renvoyée par fcntl varie suivant le type d'opération :

F_DUPFD
renvoie le nouveau descripteur.
F_GETFD
renvoie l'attribut.
F_GETFL
renvoie les attributs.
F_GETOWN
renvoie le propriétaire du descripteur fichier.
F_GETSIG
valeur du signal envoyé lorsque la lecture ou l'écriture deviennent possibles, ou zéro pour le comportement SIGIO traditionnel.
Toutes les autres commandes renvoient zéro.

En cas d'échec -1 est renvoyé, auquel cas errno contient le code d'erreur.

ERREURS

EACCESS ou EAGAIN
L'opération est impossible à cause d'un verrou maintenu par un autre processus. Ou l'opération est impossible à cause d'une projection en mémoire effectuée par un autre processus.
EBADF
fs n'est pas un descripteur de fichier ouvert, ou la commande était F_SETLK ou F_SETLKW et le mode d'ouverture du descripteur de fichier ne correspond pas à celui du type de verrou demandé.
EDEADLK
Le verrouillage F_SETLKW conduirait à un blocage.
EFAULT
lock se trouve en dehors de l'espace d'adressage.
EINTR
Pour F_SETLKW, la commande a été interrompue par un signal. Pour F_GETLK et F_SETLK, la commande a été interrompue par un signal avant la vérification ou l'acquisition du verrou. Se produit surtout lors d'un verrouillage distant (par exemple à travers NFS), mais peut également arriver localement.
EINVAL
Pour F_DUPFD, arg est soit négatif, soit trop grand. Pour F_SETSIG, arg n'est pas un numéro de signal correct.
EMFILE
Pour F_DUPFD, le processus a déjà ouvert le nombre maximal de descripteurs de fichiers.
ENOLCK
La table des verrous est pleine, ou le verrouillage distant (par exemple via NFS) a échoué.
EPERM
Essai d'effacement de l'attribut O_APPEND sur un fichier, mais il est considéré comme en-ajout-seulement.

NOTES

Les erreurs renvoyées par dup2 ne sont pas les mêmes que celles renvoyées par F_DUPFD.

Depuis le noyau 2.0, il n'y a pas d'interaction entre les verrous placés par flock(2) et ceux de fcntl(2).

POSIX 1003.1-2001 permet à l_len d'être négative (et si c'est le cas, l'intervalle décrivant le verrou couvre les octets l_start+l_len jusqu'à l_start-1 inclus). Ceci est supporté par Linux depuis les versions 2.4.21 et 2.5.49.

Plusieurs systèmes ont d'autres champs dans struct flock comme, par exemple, l_sysid. Clairement, l_pid seul ne sera pas très utile si le processus tenant le verrou s'exécute sur une autre machine.

CONFORMITÉ

SVr4, SVID, POSIX, X/OPEN, BSD 4.3. Seules les opérations F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK et F_SETLKW sont spécifiées dans POSIX.1. F_GETOWN et F_SETOWN sont des BSDismes non supportés par SVr4. F_GETSIG et F_SETSIG sont spécifiques à Linux. F_NOTIFY, F_GETLEASE, et F_SETLEASE sont spécifiques à Linux. (Définissez la macro _GNU_SOURCE avant d'inclure <fcntl.h> pour avoir ces définitions). Les attributs autorisés pour F_GETFL/F_SETFL sont ceux supportés par open(2) et peuvent être différents suivant les systèmes. O_APPEND, O_NONBLOCK, O_RDONLY, et O_RDWR sont spécifiés par POSIX.1. SVr4 propose plusieurs autres options et attributs non documentés ici.

SVr4 indique des erreurs EIO, ENOLINK et EOVERFLOW supplémentaires.

VOIR AUSSI

dup2(2), flock(2), lockf(3), open(2), socket(2),

Voir aussi les fichiers locks.txt, mandatory.txt et dnotify.txt dans la documentation du noyau.

TRADUCTION

Christophe Blaess, 1996-2003.