vsh@etnibsd.UUCP (Steve Harris) (10/18/90)
Here is a perl script to trace symbolic links.
On our network, with all its NFS mount points and symlinks to get from
one place to another, a file path often has several symlinks in it.
"ls -l" will tell you if the final component is a symlink, but not if
any of the internal pathname components are, nor will it tell you if
the thing pointed to is itself a symlink. Slinky gives you all this info.
It's also my first script to use splice. Neat stuff!
Any suggestions/improvements/bug-fixes welcome.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- cut here =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# slinky.pl
# This archive created: Wed Oct 17 14:09:58 1990
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'slinky.pl'" '(2968 characters)'
if test -f 'slinky.pl'
then
echo shar: "will not over-write existing file 'slinky.pl'"
else
sed 's/^ X//' << \SHAR_EOF > 'slinky.pl'
X#!/usr/bin/perl
X
X########################################################################
X#
X# slinky.pl -- a symbolic link walker
X#
X# For each file name on the command line, this script will resolve
X# all symbolic links in the path. If -v (verbose) option, each step
X# of the symlink resolution will be displayed. Uses splice statement.
X#
X# outline of program (for a single path):
X#
X# split the path into array @path
X# set initial $offset to 1
X# loop: while (not too many links) {
X# join the first [0..$offset] components into $path
X# if ($path is a link) {
X# read the link into $link
X# if ($link is absolute) {
X# splice $link into start of @path
X# set $offset to 1 (re-start at beginning of path)
X# } else {
X# splice $link into middle of @path
X# }
X# } elsif ($path exists) {
X# increment $offset
X# } else {
X# set $notexist flag and break out of loop
X# }
X# }
X#
X########################################################################
X
X
X# setup program path and name, and usage strings
X@prog = split(/\//, $0);
X$prog = $prog[$#prog];
X$ustr = "usage: $prog [-Uv] file...\n";
X$Ustr =<<EOF;
Xwhere
X -v verbose (show each step of symlink resolution)
X -U usage (show this message)
XEOF
X
Xsub usage {
X print STDERR $ustr;
X print STDERR $Ustr if $_[0];
X exit 1;
X}
X
Xwhile ($_ = $ARGV[0], /^-/) {
X shift;
X if ($_ eq '--') { last; }
X if (/v/) { $verbose++; next; }
X if (/U/) { &usage(1); }
X &usage();
X}
X
X&usage() if $#ARGV < 0;
X
X$maxlinks = 32;
Xwhile ($#ARGV >= 0) {
X $_ = shift;
X s!^!./! unless m!^\.{0,2}/!; # relative pathname: start with "./"
X print "$_:\n" if $verbose;
X @path = split(/\//, $_);
X $notexist = 0;
X $offset = 1;
X for ($nlinks=0; $nlinks<$maxlinks; ) {
X last if $offset > $#path; # done???
X $path = join('/', @path[0..$offset]); # get path head
X if ( -l $path ) { # it's a link:
X $nlinks++;
X printf "%5d:\t", $nlinks if $verbose;
X &printit($offset-1, $offset) if $verbose;
X print " -> " if $verbose;
X $link = readlink($path); # get the link
X @tmp = split(/\//, $link);
X if ($link =~ m!^/!) {
X # link is absolute: replace @path head
X splice(@path,0,$offset+1,@tmp);
X &printit(0,$#tmp,1) if $verbose;
X $offset = 1; # and start at top
X } else {
X # link is relative: replace @path middle
X splice(@path,$offset,1,@tmp);
X &printit($offset-1,$offset+$#tmp) if $verbose;
X }
X print "\n" if $verbose;
X } elsif ( -e $path ) { # not a link
X $offset++; # do next component of @path
X } else {
X $notexist = 1; # does not exist
X last;
X }
X }
X if ($nlinks >= $maxlinks) {
X die "tracelinks: too many links, aborted";
X }
X print "$_";
X print " -> ", join('/',@path) if $nlinks;
X print " (does not exist)" if $notexist;
X print "\n";
X print "\n" if $verbose;
X}
X
Xsub printit {
X local($d1,$d2,$abs) = @_;
X if ($abs) {
X print "{/";
X } else {
X print join('/', @path[0..$d1]);
X print "/{";
X }
X print join('/', @path[$d1+1..$d2]), "}";
X print "/", join('/', @path[$d2+1..$#path]) if $d2 < $#path;
X}
SHAR_EOF
if test 2968 -ne "`wc -c < 'slinky.pl'`"
then
echo shar: "error transmitting 'slinky.pl'" '(should have been 2968 characters)'
fi
fi
exit 0
# End of shell archive
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- cut here =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--
Steve Harris - Eaton Corp. - Beverly, MA - uunet!etnibsd!vsh