Provided by: manpages-fr-dev_3.65d1p1-1_all bug

NOM

       name_to_handle_at,  open_by_handle_at  - récupérer le gestionnaire d'un chemin et le ouvrir le fichier au
       moyen d'un gestionnaire

SYNOPSIS

       #define _GNU_SOURCE
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int name_to_handle_at(int dirfd, const char *pathname,
                             struct file_handle *handle,
                             int *mount_id, int flags);

       int open_by_handle_at(int mount_fd, struct file_handle *handle,
                             int flags);

DESCRIPTION

       Les appels système name_to_handle_at() et open_by_handle_at() scindent la fonction de openat(2)  en  deux
       parties :  name_to_handle_at()  renvoie  un  gestionnaire  opaque  qui  correspond à un fichier indiqué ;
       open_by_handle_at() ouvre le fichier correspondant à un gestionnaire renvoyé par  un  appel  antérieur  à
       name_to_handle_at() et renvoie le descripteur d'un fichier ouvert.

   name_to_handle_at()
       L'appel  système  name_to_handle_at()  renvoie  un  gestionnaire  de fichier et un identifiant de montage
       (« mount ID ») correspondant au fichier désigné par les arguments dirfd et pathname. Le  gestionnaire  de
       fichier  est  renvoyé  au moyen de l'argument handle. Cet argument est un pointeur vers une structure qui
       présente la forme suivante :

           struct file_handle {
               unsigned int  handle_bytes;   /* taille de f_handle [in, out] */
               int           handle_type;    /* type du gestionnaire handle [out] */
               unsigned char f_handle[0];    /* identifiant du fichier (dont la taille est définie
                                                lors de l'appel) [out] */
           };

       L'appelant à l'origine de l'appel doit s'assurer que la structure est créée avec  une  taille  suffisante
       pour  contenir  le  gestionnaire renvoyé dans f_handle. Avant l'appel, le champ handle_bytes devrait être
       initialisé de sorte que l'espace alloué puisse recevoir f_handle. (La  constante  MAX_HANDLE_SZ,  définie
       dans  <fcntl.h>,  précise  la  taille maximum autorisée pour un gestionnaire de fichier.) Lorsque l'appel
       réussit, le champ handle_bytes est mis à jour afin de contenir le nombre  d'octets  effectivement  écrits
       dans f_handle.

       L'appelant  peut  prendre connaissance de l'espace nécessaire à la structure file_handle en effectuant un
       appel dans lequel handle->handle_bytes vaut zéro ; dans ce cas,  l'appel  échoue  en  renvoyant  l'erreur
       EOVERFLOW  et  handle->handle_bytes  prend pour valeur la taille requise ; l'appelant peut alors utiliser
       cette information pour allouer une structure ayant la taille convenable (consultez l'exemple ci-dessous).

       Mise à part l'utilisation du champ handle_bytes, l'appelant  doit  considérer  la  structure  file_handle
       comme une « boîte noire » : les champs handle_type et f_handle ne sont utiles que pour un appel ultérieur
       à open_by_handle_at().

       L'argument flags est un masque de bits construit par OU binaire entre zéro ou plus  de  AT_EMPTY_PATH  et
       AT_SYMLINK_FOLLOW, comme décrit plus bas.

       Ensemble,  les  arguments  pathname  et  dirfd  désignent  le  fichier pour lequel on souhaite obtenir un
       gestionnaire. On distingue quatre cas :

       *  Si pathname est une chaîne non vide contenant un chemin d'accès  absolu,  alors  un  gestionnaire  est
          renvoyé pour le fichier indiqué par le chemin. Dans ce cas, dirfd est ignoré.

       *  Si  pathname  est  une  chaîne  non vide contenant un chemin relatif, et si dirfd a la valeur spéciale
          AT_FDCWD, alors pathname est interprété par rapport au répertoire courant du processus appelant, et un
          gestionnaire est renvoyé pour le fichier indiqué par le chemin.

       *  Si pathname est une chaîne non vide contenant un chemin d'accès relatif et si dirfd est le descripteur
          de fichier d'un répertoire, alors pathname est interprété par rapport au répertoire désigné par dirfd,
          et  un  gestionnaire  est  renvoyé pour le fichier indiqué par le chemin. (Consultez openat(3) si vous
          souhaitez comprendre pour quelles raisons les « descripteurs de fichier de répertoires » sont utiles).

       *  Si pathname est une chaîne vide, et si flags précise la valeur de AT_EMPTY_PATH, alors dirfd peut être
          un  descripteur  de  fichiers  ouvert faisant référence à n'importe quel type de fichier ou à AT_FDCWD
          (répertoire de travail courant), et un gestionnaire  est  renvoyé  pour  le  fichier  auquel  il  fait
          référence.

       L'argument  mount_id renvoie un identifiant pour le point de montage du système de fichiers correspondant
       à pathname. Cet identifiant correspond au premier champ des entrées de /proc/self/mountinfo.  L'ouverture
       du chemin indiqué dans le cinquième champ délivre un descripteur de fichier pour le point de montage ; ce
       descripteur de fichier peut être utilisé par la suite lors d'un appel à open_by_handle_at().

       Par défaut, name_to_handle_at() ne déréférence pas pathname s'il s'agit d'un lien symbolique, et donc  ne
       renvoie  pas  d'indicateur pour le lien symbolique. Si AT_SYMLINK_FOLLOW est précisé dans flags, pathname
       est déréférencé s'il s'agit d'un lien symbolique (de sorte que l'appel  renvoie  un  indicateur  pour  le
       fichier vers lequel pointe le lien symbolique).

   open_by_handle_at()
       L'appel  système  open_by_handle_at() ouvre le fichier auquel handle fait référence, via un indicateur de
       fichier renvoyé lors d'un précédent appel à name_to_handle_at().

       L'argument mount_fd est un descripteur de fichier pour n'importe quel type d'objet (fichier,  répertoire,
       etc.)  du  système de fichiers monté qui permet d'interpréter l'indicateur de fichier (handle). La valeur
       spéciale AT_FDCWD peut être précisée, et indique le répertoire courant du processus appelant.

       L'argument flags a la même fonction que pour open(2). Si l'indicateur handle fait  référence  à  un  lien
       symbolique,  le  processus  appelant  doit  préciser  l'attribut  O_PATH  et le lien symbolique n'est pas
       déréférencé. L'attribut O_NOFOLLOW est ignoré.

       L'appelant doit avoir la capacité CAP_DAC_READ_SEARCH pour utiliser open_by_handle_at().

VALEUR RENVOYÉE

       Lorsqu'il réussit, l'appel name_to_handle_at() renvoie 0 et open_by_handle_at() renvoie un descripteur de
       fichier positif ou nul.

       En cas d'échec, les deux appels renvoient -1 et affectent à errno l'identifiant de la cause de l'échec.

ERREURS

       Les  appels  name_to_handle_at()  et  open_by_handle_at()  peuvent  échouer  pour  les  mêmes raisons que
       openat(2). En outre, ils peuvent également échouer pour les motifs décrits plus bas.

       name_to_handle_at() peut échouer avec les erreurs suivantes :

       EFAULT pathname, mount_id ou handle pointe en‐dehors de l'espace d'adressage accessible.

       EINVAL flags comprend un bit incorrect.

       EINVAL handle->handle_bytes est supérieur à MAX_HANDLE_SZ.

       ENOENT pathname est une chaîne vide et AT_EMPTY_PATH n’était pas indiqué dans flags.

       ENOTDIR
              Le descripteur de fichiers fourni dans dirfd ne fait pas référence  à  un  répertoire,  et  il  ne
              s'agit pas du cas où flags comprend AT_EMPTY_PATH et pathname est une chaîne vide.

       EOPNOTSUPP
              Le  système  de  fichiers  ne  permet  pas  la transcription du chemin de fichier en indicateur de
              fichier.

       EOVERFLOW
              La valeur handle->handle_bytes transmise dans l'appel est trop faible.  Lorsque  cette  erreur  se
              produit, handle->handle_bytes est modifié afin d'indiquer la taille requise pour cet indicateur.

       open_by_handle_at() peut échouer avec les erreurs suivantes :

       EBADF  mount_fd n'est pas un descripteur de fichier ouvert.

       EFAULT handle pointe en‐dehors de l'espace d'adressage accessible.

       EINVAL handle->handle_bytes est supérieur à MAX_HANDLE_SZ ou égal à zéro.

       ELOOP  handle correspond à un lien symbolique et O_PATH n’était pas indiqué dans flags.

       EPERM  L'appelant n'a pas la capacité CAP_DAC_READ_SEARCH.

       ESTALE La valeur handle indiquée n'est pas correcte. Cet erreur se produit par exemple lorsque le fichier
              a été supprimé.

VERSIONS

       Ces appels système sont apparaus dans Linux 2.6.39. La glibc les gère depuis la version 2.14.

CONFORMITÉ

       Ces appels système sont des extensions spécifiques à Linux.

NOTES

       Un indicateur de fichier peut être créé dans un processus au moyen de name_to_handle_at() et utilisé plus
       tard dans un autre processus qui appelle open_by_handle_at().

       Certains  systèmes  de  fichiers ne permettent pas la transcription des chemin de fichiers en indicateurs
       (par exemple, /proc, /sys, ainsi que divers systèmes de fichiers en réseaux).

       Un indicateur de fichier peut devenir invalide (« stale ») si un fichier est supprimé, ou pour une raison
       propre au système de fichiers. Les indicateurs invalides sont signalés par une erreur ESTALE provenant de
       open_by_handle_at().

       Ces appels systèmes sont conçus pour être utilisés par des serveurs de fichiers  en  espace  utilisateur.
       Par  exemple,  un  serveur  NFS  en espace utilisateur produit un indicateur de fichier et le transmet au
       client NFS. Plus tard, lorsque le client souhaite  accéder  au  fichier  en  lecture,  il  peut  renvoyer
       l'indicateur  au  serveur. Ce type de fonctionnalité permet à un serveur de fichier en espace utilisateur
       d'opérer sans état vis à vis du fichier qu'il délivre.

       Si pathname fait référence à un lien symbolique et si  flags  ne  précise  pas  AT_SYMLINK_FOLLOW,  alors
       name_to_handle_at()  renvoie  un  indicateur pour le lien (plutôt que pour le fichier vers lequel le lien
       pointe). Le processus  recevant  l'indicateur  peut  effectuer  plus  tard  une  opération  sur  ce  lien
       symbolique,  en  convertissant  l'indicateur  en  descripteur  de fichier au moyen de open_by_handle_at()
       utilisé avec l'argument O_PATH, et en passant le descripteur de fichier  en  argument  dirfd  de  l'appel
       système (comme pour readlinkat(2) et fchownat(2)).

   Obtenir un identifiant persistant de système de fichier
       Les  identifiant  de montage de /proc/self/mountinfo peuvent être réutilisés même lorsque les systèmes de
       fichiers sont démontés et remontés. Ainsi, l'identifiant de montage renvoyé par name_to_handle_at() (dans
       *mount_id)  ne  doit  pas  être  considéré  comme  un  identifiant persistant pour le système de fichiers
       considéré. Néanmoins, il  est  possible  pour  une  application  d'utiliser  l'information  fournie  dans
       mountinfo et correspondant à l'identifiant de montage pour en déduire un identifiant persistant.

       Par  exemple,  on  peut utiliser le nom de périphérique présent dans le cinquième champ de mountinfo pour
       retrouver l'UUID du périphérique correspondant au moyen des liens symboliques de /dev/disks/by-uuid.  (Un
       moyen  plus  simple  d'obtenir  cet UUID consiste à utiliser la bibliothèque libblkid(3)). Cette façon de
       procéder peut être inversée, en utilisant l'UUID pour retrouver le nom du périphérique, et ainsi  obtenir
       le   point   de   montage   correspondant,   et   enfin   construire   l'argument  de  mount_fd  utile  à
       open_by_handle_at().

EXEMPLE

       Les deux programmes suivants illustrent l'utilisation de name_to_handle_at() et  de  open_by_handle_at().
       Le  premier  programme (t_name_to_handle_at.c) utilise name_to_handle_at() pour récupérer l'indicateur de
       fichier et l'identifiant de montage du  fichier  indiqué  dans  les  arguments  en  ligne  de  commande ;
       l'indicateur et l'identifiant de montage sont écrits sur la sortie standard.

       Le  second  programme  (t_open_by_handle_at.c)  lit un identifiant de montage et un indicateur de fichier
       depuis l'entrée standard. Le programme utilise ensuite open_by_handle_at() pour lire le fichier au  moyen
       de  cet  indicateur.  Si  un  argument  optionnel  est fourni dans la ligne de commande, alors l'argument
       mount_fd de open_by_handle_at() est obtenu en ouvrant le répertoire précisé en argument. Sinon,  mount_fd
       est  obtenu en parcourant /proc/self/mountinfo à la recherche d'un identifiant de montage correspondant à
       celui fourni via l'entrée standard, et le répertoire monté qui a été trouvé est ouvert.  (Ces  programmes
       ne tiennent pas compte du fait que les identifiants de montage ne sont pas persistants.)

       La session shell suivante montre des exemples d'utilisation de ces deux programmes :

           $ echo 'Pouvez-vous réflechir à cela ?' > cecilia.txt
           $ ./t_name_to_handle_at cecilia.txt > fh
           $ ./t_open_by_handle_at < fh
           open_by_handle_at: Operation non autorisée
           $ sudo ./t_open_by_handle_at < fh      # Nécessite CAP_SYS_ADMIN
           31 octets lus
           $ rm cecilia.txt

       A ce stade, on supprime et recrée (rapidement) le fichier, de sorte qu'il ait le même contenu et (avec un
       peu de chance) le même inoeud. Cependant, open_by_handle_at() s'aperçoit que le fichier  original  auquel
       l'indicateur fait référence n'existe plus.

           $ stat --printf="%i\n" cecilia.txt     # affiche le numéro d'inoeud
           4072121
           $ rm cecilia.txt
           $ echo 'Can you please think about it?' > cecilia.txt
           $ stat --printf="%i\n" cecilia.txt     # Vérifie le numéro d'inoeud
           4072121
           $ sudo ./t_open_by_handle_at < fh
           open_by_handle_at: Stale NFS file handle

   Source du programme : t_name_to_handle_at.c

       #define _GNU_SOURCE
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>
       #include <errno.h>
       #include <string.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       int
       main(int argc, char *argv[])
       {
           struct file_handle *fhp;
           int mount_id, fhsize, flags, dirfd, j;
           char *pathname;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s pathname\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           pathname = argv[1];

           /* Alloue la structure file_handle */

           fhsize = sizeof(*fhp);
           fhp = malloc(fhsize);
           if (fhp == NULL)
               errExit("malloc");

           /* Effectue un appel initial à name_to_handle_at() afin de connaître
              la taille nécessaire à l'indicateur de fichier */

           dirfd = AT_FDCWD;           /* pour les appels à name_to_handle_at() */
           flags = 0;                  /* Pour les appels à  name_to_handle_at() */
           fhp->handle_bytes = 0;
           if (name_to_handle_at(dirfd, pathname, fhp,
                       &mount_id, flags) != -1 || errno != EOVERFLOW) {
               fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
               exit(EXIT_FAILURE);
           }

           /* Ré-alloue la structure file_handle avec la bonne taille */

           fhsize = sizeof(struct file_handle) + fhp->handle_bytes;
           fhp = realloc(fhp, fhsize);         /* Copie fhp->handle_bytes */
           if (fhp == NULL)
               errExit("realloc");

           /* Retrouve l'indicateur de fichier à partir
              du chemin fourni dans la ligne de commande */

           if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
               errExit("name_to_handle_at");

           /* Écrit l'identifiant de montage, la taille de l'indicateur et
              l'indicateur vers la sortie standard
              pour être utilisé plus tard par t_open_by_handle_at.c */

           printf("%d\n", mount_id);
           printf("%d %d   ", fhp->handle_bytes, fhp->handle_type);
           for (j = 0; j < fhp->handle_bytes; j++)
               printf(" %02x", fhp->f_handle[j]);
           printf("\n");

           exit(EXIT_SUCCESS);
       }

   Source du programme : t_open_by_handle_at.c

       #define _GNU_SOURCE
       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>
       #include <limits.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>
       #include <string.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       /* Parcourt /proc/self/mountinfo pour trouver la ligne correspondant à
          l'ID de montage 'mount_id'. (Une méthode plus simple consiste à
          installer et à utiliser la bibliothèque (aqlibmount' fournie par le
          projet 'util-linux'.)
          Ouvre le point de montage correspondant et renvoie le descripteur de fichier associé. */

       static int
       open_mount_path_by_id(int mount_id)
       {
           char *linep;
           size_t lsize;
           char mount_path[PATH_MAX];
           int mi_mount_id, found;
           ssize_t nread;
           FILE *fp;

           fp = fopen("/proc/self/mountinfo", "r");
           if (fp == NULL)
               errExit("fopen");

           found = 0;
           linep = NULL;
           while (!found) {
               nread = getline(&linep, &lsize, fp);
               if (nread == -1)
                   break;

               nread = sscanf(linep, "%d %*d %*s %*s %s",
                              &mi_mount_id, mount_path);
               if (nread != 2) {
                   fprintf(stderr, "Bad sscanf()\n");
                   exit(EXIT_FAILURE);
               }

               if (mi_mount_id == mount_id)
                   found = 1;
           }
           free(linep);

           fclose(fp);

           if (!found) {
               fprintf(stderr, "Point de montage non trouvé\n");
               exit(EXIT_FAILURE);
           }

           return open(mount_path, O_RDONLY);
       }

       int
       main(int argc, char *argv[])
       {
           struct file_handle *fhp;
           int mount_id, fd, mount_fd, handle_bytes, j;
           ssize_t nread;
           char buf[1000];
       #define LINE_SIZE 100
           char line1[LINE_SIZE], line2[LINE_SIZE];
           char *nextp;

           if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
               fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           /* L'entrée standard contient l'identifiant de montage et les informations du l'indicateur :

                Ligne 1: <mount_id>
                Ligne 2: <handle_bytes> <handle_type>   <octets du descripteur en hexadécimal>
           */

           if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
                  (fgets(line2, sizeof(line2), stdin) == NULL)) {
               fprintf(stderr, "mount_id ou descripteur de fichier absent\n");
               exit(EXIT_FAILURE);
           }

           mount_id = atoi(line1);

           handle_bytes = strtoul(line2, &nextp, 0);

           /* handle_bytes étant connu, on peut maintenant allouer la structure file_handle */

           fhp = malloc(sizeof(struct file_handle) + handle_bytes);
           if (fhp == NULL)
               errExit("malloc");

           fhp->handle_bytes = handle_bytes;

           fhp->handle_type = strtoul(nextp, &nextp, 0);

           for (j = 0; j < fhp->handle_bytes; j++)
               fhp->f_handle[j] = strtoul(nextp, &nextp, 16);

           /* Récupère le descripteur de fichier du point de montage, soit en ouvrant
              le chemin indiqué dans la ligne de commande, soit en parcourant
              /proc/self/mounts pour retrouver un montage qui corresponde à 'mount_id'
              qui a été reçu de stdin. */

           if (argc > 1)
               mount_fd = open(argv[1], O_RDONLY);
           else
               mount_fd = open_mount_path_by_id(mount_id);

           if (mount_fd == -1)
               errExit("opening mount fd");

           /* Ouvre le fichier en utilisant l'indicateur et le point de montage */

           fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
           if (fd == -1)
               errExit("open_by_handle_at");

           /* On essaie de lire quelques octets depuis le fichier */

           nread = read(fd, buf, sizeof(buf));
           if (nread == -1)
               errExit("read");

           printf("Read %zd bytes\n", nread);

           exit(EXIT_SUCCESS);
       }

VOIR AUSSI

       open(2), libblkid(3), blkid(8), findfs(8), mount(8)

       La   document   relative   à  libblkid  et  à  libmount  de  la  dernière  publication  de  util-linux  à
       ⟨https://www.kernel.org/pub/linux/utils/util-linux/⟩

COLOPHON

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

TRADUCTION

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

       Veuillez  signaler  toute erreur de traduction en écrivant à <debian-l10n-french@lists.debian.org> ou par
       un rapport de bogue sur le paquet manpages-fr.

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