public inbox for linux-man@vger.kernel.org
 help / color / mirror / Atom feed
From: "Michael Kerrisk (man-pages)" <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Ursache Vladimir <f35f22fan-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: readlink() example sometimes fails
Date: Sat, 20 Aug 2016 15:32:41 +1200	[thread overview]
Message-ID: <28d2728c-e43c-dd90-3beb-fac899646ded@gmail.com> (raw)
In-Reply-To: <CAJbVpmwRAi1dEJw=zUtsJLE2RRMGtsjqBJk4x+_KsJGWnoRsMA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

Hello Vladimir,

On 08/18/2016 05:30 PM, Ursache Vladimir wrote:
>  Hi,
> the readlink() example from:
> 
> http://man7.org/linux/man-pages/man2/readlink.2.html
> 
> relies on lstat()'s st_size, but that doesn't work for files contents
> created dynamically by the Linux kernel which often report a zero
> size, for example the link at:
> /sys/block/sda
> 
> the example code will fail because stat.st_size reports zero and you
> try to read (stat.st_size + 1) which will succeed, which will generate
> the error : "symlink increased in size between lstat() and
> readlink()".
> 
> Somewhat related, the same issue is true for reading regular text
> files, e.g: "/proc/filesystems" which will report stat.st_size = 0.
> 
> My quick workaround:
> 
> if (stat.st_size != 0)
>     // work as usual
> else if (file_is_a_link)
>     // malloc 4K of ram and try to readlink() into it
> else if (is_regular_file)
>     // read() into a byte array that grows accordingly
> 
> In case it matters, I'm using Ubuntu 16.04 amd64.

Thanks for this report. I agree that the page needs to be fixed.
I modified the example program to be as follows:

#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
    struct stat sb;
    char *linkname;
    ssize_t r, bufsiz;

    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);
    }

    bufsiz = sb.st_size + 1;

    /* Some magic symlinks under (for example) /proc and /sys
       report 'st_size' 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) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    r = readlink(argv[1], linkname, bufsiz);
    if (r == -1) {
        perror("readlink");
        exit(EXIT_FAILURE);
    }

    linkname[r] = '\0';

    printf("'%s' points to '%s'\n", argv[1], linkname);

    if (r == bufsiz)
        printf("(Returned buffer may have been truncated)\n");

    free(linkname);
    exit(EXIT_SUCCESS);
}

Seem okay?

Cheers,

Michael


-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2016-08-20  3:32 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-18  5:30 readlink() example sometimes fails Ursache Vladimir
     [not found] ` <CAJbVpmwRAi1dEJw=zUtsJLE2RRMGtsjqBJk4x+_KsJGWnoRsMA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-08-20  3:32   ` Michael Kerrisk (man-pages) [this message]
     [not found]     ` <28d2728c-e43c-dd90-3beb-fac899646ded-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-08-20  7:57       ` Ursache Vladimir
     [not found]         ` <CAJbVpmxJWuuO9-z=pavdnQh4ou0piJ72LK-T5fzt2QkJ+WZaAg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-08-26 17:47           ` Ursache Vladimir
     [not found]             ` <CAJbVpmwb1EU5J3jh0wKosQF9pxsS3dhwTaR5g=bzf9OL-Dr=SQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-08-28 20:48               ` Michael Kerrisk (man-pages)
     [not found]                 ` <57aec2e3-be44-2389-46c8-dc62f7d2eefe-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-08-29  8:00                   ` Ursache Vladimir
2016-08-29 15:17                   ` Mats Wichmann
     [not found]                     ` <daf306a0-3e0c-8edb-016d-8e68bac02c79-mBRmNHn34rVzbRFIqnYvSA@public.gmane.org>
2016-08-29 19:04                       ` Michael Kerrisk (man-pages)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=28d2728c-e43c-dd90-3beb-fac899646ded@gmail.com \
    --to=mtk.manpages-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=f35f22fan-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    --cc=linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox