From cc6e4bf0cfd6cd3a4cc5484984f8987b7edfb43f Mon Sep 17 00:00:00 2001 From: Michael Kerrisk Date: Sat, 20 Aug 2016 15:27:13 +1200 Subject: [PATCH] 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 Signed-off-by: Michael Kerrisk --- man2/readlink.2 | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/man2/readlink.2 b/man2/readlink.2 index c64c630f6..97e79f3fe 100644 --- a/man2/readlink.2 +++ b/man2/readlink.2 @@ -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 #include +#include #include #include #include @@ -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 \\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