1OPEN_BY_HANDLE_AT(2)       Linux Programmer's Manual      OPEN_BY_HANDLE_AT(2)
2
3
4

NAME

6       name_to_handle_at, open_by_handle_at - obtain handle for a pathname and
7       open file via a handle
8

SYNOPSIS

10       #define _GNU_SOURCE         /* See feature_test_macros(7) */
11       #include <sys/types.h>
12       #include <sys/stat.h>
13       #include <fcntl.h>
14
15       int name_to_handle_at(int dirfd, const char *pathname,
16                             struct file_handle *handle,
17                             int *mount_id, int flags);
18
19       int open_by_handle_at(int mount_fd, struct file_handle *handle,
20                             int flags);
21

DESCRIPTION

23       The name_to_handle_at() and open_by_handle_at() system calls split  the
24       functionality  of openat(2) into two parts: name_to_handle_at() returns
25       an opaque handle that corresponds to  a  specified  file;  open_by_han‐
26       dle_at()  opens the file corresponding to a handle returned by a previ‐
27       ous call to name_to_handle_at() and returns an open file descriptor.
28
29   name_to_handle_at()
30       The name_to_handle_at() system call returns a file handle and  a  mount
31       ID  corresponding to the file specified by the dirfd and pathname argu‐
32       ments.  The file handle is returned via the argument handle, which is a
33       pointer to a structure of the following form:
34
35           struct file_handle {
36               unsigned int  handle_bytes;   /* Size of f_handle [in, out] */
37               int           handle_type;    /* Handle type [out] */
38               unsigned char f_handle[0];    /* File identifier (sized by
39                                                caller) [out] */
40           };
41
42       It is the caller's responsibility to allocate the structure with a size
43       large enough to hold the handle returned in f_handle.  Before the call,
44       the  handle_bytes  field should be initialized to contain the allocated
45       size for f_handle.  (The constant MAX_HANDLE_SZ, defined in  <fcntl.h>,
46       specifies  the  maximum  expected  size for a file handle.  It is not a
47       guaranteed upper limit as future filesystems may require  more  space.)
48       Upon  successful  return,  the handle_bytes field is updated to contain
49       the number of bytes actually written to f_handle.
50
51       The caller can discover the required size for the file_handle structure
52       by  making  a call in which handle->handle_bytes is zero; in this case,
53       the call fails with the error EOVERFLOW and handle->handle_bytes is set
54       to indicate the required size; the caller can then use this information
55       to allocate a structure of the correct size (see EXAMPLE below).   Some
56       care  is needed here as EOVERFLOW can also indicate that no file handle
57       is available for this particular name in a filesystem which  does  nor‐
58       mally  support  file-handle lookup.  This case can be detected when the
59       EOVERFLOW error is returned without handle_bytes being increased.
60
61       Other than the use of the handle_bytes field, the caller  should  treat
62       the  file_handle  structure as an opaque data type: the handle_type and
63       f_handle fields are needed only by a subsequent  call  to  open_by_han‐
64       dle_at().
65
66       The  flags argument is a bit mask constructed by ORing together zero or
67       more of AT_EMPTY_PATH and AT_SYMLINK_FOLLOW, described below.
68
69       Together, the pathname and dirfd arguments identify the file for  which
70       a handle is to be obtained.  There are four distinct cases:
71
72       *  If  pathname  is  a nonempty string containing an absolute pathname,
73          then a handle is returned for the file referred to by that pathname.
74          In this case, dirfd is ignored.
75
76       *  If  pathname is a nonempty string containing a relative pathname and
77          dirfd has the special value AT_FDCWD, then pathname  is  interpreted
78          relative  to the current working directory of the caller, and a han‐
79          dle is returned for the file to which it refers.
80
81       *  If pathname is a nonempty string containing a relative pathname  and
82          dirfd  is  a file descriptor referring to a directory, then pathname
83          is interpreted relative to the directory referred to by dirfd, and a
84          handle  is returned for the file to which it refers.  (See openat(2)
85          for an explanation of why "directory file descriptors" are useful.)
86
87       *  If pathname is  an  empty  string  and  flags  specifies  the  value
88          AT_EMPTY_PATH,  then  dirfd can be an open file descriptor referring
89          to any type of file, or AT_FDCWD, meaning the current working direc‐
90          tory, and a handle is returned for the file to which it refers.
91
92       The  mount_id  argument  returns an identifier for the filesystem mount
93       that corresponds to pathname.  This corresponds to the first  field  in
94       one  of  the  records in /proc/self/mountinfo.  Opening the pathname in
95       the fifth field of that record yields a file descriptor for  the  mount
96       point;  that  file  descriptor  can  be  used  in  a subsequent call to
97       open_by_handle_at().  mount_id is returned both for a  successful  call
98       and for a call that results in the error EOVERFLOW.
99
100       By  default, name_to_handle_at() does not dereference pathname if it is
101       a symbolic link, and thus returns a handle for  the  link  itself.   If
102       AT_SYMLINK_FOLLOW is specified in flags, pathname is dereferenced if it
103       is a symbolic link (so that the call returns  a  handle  for  the  file
104       referred to by the link).
105
106       name_to_handle_at()  does  not trigger a mount when the final component
107       of the pathname is an automount point.  When a filesystem supports both
108       file  handles  and  automount  points, a name_to_handle_at() call on an
109       automount  point  will  return  with  error  EOVERFLOW  without  having
110       increased handle_bytes.  This can happen since Linux 4.13 with NFS when
111       accessing a directory which is on a separate filesystem on the  server.
112       In this case, the automount can be triggered by adding a "/" to the end
113       of the pathname.
114
115   open_by_handle_at()
116       The open_by_handle_at() system call opens the file referred to by  han‐
117       dle, a file handle returned by a previous call to name_to_handle_at().
118
119       The mount_fd argument is a file descriptor for any object (file, direc‐
120       tory, etc.)  in the mounted filesystem with  respect  to  which  handle
121       should  be  interpreted.   The special value AT_FDCWD can be specified,
122       meaning the current working directory of the caller.
123
124       The flags argument is as for open(2).  If handle refers to  a  symbolic
125       link, the caller must specify the O_PATH flag, and the symbolic link is
126       not dereferenced; the O_NOFOLLOW flag, if specified, is ignored.
127
128       The caller must  have  the  CAP_DAC_READ_SEARCH  capability  to  invoke
129       open_by_handle_at().
130

RETURN VALUE

132       On  success,  name_to_handle_at()  returns  0,  and open_by_handle_at()
133       returns a file descriptor (a nonnegative integer).
134
135       In the event of an error, both system calls return -1 and set errno  to
136       indicate the cause of the error.
137

ERRORS

139       name_to_handle_at()  and  open_by_handle_at()  can  fail  for  the same
140       errors as openat(2).  In addition, they can fail with the errors  noted
141       below.
142
143       name_to_handle_at() can fail with the following errors:
144
145       EFAULT pathname,  mount_id,  or  handle  points outside your accessible
146              address space.
147
148       EINVAL flags includes an invalid bit value.
149
150       EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ.
151
152       ENOENT pathname is an empty string, but AT_EMPTY_PATH was not specified
153              in flags.
154
155       ENOTDIR
156              The file descriptor supplied in dirfd does not refer to a direc‐
157              tory,  and  it  is  not  the  case  that  both  flags   includes
158              AT_EMPTY_PATH and pathname is an empty string.
159
160       EOPNOTSUPP
161              The filesystem does not support decoding of a pathname to a file
162              handle.
163
164       EOVERFLOW
165              The handle->handle_bytes value passed  into  the  call  was  too
166              small.   When this error occurs, handle->handle_bytes is updated
167              to indicate the required size for the handle.
168
169       open_by_handle_at() can fail with the following errors:
170
171       EBADF  mount_fd is not an open file descriptor.
172
173       EFAULT handle points outside your accessible address space.
174
175       EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ or  is  equal
176              to zero.
177
178       ELOOP  handle  refers  to a symbolic link, but O_PATH was not specified
179              in flags.
180
181       EPERM  The caller does not have the CAP_DAC_READ_SEARCH capability.
182
183       ESTALE The specified handle is not valid.  This error  will  occur  if,
184              for example, the file has been deleted.
185

VERSIONS

187       These  system calls first appeared in Linux 2.6.39.  Library support is
188       provided in glibc since version 2.14.
189

CONFORMING TO

191       These system calls are nonstandard Linux extensions.
192
193       FreeBSD has a broadly similar pair of  system  calls  in  the  form  of
194       getfh() and openfh().
195

NOTES

197       A file handle can be generated in one process using name_to_handle_at()
198       and later used in a different process that calls open_by_handle_at().
199
200       Some filesystem don't support the translation of pathnames to file han‐
201       dles, for example, /proc, /sys, and various network filesystems.
202
203       A file handle may become invalid ("stale") if a file is deleted, or for
204       other filesystem-specific reasons.  Invalid handles are notified by  an
205       ESTALE error from open_by_handle_at().
206
207       These  system  calls  are  designed for use by user-space file servers.
208       For example, a user-space NFS server might generate a file  handle  and
209       pass  it  to  an  NFS client.  Later, when the client wants to open the
210       file, it could pass the handle back to the server.  This sort of  func‐
211       tionality  allows  a  user-space  file server to operate in a stateless
212       fashion with respect to the files it serves.
213
214       If pathname refers to a  symbolic  link  and  flags  does  not  specify
215       AT_SYMLINK_FOLLOW,  then  name_to_handle_at()  returns a handle for the
216       link (rather than the file to which it refers).  The process  receiving
217       the  handle  can  later perform operations on the symbolic link by con‐
218       verting the handle to a file descriptor using open_by_handle_at()  with
219       the  O_PATH  flag,  and  then  passing the file descriptor as the dirfd
220       argument in system calls such as readlinkat(2) and fchownat(2).
221
222   Obtaining a persistent filesystem ID
223       The mount IDs in /proc/self/mountinfo can be reused as filesystems  are
224       unmounted   and   mounted.    Therefore,   the  mount  ID  returned  by
225       name_to_handle_at() (in *mount_id) should not be treated as  a  persis‐
226       tent  identifier for the corresponding mounted filesystem.  However, an
227       application can use the information in the mountinfo record that corre‐
228       sponds to the mount ID to derive a persistent identifier.
229
230       For  example,  one  can  use  the device name in the fifth field of the
231       mountinfo record to search for the corresponding device  UUID  via  the
232       symbolic  links  in  /dev/disks/by-uuid.   (A  more  comfortable way of
233       obtaining the UUID is to use the libblkid(3)  library.)   That  process
234       can  then  be  reversed, using the UUID to look up the device name, and
235       then obtaining the corresponding mount point, in order to  produce  the
236       mount_fd argument used by open_by_handle_at().
237

EXAMPLES

239       The  two  programs below demonstrate the use of name_to_handle_at() and
240       open_by_handle_at().  The first  program  (t_name_to_handle_at.c)  uses
241       name_to_handle_at() to obtain the file handle and mount ID for the file
242       specified in its command-line argument; the handle  and  mount  ID  are
243       written to standard output.
244
245       The  second  program  (t_open_by_handle_at.c) reads a mount ID and file
246       handle from standard input.   The  program  then  employs  open_by_han‐
247       dle_at()  to  open the file using that handle.  If an optional command-
248       line argument is supplied, then the mount_fd argument for  open_by_han‐
249       dle_at()  is  obtained by opening the directory named in that argument.
250       Otherwise, mount_fd is obtained  by  scanning  /proc/self/mountinfo  to
251       find  a  record  whose mount ID matches the mount ID read from standard
252       input, and the mount directory specified  in  that  record  is  opened.
253       (These  programs  do not deal with the fact that mount IDs are not per‐
254       sistent.)
255
256       The following shell session demonstrates the use of these two programs:
257
258           $ echo 'Can you please think about it?' > cecilia.txt
259           $ ./t_name_to_handle_at cecilia.txt > fh
260           $ ./t_open_by_handle_at < fh
261           open_by_handle_at: Operation not permitted
262           $ sudo ./t_open_by_handle_at < fh      # Need CAP_SYS_ADMIN
263           Read 31 bytes
264           $ rm cecilia.txt
265
266       Now we delete and (quickly) re-create the file so that it has the  same
267       content  and  (by  chance)  the same inode.  Nevertheless, open_by_han‐
268       dle_at() recognizes that the original file referred to by the file han‐
269       dle no longer exists.
270
271           $ stat --printf="%i\n" cecilia.txt     # Display inode number
272           4072121
273           $ rm cecilia.txt
274           $ echo 'Can you please think about it?' > cecilia.txt
275           $ stat --printf="%i\n" cecilia.txt     # Check inode number
276           4072121
277           $ sudo ./t_open_by_handle_at < fh
278           open_by_handle_at: Stale NFS file handle
279
280   Program source: t_name_to_handle_at.c
281
282       #define _GNU_SOURCE
283       #include <sys/types.h>
284       #include <sys/stat.h>
285       #include <fcntl.h>
286       #include <stdio.h>
287       #include <stdlib.h>
288       #include <unistd.h>
289       #include <errno.h>
290       #include <string.h>
291
292       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
293                               } while (0)
294
295       int
296       main(int argc, char *argv[])
297       {
298           struct file_handle *fhp;
299           int mount_id, fhsize, flags, dirfd, j;
300           char *pathname;
301
302           if (argc != 2) {
303               fprintf(stderr, "Usage: %s pathname\n", argv[0]);
304               exit(EXIT_FAILURE);
305           }
306
307           pathname = argv[1];
308
309           /* Allocate file_handle structure */
310
311           fhsize = sizeof(*fhp);
312           fhp = malloc(fhsize);
313           if (fhp == NULL)
314               errExit("malloc");
315
316           /* Make an initial call to name_to_handle_at() to discover
317              the size required for file handle */
318
319           dirfd = AT_FDCWD;           /* For name_to_handle_at() calls */
320           flags = 0;                  /* For name_to_handle_at() calls */
321           fhp->handle_bytes = 0;
322           if (name_to_handle_at(dirfd, pathname, fhp,
323                       &mount_id, flags) != -1 || errno != EOVERFLOW) {
324               fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
325               exit(EXIT_FAILURE);
326           }
327
328           /* Reallocate file_handle structure with correct size */
329
330           fhsize = sizeof(struct file_handle) + fhp->handle_bytes;
331           fhp = realloc(fhp, fhsize);         /* Copies fhp->handle_bytes */
332           if (fhp == NULL)
333               errExit("realloc");
334
335           /* Get file handle from pathname supplied on command line */
336
337           if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
338               errExit("name_to_handle_at");
339
340           /* Write mount ID, file handle size, and file handle to stdout,
341              for later reuse by t_open_by_handle_at.c */
342
343           printf("%d\n", mount_id);
344           printf("%d %d   ", fhp->handle_bytes, fhp->handle_type);
345           for (j = 0; j < fhp->handle_bytes; j++)
346               printf(" %02x", fhp->f_handle[j]);
347           printf("\n");
348
349           exit(EXIT_SUCCESS);
350       }
351
352   Program source: t_open_by_handle_at.c
353
354       #define _GNU_SOURCE
355       #include <sys/types.h>
356       #include <sys/stat.h>
357       #include <fcntl.h>
358       #include <limits.h>
359       #include <stdio.h>
360       #include <stdlib.h>
361       #include <unistd.h>
362       #include <string.h>
363
364       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
365                               } while (0)
366
367       /* Scan /proc/self/mountinfo to find the line whose mount ID matches
368          'mount_id'. (An easier way to do this is to install and use the
369          'libmount' library provided by the 'util-linux' project.)
370          Open the corresponding mount path and return the resulting file
371          descriptor. */
372
373       static int
374       open_mount_path_by_id(int mount_id)
375       {
376           char *linep;
377           size_t lsize;
378           char mount_path[PATH_MAX];
379           int mi_mount_id, found;
380           ssize_t nread;
381           FILE *fp;
382
383           fp = fopen("/proc/self/mountinfo", "r");
384           if (fp == NULL)
385               errExit("fopen");
386
387           found = 0;
388           linep = NULL;
389           while (!found) {
390               nread = getline(&linep, &lsize, fp);
391               if (nread == -1)
392                   break;
393
394               nread = sscanf(linep, "%d %*d %*s %*s %s",
395                              &mi_mount_id, mount_path);
396               if (nread != 2) {
397                   fprintf(stderr, "Bad sscanf()\n");
398                   exit(EXIT_FAILURE);
399               }
400
401               if (mi_mount_id == mount_id)
402                   found = 1;
403           }
404           free(linep);
405
406           fclose(fp);
407
408           if (!found) {
409               fprintf(stderr, "Could not find mount point\n");
410               exit(EXIT_FAILURE);
411           }
412
413           return open(mount_path, O_RDONLY);
414       }
415
416       int
417       main(int argc, char *argv[])
418       {
419           struct file_handle *fhp;
420           int mount_id, fd, mount_fd, handle_bytes, j;
421           ssize_t nread;
422           char buf[1000];
423       #define LINE_SIZE 100
424           char line1[LINE_SIZE], line2[LINE_SIZE];
425           char *nextp;
426
427           if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
428               fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
429               exit(EXIT_FAILURE);
430           }
431
432           /* Standard input contains mount ID and file handle information:
433
434                Line 1: <mount_id>
435                Line 2: <handle_bytes> <handle_type>   <bytes of handle in hex>
436           */
437
438           if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
439                  (fgets(line2, sizeof(line2), stdin) == NULL)) {
440               fprintf(stderr, "Missing mount_id / file handle\n");
441               exit(EXIT_FAILURE);
442           }
443
444           mount_id = atoi(line1);
445
446           handle_bytes = strtoul(line2, &nextp, 0);
447
448           /* Given handle_bytes, we can now allocate file_handle structure */
449
450           fhp = malloc(sizeof(struct file_handle) + handle_bytes);
451           if (fhp == NULL)
452               errExit("malloc");
453
454           fhp->handle_bytes = handle_bytes;
455
456           fhp->handle_type = strtoul(nextp, &nextp, 0);
457
458           for (j = 0; j < fhp->handle_bytes; j++)
459               fhp->f_handle[j] = strtoul(nextp, &nextp, 16);
460
461           /* Obtain file descriptor for mount point, either by opening
462              the pathname specified on the command line, or by scanning
463              /proc/self/mounts to find a mount that matches the 'mount_id'
464              that we received from stdin. */
465
466           if (argc > 1)
467               mount_fd = open(argv[1], O_RDONLY);
468           else
469               mount_fd = open_mount_path_by_id(mount_id);
470
471           if (mount_fd == -1)
472               errExit("opening mount fd");
473
474           /* Open file using handle and mount point */
475
476           fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
477           if (fd == -1)
478               errExit("open_by_handle_at");
479
480           /* Try reading a few bytes from the file */
481
482           nread = read(fd, buf, sizeof(buf));
483           if (nread == -1)
484               errExit("read");
485
486           printf("Read %zd bytes\n", nread);
487
488           exit(EXIT_SUCCESS);
489       }
490

SEE ALSO

492       open(2), libblkid(3), blkid(8), findfs(8), mount(8)
493
494       The  libblkid  and  libmount  documentation  in  the  latest util-linux
495       release at ⟨https://www.kernel.org/pub/linux/utils/util-linux/
496

COLOPHON

498       This page is part of release 5.07 of the Linux  man-pages  project.   A
499       description  of  the project, information about reporting bugs, and the
500       latest    version    of    this    page,    can     be     found     at
501       https://www.kernel.org/doc/man-pages/.
502
503
504
505Linux                             2020-04-11              OPEN_BY_HANDLE_AT(2)
Impressum