From man 3 realpath
:
If there is no error, realpath() returns a pointer to the resolved_path.
From man 3 errno
:
The value in errno is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno.
Therefore there is no error, and the value of errno
is officially undefined.
The actual value returned is an internal detail which was implemented differently in the past. Currently (21.10), the errno
is left over from realpath
internally trying to follow symbolic links on path components which aren't, just in case.
You can see this best by making dummy.c
be a symbolic link to a file target.c
, and then running strace ./a.out
to trace linux kernel calls, specifically the lines:
readlink("/home/sachin/new-CDM", 0x7ffee6b57960, 1023) = -1 EINVAL (Invalid argument)
readlink("/home/sachin/new-CDM/dummy.c", "target.c", 1023) = 8
readlink("/home/sachin/new-CDM/target.c", 0x7ffee6b57960, 1023) = -1 EINVAL (Invalid argument)
The calls to readlink
with non-symbolic path components failed, and changed errno
to "EINVAL (Invalid argument)".
In the past (20.04), readlink
was only called after an additional check the component was a link with lstat
, therefore preserving the value of errno
.
lstat("/home/sachin/new-CDM", {st_mode=S_IFDIR|0775, st_size=20, ...}) = 0
lstat("/home/sachin/new-CDM/dummy.c", {st_mode=S_IFLNK|0777, st_size=8, ...}) = 0
readlink("/home/sachin/new-CDM/dummy.c", "target.c", 4095) = 8
lstat("/home/sachin/new-CDM/target.c", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
So this change is likely an optimization which has a side-effect on a value only in cases where you are supposed to ignore it.
Incidentally, your printing of buf
here was pointless as it would obviously still be NULL. If this surprises you, it would be worth thinking about why.