Blame man2/open_by_handle_at.2

Packit 7cfc04
.\" Copyright (c) 2014 by Michael Kerrisk <mtk.manpages@gmail.com>
Packit 7cfc04
.\"
Packit 7cfc04
.\" %%%LICENSE_START(VERBATIM)
Packit 7cfc04
.\" Permission is granted to make and distribute verbatim copies of this
Packit 7cfc04
.\" manual provided the copyright notice and this permission notice are
Packit 7cfc04
.\" preserved on all copies.
Packit 7cfc04
.\"
Packit 7cfc04
.\" Permission is granted to copy and distribute modified versions of this
Packit 7cfc04
.\" manual under the conditions for verbatim copying, provided that the
Packit 7cfc04
.\" entire resulting derived work is distributed under the terms of a
Packit 7cfc04
.\" permission notice identical to this one.
Packit 7cfc04
.\"
Packit 7cfc04
.\" Since the Linux kernel and libraries are constantly changing, this
Packit 7cfc04
.\" manual page may be incorrect or out-of-date.  The author(s) assume no
Packit 7cfc04
.\" responsibility for errors or omissions, or for damages resulting from
Packit 7cfc04
.\" the use of the information contained herein.  The author(s) may not
Packit 7cfc04
.\" have taken the same level of care in the production of this manual,
Packit 7cfc04
.\" which is licensed free of charge, as they might when working
Packit 7cfc04
.\" professionally.
Packit 7cfc04
.\"
Packit 7cfc04
.\" Formatted or processed versions of this manual, if unaccompanied by
Packit 7cfc04
.\" the source, must acknowledge the copyright and authors of this work.
Packit 7cfc04
.\" %%%LICENSE_END
Packit 7cfc04
.\"
Packit 7cfc04
.TH OPEN_BY_HANDLE_AT 2 2017-09-15 "Linux" "Linux Programmer's Manual"
Packit 7cfc04
.SH NAME
Packit 7cfc04
name_to_handle_at, open_by_handle_at \- obtain handle
Packit 7cfc04
for a pathname and open file via a handle
Packit 7cfc04
.SH SYNOPSIS
Packit 7cfc04
.nf
Packit 7cfc04
.BR "#define _GNU_SOURCE" "         /* See feature_test_macros(7) */"
Packit 7cfc04
.B #include <sys/types.h>
Packit 7cfc04
.B #include <sys/stat.h>
Packit 7cfc04
.B #include <fcntl.h>
Packit 7cfc04
.PP
Packit 7cfc04
.BI "int name_to_handle_at(int " dirfd ", const char *" pathname ,
Packit 7cfc04
.BI "                      struct file_handle *" handle ,
Packit 7cfc04
.BI "                      int *" mount_id ", int " flags );
Packit 7cfc04
.PP
Packit 7cfc04
.BI "int open_by_handle_at(int " mount_fd ", struct file_handle *" handle ,
Packit 7cfc04
.BI "                      int " flags );
Packit 7cfc04
.fi
Packit 7cfc04
.SH DESCRIPTION
Packit 7cfc04
The
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
and
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
system calls split the functionality of
Packit 7cfc04
.BR openat (2)
Packit 7cfc04
into two parts:
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
returns an opaque handle that corresponds to a specified file;
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
opens the file corresponding to a handle returned by a previous call to
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
and returns an open file descriptor.
Packit 7cfc04
.\"
Packit 7cfc04
.\"
Packit 7cfc04
.SS name_to_handle_at()
Packit 7cfc04
The
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
system call returns a file handle and a mount ID corresponding to
Packit 7cfc04
the file specified by the
Packit 7cfc04
.IR dirfd
Packit 7cfc04
and
Packit 7cfc04
.IR pathname
Packit 7cfc04
arguments.
Packit 7cfc04
The file handle is returned via the argument
Packit 7cfc04
.IR handle ,
Packit 7cfc04
which is a pointer to a structure of the following form:
Packit 7cfc04
.PP
Packit 7cfc04
.in +4n
Packit 7cfc04
.EX
Packit 7cfc04
struct file_handle {
Packit 7cfc04
    unsigned int  handle_bytes;   /* Size of f_handle [in, out] */
Packit 7cfc04
    int           handle_type;    /* Handle type [out] */
Packit 7cfc04
    unsigned char f_handle[0];    /* File identifier (sized by
Packit 7cfc04
                                     caller) [out] */
Packit 7cfc04
};
Packit 7cfc04
.EE
Packit 7cfc04
.in
Packit 7cfc04
.PP
Packit 7cfc04
It is the caller's responsibility to allocate the structure
Packit 7cfc04
with a size large enough to hold the handle returned in
Packit 7cfc04
.IR f_handle .
Packit 7cfc04
Before the call, the
Packit 7cfc04
.IR handle_bytes
Packit 7cfc04
field should be initialized to contain the allocated size for
Packit 7cfc04
.IR f_handle .
Packit 7cfc04
(The constant
Packit 7cfc04
.BR MAX_HANDLE_SZ ,
Packit 7cfc04
defined in
Packit 7cfc04
.IR <fcntl.h> ,
Packit 7cfc04
specifies the maximum expected size for a file handle.
Packit 7cfc04
It is not a
Packit 7cfc04
guaranteed upper limit as future filesystems may require more space.)
Packit 7cfc04
Upon successful return, the
Packit 7cfc04
.IR handle_bytes
Packit 7cfc04
field is updated to contain the number of bytes actually written to
Packit 7cfc04
.IR f_handle .
Packit 7cfc04
.PP
Packit 7cfc04
The caller can discover the required size for the
Packit 7cfc04
.I file_handle
Packit 7cfc04
structure by making a call in which
Packit 7cfc04
.IR handle->handle_bytes
Packit 7cfc04
is zero;
Packit 7cfc04
in this case, the call fails with the error
Packit 7cfc04
.BR EOVERFLOW
Packit 7cfc04
and
Packit 7cfc04
.IR handle->handle_bytes
Packit 7cfc04
is set to indicate the required size;
Packit 7cfc04
the caller can then use this information to allocate a structure
Packit 7cfc04
of the correct size (see EXAMPLE below).
Packit 7cfc04
Some care is needed here as
Packit 7cfc04
.BR EOVERFLOW
Packit 7cfc04
can also indicate that no file handle is available for this particular
Packit 7cfc04
name in a filesystem which does normally support file-handle lookup.
Packit 7cfc04
This case can be detected when the
Packit 7cfc04
.B EOVERFLOW
Packit 7cfc04
error is returned without
Packit 7cfc04
.I handle_bytes
Packit 7cfc04
being increased.
Packit 7cfc04
.PP
Packit 7cfc04
Other than the use of the
Packit 7cfc04
.IR handle_bytes
Packit 7cfc04
field, the caller should treat the
Packit 7cfc04
.IR file_handle
Packit 7cfc04
structure as an opaque data type: the
Packit 7cfc04
.IR handle_type
Packit 7cfc04
and
Packit 7cfc04
.IR f_handle
Packit 7cfc04
fields are needed only by a subsequent call to
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.PP
Packit 7cfc04
The
Packit 7cfc04
.I flags
Packit 7cfc04
argument is a bit mask constructed by ORing together zero or more of
Packit 7cfc04
.BR AT_EMPTY_PATH
Packit 7cfc04
and
Packit 7cfc04
.BR AT_SYMLINK_FOLLOW ,
Packit 7cfc04
described below.
Packit 7cfc04
.PP
Packit 7cfc04
Together, the
Packit 7cfc04
.I pathname
Packit 7cfc04
and
Packit 7cfc04
.I dirfd
Packit 7cfc04
arguments identify the file for which a handle is to be obtained.
Packit 7cfc04
There are four distinct cases:
Packit 7cfc04
.IP * 3
Packit 7cfc04
If
Packit 7cfc04
.I pathname
Packit 7cfc04
is a nonempty string containing an absolute pathname,
Packit 7cfc04
then a handle is returned for the file referred to by that pathname.
Packit 7cfc04
In this case,
Packit 7cfc04
.IR dirfd
Packit 7cfc04
is ignored.
Packit 7cfc04
.IP *
Packit 7cfc04
If
Packit 7cfc04
.I pathname
Packit 7cfc04
is a nonempty string containing a relative pathname and
Packit 7cfc04
.IR dirfd
Packit 7cfc04
has the special value
Packit 7cfc04
.BR AT_FDCWD ,
Packit 7cfc04
then
Packit 7cfc04
.I pathname
Packit 7cfc04
is interpreted relative to the current working directory of the caller,
Packit 7cfc04
and a handle is returned for the file to which it refers.
Packit 7cfc04
.IP *
Packit 7cfc04
If
Packit 7cfc04
.I pathname
Packit 7cfc04
is a nonempty string containing a relative pathname and
Packit 7cfc04
.IR dirfd
Packit 7cfc04
is a file descriptor referring to a directory, then
Packit 7cfc04
.I pathname
Packit 7cfc04
is interpreted relative to the directory referred to by
Packit 7cfc04
.IR dirfd ,
Packit 7cfc04
and a handle is returned for the file to which it refers.
Packit 7cfc04
(See
Packit 7cfc04
.BR openat (2)
Packit 7cfc04
for an explanation of why "directory file descriptors" are useful.)
Packit 7cfc04
.IP *
Packit 7cfc04
If
Packit 7cfc04
.I pathname
Packit 7cfc04
is an empty string and
Packit 7cfc04
.I flags
Packit 7cfc04
specifies the value
Packit 7cfc04
.BR AT_EMPTY_PATH ,
Packit 7cfc04
then
Packit 7cfc04
.IR dirfd
Packit 7cfc04
can be an open file descriptor referring to any type of file,
Packit 7cfc04
or
Packit 7cfc04
.BR AT_FDCWD ,
Packit 7cfc04
meaning the current working directory,
Packit 7cfc04
and a handle is returned for the file to which it refers.
Packit 7cfc04
.PP
Packit 7cfc04
The
Packit 7cfc04
.I mount_id
Packit 7cfc04
argument returns an identifier for the filesystem
Packit 7cfc04
mount that corresponds to
Packit 7cfc04
.IR pathname .
Packit 7cfc04
This corresponds to the first field in one of the records in
Packit 7cfc04
.IR /proc/self/mountinfo .
Packit 7cfc04
Opening the pathname in the fifth field of that record yields a file
Packit 7cfc04
descriptor for the mount point;
Packit 7cfc04
that file descriptor can be used in a subsequent call to
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.I mount_id
Packit 7cfc04
is returned both for a successful call and for a call that results
Packit 7cfc04
in the error
Packit 7cfc04
.BR EOVERFLOW .
Packit 7cfc04
.PP
Packit 7cfc04
By default,
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
does not dereference
Packit 7cfc04
.I pathname
Packit 7cfc04
if it is a symbolic link, and thus returns a handle for the link itself.
Packit 7cfc04
If
Packit 7cfc04
.B AT_SYMLINK_FOLLOW
Packit 7cfc04
is specified in
Packit 7cfc04
.IR flags ,
Packit 7cfc04
.I pathname
Packit 7cfc04
is dereferenced if it is a symbolic link
Packit 7cfc04
(so that the call returns a handle for the file referred to by the link).
Packit 7cfc04
.PP
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
does not trigger a mount when the final component of the path is an
Packit 7cfc04
automount point.
Packit 7cfc04
When a filesystem supports both file handles and
Packit 7cfc04
automount points, a
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
call on an automount point will return with error
Packit 7cfc04
.BR EOVERFLOW
Packit 7cfc04
without having increased
Packit 7cfc04
.IR handle_bytes .
Packit 7cfc04
This can happen since Linux 4.13
Packit 7cfc04
.\" commit 20fa19027286983ab2734b5910c4a687436e0c31
Packit 7cfc04
with NFS when accessing a directory
Packit 7cfc04
which is on a separate filesystem on the server.
Packit 7cfc04
In this case, the automount can be triggered by adding a "/" to the end
Packit 7cfc04
of the path.
Packit 7cfc04
.SS open_by_handle_at()
Packit 7cfc04
The
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
system call opens the file referred to by
Packit 7cfc04
.IR handle ,
Packit 7cfc04
a file handle returned by a previous call to
Packit 7cfc04
.BR name_to_handle_at ().
Packit 7cfc04
.PP
Packit 7cfc04
The
Packit 7cfc04
.IR mount_fd
Packit 7cfc04
argument is a file descriptor for any object (file, directory, etc.)
Packit 7cfc04
in the mounted filesystem with respect to which
Packit 7cfc04
.IR handle
Packit 7cfc04
should be interpreted.
Packit 7cfc04
The special value
Packit 7cfc04
.B AT_FDCWD
Packit 7cfc04
can be specified, meaning the current working directory of the caller.
Packit 7cfc04
.PP
Packit 7cfc04
The
Packit 7cfc04
.I flags
Packit 7cfc04
argument
Packit 7cfc04
is as for
Packit 7cfc04
.BR open (2).
Packit 7cfc04
If
Packit 7cfc04
.I handle
Packit 7cfc04
refers to a symbolic link, the caller must specify the
Packit 7cfc04
.B O_PATH
Packit 7cfc04
flag, and the symbolic link is not dereferenced; the
Packit 7cfc04
.B O_NOFOLLOW
Packit 7cfc04
flag, if specified, is ignored.
Packit 7cfc04
.PP
Packit 7cfc04
The caller must have the
Packit 7cfc04
.B CAP_DAC_READ_SEARCH
Packit 7cfc04
capability to invoke
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.SH RETURN VALUE
Packit 7cfc04
On success,
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
returns 0,
Packit 7cfc04
and
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
returns a nonnegative file descriptor.
Packit 7cfc04
.PP
Packit 7cfc04
In the event of an error, both system calls return \-1 and set
Packit 7cfc04
.I errno
Packit 7cfc04
to indicate the cause of the error.
Packit 7cfc04
.SH ERRORS
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
and
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
can fail for the same errors as
Packit 7cfc04
.BR openat (2).
Packit 7cfc04
In addition, they can fail with the errors noted below.
Packit 7cfc04
.PP
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
can fail with the following errors:
Packit 7cfc04
.TP
Packit 7cfc04
.B EFAULT
Packit 7cfc04
.IR pathname ,
Packit 7cfc04
.IR mount_id ,
Packit 7cfc04
or
Packit 7cfc04
.IR handle
Packit 7cfc04
points outside your accessible address space.
Packit 7cfc04
.TP
Packit 7cfc04
.B EINVAL
Packit 7cfc04
.I flags
Packit 7cfc04
includes an invalid bit value.
Packit 7cfc04
.TP
Packit 7cfc04
.B EINVAL
Packit 7cfc04
.IR handle\->handle_bytes
Packit 7cfc04
is greater than
Packit 7cfc04
.BR MAX_HANDLE_SZ .
Packit 7cfc04
.TP
Packit 7cfc04
.B ENOENT
Packit 7cfc04
.I pathname
Packit 7cfc04
is an empty string, but
Packit 7cfc04
.BR AT_EMPTY_PATH
Packit 7cfc04
was not specified in
Packit 7cfc04
.IR flags .
Packit 7cfc04
.TP
Packit 7cfc04
.B ENOTDIR
Packit 7cfc04
The file descriptor supplied in
Packit 7cfc04
.I dirfd
Packit 7cfc04
does not refer to a directory,
Packit 7cfc04
and it is not the case that both
Packit 7cfc04
.I flags
Packit 7cfc04
includes
Packit 7cfc04
.BR AT_EMPTY_PATH
Packit 7cfc04
and
Packit 7cfc04
.I pathname
Packit 7cfc04
is an empty string.
Packit 7cfc04
.TP
Packit 7cfc04
.B EOPNOTSUPP
Packit 7cfc04
The filesystem does not support decoding of a pathname to a file handle.
Packit 7cfc04
.TP
Packit 7cfc04
.B EOVERFLOW
Packit 7cfc04
The
Packit 7cfc04
.I handle->handle_bytes
Packit 7cfc04
value passed into the call was too small.
Packit 7cfc04
When this error occurs,
Packit 7cfc04
.I handle->handle_bytes
Packit 7cfc04
is updated to indicate the required size for the handle.
Packit 7cfc04
.\"
Packit 7cfc04
.\"
Packit 7cfc04
.PP
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
can fail with the following errors:
Packit 7cfc04
.TP
Packit 7cfc04
.B EBADF
Packit 7cfc04
.IR mount_fd
Packit 7cfc04
is not an open file descriptor.
Packit 7cfc04
.TP
Packit 7cfc04
.B EFAULT
Packit 7cfc04
.IR handle
Packit 7cfc04
points outside your accessible address space.
Packit 7cfc04
.TP
Packit 7cfc04
.B EINVAL
Packit 7cfc04
.I handle->handle_bytes
Packit 7cfc04
is greater than
Packit 7cfc04
.BR MAX_HANDLE_SZ
Packit 7cfc04
or is equal to zero.
Packit 7cfc04
.TP
Packit 7cfc04
.B ELOOP
Packit 7cfc04
.I handle
Packit 7cfc04
refers to a symbolic link, but
Packit 7cfc04
.B O_PATH
Packit 7cfc04
was not specified in
Packit 7cfc04
.IR flags .
Packit 7cfc04
.TP
Packit 7cfc04
.B EPERM
Packit 7cfc04
The caller does not have the
Packit 7cfc04
.BR CAP_DAC_READ_SEARCH
Packit 7cfc04
capability.
Packit 7cfc04
.TP
Packit 7cfc04
.B ESTALE
Packit 7cfc04
The specified
Packit 7cfc04
.I handle
Packit 7cfc04
is not valid.
Packit 7cfc04
This error will occur if, for example, the file has been deleted.
Packit 7cfc04
.SH VERSIONS
Packit 7cfc04
These system calls first appeared in Linux 2.6.39.
Packit 7cfc04
Library support is provided in glibc since version 2.14.
Packit 7cfc04
.SH CONFORMING TO
Packit 7cfc04
These system calls are nonstandard Linux extensions.
Packit 7cfc04
.PP
Packit 7cfc04
FreeBSD has a broadly similar pair of system calls in the form of
Packit 7cfc04
.BR getfh ()
Packit 7cfc04
and
Packit 7cfc04
.BR openfh ().
Packit 7cfc04
.SH NOTES
Packit 7cfc04
A file handle can be generated in one process using
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
and later used in a different process that calls
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.PP
Packit 7cfc04
Some filesystem don't support the translation of pathnames to
Packit 7cfc04
file handles, for example,
Packit 7cfc04
.IR /proc ,
Packit 7cfc04
.IR /sys ,
Packit 7cfc04
and various network filesystems.
Packit 7cfc04
.PP
Packit 7cfc04
A file handle may become invalid ("stale") if a file is deleted,
Packit 7cfc04
or for other filesystem-specific reasons.
Packit 7cfc04
Invalid handles are notified by an
Packit 7cfc04
.B ESTALE
Packit 7cfc04
error from
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.PP
Packit 7cfc04
These system calls are designed for use by user-space file servers.
Packit 7cfc04
For example, a user-space NFS server might generate a file handle
Packit 7cfc04
and pass it to an NFS client.
Packit 7cfc04
Later, when the client wants to open the file,
Packit 7cfc04
it could pass the handle back to the server.
Packit 7cfc04
.\" https://lwn.net/Articles/375888/
Packit 7cfc04
.\"	"Open by handle" - Jonathan Corbet, 2010-02-23
Packit 7cfc04
This sort of functionality allows a user-space file server to operate in
Packit 7cfc04
a stateless fashion with respect to the files it serves.
Packit 7cfc04
.PP
Packit 7cfc04
If
Packit 7cfc04
.I pathname
Packit 7cfc04
refers to a symbolic link and
Packit 7cfc04
.IR flags
Packit 7cfc04
does not specify
Packit 7cfc04
.BR AT_SYMLINK_FOLLOW ,
Packit 7cfc04
then
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
returns a handle for the link (rather than the file to which it refers).
Packit 7cfc04
.\" commit bcda76524cd1fa32af748536f27f674a13e56700
Packit 7cfc04
The process receiving the handle can later perform operations
Packit 7cfc04
on the symbolic link by converting the handle to a file descriptor using
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
with the
Packit 7cfc04
.BR O_PATH
Packit 7cfc04
flag, and then passing the file descriptor as the
Packit 7cfc04
.IR dirfd
Packit 7cfc04
argument in system calls such as
Packit 7cfc04
.BR readlinkat (2)
Packit 7cfc04
and
Packit 7cfc04
.BR fchownat (2).
Packit 7cfc04
.SS Obtaining a persistent filesystem ID
Packit 7cfc04
The mount IDs in
Packit 7cfc04
.IR /proc/self/mountinfo
Packit 7cfc04
can be reused as filesystems are unmounted and mounted.
Packit 7cfc04
Therefore, the mount ID returned by
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
(in
Packit 7cfc04
.IR *mount_id )
Packit 7cfc04
should not be treated as a persistent identifier
Packit 7cfc04
for the corresponding mounted filesystem.
Packit 7cfc04
However, an application can use the information in the
Packit 7cfc04
.I mountinfo
Packit 7cfc04
record that corresponds to the mount ID
Packit 7cfc04
to derive a persistent identifier.
Packit 7cfc04
.PP
Packit 7cfc04
For example, one can use the device name in the fifth field of the
Packit 7cfc04
.I mountinfo
Packit 7cfc04
record to search for the corresponding device UUID via the symbolic links in
Packit 7cfc04
.IR /dev/disks/by-uuid .
Packit 7cfc04
(A more comfortable way of obtaining the UUID is to use the
Packit 7cfc04
.\" e.g., http://stackoverflow.com/questions/6748429/using-libblkid-to-find-uuid-of-a-partition
Packit 7cfc04
.BR libblkid (3)
Packit 7cfc04
library.)
Packit 7cfc04
That process can then be reversed,
Packit 7cfc04
using the UUID to look up the device name,
Packit 7cfc04
and then obtaining the corresponding mount point,
Packit 7cfc04
in order to produce the
Packit 7cfc04
.IR mount_fd
Packit 7cfc04
argument used by
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
.SH EXAMPLE
Packit 7cfc04
The two programs below demonstrate the use of
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
and
Packit 7cfc04
.BR open_by_handle_at ().
Packit 7cfc04
The first program
Packit 7cfc04
.RI ( t_name_to_handle_at.c )
Packit 7cfc04
uses
Packit 7cfc04
.BR name_to_handle_at ()
Packit 7cfc04
to obtain the file handle and mount ID
Packit 7cfc04
for the file specified in its command-line argument;
Packit 7cfc04
the handle and mount ID are written to standard output.
Packit 7cfc04
.PP
Packit 7cfc04
The second program
Packit 7cfc04
.RI ( t_open_by_handle_at.c )
Packit 7cfc04
reads a mount ID and file handle from standard input.
Packit 7cfc04
The program then employs
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
to open the file using that handle.
Packit 7cfc04
If an optional command-line argument is supplied, then the
Packit 7cfc04
.IR mount_fd
Packit 7cfc04
argument for
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
is obtained by opening the directory named in that argument.
Packit 7cfc04
Otherwise,
Packit 7cfc04
.IR mount_fd
Packit 7cfc04
is obtained by scanning
Packit 7cfc04
.IR /proc/self/mountinfo
Packit 7cfc04
to find a record whose mount ID matches the mount ID
Packit 7cfc04
read from standard input,
Packit 7cfc04
and the mount directory specified in that record is opened.
Packit 7cfc04
(These programs do not deal with the fact that mount IDs are not persistent.)
Packit 7cfc04
.PP
Packit 7cfc04
The following shell session demonstrates the use of these two programs:
Packit 7cfc04
.PP
Packit 7cfc04
.in +4n
Packit 7cfc04
.EX
Packit 7cfc04
$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
Packit 7cfc04
$ \fB./t_name_to_handle_at cecilia.txt > fh\fP
Packit 7cfc04
$ \fB./t_open_by_handle_at < fh\fP
Packit 7cfc04
open_by_handle_at: Operation not permitted
Packit 7cfc04
$ \fBsudo ./t_open_by_handle_at < fh\fP      # Need CAP_SYS_ADMIN
Packit 7cfc04
Read 31 bytes
Packit 7cfc04
$ \fBrm cecilia.txt\fP
Packit 7cfc04
.EE
Packit 7cfc04
.in
Packit 7cfc04
.PP
Packit 7cfc04
Now we delete and (quickly) re-create the file so that
Packit 7cfc04
it has the same content and (by chance) the same inode.
Packit 7cfc04
Nevertheless,
Packit 7cfc04
.BR open_by_handle_at ()
Packit 7cfc04
.\" Christoph Hellwig: That's why the file handles contain a generation
Packit 7cfc04
.\" counter that gets incremented in this case.
Packit 7cfc04
recognizes that the original file referred to by the file handle
Packit 7cfc04
no longer exists.
Packit 7cfc04
.PP
Packit 7cfc04
.in +4n
Packit 7cfc04
.EX
Packit 7cfc04
$ \fBstat \-\-printf="%i\\n" cecilia.txt\fP     # Display inode number
Packit 7cfc04
4072121
Packit 7cfc04
$ \fBrm cecilia.txt\fP
Packit 7cfc04
$ \fBecho 'Can you please think about it?' > cecilia.txt\fP
Packit 7cfc04
$ \fBstat \-\-printf="%i\\n" cecilia.txt\fP     # Check inode number
Packit 7cfc04
4072121
Packit 7cfc04
$ \fBsudo ./t_open_by_handle_at < fh\fP
Packit 7cfc04
open_by_handle_at: Stale NFS file handle
Packit 7cfc04
.EE
Packit 7cfc04
.in
Packit 7cfc04
.SS Program source: t_name_to_handle_at.c
Packit 7cfc04
\&
Packit 7cfc04
.EX
Packit 7cfc04
#define _GNU_SOURCE
Packit 7cfc04
#include <sys/types.h>
Packit 7cfc04
#include <sys/stat.h>
Packit 7cfc04
#include <fcntl.h>
Packit 7cfc04
#include <stdio.h>
Packit 7cfc04
#include <stdlib.h>
Packit 7cfc04
#include <unistd.h>
Packit 7cfc04
#include <errno.h>
Packit 7cfc04
#include <string.h>
Packit 7cfc04
Packit 7cfc04
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \\
Packit 7cfc04
                        } while (0)
Packit 7cfc04
Packit 7cfc04
int
Packit 7cfc04
main(int argc, char *argv[])
Packit 7cfc04
{
Packit 7cfc04
    struct file_handle *fhp;
Packit 7cfc04
    int mount_id, fhsize, flags, dirfd, j;
Packit 7cfc04
    char *pathname;
Packit 7cfc04
Packit 7cfc04
    if (argc != 2) {
Packit 7cfc04
        fprintf(stderr, "Usage: %s pathname\\n", argv[0]);
Packit 7cfc04
        exit(EXIT_FAILURE);
Packit 7cfc04
    }
Packit 7cfc04
Packit 7cfc04
    pathname = argv[1];
Packit 7cfc04
Packit 7cfc04
    /* Allocate file_handle structure */
Packit 7cfc04
Packit 7cfc04
    fhsize = sizeof(*fhp);
Packit 7cfc04
    fhp = malloc(fhsize);
Packit 7cfc04
    if (fhp == NULL)
Packit 7cfc04
        errExit("malloc");
Packit 7cfc04
Packit 7cfc04
    /* Make an initial call to name_to_handle_at() to discover
Packit 7cfc04
       the size required for file handle */
Packit 7cfc04
Packit 7cfc04
    dirfd = AT_FDCWD;           /* For name_to_handle_at() calls */
Packit 7cfc04
    flags = 0;                  /* For name_to_handle_at() calls */
Packit 7cfc04
    fhp\->handle_bytes = 0;
Packit 7cfc04
    if (name_to_handle_at(dirfd, pathname, fhp,
Packit 7cfc04
                &mount_id, flags) != \-1 || errno != EOVERFLOW) {
Packit 7cfc04
        fprintf(stderr, "Unexpected result from name_to_handle_at()\\n");
Packit 7cfc04
        exit(EXIT_FAILURE);
Packit 7cfc04
    }
Packit 7cfc04
Packit 7cfc04
    /* Reallocate file_handle structure with correct size */
Packit 7cfc04
Packit 7cfc04
    fhsize = sizeof(struct file_handle) + fhp\->handle_bytes;
Packit 7cfc04
    fhp = realloc(fhp, fhsize);         /* Copies fhp\->handle_bytes */
Packit 7cfc04
    if (fhp == NULL)
Packit 7cfc04
        errExit("realloc");
Packit 7cfc04
Packit 7cfc04
    /* Get file handle from pathname supplied on command line */
Packit 7cfc04
Packit 7cfc04
    if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == \-1)
Packit 7cfc04
        errExit("name_to_handle_at");
Packit 7cfc04
Packit 7cfc04
    /* Write mount ID, file handle size, and file handle to stdout,
Packit 7cfc04
       for later reuse by t_open_by_handle_at.c */
Packit 7cfc04
Packit 7cfc04
    printf("%d\\n", mount_id);
Packit 7cfc04
    printf("%d %d   ", fhp\->handle_bytes, fhp\->handle_type);
Packit 7cfc04
    for (j = 0; j < fhp\->handle_bytes; j++)
Packit 7cfc04
        printf(" %02x", fhp\->f_handle[j]);
Packit 7cfc04
    printf("\\n");
Packit 7cfc04
Packit 7cfc04
    exit(EXIT_SUCCESS);
Packit 7cfc04
}
Packit 7cfc04
.EE
Packit 7cfc04
.SS Program source: t_open_by_handle_at.c
Packit 7cfc04
\&
Packit 7cfc04
.EX
Packit 7cfc04
#define _GNU_SOURCE
Packit 7cfc04
#include <sys/types.h>
Packit 7cfc04
#include <sys/stat.h>
Packit 7cfc04
#include <fcntl.h>
Packit 7cfc04
#include <limits.h>
Packit 7cfc04
#include <stdio.h>
Packit 7cfc04
#include <stdlib.h>
Packit 7cfc04
#include <unistd.h>
Packit 7cfc04
#include <string.h>
Packit 7cfc04
Packit 7cfc04
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \\
Packit 7cfc04
                        } while (0)
Packit 7cfc04
Packit 7cfc04
/* Scan /proc/self/mountinfo to find the line whose mount ID matches
Packit 7cfc04
   \(aqmount_id\(aq. (An easier way to do this is to install and use the
Packit 7cfc04
   \(aqlibmount\(aq library provided by the \(aqutil\-linux\(aq project.)
Packit 7cfc04
   Open the corresponding mount path and return the resulting file
Packit 7cfc04
   descriptor. */
Packit 7cfc04
Packit 7cfc04
static int
Packit 7cfc04
open_mount_path_by_id(int mount_id)
Packit 7cfc04
{
Packit 7cfc04
    char *linep;
Packit 7cfc04
    size_t lsize;
Packit 7cfc04
    char mount_path[PATH_MAX];
Packit 7cfc04
    int mi_mount_id, found;
Packit 7cfc04
    ssize_t nread;
Packit 7cfc04
    FILE *fp;
Packit 7cfc04
Packit 7cfc04
    fp = fopen("/proc/self/mountinfo", "r");
Packit 7cfc04
    if (fp == NULL)
Packit 7cfc04
        errExit("fopen");
Packit 7cfc04
Packit 7cfc04
    found = 0;
Packit 7cfc04
    linep = NULL;
Packit 7cfc04
    while (!found) {
Packit 7cfc04
        nread = getline(&linep, &lsize, fp);
Packit 7cfc04
        if (nread == \-1)
Packit 7cfc04
            break;
Packit 7cfc04
Packit 7cfc04
        nread = sscanf(linep, "%d %*d %*s %*s %s",
Packit 7cfc04
                       &mi_mount_id, mount_path);
Packit 7cfc04
        if (nread != 2) {
Packit 7cfc04
            fprintf(stderr, "Bad sscanf()\\n");
Packit 7cfc04
            exit(EXIT_FAILURE);
Packit 7cfc04
        }
Packit 7cfc04
Packit 7cfc04
        if (mi_mount_id == mount_id)
Packit 7cfc04
            found = 1;
Packit 7cfc04
    }
Packit 7cfc04
    free(linep);
Packit 7cfc04
Packit 7cfc04
    fclose(fp);
Packit 7cfc04
Packit 7cfc04
    if (!found) {
Packit 7cfc04
        fprintf(stderr, "Could not find mount point\\n");
Packit 7cfc04
        exit(EXIT_FAILURE);
Packit 7cfc04
    }
Packit 7cfc04
Packit 7cfc04
    return open(mount_path, O_RDONLY);
Packit 7cfc04
}
Packit 7cfc04
Packit 7cfc04
int
Packit 7cfc04
main(int argc, char *argv[])
Packit 7cfc04
{
Packit 7cfc04
    struct file_handle *fhp;
Packit 7cfc04
    int mount_id, fd, mount_fd, handle_bytes, j;
Packit 7cfc04
    ssize_t nread;
Packit 7cfc04
    char buf[1000];
Packit 7cfc04
#define LINE_SIZE 100
Packit 7cfc04
    char line1[LINE_SIZE], line2[LINE_SIZE];
Packit 7cfc04
    char *nextp;
Packit 7cfc04
Packit 7cfc04
    if ((argc > 1 && strcmp(argv[1], "\-\-help") == 0) || argc > 2) {
Packit 7cfc04
        fprintf(stderr, "Usage: %s [mount\-path]\\n", argv[0]);
Packit 7cfc04
        exit(EXIT_FAILURE);
Packit 7cfc04
    }
Packit 7cfc04
Packit 7cfc04
    /* Standard input contains mount ID and file handle information:
Packit 7cfc04
Packit 7cfc04
         Line 1: <mount_id>
Packit 7cfc04
         Line 2: <handle_bytes> <handle_type>   <bytes of handle in hex>
Packit 7cfc04
    */
Packit 7cfc04
Packit 7cfc04
    if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
Packit 7cfc04
           (fgets(line2, sizeof(line2), stdin) == NULL)) {
Packit 7cfc04
        fprintf(stderr, "Missing mount_id / file handle\\n");
Packit 7cfc04
        exit(EXIT_FAILURE);
Packit 7cfc04
    }
Packit 7cfc04
Packit 7cfc04
    mount_id = atoi(line1);
Packit 7cfc04
Packit 7cfc04
    handle_bytes = strtoul(line2, &nextp, 0);
Packit 7cfc04
Packit 7cfc04
    /* Given handle_bytes, we can now allocate file_handle structure */
Packit 7cfc04
Packit 7cfc04
    fhp = malloc(sizeof(struct file_handle) + handle_bytes);
Packit 7cfc04
    if (fhp == NULL)
Packit 7cfc04
        errExit("malloc");
Packit 7cfc04
Packit 7cfc04
    fhp\->handle_bytes = handle_bytes;
Packit 7cfc04
Packit 7cfc04
    fhp\->handle_type = strtoul(nextp, &nextp, 0);
Packit 7cfc04
Packit 7cfc04
    for (j = 0; j < fhp\->handle_bytes; j++)
Packit 7cfc04
        fhp\->f_handle[j] = strtoul(nextp, &nextp, 16);
Packit 7cfc04
Packit 7cfc04
    /* Obtain file descriptor for mount point, either by opening
Packit 7cfc04
       the pathname specified on the command line, or by scanning
Packit 7cfc04
       /proc/self/mounts to find a mount that matches the \(aqmount_id\(aq
Packit 7cfc04
       that we received from stdin. */
Packit 7cfc04
Packit 7cfc04
    if (argc > 1)
Packit 7cfc04
        mount_fd = open(argv[1], O_RDONLY);
Packit 7cfc04
    else
Packit 7cfc04
        mount_fd = open_mount_path_by_id(mount_id);
Packit 7cfc04
Packit 7cfc04
    if (mount_fd == \-1)
Packit 7cfc04
        errExit("opening mount fd");
Packit 7cfc04
Packit 7cfc04
    /* Open file using handle and mount point */
Packit 7cfc04
Packit 7cfc04
    fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
Packit 7cfc04
    if (fd == \-1)
Packit 7cfc04
        errExit("open_by_handle_at");
Packit 7cfc04
Packit 7cfc04
    /* Try reading a few bytes from the file */
Packit 7cfc04
Packit 7cfc04
    nread = read(fd, buf, sizeof(buf));
Packit 7cfc04
    if (nread == \-1)
Packit 7cfc04
        errExit("read");
Packit 7cfc04
Packit 7cfc04
    printf("Read %zd bytes\\n", nread);
Packit 7cfc04
Packit 7cfc04
    exit(EXIT_SUCCESS);
Packit 7cfc04
}
Packit 7cfc04
.EE
Packit 7cfc04
.SH SEE ALSO
Packit 7cfc04
.BR open (2),
Packit 7cfc04
.BR libblkid (3),
Packit 7cfc04
.BR blkid (8),
Packit 7cfc04
.BR findfs (8),
Packit 7cfc04
.BR mount (8)
Packit 7cfc04
.PP
Packit 7cfc04
The
Packit 7cfc04
.I libblkid
Packit 7cfc04
and
Packit 7cfc04
.I libmount
Packit 7cfc04
documentation in the latest
Packit 7cfc04
.I util-linux
Packit 7cfc04
release at
Packit 7cfc04
.UR https://www.kernel.org/pub/linux/utils/util\-linux/
Packit 7cfc04
.UE
Packit 7cfc04
.SH COLOPHON
Packit 7cfc04
This page is part of release 4.15 of the Linux
Packit 7cfc04
.I man-pages
Packit 7cfc04
project.
Packit 7cfc04
A description of the project,
Packit 7cfc04
information about reporting bugs,
Packit 7cfc04
and the latest version of this page,
Packit 7cfc04
can be found at
Packit 7cfc04
\%https://www.kernel.org/doc/man\-pages/.