readlink.2: Make example program handle links that report a size of zero

Some "magic" symlinks created by the kernel (e.g., those under
/proc and /sys) report 'st_size' as zero. Modify the example
program to handle that possibility.

Reported-by: Ursache Vladimir <f35f22fan@gmail.com>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Michael Kerrisk 2016-08-20 15:27:13 +12:00
parent e9979dff7c
commit cc6e4bf0cf
1 changed files with 24 additions and 13 deletions

View File

@ -277,11 +277,16 @@ The following program allocates the buffer needed by
.BR readlink ()
dynamically from the information provided by
.BR lstat (2),
making sure there's no race condition between the calls.
falling back to a buffer of size
.BR PATH_MAX
in cases where
.BR lstat (2)
reports a size of zero.
.nf
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -291,7 +296,7 @@ main(int argc, char *argv[])
{
struct stat sb;
char *linkname;
ssize_t r;
ssize_t r, bufsiz;
if (argc != 2) {
fprintf(stderr, "Usage: %s <pathname>\\n", argv[0]);
@ -303,31 +308,37 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
linkname = malloc(sb.st_size + 1);
bufsiz = sb.st_size + 1;
/* Some magic symlinks under (for example) /proc and /sys
report \(aqst_size\(aq as zero. In that case, take PATH_MAX as
a "good enough" estimate */
if (sb.st_size == 0)
bufsiz = PATH_MAX;
printf("%zd\\n", bufsiz);
linkname = malloc(bufsiz);
if (linkname == NULL) {
fprintf(stderr, "insufficient memory\\n");
perror("malloc");
exit(EXIT_FAILURE);
}
r = readlink(argv[1], linkname, sb.st_size + 1);
r = readlink(argv[1], linkname, bufsiz);
if (r == \-1) {
perror("readlink");
exit(EXIT_FAILURE);
}
if (r > sb.st_size) {
fprintf(stderr, "symlink increased in size "
"between lstat() and readlink()\\n");
exit(EXIT_FAILURE);
}
linkname[r] = \(aq\\0\(aq;
printf("\(aq%s\(aq points to \(aq%s\(aq\\n", argv[1], linkname);
free(linkname);
if (r == bufsiz)
printf("(Returned buffer may have been truncated)\\n");
free(linkname);
exit(EXIT_SUCCESS);
}
.fi