Provided by: manpages-fr-dev_4.15.0-9_all bug

NOM

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

SYNOPSIS

       #define _GNU_SOURCE         /* Consultez feature_test_macros(7) */
       #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 [out] */
               unsigned char f_handle[0];    /* identifiant du fichier (taille
                                                définie par l’appelant) [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  maximale
       autorisée  pour un gestionnaire de fichier. La limite supérieure n'est pas garantie car de
       futurs systèmes de fichiers  pourraient  avoir  besoin  de  davantage  d'espace).  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 EXEMPLES ci-dessous). Il faut  faire  attention  ici
       car  EOVERFLOW peut indiquer qu'aucun gestionnaire de fichier n'est disponible pour ce nom
       particulier dans un système de fichiers qui prend normalement en charge  la  recherche  de
       gestionnaire  de  fichiers.  Ce cas peut se détecter quand l'erreur EOVERFLOW est renvoyée
       sans que handle_bytes ne soit augmenté.

       Mise à part l'utilisation du champ handle_bytes, l'appelant doit considérer  la  structure
       file_handle  comme  de type opaque de données : 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, décrits 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 ce 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  à  quoi  servent  les
          « descripteurs de fichier de répertoires »).

       –  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(). mount_id est renvoyé  tant  en
       cas de succès qu'en cas d'erreur EOVERFLOW de l'appel.

       Par  défaut,  name_to_handle_at()  ne  déréférence  pas  pathname  s'il  s'agit  d'un lien
       symbolique, et donc renvoie un gestionnaire pour le lien  lui-même.  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).

       name_to_handle_at()  ne  récupère pas un montage quand le composant final du chemin est un
       point  de  montage  automatique.  Quand  un  système  de  fichiers  gère  à  la  fois  les
       gestionnaires   de   fichier   et   les   points   de   montage   automatique,   un  appel
       name_to_handle_at() sur un point de montage automatique renverra une erreur EOVERFLOW sans
       augmenter  handle_bytes. Cela peut arriver depuis Linux 4.13 avec NFS lors d'un accès à un
       répertoire sur un système  de  fichiers  séparé  du  serveur.  Dans  ce  cas,  le  montage
       automatique peut être provoqué en ajoutant un « / » à la fin du chemin.

   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 (un entier non négatif).

       In the event of an error, both system calls return -1 and set errno to indicate the error.

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.

       EBADF  pathname  est  relatif  mais  dirfd  n'est ni AT_FDWCD ni un descripteur de fichier
              valable.

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

       FreeBSD offre un couple d'appels système similaires : getfh() et openfh().

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 chemins de fichier en
       indicateurs (par exemple, /proc, /sys, ainsi que divers systèmes de fichiers en réseaux).

       Un indicateur de fichier peut devenir non valable (« stale ») si un fichier est  supprimé,
       ou  pour  une  raison  propre  au  système de fichiers. Les indicateurs non autorisés 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,  il  peut renvoyer l'indicateur au serveur. Ce type de fonctionnalité permet à un
       serveur de fichiers en espace utilisateur d'opérer sans état vis à vis des fichiers  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  d’appels  système  (tels  que
       readlinkat(2) et fchownat(2)).

   Obtenir un identifiant persistant de système de fichier
       Les identifiants de montage dans /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 dans /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().

EXEMPLES

       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 'Can you please think about it?' > cecilia.txt
           $ ./t_name_to_handle_at cecilia.txt > fh
           $ ./t_open_by_handle_at < fh
           open_by_handle_at: Operation not permitted
           $ sudo ./t_open_by_handle_at < fh      # Need CAP_SYS_ADMIN
           Read 31 bytes
           $ 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  inœud.  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     # Display inode number
           4072121
           $ rm cecilia.txt
           $ echo 'Can you please think about it?' > cecilia.txt
           $ stat --printf="%i\n" cecilia.txt     # Check inode number
           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;
           char *pathname;

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

           pathname = argv[1];

           /* Allocate file_handle structure. */

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

           /* Make an initial call to name_to_handle_at() to discover
              the size required for file handle. */

           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);
           }

           /* Reallocate file_handle structure with correct size. */

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

           /* Get file handle from pathname supplied on command line. */

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

           /* Write mount ID, file handle size, and file handle to stdout,
              for later reuse by t_open_by_handle_at.c. */

           printf("%d\n", mount_id);
           printf("%u %d   ", fhp->handle_bytes, fhp->handle_type);
           for (int 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;
           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 de 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);

           /* Given handle_bytes, we can now allocate file_handle structure. */

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

           fhp->handle_bytes = handle_bytes;

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

           for (int 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");

           /* Open file using handle and mount point. */

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

           /* Try reading a few bytes from the file. */

           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 documentation 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 5.13 du projet man-pages Linux. Une description
       du projet et des instructions pour signaler des anomalies et la dernière version de  cette
       page peuvent être trouvées à l'adresse https://www.kernel.org/doc/man-pages/.

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>,   Frédéric   Hantrais
       <fhantrais@gmail.com> et Jean-Philippe MENGUAL <jpmengual@debian.org>

       Cette  traduction  est  une  documentation libre ; veuillez vous reporter à la GNU General
       Public  License  version 3  ⟨https://www.gnu.org/licenses/gpl-3.0.html⟩   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⟩.