1OPEN_BY_HANDLE_AT(2) Linux Programmer's Manual OPEN_BY_HANDLE_AT(2)
2
3
4
6 name_to_handle_at, open_by_handle_at - obtain handle for a pathname and
7 open file via a handle
8
10 #define _GNU_SOURCE /* See feature_test_macros(7) */
11 #include <fcntl.h>
12
13 int name_to_handle_at(int dirfd, const char *pathname,
14 struct file_handle *handle,
15 int *mount_id, int flags);
16 int open_by_handle_at(int mount_fd, struct file_handle *handle,
17 int flags);
18
20 The name_to_handle_at() and open_by_handle_at() system calls split the
21 functionality of openat(2) into two parts: name_to_handle_at() returns
22 an opaque handle that corresponds to a specified file; open_by_han‐
23 dle_at() opens the file corresponding to a handle returned by a previ‐
24 ous call to name_to_handle_at() and returns an open file descriptor.
25
26 name_to_handle_at()
27 The name_to_handle_at() system call returns a file handle and a mount
28 ID corresponding to the file specified by the dirfd and pathname argu‐
29 ments. The file handle is returned via the argument handle, which is a
30 pointer to a structure of the following form:
31
32 struct file_handle {
33 unsigned int handle_bytes; /* Size of f_handle [in, out] */
34 int handle_type; /* Handle type [out] */
35 unsigned char f_handle[0]; /* File identifier (sized by
36 caller) [out] */
37 };
38
39 It is the caller's responsibility to allocate the structure with a size
40 large enough to hold the handle returned in f_handle. Before the call,
41 the handle_bytes field should be initialized to contain the allocated
42 size for f_handle. (The constant MAX_HANDLE_SZ, defined in <fcntl.h>,
43 specifies the maximum expected size for a file handle. It is not a
44 guaranteed upper limit as future filesystems may require more space.)
45 Upon successful return, the handle_bytes field is updated to contain
46 the number of bytes actually written to f_handle.
47
48 The caller can discover the required size for the file_handle structure
49 by making a call in which handle->handle_bytes is zero; in this case,
50 the call fails with the error EOVERFLOW and handle->handle_bytes is set
51 to indicate the required size; the caller can then use this information
52 to allocate a structure of the correct size (see EXAMPLES below). Some
53 care is needed here as EOVERFLOW can also indicate that no file handle
54 is available for this particular name in a filesystem which does nor‐
55 mally support file-handle lookup. This case can be detected when the
56 EOVERFLOW error is returned without handle_bytes being increased.
57
58 Other than the use of the handle_bytes field, the caller should treat
59 the file_handle structure as an opaque data type: the handle_type and
60 f_handle fields are needed only by a subsequent call to open_by_han‐
61 dle_at().
62
63 The flags argument is a bit mask constructed by ORing together zero or
64 more of AT_EMPTY_PATH and AT_SYMLINK_FOLLOW, described below.
65
66 Together, the pathname and dirfd arguments identify the file for which
67 a handle is to be obtained. There are four distinct cases:
68
69 * If pathname is a nonempty string containing an absolute pathname,
70 then a handle is returned for the file referred to by that pathname.
71 In this case, dirfd is ignored.
72
73 * If pathname is a nonempty string containing a relative pathname and
74 dirfd has the special value AT_FDCWD, then pathname is interpreted
75 relative to the current working directory of the caller, and a han‐
76 dle is returned for the file to which it refers.
77
78 * If pathname is a nonempty string containing a relative pathname and
79 dirfd is a file descriptor referring to a directory, then pathname
80 is interpreted relative to the directory referred to by dirfd, and a
81 handle is returned for the file to which it refers. (See openat(2)
82 for an explanation of why "directory file descriptors" are useful.)
83
84 * If pathname is an empty string and flags specifies the value
85 AT_EMPTY_PATH, then dirfd can be an open file descriptor referring
86 to any type of file, or AT_FDCWD, meaning the current working direc‐
87 tory, and a handle is returned for the file to which it refers.
88
89 The mount_id argument returns an identifier for the filesystem mount
90 that corresponds to pathname. This corresponds to the first field in
91 one of the records in /proc/self/mountinfo. Opening the pathname in
92 the fifth field of that record yields a file descriptor for the mount
93 point; that file descriptor can be used in a subsequent call to
94 open_by_handle_at(). mount_id is returned both for a successful call
95 and for a call that results in the error EOVERFLOW.
96
97 By default, name_to_handle_at() does not dereference pathname if it is
98 a symbolic link, and thus returns a handle for the link itself. If
99 AT_SYMLINK_FOLLOW is specified in flags, pathname is dereferenced if it
100 is a symbolic link (so that the call returns a handle for the file re‐
101 ferred to by the link).
102
103 name_to_handle_at() does not trigger a mount when the final component
104 of the pathname is an automount point. When a filesystem supports both
105 file handles and automount points, a name_to_handle_at() call on an au‐
106 tomount point will return with error EOVERFLOW without having increased
107 handle_bytes. This can happen since Linux 4.13 with NFS when accessing
108 a directory which is on a separate filesystem on the server. In this
109 case, the automount can be triggered by adding a "/" to the end of the
110 pathname.
111
112 open_by_handle_at()
113 The open_by_handle_at() system call opens the file referred to by han‐
114 dle, a file handle returned by a previous call to name_to_handle_at().
115
116 The mount_fd argument is a file descriptor for any object (file, direc‐
117 tory, etc.) in the mounted filesystem with respect to which handle
118 should be interpreted. The special value AT_FDCWD can be specified,
119 meaning the current working directory of the caller.
120
121 The flags argument is as for open(2). If handle refers to a symbolic
122 link, the caller must specify the O_PATH flag, and the symbolic link is
123 not dereferenced; the O_NOFOLLOW flag, if specified, is ignored.
124
125 The caller must have the CAP_DAC_READ_SEARCH capability to invoke
126 open_by_handle_at().
127
129 On success, name_to_handle_at() returns 0, and open_by_handle_at() re‐
130 turns a file descriptor (a nonnegative integer).
131
132 In the event of an error, both system calls return -1 and set errno to
133 indicate the error.
134
136 name_to_handle_at() and open_by_handle_at() can fail for the same er‐
137 rors as openat(2). In addition, they can fail with the errors noted
138 below.
139
140 name_to_handle_at() can fail with the following errors:
141
142 EFAULT pathname, mount_id, or handle points outside your accessible ad‐
143 dress space.
144
145 EINVAL flags includes an invalid bit value.
146
147 EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ.
148
149 ENOENT pathname is an empty string, but AT_EMPTY_PATH was not specified
150 in flags.
151
152 ENOTDIR
153 The file descriptor supplied in dirfd does not refer to a direc‐
154 tory, and it is not the case that both flags includes
155 AT_EMPTY_PATH and pathname is an empty string.
156
157 EOPNOTSUPP
158 The filesystem does not support decoding of a pathname to a file
159 handle.
160
161 EOVERFLOW
162 The handle->handle_bytes value passed into the call was too
163 small. When this error occurs, handle->handle_bytes is updated
164 to indicate the required size for the handle.
165
166 open_by_handle_at() can fail with the following errors:
167
168 EBADF mount_fd is not an open file descriptor.
169
170 EBADF pathname is relative but dirfd is neither AT_FDCWD nor a valid
171 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
187 These system calls first appeared in Linux 2.6.39. Library support is
188 provided in glibc since version 2.14.
189
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
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 ar‐
220 gument 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 ob‐
233 taining the UUID is to use the libblkid(3) library.) That process can
234 then be reversed, using the UUID to look up the device name, and then
235 obtaining the corresponding mount point, in order to produce the
236 mount_fd argument used by open_by_handle_at().
237
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;
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(*fhp) + 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("%u %d ", fhp->handle_bytes, fhp->handle_type);
345 for (int 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;
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(*fhp) + 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 (int 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
492 open(2), libblkid(3), blkid(8), findfs(8), mount(8)
493
494 The libblkid and libmount documentation in the latest util-linux re‐
495 lease at ⟨https://www.kernel.org/pub/linux/utils/util-linux/⟩
496
498 This page is part of release 5.13 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 2021-08-27 OPEN_BY_HANDLE_AT(2)