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> ».