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;