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 EFAULT handle points outside your accessible address space.
171
172 EINVAL handle->handle_bytes is greater than MAX_HANDLE_SZ or is equal
173 to zero.
174
175 ELOOP handle refers to a symbolic link, but O_PATH was not specified
176 in flags.
177
178 EPERM The caller does not have the CAP_DAC_READ_SEARCH capability.
179
180 ESTALE The specified handle is not valid. This error will occur if,
181 for example, the file has been deleted.
182
184 These system calls first appeared in Linux 2.6.39. Library support is
185 provided in glibc since version 2.14.
186
188 These system calls are nonstandard Linux extensions.
189
190 FreeBSD has a broadly similar pair of system calls in the form of
191 getfh() and openfh().
192
194 A file handle can be generated in one process using name_to_handle_at()
195 and later used in a different process that calls open_by_handle_at().
196
197 Some filesystem don't support the translation of pathnames to file han‐
198 dles, for example, /proc, /sys, and various network filesystems.
199
200 A file handle may become invalid ("stale") if a file is deleted, or for
201 other filesystem-specific reasons. Invalid handles are notified by an
202 ESTALE error from open_by_handle_at().
203
204 These system calls are designed for use by user-space file servers.
205 For example, a user-space NFS server might generate a file handle and
206 pass it to an NFS client. Later, when the client wants to open the
207 file, it could pass the handle back to the server. This sort of func‐
208 tionality allows a user-space file server to operate in a stateless
209 fashion with respect to the files it serves.
210
211 If pathname refers to a symbolic link and flags does not specify
212 AT_SYMLINK_FOLLOW, then name_to_handle_at() returns a handle for the
213 link (rather than the file to which it refers). The process receiving
214 the handle can later perform operations on the symbolic link by con‐
215 verting the handle to a file descriptor using open_by_handle_at() with
216 the O_PATH flag, and then passing the file descriptor as the dirfd ar‐
217 gument in system calls such as readlinkat(2) and fchownat(2).
218
219 Obtaining a persistent filesystem ID
220 The mount IDs in /proc/self/mountinfo can be reused as filesystems are
221 unmounted and mounted. Therefore, the mount ID returned by
222 name_to_handle_at() (in *mount_id) should not be treated as a persis‐
223 tent identifier for the corresponding mounted filesystem. However, an
224 application can use the information in the mountinfo record that corre‐
225 sponds to the mount ID to derive a persistent identifier.
226
227 For example, one can use the device name in the fifth field of the
228 mountinfo record to search for the corresponding device UUID via the
229 symbolic links in /dev/disks/by-uuid. (A more comfortable way of ob‐
230 taining the UUID is to use the libblkid(3) library.) That process can
231 then be reversed, using the UUID to look up the device name, and then
232 obtaining the corresponding mount point, in order to produce the
233 mount_fd argument used by open_by_handle_at().
234
236 The two programs below demonstrate the use of name_to_handle_at() and
237 open_by_handle_at(). The first program (t_name_to_handle_at.c) uses
238 name_to_handle_at() to obtain the file handle and mount ID for the file
239 specified in its command-line argument; the handle and mount ID are
240 written to standard output.
241
242 The second program (t_open_by_handle_at.c) reads a mount ID and file
243 handle from standard input. The program then employs open_by_han‐
244 dle_at() to open the file using that handle. If an optional command-
245 line argument is supplied, then the mount_fd argument for open_by_han‐
246 dle_at() is obtained by opening the directory named in that argument.
247 Otherwise, mount_fd is obtained by scanning /proc/self/mountinfo to
248 find a record whose mount ID matches the mount ID read from standard
249 input, and the mount directory specified in that record is opened.
250 (These programs do not deal with the fact that mount IDs are not per‐
251 sistent.)
252
253 The following shell session demonstrates the use of these two programs:
254
255 $ echo 'Can you please think about it?' > cecilia.txt
256 $ ./t_name_to_handle_at cecilia.txt > fh
257 $ ./t_open_by_handle_at < fh
258 open_by_handle_at: Operation not permitted
259 $ sudo ./t_open_by_handle_at < fh # Need CAP_SYS_ADMIN
260 Read 31 bytes
261 $ rm cecilia.txt
262
263 Now we delete and (quickly) re-create the file so that it has the same
264 content and (by chance) the same inode. Nevertheless, open_by_han‐
265 dle_at() recognizes that the original file referred to by the file han‐
266 dle no longer exists.
267
268 $ stat --printf="%i\n" cecilia.txt # Display inode number
269 4072121
270 $ rm cecilia.txt
271 $ echo 'Can you please think about it?' > cecilia.txt
272 $ stat --printf="%i\n" cecilia.txt # Check inode number
273 4072121
274 $ sudo ./t_open_by_handle_at < fh
275 open_by_handle_at: Stale NFS file handle
276
277 Program source: t_name_to_handle_at.c
278
279 #define _GNU_SOURCE
280 #include <sys/types.h>
281 #include <sys/stat.h>
282 #include <fcntl.h>
283 #include <stdio.h>
284 #include <stdlib.h>
285 #include <unistd.h>
286 #include <errno.h>
287 #include <string.h>
288
289 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
290 } while (0)
291
292 int
293 main(int argc, char *argv[])
294 {
295 struct file_handle *fhp;
296 int mount_id, fhsize, flags, dirfd;
297 char *pathname;
298
299 if (argc != 2) {
300 fprintf(stderr, "Usage: %s pathname\n", argv[0]);
301 exit(EXIT_FAILURE);
302 }
303
304 pathname = argv[1];
305
306 /* Allocate file_handle structure. */
307
308 fhsize = sizeof(*fhp);
309 fhp = malloc(fhsize);
310 if (fhp == NULL)
311 errExit("malloc");
312
313 /* Make an initial call to name_to_handle_at() to discover
314 the size required for file handle. */
315
316 dirfd = AT_FDCWD; /* For name_to_handle_at() calls */
317 flags = 0; /* For name_to_handle_at() calls */
318 fhp->handle_bytes = 0;
319 if (name_to_handle_at(dirfd, pathname, fhp,
320 &mount_id, flags) != -1 || errno != EOVERFLOW) {
321 fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
322 exit(EXIT_FAILURE);
323 }
324
325 /* Reallocate file_handle structure with correct size. */
326
327 fhsize = sizeof(*fhp) + fhp->handle_bytes;
328 fhp = realloc(fhp, fhsize); /* Copies fhp->handle_bytes */
329 if (fhp == NULL)
330 errExit("realloc");
331
332 /* Get file handle from pathname supplied on command line. */
333
334 if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
335 errExit("name_to_handle_at");
336
337 /* Write mount ID, file handle size, and file handle to stdout,
338 for later reuse by t_open_by_handle_at.c. */
339
340 printf("%d\n", mount_id);
341 printf("%u %d ", fhp->handle_bytes, fhp->handle_type);
342 for (int j = 0; j < fhp->handle_bytes; j++)
343 printf(" %02x", fhp->f_handle[j]);
344 printf("\n");
345
346 exit(EXIT_SUCCESS);
347 }
348
349 Program source: t_open_by_handle_at.c
350
351 #define _GNU_SOURCE
352 #include <sys/types.h>
353 #include <sys/stat.h>
354 #include <fcntl.h>
355 #include <limits.h>
356 #include <stdio.h>
357 #include <stdlib.h>
358 #include <unistd.h>
359 #include <string.h>
360
361 #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
362 } while (0)
363
364 /* Scan /proc/self/mountinfo to find the line whose mount ID matches
365 'mount_id'. (An easier way to do this is to install and use the
366 'libmount' library provided by the 'util-linux' project.)
367 Open the corresponding mount path and return the resulting file
368 descriptor. */
369
370 static int
371 open_mount_path_by_id(int mount_id)
372 {
373 char *linep;
374 size_t lsize;
375 char mount_path[PATH_MAX];
376 int mi_mount_id, found;
377 ssize_t nread;
378 FILE *fp;
379
380 fp = fopen("/proc/self/mountinfo", "r");
381 if (fp == NULL)
382 errExit("fopen");
383
384 found = 0;
385 linep = NULL;
386 while (!found) {
387 nread = getline(&linep, &lsize, fp);
388 if (nread == -1)
389 break;
390
391 nread = sscanf(linep, "%d %*d %*s %*s %s",
392 &mi_mount_id, mount_path);
393 if (nread != 2) {
394 fprintf(stderr, "Bad sscanf()\n");
395 exit(EXIT_FAILURE);
396 }
397
398 if (mi_mount_id == mount_id)
399 found = 1;
400 }
401 free(linep);
402
403 fclose(fp);
404
405 if (!found) {
406 fprintf(stderr, "Could not find mount point\n");
407 exit(EXIT_FAILURE);
408 }
409
410 return open(mount_path, O_RDONLY);
411 }
412
413 int
414 main(int argc, char *argv[])
415 {
416 struct file_handle *fhp;
417 int mount_id, fd, mount_fd, handle_bytes;
418 ssize_t nread;
419 char buf[1000];
420 #define LINE_SIZE 100
421 char line1[LINE_SIZE], line2[LINE_SIZE];
422 char *nextp;
423
424 if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
425 fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
426 exit(EXIT_FAILURE);
427 }
428
429 /* Standard input contains mount ID and file handle information:
430
431 Line 1: <mount_id>
432 Line 2: <handle_bytes> <handle_type> <bytes of handle in hex>
433 */
434
435 if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
436 (fgets(line2, sizeof(line2), stdin) == NULL)) {
437 fprintf(stderr, "Missing mount_id / file handle\n");
438 exit(EXIT_FAILURE);
439 }
440
441 mount_id = atoi(line1);
442
443 handle_bytes = strtoul(line2, &nextp, 0);
444
445 /* Given handle_bytes, we can now allocate file_handle structure. */
446
447 fhp = malloc(sizeof(*fhp) + handle_bytes);
448 if (fhp == NULL)
449 errExit("malloc");
450
451 fhp->handle_bytes = handle_bytes;
452
453 fhp->handle_type = strtoul(nextp, &nextp, 0);
454
455 for (int j = 0; j < fhp->handle_bytes; j++)
456 fhp->f_handle[j] = strtoul(nextp, &nextp, 16);
457
458 /* Obtain file descriptor for mount point, either by opening
459 the pathname specified on the command line, or by scanning
460 /proc/self/mounts to find a mount that matches the 'mount_id'
461 that we received from stdin. */
462
463 if (argc > 1)
464 mount_fd = open(argv[1], O_RDONLY);
465 else
466 mount_fd = open_mount_path_by_id(mount_id);
467
468 if (mount_fd == -1)
469 errExit("opening mount fd");
470
471 /* Open file using handle and mount point. */
472
473 fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
474 if (fd == -1)
475 errExit("open_by_handle_at");
476
477 /* Try reading a few bytes from the file. */
478
479 nread = read(fd, buf, sizeof(buf));
480 if (nread == -1)
481 errExit("read");
482
483 printf("Read %zd bytes\n", nread);
484
485 exit(EXIT_SUCCESS);
486 }
487
489 open(2), libblkid(3), blkid(8), findfs(8), mount(8)
490
491 The libblkid and libmount documentation in the latest util-linux re‐
492 lease at ⟨https://www.kernel.org/pub/linux/utils/util-linux/⟩
493
495 This page is part of release 5.12 of the Linux man-pages project. A
496 description of the project, information about reporting bugs, and the
497 latest version of this page, can be found at
498 https://www.kernel.org/doc/man-pages/.
499
500
501
502Linux 2021-03-22 OPEN_BY_HANDLE_AT(2)