.\" Copyright (c) 1983, 1991 The Regents of the University of California.
-.\" Adn Copyright (C) 2011 Guillem Jover <guillem@hadrons.org>
+.\" And Copyright (C) 2011 Guillem Jover <guillem@hadrons.org>
+.\" And Copyright (C) 2006, 2014 Michael Kerrisk
.\" All rights reserved.
.\"
+.\" %%%LICENSE_START(BSD_4_CLAUSE_UCB)
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
+.\" %%%LICENSE_END
.\"
.\" @(#)readlink.2 6.8 (Berkeley) 3/10/91
.\"
.\" 2011-09-20, Guillem Jover <guillem@hadrons.org>:
.\" Added text on dynamically allocating buffer + example program
.\"
-.TH READLINK 2 2011-09-20 "Linux" "Linux Programmer's Manual"
+.TH READLINK 2 2014-10-15 "Linux" "Linux Programmer's Manual"
.SH NAME
-readlink \- read value of a symbolic link
+readlink, readlinkat \- read value of a symbolic link
.SH SYNOPSIS
+.nf
+.B #include <unistd.h>
+.sp
+.BI "ssize_t readlink(const char *" pathname ", char *" buf \
+", size_t " bufsiz );
+.sp
+.BR "#include <fcntl.h> " "/* Definition of AT_* constants */"
.B #include <unistd.h>
.sp
-.BI "ssize_t readlink(const char *" path ", char *" buf ", size_t " bufsiz );
+.BI "ssize_t readlinkat(int " dirfd ", const char *" pathname ,
+.BI " char *" buf ", size_t " bufsiz );
.sp
+.fi
.in -4n
Feature Test Macro Requirements for glibc (see
.BR feature_test_macros (7)):
_BSD_SOURCE || _XOPEN_SOURCE\ >=\ 500 ||
_XOPEN_SOURCE\ &&\ _XOPEN_SOURCE_EXTENDED || _POSIX_C_SOURCE\ >=\ 200112L
.RE
+.sp
+.BR readlinkat ():
+.PD 0
+.ad l
+.RS 4
+.TP 4
+Since glibc 2.10:
+_XOPEN_SOURCE\ >=\ 700 || _POSIX_C_SOURCE\ >=\ 200809L
+.TP
+Before glibc 2.10:
+_ATFILE_SOURCE
+.RE
.ad b
+.PD
.SH DESCRIPTION
.BR readlink ()
places the contents of the symbolic link
-.I path
+.I pathname
in the buffer
.IR buf ,
which has size
It will truncate the contents (to a length of
.I bufsiz
characters), in case the buffer is too small to hold all of the contents.
-.SH "RETURN VALUE"
-On success,
+.SS readlinkat()
+The
+.BR readlinkat ()
+system call operates in exactly the same way as
+.BR readlink (),
+except for the differences described here.
+
+If the pathname given in
+.I pathname
+is relative, then it is interpreted relative to the directory
+referred to by the file descriptor
+.I dirfd
+(rather than relative to the current working directory of
+the calling process, as is done by
.BR readlink ()
-returns the number of bytes placed in
+for a relative pathname).
+
+If
+.I pathname
+is relative and
+.I dirfd
+is the special value
+.BR AT_FDCWD ,
+then
+.I pathname
+is interpreted relative to the current working
+directory of the calling process (like
+.BR readlink ()).
+
+If
+.I pathname
+is absolute, then
+.I dirfd
+is ignored.
+
+Since Linux 2.6.39,
+.\" commit 65cfc6722361570bfe255698d9cd4dccaf47570d
+.I pathname
+can be an empty string,
+in which case the call operates on the symbolic link referred to by
+.IR dirfd
+(which should have been obtained using
+.BR open (2)
+with the
+.B O_PATH
+and
+.B O_NOFOLLOW
+flags).
+.PP
+See
+.BR openat (2)
+for an explanation of the need for
+.BR readlinkat ().
+.SH RETURN VALUE
+On success, these calls return the number of bytes placed in
.IR buf .
On error, \-1 is returned and
.I errno
The named file is not a symbolic link.
.TP
.B EIO
-An I/O error occurred while reading from the file system.
+An I/O error occurred while reading from the filesystem.
.TP
.B ELOOP
Too many symbolic links were encountered in translating the pathname.
.TP
.B ENOTDIR
A component of the path prefix is not a directory.
-.SH "CONFORMING TO"
+.PP
+The following additional errors can occur for
+.BR readlinkat ():
+.TP
+.B EBADF
+.I dirfd
+is not a valid file descriptor.
+.TP
+.B ENOTDIR
+.I pathname
+is relative and
+.I dirfd
+is a file descriptor referring to a file other than a directory.
+.SH VERSIONS
+.BR readlinkat ()
+was added to Linux in kernel 2.6.16;
+library support was added to glibc in version 2.4.
+.SH CONFORMING TO
+.BR readlink ():
4.4BSD
.RB ( readlink ()
first appeared in 4.2BSD),
-POSIX.1-2001.
+POSIX.1-2001, POSIX.1-2008.
+
+.BR readlinkat ():
+POSIX.1-2008.
.SH NOTES
In versions of glibc up to and including glibc 2.4, the return type of
.BR readlink ()
on the link.
However, the number of bytes written by
.BR readlink ()
+and
+.BR readlinkat ()
should be checked to make sure that the size of the
symbolic link did not increase between the calls.
Dynamically allocating the buffer for
.BR readlink ()
+and
+.BR readlinkat ()
also addresses a common portability problem when using
.I PATH_MAX
for the buffer size,
as this constant is not guaranteed to be defined per POSIX
if the system does not have such limit.
+.SS Glibc notes
+On older kernels where
+.BR readlinkat ()
+is unavailable, the glibc wrapper function falls back to the use of
+.BR readlink ().
+When
+.I pathname
+is a relative pathname,
+glibc constructs a pathname based on the symbolic link in
+.IR /proc/self/fd
+that corresponds to the
+.IR dirfd
+argument.
.SH EXAMPLE
The following program allocates the buffer needed by
.BR readlink ()
r = readlink(argv[1], linkname, sb.st_size + 1);
- if (r < 0) {
- perror("lstat");
+ if (r == \-1) {
+ perror("readlink");
exit(EXIT_FAILURE);
}
- if (r != sb.st_size) {
+ if (r > sb.st_size) {
fprintf(stderr, "symlink increased in size "
"between lstat() and readlink()\\n");
exit(EXIT_FAILURE);
}
- linkname[sb.st_size] = '\\0';
+ linkname[r] = \(aq\\0\(aq;
+
+ printf("\(aq%s\(aq points to \(aq%s\(aq\\n", argv[1], linkname);
- printf("'%s' points to '%s'\\n", argv[1], linkname);
+ free(linkname);
exit(EXIT_SUCCESS);
}
.fi
-.SH "SEE ALSO"
+.SH SEE ALSO
.BR readlink (1),
.BR lstat (2),
-.BR readlinkat (2),
.BR stat (2),
.BR symlink (2),
+.BR realpath (3),
.BR path_resolution (7),
.BR symlink (7)
+.SH COLOPHON
+This page is part of release 3.79 of the Linux
+.I man-pages
+project.
+A description of the project,
+information about reporting bugs,
+and the latest version of this page,
+can be found at
+\%http://www.kernel.org/doc/man\-pages/.