readlink.2: Document using st_size to allocate the buffer

Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Guillem Jover 2011-09-20 08:19:52 +02:00 committed by Michael Kerrisk
parent 1e0819c860
commit f91c6bd76f
1 changed files with 68 additions and 1 deletions

View File

@ -35,7 +35,7 @@
.\" Modified Tue Jul 9 23:55:17 1996 by aeb
.\" Modified Fri Jan 24 00:26:00 1997 by aeb
.\"
.TH READLINK 2 2010-09-20 "Linux" "Linux Programmer's Manual"
.TH READLINK 2 2011-04-20 "Linux" "Linux Programmer's Manual"
.SH NAME
readlink \- read value of a symbolic link
.SH SYNOPSIS
@ -69,6 +69,21 @@ does not append a null byte to
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.
Using a statically sized buffer might not give enough room for the
symbolic link contents, which might end up getting truncated. The
needed size for the buffer can be obtained from the symbolic link's
.I stat
structure
.I st_size
field with
.BR lstat (),
but the number of written characters should be checked to make sure the
symbolic link did not change between both calls, and no truncation
happened. This also fixes a common portability problem when using
.I PATH_MAX
for the buffer size, as this is not guaranteed to be defined per POSIX
if the system does not have such limit.
.SH "RETURN VALUE"
On success,
.BR readlink ()
@ -130,6 +145,58 @@ was declared as
Nowadays, the return type is declared as
.IR ssize_t ,
as (newly) required in POSIX.1-2001.
.SH EXAMPLE
The following program allocates the space needed by
.BR readlink ()
dynamically from the information provided by
.BR lstat (),
making sure there's no race condition between both 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);
} else if (r != sb.st_size) {
fprintf(stderr, "symlink changed between lstat and readlink\\n");
exit(EXIT_FAILURE);
}
linkname[sb.st_size] = '\\0';
printf("'%s' points to '%s'\\n", argv[1], linkname);
exit(EXIT_SUCCESS);
}
.fi
.SH "SEE ALSO"
.BR readlink (1),
.BR lstat (2),