name_to_handle_at

OPEN_BY_HANDLE_AT(2)      Manuel du programmeur Linux     OPEN_BY_HANDLE_AT(2)



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



Linux                            24 mars 2014             OPEN_BY_HANDLE_AT(2)