NOM

mmap, munmap - Établir/supprimer une projection en mémoire (map/unmap) des fichiers ou des périphériques

BIBLIOTHÈQUE

Bibliothèque C standard ( libc, -lc)

SYNOPSIS

#include <sys/mman.h>
void *mmap(void addr[.length], size_t length, int prot, int flags,
           int fd, off_t offset);
int munmap(void addr[.length], size_t length);
Consultez la section NOTES pour plus d'informations sur les exigences de la macro de test de fonctionnalité.

DESCRIPTION

mmap() crée une nouvelle projection dans l'espace d'adressage virtuel du processus appelant. L'adresse de démarrage de la nouvelle projection est indiquée dans addr. Le paramètre length indique la longueur de la projection (qui doit être supérieure à 0).
Si addr est NULL, le noyau choisit l'adresse (alignée sur une page) à laquelle démarrer la projection ; c'est la méthode la plus portable pour créer une nouvelle projection. Si addr n'est pas NULL, le noyau le considère comme une indication sur l'endroit où placer la projection ; sous Linux, elle sera placée à une frontière de page proche (mais toujours supérieure ou égale à la valeur indiquée par /proc/sys/vm/mmap_min_addr) et tente d'y créer la projection. Si une projection y existe déjà, le noyau prend une nouvelle adresse qui peut ou pas dépendre de l'indication. L'adresse de la nouvelle projection est renvoyée comme résultat de l'appel.
Le contenu d'une projection de fichier (par opposition à une projection anonyme ; voir ci-dessous MAP_ANONYMOUS) est initialisé avec length octets à partir de la position offset dans le fichier (ou autre objet) correspondant au descripteur de fichier fd. offset doit être un multiple de la taille de la page renvoyée par sysconf(_SC_PAGE_SIZE).
Après le retour de l'appel mmap(), le descripteur de fichier fd peut être fermé immédiatement sans invalider la projection.
L'argument prot indique la protection que l'on désire pour cette zone de mémoire et ne doit pas entrer en conflit avec le mode d'ouverture du fichier. Il s'agit soit de PROT_NONE (le contenu de la mémoire est inaccessible) soit d'un OU binaire entre les constantes suivantes :
PROT_EXEC
Il est possible d'exécuter les pages.
PROT_READ
Il est possible de lire les pages.
PROT_WRITE
Il est possible d'écrire les pages.
PROT_NONE
Il n'est pas possible d'accéder aux pages.

Le paramètre des attributs

Le paramètre flags détermine si les modifications de la projection sont visibles depuis les autres processus projetant la même région et si les modifications sont appliquées au fichier sous-jacent. Ce comportement est déterminé en incluant exactement une des valeurs suivantes dans flags :
MAP_SHARED
Partager la projection. Les modifications de la projection sont visibles dans les autres processus qui projettent la même région et (en cas de projection file-backed) elles sont appliquées au fichier sous-jacent (pour contrôler précisément le moment des mises à jour du fichier sous-jacent, il faut utiliser msync(2)).
MAP_SHARED_VALIDATE (depuis Linux 4.15)
Cet attribut apporte le même comportement que MAP_SHARED sauf que les projections MAP_SHARED ignorent les attributs inconnus dans flags. Au contraire, lors de la création d'une projection en utilisant MAP_SHARED_VALIDATE, le noyau vérifie que tous les attributs passés sont connus et il fait échouer la projection avec l'erreur EOPNOTSUPP pour les attributs inconnus. Ce type de projection est aussi nécessaire pour pouvoir utiliser certains attributs de projection (comme MAP_SYNC).
MAP_PRIVATE
Créer une projection privée, utilisant la méthode de copie à l'écriture. Les modifications de la projection ne sont pas visibles depuis les autres processus projetant le même fichier, et ne modifient pas le fichier lui-même. Il n'est pas précisé si les changements effectués dans le fichier après l'appel mmap() seront visibles dans la région projetée.
MAP_SHARED et MAP_PRIVATE sont décrits dans POSIX.1-2001 et POSIX.1-2008. MAP_SHARED_VALIDATE est une extension Linux.
De plus, zéro ou plus des valeurs suivantes peuvent être incluses dans flags (avec un OU binaire) :
MAP_32BIT (depuis Linux 2.4.20, 2.6)
Placer la projection dans les deux premiers gigaoctets de l'espace d'adressage du processus. Cet attribut n'est pris en charge que sous x86-64, pour les programmes 64 bits. Il a été ajouté pour permettre à la pile d'un fil d'exécution d'être allouée dans les deux premiers gigaoctets de mémoire, afin d'améliorer les performances des changements de contexte sur les premiers processeurs 64 bits. Les processeurs x86-64 modernes n'ont plus ces problèmes de performance, donc l'utilisation de cet attribut n'est pas nécessaire sur ces systèmes. L'attribut MAP_32BIT est ignoré quand MAP_FIXED est positionné.
MAP_ANON
Synonyme de MAP_ANONYMOUS ; fourni pour une compatibilité avec d'autres implémentations.
MAP_ANONYMOUS
La projection n'est prise en charge par aucun fichier ; son contenu est initialisé à 0. L'argument fd est ignoré ; cependant, certaines implémentations demandent que fd soit -1 si MAP_ANONYMOUS (ou MAP_ANON) est utilisé, et les applications portables doivent donc s'en assurer. L'argument offset devrait être 0. La prise en charge de MAP_ANONYMOUS avec MAP_SHARED a été ajoutée dans Linux 2.4.
MAP_DENYWRITE
Cet attribut est ignoré (autrefois — Linux 2.0 et antérieur — il signalait une tentative d'écriture dans le fichier sous-jacent et qui échouait avec l'erreur ETXTBUSY. Mais cela permettait des attaques par déni de service).
MAP_EXECUTABLE
Cet attribut est ignoré.
MAP_FILE
Attribut pour compatibilité. Ignoré.
MAP_FIXED
Ne pas considérer addr comme une indication : n'utiliser que l'adresse indiquée. addr doit être correctement alignée : pour la plupart des architectures, un multiple de la taille de page suffit, toutefois certaines architectures imposent des limitations supplémentaires. Si la zone mémoire indiquée par addr et length recouvre des pages d'une projection existante, la partie recouverte de la projection existante sera ignorée. Si l'adresse indiquée ne peut être utilisée, mmap() échouera.
Les logiciels qui aspirent à la portabilité devraient utiliser l'attribut MAP_FIXED prudemment, en gardant à l'esprit que l'aspect exact des projections de mémoire du processus est autorisé à changer significativement entre les versions de Linux, de la glibc et du système d'exploitation. Lisez attentivement le point sur cet attribut dans les NOTES !
MAP_FIXED_NOREPLACE (depuis Linux 4.17)
Cet attribut offre un comportement identique à MAP_FIXED par rapport à l'application de addr, mais il s'en distingue en ce que MAP_FIXED_NOREPLACE n’écrase jamais une plage projetée existante. Si la plage demandée entre en conflit avec une projection existante, cet appel échoue avec l'erreur EEXIST. Cet attribut peut donc être utilisé comme une façon d'essayer de projeter une plage d'adresses de manière atomique (vis-à-vis d'autres fils d'exécutions) : un thread réussira, tous les autres signaleront un échec.
Remarquez que les anciens noyaux qui ne reconnaissent pas l'attribut MAP_FIXED_NOREPLACE se rabattront généralement (en détectant une collision avec une projection existante) sur un type de comportement « sans MAP_FIXED » : ils renverront une adresse différente de celle demandée. Les logiciels rétro-compatibles devront donc vérifier l'adresse renvoyée vis-à-vis de l'adresse demandée.
MAP_GROWSDOWN
Cet attribut est utilisé pour les piles. Il indique au noyau le système de mémoire virtuelle vers lequel la projection devrait descendre dans la mémoire. L'adresse renvoyée est une page inférieure à la zone de mémoire créée dans l'espace d'adressage virtuel du processus. La modification d'une adresse dans la page de « garde » sous la projection fera agrandir la projection d’une page. Cette croissance peut se répéter jusqu'à ce que la taille de la projection dans la page atteigne l’extrémité haute de la projection plus basse suivante, point où la modification de la page de « garde » donnera un signal SIGSEGV.
MAP_HUGETLB (depuis Linux 2.6.32)
Allouer la projection à l'aide de « pages immenses ». Consultez le fichier Documentation/vm/hugetlbpage.txt des sources du noyau Linux pour plus d'informations ainsi que les NOTES ci-dessous.
MAP_HUGE_2MB, MAP_HUGE_1GB (depuis Linux 3.8)
Utilisé avec MAP_HUGETLB pour sélectionner d'autres tailles de pages immenses (hugetlb) (respectivement 2 Mo et 1 Go) sur les systèmes qui gèrent plusieurs tailles de page hugetlb.
Plus généralement, la taille de la page immense souhaitée peut être configurée en encodant le logarithme de base 2 de la taille de la page désirée dans les six bits situés sur MAP_HUGE_SHIFT (une valeur de zéro dans ce champ de bit fournit la taille de page immense par défaut ; vous pouvez connaître celle-ci à l'aide du champ Hugepagesize qui apparaît dans /proc/meminfo). Ainsi, les deux constantes ci-dessus sont définies comme suit :

#define MAP_HUGE_2MB    (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB    (30 << MAP_HUGE_SHIFT)
    

Vous pouvez connaître l'intervalle de tailles des pages immenses gérées par le système en listant les sous-répertoires de /sys/kernel/mm/hugepages.
MAP_LOCKED (depuis Linux 2.5.37)
Marquer la région projetée pour qu'elle soit verrouillée de la même manière que mlock(2). Cette implémentation essaiera de remplir (prefault) toute la plage mais l'appel mmap() n’échouera pas avec ENOMEM si cela échoue. Des erreurs énormes pourraient donc se produire ultérieurement. La sémantique n'est donc pas aussi robuste que mlock(2). Vous devriez utiliser mmap() et mlock(2) si d'énormes erreurs ne sont pas acceptables après l'initialisation de la projection. L'attribut MAP_LOCKED est ignoré sur les anciens noyaux.
MAP_NONBLOCK (depuis Linux 2.5.46)
Cet attribut n'a de sens qu'en conjonction avec MAP_POPULATE. Ne pas effectuer de lecture anticipée : créer seulement les entrées de tables de page pour les pages déjà présentes en RAM. Depuis Linux 2.6.23, cet attribut fait que MAP_POPULATE n'a aucun effet. Un jour la combinaison de MAP_POPULATE et MAP_NONBLOCK pourra être implémentée de nouveau.
MAP_NORESERVE
Ne pas réserver d'espace de swap pour les pages de cette projection. Une telle réservation garantit que l'on puisse modifier les zones soumises à une copie-en-écriture. Sans réservation, on peut recevoir un signal SIGSEGV durant une écriture, s'il n'y a plus de place disponible. Consultez également la description du fichier /proc/sys/vm/overcommit_memory dans la page proc(5). Avant Linux 2.6, cet attribut n'avait d'effet que pour les projections privées modifiables.
MAP_POPULATE (depuis Linux 2.5.46)
Remplir (prefault) les tables de pages pour une projection. Pour une projection de fichier, cela provoque une lecture anticipée du fichier. Les accès ultérieurs à la projection ne seront pas bloqués par des erreurs de pages. L'appel mmap n'échoue pas si la projection ne peut pas être remplie (par exemple à cause de limitation sur le nombre de pages immenses mappées lors de l'utilisation de MAP_HUGETLB). La prise en charge de MAP_POPULATE avec les projections privées a été ajoutée dans Linux 2.6.23.
MAP_STACK (depuis Linux 2.6.27)
Allouer la projection à une adresse qui convient à la pile d'un processus ou d'un thread.
Cet attribut n'est pas opérationnel pour l'instant sur Linux. Mais son utilisation permet aux applications de s'assurer qu'elles le gèreront de manière transparente s'il est implémenté dans le futur. Ainsi, il est utilisé dans l'implémentation de threading de la glibc pour accepter le fait que certaines architectures pourront (plus tard) nécessiter un traitement spécial pour allouer des piles. Une autre raison d'utiliser cet attribut est la portabilité : MAP_STACK existe et a un effet sur d'autres systèmes (comme certains BSD).
MAP_SYNC (depuis Linux 4.15)
Cet attribut n'est possible qu'avec le type de projection MAP_SHARED_VALIDATE ; les projections de type MAP_SHARED ignoreront silencieusement cet attribut. Il n'est pris en charge que pour des fichiers gérant le DAX (projection directe de mémoire persistante). Pour les autres fichiers, créer une projection avec cet attribut provoquera une erreur EOPNOTSUPP.
Les projections de fichier partagé ayant cet attribut fournissent une garantie que tant que la mémoire est projetée avec accès en écriture dans l'espace d'adressage du processus, elle sera visible dans le même fichier et au même endroit même après un plantage ou un redémarrage du système. Couplé à l'utilisation des instructions adéquates du processeur, cela offre aux utilisateurs de telles projections une manière plus efficace de rendre des modifications de données persistantes.
MAP_UNINITIALIZED (depuis Linux 2.6.33)
Ne pas effacer pas les pages anonymes. Cet attribut n'a pour l'instant un effet que si le noyau a été configuré avec l'option CONFIG_MMAP_ALLOW_UNINITIALIZED. À cause des implications sur la sécurité, cette option n'est normalement active que sur des périphériques embarqués (c'est-à-dire avec des périphériques avec lesquels il est possible d'avoir un contrôle total de la mémoire utilisateur).
Parmi les attributs ci-dessus, seul MAP_FIXED est spécifié dans POSIX.1-2001 et POSIX.1-2008. Cependant, la plupart des systèmes gèrent aussi MAP_ANONYMOUS (ou son synonyme MAP_ANON).

munmap()

L'appel système munmap() détruit la projection dans la zone de mémoire spécifiée et s'arrange pour que toute référence ultérieure à cette zone mémoire déclenche une erreur d'adressage. La projection est aussi automatiquement détruite lorsque le processus se termine. À l'inverse, la fermeture du descripteur de fichier ne supprime pas la projection.
L'adresse addr doit être un multiple de la taille de la page (mais ce n'est pas obligatoire pour length). Toutes les pages contenant une partie de l'intervalle indiqué sont libérées, et tout accès ultérieur déclenchera SIGSEGV. Aucune erreur n'est détectée si l'intervalle indiqué ne contient pas de page projetée.

VALEUR RENVOYÉE

En cas de succès, mmap() renvoie un pointeur sur la zone projetée. En cas d'échec, la valeur MAP_FAILED (c'est-à-dire (void *) -1) est renvoyée et errno est défini pour indiquer l'erreur.
S'il réussit, munmap() renvoie 0. En cas d'échec, -1 est renvoyé et errno est défini pour indiquer l'erreur (probablement EINVAL).

ERREURS

EACCES
Le descripteur ne correspond pas à un fichier normal ou une demande de projection de fichier a été demandée mais fd n'est pas ouvert en lecture, ou une demande de projection partagée MAP_SHARED avec protection PROT_WRITE a été demandée mais fd n'est pas ouvert en lecture et écriture ( O_RDWR), ou encore PROT_WRITE est demandé mais le fichier est ouvert en ajout seulement.
EAGAIN
Le fichier est verrouillé ou trop de pages ont été verrouillées en mémoire (consultez setrlimit(2)).
EBADF
fd n'est pas un descripteur de fichier valable (et MAP_ANONYMOUS n'était pas précisé).
EEXIST
MAP_FIXED_NOREPLACE était indiqué dans flags et la plage couverte par addr et length est en conflit avec une projection existante.
EINVAL
addr ou length ou offset sont non valables (par exemple : zone trop grande, ou non alignée sur une frontière de page).
EINVAL
(depuis Linux 2.6.12) length est nul.
EINVAL
flags ne contenait ni MAP_PRIVATE, ni MAP_SHARED, ni MAP_SHARED_VALIDATE.
ENFILE
La limite du nombre total de fichiers ouverts pour le système entier a été atteinte.
ENODEV
Le système de fichiers sous‐jacent ne gère pas la projection en mémoire.
ENOMEM
Aucune mémoire disponible.
ENOMEM
Le nombre maximal de projections du processus serait dépassé. Cette erreur peut aussi se produire pour munmap() lors de la suppression d'une projection d'une région au milieu d'une projection existante, puisque cela provoque deux régions plus petites de chaque côté de la région à supprimer.
ENOMEM
(Depuis Linux 4.7) La limite RLIMIT_DATA du processus, décrite dans getrlimit(2), serait dépassée.
ENOMEM
addr n'est pas apprécié parce qu'il dépasse l'espace d'adressage virtuel du processeur 
EOVERFLOW
Sur architecture 32 bits avec l'extension de fichiers très grands (c'est-à-dire utilisant un off_t sur 64 bits) : le nombre de pages utilisées pour length plus le nombre de pages utilisées pour offset dépasserait unsigned long (32 bits).
EPERM
L'argument prot a demandé PROT_EXEC mais la zone appartient à un fichier sur un système de fichiers monté sans permission d'exécution.
EPERM
La lecture a été interrompue par un signal ; consultez fnctl(2).
EPERM
L'attribut MAP_HUGETLB était indiqué, mais l'appelant n'était pas priviliégié (il n'avait pas la capacité CAP_IPC_LOCK) et n'appartient pas au groupe sysctl_hugetlb_shm_group ; voir la desription de /proc/sys/vm/sysctl_hugetlb_shm_group dans
ETXTBSY
MAP_DENYWRITE a été réclamé mais fd est ouvert en écriture.
L'accès à une zone de projection peut déclencher les signaux suivants :
SIGSEGV
Tentative d'écriture dans une zone en lecture seule.
SIGBUS
Tentative d'accès à une page du tampon au-delà de la fin du fichier projeté. Pour une explication du traitement des octets dans la page correspondant à la fin du fichier projeté n'étant pas un multiple de la taille de la page, voir les NOTES.

ATTRIBUTS

Pour une explication des termes utilisés dans cette section, consulter attributes(7).
Interface Attribut Valeur
mmap(), munmap() Sécurité des threads MT-Safe
 

STANDARDS

POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD.
Sur les systèmes POSIX sur lesquels mmap(), msync(2) et munmap() sont disponibles, _POSIX_MAPPED_FILES est définie dans <unistd.h> comme étant une valeur supérieure à 0 (consultez aussi sysconf(3)).

NOTES

La mémoire obtenue par mmap est préservée au travers d'un fork(2), avec les mêmes attributs.
Un fichier est projeté en multiples de de la taille de la page. Pour un fichier dont la longueur n'est pas un multiple de la taille de page, la mémoire restante est remplie de zéros lors de la projection, et les écritures dans cette zone n'affectent pas le fichier. Les effets de la modification de la taille du fichier sous‐jacent sur les pages correspondant aux zones ajoutées ou supprimées ne sont pas précisés.
Sur certaines architectures matérielles (par exemple, i386), PROT_WRITE implique PROT_READ. Cela dépend de l'architecture si PROT_READ implique PROT_EXEC ou non. Les programmes portables doivent toujours indiquer PROT_EXEC s'ils veulent exécuter du code dans la projection.
La manière portable de créer une projection est de spécifier addr à 0 (NULL), et d'omettre MAP_FIXED dans flags. Dans ce cas, le système choisit l'adresse de la projection ; l'adresse est choisie de manière à ne pas entrer en conflit avec une projection existante et de ne pas être nulle. Si l'attribut MAP_FIXED est indiqué et si addr vaut 0 (NULL), l'adresse projetée sera zéro (NULL).
Certaines constantes de flags sont définies seulement si des macros de test de fonctionnalités adaptées sont définies (potentiellement par défaut) : _DEFAULT_SOURCE avec la glibc 2.19 ou supérieure, ou bien _BSD_SOURCE ou _SVID_SOURCE dans la glibc 2.19 et antérieure (la définition de _GNU_SOURCE suffit également, et son usage aurait été plus logique, puisque ces attributs sont tous spécifiques à Linux). Les attributs adéquats sont : MAP_32BIT, MAP_ANONYMOUS (et son synonyme MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE, et MAP_STACK.
Une application peut déterminer les pages d'une projection se trouvant dans le tampon/le cache de page en utilisant mincore(2).

Utilisation sûre de MAP_FIXED

La seule utilisation sûre de MAP_FIXED est quand la plage d'adresses indiquée par addr et length a été préalablement réservée en utilisant une autre projection ; sans quoi l'utilisation de MAP_FIXED est hasardeuse car elle supprime brutalement des projections préexistantes, ce qui facilite la corruption par un processus multithread de son propre espace d'adressage.
Par exemple, supposons qu'un thread A cherche dans /proc/<pid>/maps une plage d'adresses inutilisée où il peut se projeter en utilisant MAP_FIXED, tandis qu'un thread B acquiert en même temps tout ou partie de cette même plage d'adresses. Quand le thread A utilisera ensuite mmap(MAP_FIXED), il va de fait écraser la projection créée par le thread B. Dans ce scénario, le thread B ne doit pas créer de projection directement ; un appel de bibliothèque qui, en interne, utilise dlopen(3) pour charger d'autres bibliothèques partagées, est suffisant. L'appel dlopen(3) projettera la bibliothèque dans l'espace d'adressage du processus. De plus, presque tous les appels de bibliothèques peuvent être implémentés d'une manière qui ajoute des projections de mémoire aux espaces d'adressage, à l'aide de cette technique ou en allouant simplement de la mémoire. Parmi les exemples, figurent brk(2), malloc(3), pthread_create(3) et les bibliothèques PAM http://www.linux-pam.org
Depuis Linux 4.17, un programme multithreadé peut utiliser l'attribut MAP_FIXED_NOREPLACE pour éviter le risque décrit ci-dessus quand on essaie de créer une projection à une adresse fixe non réservée par une projection préexistante.

Modifications d'horodatage pour les projections prises en charge par un fichier

Pour les projections prises en charge par un fichier, le champ st_atime du fichier peut être mis à jour à tout moment entre l'appel mmap() et le munmap() correspondant. Le premier accès dans la page projetée mettra le champ à jour si cela n'a pas été déjà fait.
Les champs st_ctime et st_mtime pour un fichier projeté avec PROT_WRITE et MAP_SHARED seront mis à jour après une écriture dans la région projetée, et avant l'éventuel msync(2) suivant avec l'attribut MS_SYNC ou MS_ASYNC.

Projections de pages immenses (Huge TLB)

Pour les projections qui utilisent des pages immenses, les exigences des attributs de mmap() et de munmap() diffèrent quelque peu de celles pour des projections qui utilisent la taille native des pages du système.
Pour mmap(), offset doit être un multiple de la taille de la page immense sous-jacente. Le système aligne automatiquement length pour qu'il soit un multiple de la taille de la page immense sous-jacente.
Pour munmap(), addr et length doivent être tous deux un multiple de la taille de la page immense sous-jacente.

différences entre bibliothèque C et noyau

Cette page décrit l'interface fournie par la fonction mmap() de la glibc. Initialement, cette fonction appelait un appel système du même nom. Depuis Linux 2.4, cet appel système a été remplacé par mmap2(2). De nos jours, la fonction mmap() de la glibc appelle mmap2(2) avec la bonne valeur pour offset.

BOGUES

Sous Linux, il n'y a aucune garantie comme celles indiquées plus haut à propos de MAP_NORESERVE. Par défaut, n'importe quel processus peut être tué à tout moment lorsque le système n'a plus de mémoire.
Avant Linux 2.6.7, l'attribut MAP_POPULATE n'avait d'effet que si prot était PROT_NONE.
SUSv3 indique que mmap() devrait échouer si length est 0. Cependant, avant Linux 2.6.12, mmap() réussissait dans ce cas : aucune projection n'était créée, et l'appel renvoyait addr. Depuis Linux 2.6.12, mmap() échoue avec le code d'erreur EINVAL si length est nul.
POSIX spécifie que le système devrait toujours remplir de zéros toutes les pages incomplètes à la fin de l'objet et que le système n'écrira jamais de modification de l'objet au-delà de sa fin. Sous Linux, lors de l'écriture de données vers ce genre de pages incomplètes après la fin de l'objet, les données restent dans le cache de page même après que le fichier soit fermé et déprojeté, et même si les données ne sont jamais écrites vers le fichier lui-même, les projections suivantes pourraient voir le contenu modifié. Dans certains cas, cela pourrait être corrigé en appelant msync(2) avant la déprojection. Cependant, cela ne fonctionne pas sur tmpfs(5) (par exemple en utilisant l'interface de mémoire partagée POSIX documentée dans shm_overview(7)).

EXEMPLES

Le programme suivant affiche la partie du fichier, précisé par le premier argument de la ligne de commande, sur la sortie standard. Les octets qui seront affichés sont précisés à partir d'un offset (déplacement) et d'une longueur en deuxième et troisième paramètre. Le code fait une projection mémoire des pages nécessaires du fichier puis utilise write(2) pour afficher les octets voulus.

Source du programme

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[]) { int fd; char *addr; off_t offset, pa_offset; size_t length; ssize_t s; struct stat sb;
if (argc < 3 || argc > 4) { fprintf(stderr, "%s fichier offset [longueur]\n", argv[0]); exit(EXIT_FAILURE); }
fd = open(argv[1], O_RDONLY); if (fd == -1) handle_error("open");
if (fstat(fd, &sb) == -1) /* Pour obtenir la taille du fichier */ handle_error("fstat");
offset = atoi(argv[2]); pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1); /* la position de mmap() doit être alignée sur la page */
if (offset >= sb.st_size) { fprintf(stderr, "L'offset dépasse la fin du fichier\n"); exit(EXIT_FAILURE); }
if (argc == 4) { length = atoi(argv[3]); if (offset + length > sb.st_size) length = sb.st_size - offset; /* Impossible d'afficher les octets en dehors du fichier */
} else { /* Pas de paramètre longueur ==> affichage jusqu'à la fin du fichier */ length = sb.st_size - offset; }
addr = mmap(NULL, length + offset - pa_offset, PROT_READ, MAP_PRIVATE, fd, pa_offset); if (addr == MAP_FAILED) handle_error("mmap");
s = write(STDOUT_FILENO, addr + offset - pa_offset, length); if (s != length) { if (s == -1) handle_error("write");
fprintf(stderr, "écriture partielle"); exit(EXIT_FAILURE); }
munmap(addr, length + offset - pa_offset); close(fd);
exit(EXIT_SUCCESS); }

VOIR AUSSI

ftruncate(2), getpagesize(2), memfd_create(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shmat(2), userfaultfd(2), shm_open(3), shm_overview(7)
Dans proc(5), les descriptions des fichiers /proc/[pid]/maps, /proc/[pid]/map_files et /proc/[pid]/smaps.
B.O. Gallmeister, POSIX.4, O'Reilly, p. 128–129 et 389–391.

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 <[email protected]>, Thierry Vignaud <[email protected]>, François Micaux, Alain Portal <[email protected]>, Jean-Philippe Guérard <[email protected]>, Jean-Luc Coulon (f5ibh) <[email protected]>, Julien Cristau <[email protected]>, Thomas Huriaux <[email protected]>, Nicolas François <[email protected]>, Florentin Duneau <[email protected]>, Simon Paillard <[email protected]>, Denis Barbier <[email protected]>, David Prévot <[email protected]> et Jean-Philippe MENGUAL <[email protected]>
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 à [email protected]