.\" Copyright (c) 1983, 1991 The Regents of the University of California.
+.\" And Copyright (C) 2011 Guillem Jover <guillem@hadrons.org>
.\" 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
.\"
.\" Modified Sat Jul 24 00:10:21 1993 by Rik Faith (faith@cs.unc.edu)
.\" Modified Tue Jul 9 23:55:17 1996 by aeb
.\" Modified Fri Jan 24 00:26:00 1997 by aeb
+.\" 2011-09-20, Guillem Jover <guillem@hadrons.org>:
+.\" Added text on dynamically allocating buffer + example program
.\"
-.TH READLINK 2 2007-07-26 "Linux" "Linux Programmer's Manual"
+.TH READLINK 2 2011-09-20 "Linux" "Linux Programmer's Manual"
.SH NAME
readlink \- read value of a symbolic link
.SH SYNOPSIS
.sp
.ad l
.BR readlink ():
-_BSD_SOURCE || _XOPEN_SOURCE\ >=\ 500 || _POSIX_C_SOURCE\ >=\ 200112L
+.RS 4
+_BSD_SOURCE || _XOPEN_SOURCE\ >=\ 500 ||
+_XOPEN_SOURCE\ &&\ _XOPEN_SOURCE_EXTENDED || _POSIX_C_SOURCE\ >=\ 200112L
+.RE
.ad b
.SH DESCRIPTION
.BR readlink ()
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"
+.SH RETURN VALUE
On success,
.BR readlink ()
returns the number of bytes placed in
.TP
.B ENOTDIR
A component of the path prefix is not a directory.
-.SH "CONFORMING TO"
-4.4BSD (the
-.BR readlink ()
-function call appeared in 4.2BSD),
+.SH CONFORMING TO
+4.4BSD
+.RB ( readlink ()
+first appeared in 4.2BSD),
POSIX.1-2001.
.SH NOTES
In versions of glibc up to and including glibc 2.4, the return type of
Nowadays, the return type is declared as
.IR ssize_t ,
as (newly) required in POSIX.1-2001.
-.SH "SEE ALSO"
+
+Using a statically sized buffer might not provide enough room for the
+symbolic link contents.
+The required size for the buffer can be obtained from the
+.I stat.st_size
+value returned by a call to
+.BR lstat (2)
+on the link.
+However, the number of bytes written by
+.BR readlink ()
+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 ()
+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.
+.SH EXAMPLE
+The following program allocates the buffer needed by
+.BR readlink ()
+dynamically from the information provided by
+.BR lstat (),
+making sure there's no race condition between the calls.
+.nf
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ char *linkname;
+ ssize_t r;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <pathname>\\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (lstat(argv[1], &sb) == \-1) {
+ perror("lstat");
+ exit(EXIT_FAILURE);
+ }
+
+ linkname = malloc(sb.st_size + 1);
+ if (linkname == NULL) {
+ fprintf(stderr, "insufficient memory\\n");
+ exit(EXIT_FAILURE);
+ }
+
+ r = readlink(argv[1], linkname, sb.st_size + 1);
+
+ if (r < 0) {
+ perror("lstat");
+ exit(EXIT_FAILURE);
+ }
+
+ if (r > sb.st_size) {
+ fprintf(stderr, "symlink increased in size "
+ "between lstat() and readlink()\\n");
+ exit(EXIT_FAILURE);
+ }
+
+ linkname[sb.st_size] = \(aq\\0\(aq;
+
+ printf("\(aq%s\(aq points to \(aq%s\(aq\\n", argv[1], linkname);
+
+ exit(EXIT_SUCCESS);
+}
+.fi
+.SH SEE ALSO
+.BR readlink (1),
.BR lstat (2),
.BR readlinkat (2),
.BR stat (2),