Page MenuHomeFreeBSD

readlink: Standalone implementation
Needs ReviewPublic

Authored by des on May 2 2026, 6:54 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Jun 9, 6:01 AM
Unknown Object (File)
Fri, Jun 5, 12:12 AM
Unknown Object (File)
Thu, Jun 4, 10:51 PM
Unknown Object (File)
Sun, May 31, 1:43 AM
Unknown Object (File)
Sat, May 30, 6:55 AM
Unknown Object (File)
May 17 2026, 10:31 AM
Unknown Object (File)
May 17 2026, 7:23 AM
Unknown Object (File)
May 16 2026, 10:32 PM
Subscribers

Details

Reviewers
kevans
markj
Summary

Although readlink(1) may seem like a subset of stat(1), it is such a
small subset that the added complexity of supporting two commands in a
single codebase far outweighs the cost of duplicating what little code
they have in common. This implementation is also much closer to POSIX
conformance than the previous one.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 72732
Build 69615: arc lint + arc unit

Event Timeline

expand notlink test case

usr.bin/readlink/readlink.c
16
52

The man page says this should "print the canonical path of the target, even if the final component of the resolved path does not exist," but:

$ ls /foo
ls: /foo: No such file or directory
$ readlink -f /foo/bar/baz
/foo
usr.bin/stat/stat.c
162

Extra newline

168
des marked 3 inline comments as done.May 5 2026, 7:45 PM
des added inline comments.
usr.bin/readlink/readlink.c
52

I realize this is incorrect, but it is not a regression as the current implementation has the exact same bug. Fixing it is non-trivial.

usr.bin/readlink/readlink.c
52

The current implementation's behaviour is different though:

$ ls /foo
ls: /foo: No such file or directory
$ readlink -f /foo/bar/baz
/foo
$ echo $?
0

vs. the current behaviour on main:

$ ls /foo
ls: /foo: No such file or directory
$ readlink -f /foo/bar/baz
$ echo $?
1
usr.bin/readlink/readlink.c
52

They are both supposed to print an error message and return a non-zero exit code, but that requires determining which component failed, which essentially means implementing at least part of realpath(3) ourselves.

usr.bin/readlink/readlink.c
52

Uh sorry I was thinking of a different test case than what you are showing here. This can be fixed with an lstat(2).