NetBSD Problem Report #47333
From www@NetBSD.org Sat Dec 15 15:20:55 2012
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
by www.NetBSD.org (Postfix) with ESMTP id 9BBBC63E529
for <gnats-bugs@gnats.NetBSD.org>; Sat, 15 Dec 2012 15:20:55 +0000 (UTC)
Message-Id: <20121215152054.AA92C63E529@www.NetBSD.org>
Date: Sat, 15 Dec 2012 15:20:54 +0000 (UTC)
From: tobiasu@tmux.org
Reply-To: tobiasu@tmux.org
To: gnats-bugs@NetBSD.org
Subject: stat -L undocumented behavior
X-Send-Pr-Version: www-1.0
>Number: 47333
>Category: bin
>Synopsis: stat -L undocumented behavior
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Dec 15 15:25:01 +0000 2012
>Last-Modified: Sat May 03 21:05:01 +0000 2025
>Originator: Tobias Ulmer
>Release:
>Organization:
>Environment:
>Description:
"stat -L" claims to "Use stat(2) instead of lstat(2). The information reported by stat will refer to the target of file, if file is a symbolic link, and not to file itself."
This is fine, and could for example be used to detect broken symlinks. Except it's not what it does. In case of a broken symlink it will fall back to lstat(2) and return the symlink info.
The only way to figure this out would be to compare the output of stat (without -L) or realize that symlinks can't show up with "stat -L" - and it must be broken (which requires one to be well caffeinated!).
The change was introduced quite some time ago:
http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/stat/stat.c?only_with_tag=MAIN#rev1.18
I argue that this should be reverted. Going by the very explicit documentation, the code is in error. Aside from that, stat(1) seems to be a designed as a simple scriptable wrapper around stat(2), not a higher-level tool like find(1) with all sorts of smarts. It makes scripting harder, because you either don't want to hear about symlinks at all, or you are interested in broken symlinks and would like to do something based on that information.
So, what does everyone else do? GNU stat prints an error message (-L is one of the few "standard" options). FreeBSD and OpenBSD use NetBSD's stat.
>How-To-Repeat:
ln -s doesnotexist foo
stat -L foo
<stat should print errno and return != 0>
>Fix:
Revert http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.bin/stat/stat.c.diff?r1=1.17&r2=1.18&only_with_tag=MAIN
>Audit-Trail:
From: David Laight <david@l8s.co.uk>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 15 Dec 2012 16:43:47 +0000
On Sat, Dec 15, 2012 at 03:25:01PM +0000, tobiasu@tmux.org wrote:
> >Number: 47333
> >Category: bin
> >Synopsis: stat -L undocumented behavior
...
> "stat -L" claims to "Use stat(2) instead of lstat(2).
> The information reported by stat will refer to the target of file,
> if file is a symbolic link, and not to file itself."
>
> This is fine, and could for example be used to detect broken symlinks.
> Except it's not what it does. In case of a broken symlink it will fall
> back to lstat(2) and return the symlink info.
So you can detect that by noticing that the output of 'stat -L' is
still a symlink.
The man page needs fixing.
David
--
David Laight: david@l8s.co.uk
From: Tobias Ulmer <tobiasu@tmux.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 15 Dec 2012 19:13:17 +0100
On Sat, Dec 15, 2012 at 04:30:13PM +0000, David Laight wrote:
> The following reply was made to PR bin/47333; it has been noted by GNATS.
>
> From: David Laight <david@l8s.co.uk>
> To: gnats-bugs@NetBSD.org
> Cc:
> Subject: Re: bin/47333: stat -L undocumented behavior
> Date: Sat, 15 Dec 2012 16:43:47 +0000
>
> On Sat, Dec 15, 2012 at 03:25:01PM +0000, tobiasu@tmux.org wrote:
> > >Number: 47333
> > >Category: bin
> > >Synopsis: stat -L undocumented behavior
> ...
> > "stat -L" claims to "Use stat(2) instead of lstat(2).
> > The information reported by stat will refer to the target of file,
> > if file is a symbolic link, and not to file itself."
> >
> > This is fine, and could for example be used to detect broken symlinks.
> > Except it's not what it does. In case of a broken symlink it will fall
> > back to lstat(2) and return the symlink info.
>
> So you can detect that by noticing that the output of 'stat -L' is
> still a symlink.
>
> The man page needs fixing.
Yes, that is easy. Yes one can hack around it, but the whole point of -L
is to use stat(2) - not lstat(2), right? Also why be gratuitously
incompatible with GNU stat? Is there an actual use case?
Once it's documented, it would be very hard to remove again. For now
it's simply a bug.
>
> David
>
> --
> David Laight: david@l8s.co.uk
>
From: David Holland <dholland-bugs@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 15 Dec 2012 20:02:35 +0000
On Sat, Dec 15, 2012 at 04:30:13PM +0000, David Laight wrote:
> On Sat, Dec 15, 2012 at 03:25:01PM +0000, tobiasu@tmux.org wrote:
> > >Number: 47333
> > >Category: bin
> > >Synopsis: stat -L undocumented behavior
> ...
> > "stat -L" claims to "Use stat(2) instead of lstat(2).
> > The information reported by stat will refer to the target of file,
> > if file is a symbolic link, and not to file itself."
> >
> > This is fine, and could for example be used to detect broken symlinks.
> > Except it's not what it does. In case of a broken symlink it will fall
> > back to lstat(2) and return the symlink info.
>
> So you can detect that by noticing that the output of 'stat -L' is
> still a symlink.
>
> The man page needs fixing.
Please check the standards (since this is where this program came
from, it isn't either native or historical) before proposing things
like this.
--
David A. Holland
dholland@netbsd.org
From: Tobias Ulmer <tobiasu@tmux.org>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 15 Dec 2012 21:56:37 +0100
On Sat, Dec 15, 2012 at 08:05:02PM +0000, David Holland wrote:
> The following reply was made to PR bin/47333; it has been noted by GNATS.
>
> From: David Holland <dholland-bugs@netbsd.org>
> To: gnats-bugs@NetBSD.org
> Cc:
> Subject: Re: bin/47333: stat -L undocumented behavior
> Date: Sat, 15 Dec 2012 20:02:35 +0000
>
> On Sat, Dec 15, 2012 at 04:30:13PM +0000, David Laight wrote:
> > On Sat, Dec 15, 2012 at 03:25:01PM +0000, tobiasu@tmux.org wrote:
> > > >Number: 47333
> > > >Category: bin
> > > >Synopsis: stat -L undocumented behavior
> > ...
> > > "stat -L" claims to "Use stat(2) instead of lstat(2).
> > > The information reported by stat will refer to the target of file,
> > > if file is a symbolic link, and not to file itself."
> > >
> > > This is fine, and could for example be used to detect broken symlinks.
> > > Except it's not what it does. In case of a broken symlink it will fall
> > > back to lstat(2) and return the symlink info.
> >
> > So you can detect that by noticing that the output of 'stat -L' is
> > still a symlink.
> >
> > The man page needs fixing.
>
> Please check the standards (since this is where this program came
> from, it isn't either native or historical) before proposing things
> like this.
After a bit more digging, it turns out that the original stat was
devised by Michael Meskes. It was later integrated into coreutils.
See here for history:
http://fossies.org/linux/misc/stat-3.3.tar.gz:a/stat-3.3/README
>
> --
> David A. Holland
> dholland@netbsd.org
>
From: "Jeremy C. Reed" <reed@reedmedia.net>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Fri, 2 May 2025 19:16:14 +0000 (UTC)
This ticket is over a decade old. But the change is over two decades
so maybe we should just document it.
I don't see any Unix spec for this. But here is example from Linux
coreutils:
reed@ns1:~$ ln -s doesnotexist linktest
reed@ns1:~$ stat linktest
File: linktest -> doesnotexist
Size: 12 Blocks: 0 IO Block: 4096 symbolic link
Device: 8,1 Inode: 129555 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1000/ reed) Gid: ( 1000/ reed)
Access: 2025-05-02 21:09:33.291973078 +0200
Modify: 2025-05-02 21:09:29.739973078 +0200
Change: 2025-05-02 21:09:29.739973078 +0200
Birth: 2025-05-02 21:09:29.739973078 +0200
reed@ns1:~$ stat -L linktest
stat: cannot statx 'linktest': No such file or directory
reed@ns1:~$ ls -l linktest
lrwxrwxrwx 1 reed reed 12 May 2 21:09 linktest -> doesnotexist
From: Robert Elz <kre@munnari.OZ.AU>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 03 May 2025 17:55:11 +0700
Date: Fri, 2 May 2025 19:20:01 +0000 (UTC)
From: "Jeremy C. Reed via gnats" <gnats-admin@NetBSD.org>
Message-ID: <20250502192001.4F7D71A923C@mollari.NetBSD.org>
| This ticket is over a decade old. But the change is over two decades
| so maybe we should just document it.
That's what we should do, making it return an error makes it
harder to tell the difference between
stat -L doesnotexist
and
stat -L linktest
(using the names from the test).
That is, in this example:
reed@ns1:~$ stat -L linktest
stat: cannot statx 'linktest': No such file or directory
is it linktest that does not exist, or the target of linktest?
The only way to know is to do another command.
The test for a symlink which points to non-existent files is just
test "$(stat -Lf%t linkname)" = @
That's simple, easy, and unambiguous, and only requires a single
command (regardless of what "linkname" might happen to be).
kre
From: Robert Elz <kre@munnari.OZ.AU>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/47333: stat -L undocumented behavior
Date: Sat, 03 May 2025 19:55:44 +0700
Date: Sat, 3 May 2025 11:00:04 +0000 (UTC)
From: "Robert Elz via gnats" <gnats-admin@NetBSD.org>
Message-ID: <20250503110004.84B551A923E@mollari.NetBSD.org>
| test "$(stat -Lf%t linkname)" = @
Oops, transcription error between test and e-mail (I didn't cut&paste
that one), I meant:
test "$(stat -Lf%T linkname)" = @
kre
From: "Robert Elz" <kre@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/47333 CVS commit: src/usr.bin/stat
Date: Sat, 3 May 2025 21:00:58 +0000
Module Name: src
Committed By: kre
Date: Sat May 3 21:00:58 UTC 2025
Modified Files:
src/usr.bin/stat: stat.1
Log Message:
PR bin/47333
Note that -L will fall back to use lstat() if the stat() requested
returns ENOENT (if the following lstat() fails, the ENOENT from
the lstat() is returned - that generally indicates that the original
ENOENT came from the filename passed to stat() rather than the
value of the symlink. (The man page doesn't say all of that.)
If "stat -L name" returns data from a symlink (eg: if -f %T is @)
then name must refer to a symlink which points to nothing.
(The man page does say that.)
To generate a diff of this commit:
cvs rdiff -u -r1.47 -r1.48 src/usr.bin/stat/stat.1
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2025
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.