How to find what symlink points to?

Mel Flynn mel.flynn+fbsd.questions at mailing.thruhere.net
Tue Jul 28 05:30:04 UTC 2009


On Monday 27 July 2009 20:54:51 Unga wrote:

> Thanks everybody for valuable replies. In fact, I also used readlink(2) but
> fed the symlink path directly from dirent, which was partial, readlink(2)
> requires full path.

Nope it doesn't. It's the classical "opendir does not chdir" problem. 
readlink(2) requires a path that resolves from the current working directory 
of the program. If you opendir(3) /dev and are in /, then dirent->d_name is 
not valid for your cwd. Either you have to chdir or prepend the path given to 
opendir to dirent->d_name.

% ./rl /dev/stdout
stdout => fd/1

See the diff on previous rl.c below.

-- 
Mel

--- rl.c.orig   2009-07-27 09:19:58.000000000 -0800
+++ rl.c        2009-07-27 21:25:48.000000000 -0800
@@ -9,13 +9,31 @@

 int main(int argc, char **argv)
 {
-       char path[MAXPATHLEN], buf[MAXPATHLEN+1];
+       char path[MAXPATHLEN], buf[MAXPATHLEN+1], *ptr;
        ssize_t res;

        if( argc != 2 )
                exit(67);

        (void)strlcpy(path, argv[1], sizeof(path));
+       ptr = strrchr(path, '/');
+       if( ptr != NULL )
+       {
+               char *tmp = ptr + 1;
+
+               if( ptr == path )
+               {
+                       if( strlen(path) == 1 )
+                               errx(67, "/ can never be a symlink");
+                       chdir("/");
+               }
+               else
+               {
+                       *ptr = '\0';
+                       (void)chdir(path);
+               }
+               (void)strlcpy(path, tmp, sizeof(path));
+       }
        res = readlink(path, buf, sizeof(buf));
        if( res < 0 )
                err(EXIT_FAILURE, "readlink()");



More information about the freebsd-questions mailing list