1029 lines
30 KiB
HTML
1029 lines
30 KiB
HTML
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
<HTML><HEAD><TITLE>Man page of OPEN_BY_HANDLE_AT</TITLE>
|
|
</HEAD><BODY>
|
|
<H1>OPEN_BY_HANDLE_AT</H1>
|
|
Section: Linux Programmer's Manual (2)<BR>Updated: 2019-03-06<BR><A HREF="#index">Index</A>
|
|
<A HREF="/cgi-bin/man/man2html">Return to Main Contents</A><HR>
|
|
|
|
<A NAME="lbAB"> </A>
|
|
<H2>NAME</H2>
|
|
|
|
name_to_handle_at, open_by_handle_at - obtain handle
|
|
for a pathname and open file via a handle
|
|
<A NAME="lbAC"> </A>
|
|
<H2>SYNOPSIS</H2>
|
|
|
|
<PRE>
|
|
<B>#define _GNU_SOURCE</B> /* See <A HREF="/cgi-bin/man/man2html?7+feature_test_macros">feature_test_macros</A>(7) */
|
|
<B>#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>></B>
|
|
<B>#include <<A HREF="file:///usr/include/sys/stat.h">sys/stat.h</A>></B>
|
|
<B>#include <<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>></B>
|
|
|
|
<B>int name_to_handle_at(int </B><I>dirfd</I><B>, const char *</B><I>pathname</I><B>,</B>
|
|
<B> struct file_handle *</B><I>handle</I><B>,</B>
|
|
<B> int *</B><I>mount_id</I><B>, int </B><I>flags</I><B>);</B>
|
|
|
|
<B>int open_by_handle_at(int </B><I>mount_fd</I><B>, struct file_handle *</B><I>handle</I><B>,</B>
|
|
<B> int </B><I>flags</I><B>);</B>
|
|
</PRE>
|
|
|
|
<A NAME="lbAD"> </A>
|
|
<H2>DESCRIPTION</H2>
|
|
|
|
The
|
|
<B>name_to_handle_at</B>()
|
|
|
|
and
|
|
<B>open_by_handle_at</B>()
|
|
|
|
system calls split the functionality of
|
|
<B><A HREF="/cgi-bin/man/man2html?2+openat">openat</A></B>(2)
|
|
|
|
into two parts:
|
|
<B>name_to_handle_at</B>()
|
|
|
|
returns an opaque handle that corresponds to a specified file;
|
|
<B>open_by_handle_at</B>()
|
|
|
|
opens the file corresponding to a handle returned by a previous call to
|
|
<B>name_to_handle_at</B>()
|
|
|
|
and returns an open file descriptor.
|
|
|
|
|
|
<A NAME="lbAE"> </A>
|
|
<H3>name_to_handle_at()</H3>
|
|
|
|
The
|
|
<B>name_to_handle_at</B>()
|
|
|
|
system call returns a file handle and a mount ID corresponding to
|
|
the file specified by the
|
|
<I>dirfd</I>
|
|
|
|
and
|
|
<I>pathname</I>
|
|
|
|
arguments.
|
|
The file handle is returned via the argument
|
|
<I>handle</I>,
|
|
|
|
which is a pointer to a structure of the following form:
|
|
<P>
|
|
|
|
|
|
|
|
struct file_handle {
|
|
<BR> unsigned int handle_bytes; /* Size of f_handle [in, out] */
|
|
<BR> int handle_type; /* Handle type [out] */
|
|
<BR> unsigned char f_handle[0]; /* File identifier (sized by
|
|
<BR> caller) [out] */
|
|
};
|
|
|
|
|
|
<P>
|
|
|
|
It is the caller's responsibility to allocate the structure
|
|
with a size large enough to hold the handle returned in
|
|
<I>f_handle</I>.
|
|
|
|
Before the call, the
|
|
<I>handle_bytes</I>
|
|
|
|
field should be initialized to contain the allocated size for
|
|
<I>f_handle</I>.
|
|
|
|
(The constant
|
|
<B>MAX_HANDLE_SZ</B>,
|
|
|
|
defined in
|
|
<I><<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>></I>,
|
|
|
|
specifies the maximum expected size for a file handle.
|
|
It is not a
|
|
guaranteed upper limit as future filesystems may require more space.)
|
|
Upon successful return, the
|
|
<I>handle_bytes</I>
|
|
|
|
field is updated to contain the number of bytes actually written to
|
|
<I>f_handle</I>.
|
|
|
|
<P>
|
|
|
|
The caller can discover the required size for the
|
|
<I>file_handle</I>
|
|
|
|
structure by making a call in which
|
|
<I>handle->handle_bytes</I>
|
|
|
|
is zero;
|
|
in this case, the call fails with the error
|
|
<B>EOVERFLOW</B>
|
|
|
|
and
|
|
<I>handle->handle_bytes</I>
|
|
|
|
is set to indicate the required size;
|
|
the caller can then use this information to allocate a structure
|
|
of the correct size (see EXAMPLE below).
|
|
Some care is needed here as
|
|
<B>EOVERFLOW</B>
|
|
|
|
can also indicate that no file handle is available for this particular
|
|
name in a filesystem which does normally support file-handle lookup.
|
|
This case can be detected when the
|
|
<B>EOVERFLOW</B>
|
|
|
|
error is returned without
|
|
<I>handle_bytes</I>
|
|
|
|
being increased.
|
|
<P>
|
|
|
|
Other than the use of the
|
|
<I>handle_bytes</I>
|
|
|
|
field, the caller should treat the
|
|
<I>file_handle</I>
|
|
|
|
structure as an opaque data type: the
|
|
<I>handle_type</I>
|
|
|
|
and
|
|
<I>f_handle</I>
|
|
|
|
fields are needed only by a subsequent call to
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<P>
|
|
|
|
The
|
|
<I>flags</I>
|
|
|
|
argument is a bit mask constructed by ORing together zero or more of
|
|
<B>AT_EMPTY_PATH</B>
|
|
|
|
and
|
|
<B>AT_SYMLINK_FOLLOW</B>,
|
|
|
|
described below.
|
|
<P>
|
|
|
|
Together, the
|
|
<I>pathname</I>
|
|
|
|
and
|
|
<I>dirfd</I>
|
|
|
|
arguments identify the file for which a handle is to be obtained.
|
|
There are four distinct cases:
|
|
<DL COMPACT>
|
|
<DT id="1">*<DD>
|
|
If
|
|
<I>pathname</I>
|
|
|
|
is a nonempty string containing an absolute pathname,
|
|
then a handle is returned for the file referred to by that pathname.
|
|
In this case,
|
|
<I>dirfd</I>
|
|
|
|
is ignored.
|
|
<DT id="2">*<DD>
|
|
If
|
|
<I>pathname</I>
|
|
|
|
is a nonempty string containing a relative pathname and
|
|
<I>dirfd</I>
|
|
|
|
has the special value
|
|
<B>AT_FDCWD</B>,
|
|
|
|
then
|
|
<I>pathname</I>
|
|
|
|
is interpreted relative to the current working directory of the caller,
|
|
and a handle is returned for the file to which it refers.
|
|
<DT id="3">*<DD>
|
|
If
|
|
<I>pathname</I>
|
|
|
|
is a nonempty string containing a relative pathname and
|
|
<I>dirfd</I>
|
|
|
|
is a file descriptor referring to a directory, then
|
|
<I>pathname</I>
|
|
|
|
is interpreted relative to the directory referred to by
|
|
<I>dirfd</I>,
|
|
|
|
and a handle is returned for the file to which it refers.
|
|
(See
|
|
<B><A HREF="/cgi-bin/man/man2html?2+openat">openat</A></B>(2)
|
|
|
|
for an explanation of why "directory file descriptors" are useful.)
|
|
<DT id="4">*<DD>
|
|
If
|
|
<I>pathname</I>
|
|
|
|
is an empty string and
|
|
<I>flags</I>
|
|
|
|
specifies the value
|
|
<B>AT_EMPTY_PATH</B>,
|
|
|
|
then
|
|
<I>dirfd</I>
|
|
|
|
can be an open file descriptor referring to any type of file,
|
|
or
|
|
<B>AT_FDCWD</B>,
|
|
|
|
meaning the current working directory,
|
|
and a handle is returned for the file to which it refers.
|
|
</DL>
|
|
<P>
|
|
|
|
The
|
|
<I>mount_id</I>
|
|
|
|
argument returns an identifier for the filesystem
|
|
mount that corresponds to
|
|
<I>pathname</I>.
|
|
|
|
This corresponds to the first field in one of the records in
|
|
<I>/proc/self/mountinfo</I>.
|
|
|
|
Opening the pathname in the fifth field of that record yields a file
|
|
descriptor for the mount point;
|
|
that file descriptor can be used in a subsequent call to
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<I>mount_id</I>
|
|
|
|
is returned both for a successful call and for a call that results
|
|
in the error
|
|
<B>EOVERFLOW</B>.
|
|
|
|
<P>
|
|
|
|
By default,
|
|
<B>name_to_handle_at</B>()
|
|
|
|
does not dereference
|
|
<I>pathname</I>
|
|
|
|
if it is a symbolic link, and thus returns a handle for the link itself.
|
|
If
|
|
<B>AT_SYMLINK_FOLLOW</B>
|
|
|
|
is specified in
|
|
<I>flags</I>,
|
|
|
|
<I>pathname</I>
|
|
|
|
is dereferenced if it is a symbolic link
|
|
(so that the call returns a handle for the file referred to by the link).
|
|
<P>
|
|
|
|
<B>name_to_handle_at</B>()
|
|
|
|
does not trigger a mount when the final component of the pathname is an
|
|
automount point.
|
|
When a filesystem supports both file handles and
|
|
automount points, a
|
|
<B>name_to_handle_at</B>()
|
|
|
|
call on an automount point will return with error
|
|
<B>EOVERFLOW</B>
|
|
|
|
without having increased
|
|
<I>handle_bytes</I>.
|
|
|
|
This can happen since Linux 4.13
|
|
|
|
with NFS when accessing a directory
|
|
which is on a separate filesystem on the server.
|
|
In this case, the automount can be triggered by adding a "/" to the end
|
|
of the pathname.
|
|
<A NAME="lbAF"> </A>
|
|
<H3>open_by_handle_at()</H3>
|
|
|
|
The
|
|
<B>open_by_handle_at</B>()
|
|
|
|
system call opens the file referred to by
|
|
<I>handle</I>,
|
|
|
|
a file handle returned by a previous call to
|
|
<B>name_to_handle_at</B>().
|
|
|
|
<P>
|
|
|
|
The
|
|
<I>mount_fd</I>
|
|
|
|
argument is a file descriptor for any object (file, directory, etc.)
|
|
in the mounted filesystem with respect to which
|
|
<I>handle</I>
|
|
|
|
should be interpreted.
|
|
The special value
|
|
<B>AT_FDCWD</B>
|
|
|
|
can be specified, meaning the current working directory of the caller.
|
|
<P>
|
|
|
|
The
|
|
<I>flags</I>
|
|
|
|
argument
|
|
is as for
|
|
<B><A HREF="/cgi-bin/man/man2html?2+open">open</A></B>(2).
|
|
|
|
If
|
|
<I>handle</I>
|
|
|
|
refers to a symbolic link, the caller must specify the
|
|
<B>O_PATH</B>
|
|
|
|
flag, and the symbolic link is not dereferenced; the
|
|
<B>O_NOFOLLOW</B>
|
|
|
|
flag, if specified, is ignored.
|
|
<P>
|
|
|
|
The caller must have the
|
|
<B>CAP_DAC_READ_SEARCH</B>
|
|
|
|
capability to invoke
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<A NAME="lbAG"> </A>
|
|
<H2>RETURN VALUE</H2>
|
|
|
|
On success,
|
|
<B>name_to_handle_at</B>()
|
|
|
|
returns 0,
|
|
and
|
|
<B>open_by_handle_at</B>()
|
|
|
|
returns a nonnegative file descriptor.
|
|
<P>
|
|
|
|
In the event of an error, both system calls return -1 and set
|
|
<I>errno</I>
|
|
|
|
to indicate the cause of the error.
|
|
<A NAME="lbAH"> </A>
|
|
<H2>ERRORS</H2>
|
|
|
|
<B>name_to_handle_at</B>()
|
|
|
|
and
|
|
<B>open_by_handle_at</B>()
|
|
|
|
can fail for the same errors as
|
|
<B><A HREF="/cgi-bin/man/man2html?2+openat">openat</A></B>(2).
|
|
|
|
In addition, they can fail with the errors noted below.
|
|
<P>
|
|
|
|
<B>name_to_handle_at</B>()
|
|
|
|
can fail with the following errors:
|
|
<DL COMPACT>
|
|
<DT id="5"><B>EFAULT</B>
|
|
|
|
<DD>
|
|
<I>pathname</I>,
|
|
|
|
<I>mount_id</I>,
|
|
|
|
or
|
|
<I>handle</I>
|
|
|
|
points outside your accessible address space.
|
|
<DT id="6"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>flags</I>
|
|
|
|
includes an invalid bit value.
|
|
<DT id="7"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>handle->handle_bytes</I>
|
|
|
|
is greater than
|
|
<B>MAX_HANDLE_SZ</B>.
|
|
|
|
<DT id="8"><B>ENOENT</B>
|
|
|
|
<DD>
|
|
<I>pathname</I>
|
|
|
|
is an empty string, but
|
|
<B>AT_EMPTY_PATH</B>
|
|
|
|
was not specified in
|
|
<I>flags</I>.
|
|
|
|
<DT id="9"><B>ENOTDIR</B>
|
|
|
|
<DD>
|
|
The file descriptor supplied in
|
|
<I>dirfd</I>
|
|
|
|
does not refer to a directory,
|
|
and it is not the case that both
|
|
<I>flags</I>
|
|
|
|
includes
|
|
<B>AT_EMPTY_PATH</B>
|
|
|
|
and
|
|
<I>pathname</I>
|
|
|
|
is an empty string.
|
|
<DT id="10"><B>EOPNOTSUPP</B>
|
|
|
|
<DD>
|
|
The filesystem does not support decoding of a pathname to a file handle.
|
|
<DT id="11"><B>EOVERFLOW</B>
|
|
|
|
<DD>
|
|
The
|
|
<I>handle->handle_bytes</I>
|
|
|
|
value passed into the call was too small.
|
|
When this error occurs,
|
|
<I>handle->handle_bytes</I>
|
|
|
|
is updated to indicate the required size for the handle.
|
|
|
|
|
|
</DL>
|
|
<P>
|
|
|
|
<B>open_by_handle_at</B>()
|
|
|
|
can fail with the following errors:
|
|
<DL COMPACT>
|
|
<DT id="12"><B>EBADF</B>
|
|
|
|
<DD>
|
|
<I>mount_fd</I>
|
|
|
|
is not an open file descriptor.
|
|
<DT id="13"><B>EFAULT</B>
|
|
|
|
<DD>
|
|
<I>handle</I>
|
|
|
|
points outside your accessible address space.
|
|
<DT id="14"><B>EINVAL</B>
|
|
|
|
<DD>
|
|
<I>handle->handle_bytes</I>
|
|
|
|
is greater than
|
|
<B>MAX_HANDLE_SZ</B>
|
|
|
|
or is equal to zero.
|
|
<DT id="15"><B>ELOOP</B>
|
|
|
|
<DD>
|
|
<I>handle</I>
|
|
|
|
refers to a symbolic link, but
|
|
<B>O_PATH</B>
|
|
|
|
was not specified in
|
|
<I>flags</I>.
|
|
|
|
<DT id="16"><B>EPERM</B>
|
|
|
|
<DD>
|
|
The caller does not have the
|
|
<B>CAP_DAC_READ_SEARCH</B>
|
|
|
|
capability.
|
|
<DT id="17"><B>ESTALE</B>
|
|
|
|
<DD>
|
|
The specified
|
|
<I>handle</I>
|
|
|
|
is not valid.
|
|
This error will occur if, for example, the file has been deleted.
|
|
</DL>
|
|
<A NAME="lbAI"> </A>
|
|
<H2>VERSIONS</H2>
|
|
|
|
These system calls first appeared in Linux 2.6.39.
|
|
Library support is provided in glibc since version 2.14.
|
|
<A NAME="lbAJ"> </A>
|
|
<H2>CONFORMING TO</H2>
|
|
|
|
These system calls are nonstandard Linux extensions.
|
|
<P>
|
|
|
|
FreeBSD has a broadly similar pair of system calls in the form of
|
|
<B>getfh</B>()
|
|
|
|
and
|
|
<B>openfh</B>().
|
|
|
|
<A NAME="lbAK"> </A>
|
|
<H2>NOTES</H2>
|
|
|
|
A file handle can be generated in one process using
|
|
<B>name_to_handle_at</B>()
|
|
|
|
and later used in a different process that calls
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<P>
|
|
|
|
Some filesystem don't support the translation of pathnames to
|
|
file handles, for example,
|
|
<I>/proc</I>,
|
|
|
|
<I>/sys</I>,
|
|
|
|
and various network filesystems.
|
|
<P>
|
|
|
|
A file handle may become invalid ("stale") if a file is deleted,
|
|
or for other filesystem-specific reasons.
|
|
Invalid handles are notified by an
|
|
<B>ESTALE</B>
|
|
|
|
error from
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<P>
|
|
|
|
These system calls are designed for use by user-space file servers.
|
|
For example, a user-space NFS server might generate a file handle
|
|
and pass it to an NFS client.
|
|
Later, when the client wants to open the file,
|
|
it could pass the handle back to the server.
|
|
|
|
|
|
This sort of functionality allows a user-space file server to operate in
|
|
a stateless fashion with respect to the files it serves.
|
|
<P>
|
|
|
|
If
|
|
<I>pathname</I>
|
|
|
|
refers to a symbolic link and
|
|
<I>flags</I>
|
|
|
|
does not specify
|
|
<B>AT_SYMLINK_FOLLOW</B>,
|
|
|
|
then
|
|
<B>name_to_handle_at</B>()
|
|
|
|
returns a handle for the link (rather than the file to which it refers).
|
|
|
|
The process receiving the handle can later perform operations
|
|
on the symbolic link by converting the handle to a file descriptor using
|
|
<B>open_by_handle_at</B>()
|
|
|
|
with the
|
|
<B>O_PATH</B>
|
|
|
|
flag, and then passing the file descriptor as the
|
|
<I>dirfd</I>
|
|
|
|
argument in system calls such as
|
|
<B><A HREF="/cgi-bin/man/man2html?2+readlinkat">readlinkat</A></B>(2)
|
|
|
|
and
|
|
<B><A HREF="/cgi-bin/man/man2html?2+fchownat">fchownat</A></B>(2).
|
|
|
|
<A NAME="lbAL"> </A>
|
|
<H3>Obtaining a persistent filesystem ID</H3>
|
|
|
|
The mount IDs in
|
|
<I>/proc/self/mountinfo</I>
|
|
|
|
can be reused as filesystems are unmounted and mounted.
|
|
Therefore, the mount ID returned by
|
|
<B>name_to_handle_at</B>()
|
|
|
|
(in
|
|
<I>*mount_id</I>)
|
|
|
|
should not be treated as a persistent identifier
|
|
for the corresponding mounted filesystem.
|
|
However, an application can use the information in the
|
|
<I>mountinfo</I>
|
|
|
|
record that corresponds to the mount ID
|
|
to derive a persistent identifier.
|
|
<P>
|
|
|
|
For example, one can use the device name in the fifth field of the
|
|
<I>mountinfo</I>
|
|
|
|
record to search for the corresponding device UUID via the symbolic links in
|
|
<I>/dev/disks/by-uuid</I>.
|
|
|
|
(A more comfortable way of obtaining the UUID is to use the
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+libblkid">libblkid</A></B>(3)
|
|
|
|
library.)
|
|
That process can then be reversed,
|
|
using the UUID to look up the device name,
|
|
and then obtaining the corresponding mount point,
|
|
in order to produce the
|
|
<I>mount_fd</I>
|
|
|
|
argument used by
|
|
<B>open_by_handle_at</B>().
|
|
|
|
<A NAME="lbAM"> </A>
|
|
<H2>EXAMPLE</H2>
|
|
|
|
The two programs below demonstrate the use of
|
|
<B>name_to_handle_at</B>()
|
|
|
|
and
|
|
<B>open_by_handle_at</B>().
|
|
|
|
The first program
|
|
(<I>t_name_to_handle_at.c</I>)
|
|
|
|
uses
|
|
<B>name_to_handle_at</B>()
|
|
|
|
to obtain the file handle and mount ID
|
|
for the file specified in its command-line argument;
|
|
the handle and mount ID are written to standard output.
|
|
<P>
|
|
|
|
The second program
|
|
(<I>t_open_by_handle_at.c</I>)
|
|
|
|
reads a mount ID and file handle from standard input.
|
|
The program then employs
|
|
<B>open_by_handle_at</B>()
|
|
|
|
to open the file using that handle.
|
|
If an optional command-line argument is supplied, then the
|
|
<I>mount_fd</I>
|
|
|
|
argument for
|
|
<B>open_by_handle_at</B>()
|
|
|
|
is obtained by opening the directory named in that argument.
|
|
Otherwise,
|
|
<I>mount_fd</I>
|
|
|
|
is obtained by scanning
|
|
<I>/proc/self/mountinfo</I>
|
|
|
|
to find a record whose mount ID matches the mount ID
|
|
read from standard input,
|
|
and the mount directory specified in that record is opened.
|
|
(These programs do not deal with the fact that mount IDs are not persistent.)
|
|
<P>
|
|
|
|
The following shell session demonstrates the use of these two programs:
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>echo 'Can you please think about it?' > cecilia.txt</B>
|
|
$ <B>./t_name_to_handle_at cecilia.txt > fh</B>
|
|
$ <B>./t_open_by_handle_at < fh</B>
|
|
open_by_handle_at: Operation not permitted
|
|
$ <B>sudo ./t_open_by_handle_at < fh</B> # Need CAP_SYS_ADMIN
|
|
Read 31 bytes
|
|
$ <B>rm cecilia.txt</B>
|
|
|
|
|
|
<P>
|
|
|
|
Now we delete and (quickly) re-create the file so that
|
|
it has the same content and (by chance) the same inode.
|
|
Nevertheless,
|
|
<B>open_by_handle_at</B>()
|
|
|
|
|
|
|
|
recognizes that the original file referred to by the file handle
|
|
no longer exists.
|
|
<P>
|
|
|
|
|
|
|
|
$ <B>stat --printf="%i\n" cecilia.txt</B> # Display inode number
|
|
4072121
|
|
$ <B>rm cecilia.txt</B>
|
|
$ <B>echo 'Can you please think about it?' > cecilia.txt</B>
|
|
$ <B>stat --printf="%i\n" cecilia.txt</B> # Check inode number
|
|
4072121
|
|
$ <B>sudo ./t_open_by_handle_at < fh</B>
|
|
open_by_handle_at: Stale NFS file handle
|
|
|
|
|
|
<A NAME="lbAN"> </A>
|
|
<H3>Program source: t_name_to_handle_at.c</H3>
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/stat.h">sys/stat.h</A>>
|
|
#include <<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
#include <<A HREF="file:///usr/include/errno.h">errno.h</A>>
|
|
#include <<A HREF="file:///usr/include/string.h">string.h</A>>
|
|
<P>
|
|
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
|
|
<BR> } while (0)
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> struct file_handle *fhp;
|
|
<BR> int mount_id, fhsize, flags, dirfd, j;
|
|
<BR> char *pathname;
|
|
<P>
|
|
<BR> if (argc != 2) {
|
|
<BR> fprintf(stderr, "Usage: %s pathname\n", argv[0]);
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> pathname = argv[1];
|
|
<P>
|
|
<BR> /* Allocate file_handle structure */
|
|
<P>
|
|
<BR> fhsize = sizeof(*fhp);
|
|
<BR> fhp = malloc(fhsize);
|
|
<BR> if (fhp == NULL)
|
|
<BR> errExit("malloc");
|
|
<P>
|
|
<BR> /* Make an initial call to name_to_handle_at() to discover
|
|
<BR> the size required for file handle */
|
|
<P>
|
|
<BR> dirfd = AT_FDCWD; /* For name_to_handle_at() calls */
|
|
<BR> flags = 0; /* For name_to_handle_at() calls */
|
|
<BR> fhp->handle_bytes = 0;
|
|
<BR> if (name_to_handle_at(dirfd, pathname, fhp,
|
|
<BR> &mount_id, flags) != -1 || errno != EOVERFLOW) {
|
|
<BR> fprintf(stderr, "Unexpected result from name_to_handle_at()\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Reallocate file_handle structure with correct size */
|
|
<P>
|
|
<BR> fhsize = sizeof(struct file_handle) + fhp->handle_bytes;
|
|
<BR> fhp = realloc(fhp, fhsize); /* Copies fhp->handle_bytes */
|
|
<BR> if (fhp == NULL)
|
|
<BR> errExit("realloc");
|
|
<P>
|
|
<BR> /* Get file handle from pathname supplied on command line */
|
|
<P>
|
|
<BR> if (name_to_handle_at(dirfd, pathname, fhp, &mount_id, flags) == -1)
|
|
<BR> errExit("name_to_handle_at");
|
|
<P>
|
|
<BR> /* Write mount ID, file handle size, and file handle to stdout,
|
|
<BR> for later reuse by t_open_by_handle_at.c */
|
|
<P>
|
|
<BR> printf("%d\n", mount_id);
|
|
<BR> printf("%d %d ", fhp->handle_bytes, fhp->handle_type);
|
|
<BR> for (j = 0; j < fhp->handle_bytes; j++)
|
|
<BR> printf(" %02x", fhp->f_handle[j]);
|
|
<BR> printf("\n");
|
|
<P>
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAO"> </A>
|
|
<H3>Program source: t_open_by_handle_at.c</H3>
|
|
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
#include <<A HREF="file:///usr/include/sys/types.h">sys/types.h</A>>
|
|
#include <<A HREF="file:///usr/include/sys/stat.h">sys/stat.h</A>>
|
|
#include <<A HREF="file:///usr/include/fcntl.h">fcntl.h</A>>
|
|
#include <<A HREF="file:///usr/include/limits.h">limits.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdio.h">stdio.h</A>>
|
|
#include <<A HREF="file:///usr/include/stdlib.h">stdlib.h</A>>
|
|
#include <<A HREF="file:///usr/include/unistd.h">unistd.h</A>>
|
|
#include <<A HREF="file:///usr/include/string.h">string.h</A>>
|
|
<P>
|
|
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
|
|
<BR> } while (0)
|
|
<P>
|
|
/* Scan /proc/self/mountinfo to find the line whose mount ID matches
|
|
<BR> 'mount_id'. (An easier way to do this is to install and use the
|
|
<BR> 'libmount' library provided by the 'util-linux' project.)
|
|
<BR> Open the corresponding mount path and return the resulting file
|
|
<BR> descriptor. */
|
|
<P>
|
|
static int
|
|
open_mount_path_by_id(int mount_id)
|
|
{
|
|
<BR> char *linep;
|
|
<BR> size_t lsize;
|
|
<BR> char mount_path[PATH_MAX];
|
|
<BR> int mi_mount_id, found;
|
|
<BR> ssize_t nread;
|
|
<BR> FILE *fp;
|
|
<P>
|
|
<BR> fp = fopen("/proc/self/mountinfo", "r");
|
|
<BR> if (fp == NULL)
|
|
<BR> errExit("fopen");
|
|
<P>
|
|
<BR> found = 0;
|
|
<BR> linep = NULL;
|
|
<BR> while (!found) {
|
|
<BR> nread = getline(&linep, &lsize, fp);
|
|
<BR> if (nread == -1)
|
|
<BR> break;
|
|
<P>
|
|
<BR> nread = sscanf(linep, "%d %*d %*s %*s %s",
|
|
<BR> &mi_mount_id, mount_path);
|
|
<BR> if (nread != 2) {
|
|
<BR> fprintf(stderr, "Bad sscanf()\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> if (mi_mount_id == mount_id)
|
|
<BR> found = 1;
|
|
<BR> }
|
|
<BR> free(linep);
|
|
<P>
|
|
<BR> fclose(fp);
|
|
<P>
|
|
<BR> if (!found) {
|
|
<BR> fprintf(stderr, "Could not find mount point\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> return open(mount_path, O_RDONLY);
|
|
}
|
|
<P>
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
<BR> struct file_handle *fhp;
|
|
<BR> int mount_id, fd, mount_fd, handle_bytes, j;
|
|
<BR> ssize_t nread;
|
|
<BR> char buf[1000];
|
|
#define LINE_SIZE 100
|
|
<BR> char line1[LINE_SIZE], line2[LINE_SIZE];
|
|
<BR> char *nextp;
|
|
<P>
|
|
<BR> if ((argc > 1 && strcmp(argv[1], "--help") == 0) || argc > 2) {
|
|
<BR> fprintf(stderr, "Usage: %s [mount-path]\n", argv[0]);
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> /* Standard input contains mount ID and file handle information:
|
|
<P>
|
|
<BR> Line 1: <mount_id>
|
|
<BR> Line 2: <handle_bytes> <handle_type> <bytes of handle in hex>
|
|
<BR> */
|
|
<P>
|
|
<BR> if ((fgets(line1, sizeof(line1), stdin) == NULL) ||
|
|
<BR> (fgets(line2, sizeof(line2), stdin) == NULL)) {
|
|
<BR> fprintf(stderr, "Missing mount_id / file handle\n");
|
|
<BR> exit(EXIT_FAILURE);
|
|
<BR> }
|
|
<P>
|
|
<BR> mount_id = atoi(line1);
|
|
<P>
|
|
<BR> handle_bytes = strtoul(line2, &nextp, 0);
|
|
<P>
|
|
<BR> /* Given handle_bytes, we can now allocate file_handle structure */
|
|
<P>
|
|
<BR> fhp = malloc(sizeof(struct file_handle) + handle_bytes);
|
|
<BR> if (fhp == NULL)
|
|
<BR> errExit("malloc");
|
|
<P>
|
|
<BR> fhp->handle_bytes = handle_bytes;
|
|
<P>
|
|
<BR> fhp->handle_type = strtoul(nextp, &nextp, 0);
|
|
<P>
|
|
<BR> for (j = 0; j < fhp->handle_bytes; j++)
|
|
<BR> fhp->f_handle[j] = strtoul(nextp, &nextp, 16);
|
|
<P>
|
|
<BR> /* Obtain file descriptor for mount point, either by opening
|
|
<BR> the pathname specified on the command line, or by scanning
|
|
<BR> /proc/self/mounts to find a mount that matches the 'mount_id'
|
|
<BR> that we received from stdin. */
|
|
<P>
|
|
<BR> if (argc > 1)
|
|
<BR> mount_fd = open(argv[1], O_RDONLY);
|
|
<BR> else
|
|
<BR> mount_fd = open_mount_path_by_id(mount_id);
|
|
<P>
|
|
<BR> if (mount_fd == -1)
|
|
<BR> errExit("opening mount fd");
|
|
<P>
|
|
<BR> /* Open file using handle and mount point */
|
|
<P>
|
|
<BR> fd = open_by_handle_at(mount_fd, fhp, O_RDONLY);
|
|
<BR> if (fd == -1)
|
|
<BR> errExit("open_by_handle_at");
|
|
<P>
|
|
<BR> /* Try reading a few bytes from the file */
|
|
<P>
|
|
<BR> nread = read(fd, buf, sizeof(buf));
|
|
<BR> if (nread == -1)
|
|
<BR> errExit("read");
|
|
<P>
|
|
<BR> printf("Read %zd bytes\n", nread);
|
|
<P>
|
|
<BR> exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
<A NAME="lbAP"> </A>
|
|
<H2>SEE ALSO</H2>
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?2+open">open</A></B>(2),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?3+libblkid">libblkid</A></B>(3),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?8+blkid">blkid</A></B>(8),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?8+findfs">findfs</A></B>(8),
|
|
|
|
<B><A HREF="/cgi-bin/man/man2html?8+mount">mount</A></B>(8)
|
|
|
|
<P>
|
|
|
|
The
|
|
<I>libblkid</I>
|
|
|
|
and
|
|
<I>libmount</I>
|
|
|
|
documentation in the latest
|
|
<I>util-linux</I>
|
|
|
|
release at
|
|
|
|
|
|
<A NAME="lbAQ"> </A>
|
|
<H2>COLOPHON</H2>
|
|
|
|
This page is part of release 5.05 of the Linux
|
|
<I>man-pages</I>
|
|
|
|
project.
|
|
A description of the project,
|
|
information about reporting bugs,
|
|
and the latest version of this page,
|
|
can be found at
|
|
<A HREF="https://www.kernel.org/doc/man-pages/.">https://www.kernel.org/doc/man-pages/.</A>
|
|
<P>
|
|
|
|
<HR>
|
|
<A NAME="index"> </A><H2>Index</H2>
|
|
<DL>
|
|
<DT id="18"><A HREF="#lbAB">NAME</A><DD>
|
|
<DT id="19"><A HREF="#lbAC">SYNOPSIS</A><DD>
|
|
<DT id="20"><A HREF="#lbAD">DESCRIPTION</A><DD>
|
|
<DL>
|
|
<DT id="21"><A HREF="#lbAE">name_to_handle_at()</A><DD>
|
|
<DT id="22"><A HREF="#lbAF">open_by_handle_at()</A><DD>
|
|
</DL>
|
|
<DT id="23"><A HREF="#lbAG">RETURN VALUE</A><DD>
|
|
<DT id="24"><A HREF="#lbAH">ERRORS</A><DD>
|
|
<DT id="25"><A HREF="#lbAI">VERSIONS</A><DD>
|
|
<DT id="26"><A HREF="#lbAJ">CONFORMING TO</A><DD>
|
|
<DT id="27"><A HREF="#lbAK">NOTES</A><DD>
|
|
<DL>
|
|
<DT id="28"><A HREF="#lbAL">Obtaining a persistent filesystem ID</A><DD>
|
|
</DL>
|
|
<DT id="29"><A HREF="#lbAM">EXAMPLE</A><DD>
|
|
<DL>
|
|
<DT id="30"><A HREF="#lbAN">Program source: t_name_to_handle_at.c</A><DD>
|
|
<DT id="31"><A HREF="#lbAO">Program source: t_open_by_handle_at.c</A><DD>
|
|
</DL>
|
|
<DT id="32"><A HREF="#lbAP">SEE ALSO</A><DD>
|
|
<DT id="33"><A HREF="#lbAQ">COLOPHON</A><DD>
|
|
</DL>
|
|
<HR>
|
|
This document was created by
|
|
<A HREF="/cgi-bin/man/man2html">man2html</A>,
|
|
using the manual pages.<BR>
|
|
Time: 00:05:33 GMT, March 31, 2021
|
|
</BODY>
|
|
</HTML>
|