There's a reason for this. To find out what a link "really is" requires making a system call, readlink. In most circumstances, open (the system call used to open a file) is the only call that does this automatically. I don't know of a command line utility this does the readlink. A long time ago, we needed something to do this - here is a small utility to do that. This could be written in other languages, it happens to be C.
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <stddef.h>
#include <pwd.h>
#define ck_null(x) if((x)==NULL){perror(""); exit(EXIT_FAILURE);}
#define ck_ltz(x) if((x)==(-1)){perror(""); exit(EXIT_FAILURE);}
#ifndef PATH_MAX
#define PATH_MAX 255
#endif
#define DEPTH 16
size_t signal_arglen =0;
char signal_buffer[PATH_MAX+1]={0x0};
void sig_int(int signo)
{
write(STDERR_FILENO,signal_buffer,signal_arglen);
exit(EXIT_FAILURE);
}
void expand_path(char *path)
{
char *prepend=malloc(2*PATH_MAX);
char *ptr=path;
ck_null(prepend);
if(memcmp(path,"~/",2)==0 || memcmp(path,"./",2)==0)
{
struct passwd *pw=NULL;
char tmp[PATH_MAX+1]={0x0};
ptr++;
switch(*path)
{
case '.':
sprintf(prepend,"%s%s", getcwd(tmp,PATH_MAX), ptr);
break;
case '~': /* not normally executed ~/ expanded by shell */
pw=getpwuid(getuid() );
sprintf(prepend,"%s%s", pw->pw_dir, ptr);
break;
default:
break;
}
strcpy(path,prepend);
}
free(prepend);
}
void get_link_info(char *path)
{
char buf[PATH_MAX+1]={0x0};
ssize_t buflen=readlink(path,buf,PATH_MAX);
if(buflen>0)
{
char *p=strrchr(path,'/');
if(p==NULL)
p=path;
buf[buflen]=0x0;
strcpy(p,buf);
}
}
void recurse_path(char elements[][PATH_MAX],char *path)
{
int i=0;
char *p=path;
char *q=NULL;
if(*p=='/') i=(-1);
if(strchr(path,'/')==NULL)
{
strcpy(elements[0],path);
}
else
{
for(p=path;*p;p++)
{
if(*p=='/')
q=elements[++i];
*q++=*p;
}
}
}
char *get_path_elements(char *dest, char *path)
{
char *working=calloc(1,PATH_MAX*2);
int i=0;
char elements[DEPTH][PATH_MAX]={0x0};
ck_null(working);
recurse_path(elements,path);
while(*elements)
{
strcat(working,elements[i++]);
get_link_info(working);
}
strcpy(dest,working);
free(working);
return dest;
}
int main(int argc, char *argv[])
{
char path[PATH_MAX*2]={0x0};
char working_path[PATH_MAX*2]={0x0};
int i=1;
char *p=argv;
sprintf(signal_buffer,"%s interrupt\n",argv[0]);
signal_arglen=strlen(signal_buffer);
signal(SIGINT,sig_int);
if (argc >1)
{
while(*p)
{
strcpy(working_path,p);
expand_path(working_path);
printf("%s\n",
get_path_elements(path, working_path));
i++;
p=argv;
}
}
else
{
while(fgets(working_path,sizeof(working_path),stdin)!=NULL)
{
expand_path(working_path);
printf("%s\n",
get_path_elements(path, working_path));
}
}
return 0;
}