Score:0

realpath API returns error 22(Invalid arg) or 38(function not implemented) on latest Ubuntu 21.04 & other latest linux flavours

us flag
sachin@sachin:~$ cat 1.c
#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
void main(void) {
    char *buf=NULL; 
    
    char *res = realpath("./new-CDM/dummy.c", buf);
    
    printf("result = %s",res);
    printf("\nerrno = %d\n",errno);
    printf("\nBuf = %s\n",buf);
}
sachin@sachin:~$ gcc 1.c
sachin@sachin:~$ ./a.out 
result = /home/sachin/new-CDM/dummy.c
errno = 22

Buf = (null)

The same program when it ran on Ubuntu 18.04 or 20.04 gives no error.

Score:0
cn flag

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.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.