Project Home
Project Home
Documents
Documents
Wiki
Wiki
Discussion Forums
Discussions
Project Information
Project Info
Forum Topic - Behavior of readlink() on QNX: (7 Items)
   
Behavior of readlink() on QNX  
Hi,

I've noticed that on QNX one of the possible errnos of readlink() is ENOSYS,
which is returned in case the ResMgr offering the specified path does not support symlinks (e.g. true for /tmp on 
embedded systems, which resides in shmen).

This breaks some apps, which don't expect ENOSYS. I've patched those to treat ENOSYS the same as EINVAL (which means: 
checked path is not a symlink).

Is ENOSYS for readlink() part of POSIX or is this a QNX extension? Would returning EINVAL instead of ENOSYS  break 
anything?


Another thing I've noticed:
When calling readlink() on a path of "." on Linux, it correctly returns EINVAL ("is not a link").
When trying this on QNX (running the app via the IDE), the app runs in /tmp, which is symlinked to /dev/shmem. Calling 
readlink() with path "." here returns ENOENT ("The named file doesn't exist").
Again, not sure what POSIX really says here, but I feel that the QNX readlink() behavior is not what I'd have expected..
.
Using realpath() before readlink() doesn't help as quick fix, since realpath() on /dev/shmem returns ENOENT as well


Greetings,
 Marc
Re: Behavior of readlink() on QNX  
> Hi,
> 
> I've noticed that on QNX one of the possible errnos of readlink() is ENOSYS,
> which is returned in case the ResMgr offering the specified path does not 
> support symlinks (e.g. true for /tmp on embedded systems, which resides in 
> shmen).
> 
> This breaks some apps, which don't expect ENOSYS. I've patched those to treat 
> ENOSYS the same as EINVAL (which means: checked path is not a symlink).
> 
> Is ENOSYS for readlink() part of POSIX or is this a QNX extension? Would 
> returning EINVAL instead of ENOSYS  break anything?

Yes, ENOSYS is a Neutrino extension (resource managers are a Neutrino thing). I looked at the error codes that POSIX 
gives, and none of them really covers the problem of the underlying filesystem not supporting symlinks. Someone else 
might be able to comment further. At the very least, the documentation should say that ENOSYS is an extension.

> 
> 
> Another thing I've noticed:
> When calling readlink() on a path of "." on Linux, it correctly returns EINVAL
>  ("is not a link").
> When trying this on QNX (running the app via the IDE), the app runs in /tmp, 
> which is symlinked to /dev/shmem. Calling readlink() with path "." here 
> returns ENOENT ("The named file doesn't exist").
> Again, not sure what POSIX really says here, but I feel that the QNX readlink(
> ) behavior is not what I'd have expected...
> Using realpath() before readlink() doesn't help as quick fix, since realpath()
>  on /dev/shmem returns ENOENT as well
> 

A RAM "filesystem" doesn't provide "." and ".." directory entries, so you could argue that readlink() is doing the right
 thing (depending on the order that it checks things). If you run your program somewhere other than /dev/shmem, does it 
give EINVAL?

Steve Reid (stever@qnx.com)
Technical Editor
QNX Software Systems 



Re: Behavior of readlink() on QNX  
On Thu, 2009-08-27 at 10:16 -0400, Steve Reid wrote:
> > Is ENOSYS for readlink() part of POSIX or is this a QNX extension? Would 
> > returning EINVAL instead of ENOSYS  break anything?
> 
> Yes, ENOSYS is a Neutrino extension (resource managers are a Neutrino
> thing). I looked at the error codes that POSIX gives, and none of them
> really covers the problem of the underlying filesystem not supporting
> symlinks. Someone else might be able to comment further. At the very
> least, the documentation should say that ENOSYS is an extension.

In general one the safest thing to assume is that the codes defined by
the standard are the minimal subset: any compliant implementation is
free to return others....  (I agree that our documentation should be as
complete as possible, though.)

Regards,
Neil
Re: Behavior of readlink() on QNX  
Neil, I think generally speaking you are right, but in this special case I don't fully agree...

What should an application do when it encounters a return/errno value that it doesn't know? It should log it and 
probably exit, because something is not as expected and this probably means something is awfully wrong.

In this special case, EINVAL is not even an error, it is expected behavior: it happens whenever a path passed to 
readlink() is not a link. ENOSYS means just the same: file system doesn't support symlinks, so of course the file is not
 a symlink.
So ENOSYS needs to be handled the same way as EINVAL, but different from all other errnos that can occur. How does one 
code that without the knowlwedge that EINVAL and ENOSYS practically mean the same on QNX? Exiting on unknown errnos 
would be the wrong behavior, and continuing on unknown errors (hypothetical example: ENULL .. tha path is a NULL 
pointer) would also be wrong.

So what this means is that an #ifdef QNX is required - which is kludgy.

Greetings,
 Marc
Re: Behavior of readlink() on QNX  
On Thu, 2009-08-27 at 11:06 -0400, Marc Roessler wrote:
> Neil, I think generally speaking you are right, but in this special case I don't fully agree...
> 
> What should an application do when it encounters a return/errno value that it doesn't know? It should log it and 
probably exit, because something is not as expected and this probably means something is awfully wrong.
> 
> In this special case, EINVAL is not even an error, it is expected behavior: it happens whenever a path passed to 
readlink() is not a link. ENOSYS means just the same: file system doesn't support symlinks, so of course the file is not
 a symlink.
> So ENOSYS needs to be handled the same way as EINVAL, but different from all other errnos that can occur. How does one
 code that without the knowlwedge that EINVAL and ENOSYS practically mean the same on QNX? Exiting on unknown errnos 
would be the wrong behavior, and continuing on unknown errors (hypothetical example: ENULL .. tha path is a NULL 
pointer) would also be wrong.
> 
> So what this means is that an #ifdef QNX is required - which is kludgy.

My observation was just a general one.  However, I would argue -- again
from a general standpoint -- that if an application needs to perform a
certain way on a particular POSIX implementation, then it must perforce
contain implementation specific code.  Consider the case where two
different implementations attach different semantics to a particular
errno return....

Regards,
Neil

P.S. Welcome to the joys of multi-platform programming ;-) 
Re: Behavior of readlink() on QNX  
OK, considering that the shmem fs doesn't have . and .. entries, the readlink() behavior is indeed correct.

So the real question is whether the shmem RAM fs should have . and .. directory entries. Not being able to create 
directories is one thing... but missing . and .., doesn't this break other things as well? Would "faking"those entries 
without really creating directory support for the RAM/shmem fs break anything?

On the other hand, having real directory support for shmem filesystems also would be nice... Would it be hard to 
implement? Or was this a design decision from the start not to have and directories in shmem?

Thanks & Greetings,
 Marc

RE: Behavior of readlink() on QNX  
I think it's intentional, in order to reduce the amount of code:

 
http://www.qnx.com/developers/docs/6.4.1/neutrino/user_guide/fsystems.ht
ml#RAM


Steve Reid (stever@qnx.com)
Technical Editor
QNX Software Systems