realpath(3) on a symlink that points to a non-existent path returns
that path (but also sets errno), rather than returning NULL and
setting errno. This is inconsistent with at least Linux, FreeBSD,
and macOS.
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main()
{
char resolved[1024];
char *ret;
unlink("/tmp/link");
unlink("/tmp/nonexistent");
symlink("/tmp/link", "/tmp/nonexistent");
ret = realpath("/tmp/link", resolved);
if (ret == NULL)
printf("realpath failed: %s\n", strerror(errno));
else
printf("resolved realpath of %s (returned %s), errno is %d\n",
resolved, ret, errno);
return (0);
}
Should print:
realpath failed: No such file or directory
But prints:
resolved realpath of /tmp/link (returned /tmp/link), errno is 2
This makes it fall through to the error case (in case any memory
needs to be freed) and return NULL.
Index: lib/libc/stdlib/realpath.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/realpath.c,v
retrieving revision 1.22
diff -u -p -u -p -r1.22 realpath.c
--- lib/libc/stdlib/realpath.c 24 Dec 2017 01:50:50 -0000 1.22
+++ lib/libc/stdlib/realpath.c 28 Jun 2018 02:24:37 -0000
@@ -163,10 +163,8 @@ realpath(const char *path, char *resolve
/* not a symlink, continue to next component */
continue;
case ENOENT:
- if (p == NULL) {
+ if (p == NULL)
errno = serrno;
- return (resolved);
- }
/* FALLTHROUGH */
default:
goto err;