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