2

I would like a version of "readlink -f" that provides a trace of every individual symlink resolution it performs. Something like:

$ linktrace /usr/lib64/sendmail
/usr/lib64 -> lib
/usr/lib/sendmail -> ../sbin/sendmail
/usr/sbin/sendmail
$ 

I know I have used this utility in the past, on linux, and also remember at the time thinking "the name of this tool is completely unintuitive and I will forget it". Well, that day has arrived.

Ben Jackson
  • 78,375
  • 8
  • 86
  • 141
jonrock
  • 119
  • 2
  • 6
  • Not sure if this is what you're asking for, but there's a libc function `realpath` and a GNU tool of the same name. – asveikau Jan 08 '11 at 05:44

3 Answers3

1

NOBODY WINS. The correct answer is "namei".

jonrock
  • 119
  • 2
  • 6
0

This Serverfault answer (in Bash) may be helpful (although it does not claim to be handling all edge cases).

Community
  • 1
  • 1
ChristopheD
  • 100,699
  • 26
  • 154
  • 173
  • Similar to Ben Jackson's attempt, these scripts only resolve the last symlink in the path, and not any "directory-level" symlinks earlier. "chain /usr/lib64/sendmail" prints only "/usr/lib64/sendmail -> ../sbin/sendmail" which is not enough. – jonrock Jan 08 '11 at 00:10
0

Code golf anyone?

#!/usr/bin/perl

use File::Spec;
my $g;
my $f = shift;
while (1) {
    print $f;
    $g = readlink($f);
    last unless defined $g;
    printf " -> %s\n", $g;
    $f =~ s,/[^/]*$,,;
    $f = File::Spec->rel2abs($g, $f);
}
print "\n";

Ok, how about this:

#!/usr/bin/perl

use File::Spec;

sub r {
    my ($p, $s) = @_;
    my $l = readlink $p;
    if ($l) {
        printf "%s -> %s\n", $p, $l;
        $p =~ s,/[^/]*$,,;
        r("",File::Spec->rel2abs($l,$p) . $s)
    } else {
        $s =~ s!^(/?[^/]+)(.*)! r($p.$1, $2) !e;
    }
}
r("",shift);

The output is not quite as described but it's understandable. And dig that craaazy recursive executable regexp substitution!

Ben Jackson
  • 78,375
  • 8
  • 86
  • 141
  • Doesn't handle the /usr/lib64 -> /usr/lib step. – jonrock Jan 07 '11 at 23:18
  • I specifically added code (rel2abs) to handle that case and tested it. Not sure what you mean... – Ben Jackson Jan 07 '11 at 23:49
  • /usr/lib64 is also a symlink. It points to /usr/lib. It needs to be resolved as part of resolving any path beginning with it. Your script resolves the end symlink only. The final result of "linktrace.BenJ /usr/lib64/sendmail" is "/usr/lib64/../sbin/sendmail" which is not sufficient. – jonrock Jan 08 '11 at 00:04
  • On most systems, `/usr/lib64` is not a symlink, though. (Yes, there are some distros around that do this weird stuff. According to https://features.opensuse.org/308372 though, that's against standards.) – user562374 Jan 08 '11 at 00:55