#! /usr/local/bin/perl # output AFS file permissions as table (Unix ls style) # Usage: als [-an] [-c ] [-w ] [] # # Options: # -a list all subdirectories of , even if access control lists # are identical # -n don't list access control lists, just directory names, # implies -a option # -c use columns with user or group names on each sublist, # -c 0 : make one single list with all user and group names # -w if -c not specified, compute number of columns from of # output; default 79 # # Note that only a single parameter is allowed. sub find { local ($dir, $txt) = @_; local ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks); local ($pref, $file, @files); push (@dir, $dir); push (@txt, $txt); $pref = length ($txt); if ($pref > $maxlen) { $maxlen = $pref; }; $txt =~ /^( *)[^ ]/; $pref = $1; ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat ("$dir"); if ($in_tree) { return if (($mode & 0170000) != 040000) || ! ($ino & 1); # not a directory (may be a symbolic link or a volume mount point) }; $in_tree = 1; if (! opendir (DIR, $dir)) { $permit[$#dir] = '*??*'; return; }; @files = sort readdir (DIR); closedir (DIR); foreach $file (@files) { if ($file !~ /^\.\.?$/) { ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat ("$dir/$file"); if (($mode & 0170000) == 040000) { # directory &find ("$dir/$file", "$pref $file"); }; }; }; } sub abbrev { local ($prin) = $_[0]; local ($sugg, $old); if (! $abbrev{$prin}) { if ($prin =~ /(^|:)([^:]*)$/) { $sugg = $2; if (length ($sugg) < 5) { $sugg = substr (" $sugg", -4, 4); } elsif ($sugg =~ /^[a-z]+$/) { $sugg = substr ($sugg, 0, 4); } else { $sugg = substr ($sugg, -4, 4); }; } else { $sugg = 'user'; # always wrong }; foreach $old (values %abbrev) { if ($sugg eq $old) { $invent++; $sugg = sprintf ("~%3.3d", $invent); last; }; }; $abbrev{$prin} = $sugg; }; $count{$prin}++; return $abbrev{$prin}; }; # Define default abbreviations. @unixuser = getpwuid ($<); $invent = 0; $abbrev{$unixuser[0]} = 'user'; $abbrev{'system:anyuser'} = ' any'; $abbrev{'system:authuser'} = 'auth'; # Read command options. $wd = `pwd`; chop $wd; foreach $it (@ARGV) { if ($noMORE) { die "too many parameters"; }; if ($cORw) { if ($it =~ /^\d+$/) { if ($cORw eq 'c') { $cPar = $it; } else { $wPar = $it; }; undef $cORw; } else { die "illegal value for -$cORw option: $it"; }; next; }; if ($it !~ /^-/) { $arg = $it; $noMORE = 1; next; }; while ($it =~ /^-./) { if ($it =~ /^-a/) { $it = '-' . $'; $aPar = 1; } elsif ($it =~ /^-n/) { $it = '-' . $'; $nPar = 1; $aPar = 1; } elsif ($it =~ /^-([cw])(\d*)$/) { $cORw = $1; $val = $2; if ($val ne '') { if ($cORw eq 'c') { $cPar = $val; } else { $wPar = $val; }; undef $cORw; }; $it = ''; } else { die "illegal option: $it"; }; }; }; if ($cORw) { die "-$cORw option: value missing"; }; if (!$wPar) { $wPar = 79; }; if (!$arg || $arg eq '.') { $arg = $wd; } elsif ($arg !~ m+^/+) { $arg = "$wd/$arg"; }; # Find all directories. &find ($arg, $arg); # Find permits in directories. foreach $i (0 .. $#dir) { ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = lstat ("$dir[$i]"); if (($mode & 0170000) == 040000) { # directory if ($txt[$i] !~ /^[^ ]/ && ! ($ino & 1)) { # mount point $permit[$i] = '*mp*'; next; } elsif ($nPar) { $permit[$i] = '* *'; next; } elsif ($permit[$i] eq '*??*') { next; }; } elsif (($mode & 0170000) == 0120000) { # symbolic link $permit[$i] = '*ln*'; next; }; open (FSLA, "/usr/bin/fs la \"$dir[$i]\" |"); $norm = 0; undef @res; while () { chop; if (/^Normal rights:/) { $norm = 1; } elsif (/^Negative rights:/) { $norm = 0; } elsif ($norm) { if (/\s*(\S+)\s+([rlidwka]+)$/) { $prin = $1; $right = $2; $r = $l = $w = $a = '-'; if ($right =~ /r/) { $r = 'r'; }; if ($right =~ /l/) { $l = 'l'; }; if ($right =~ /[idwk]/) { $w = 'w'; }; if ($right =~ /a/) { $a = 'a'; }; $prin = &abbrev ($prin); push (@res, "$prin $r$l$w$a"); }; }; }; close (FSLA); $permit[$i] = join (',', @res); }; # Identify directories with equal acls. if (! $aPar) { $id = 1; while ($id < $#txt) { $txt[$id] =~ /^( *)[^ ]/; $pref = $1 . ' '; $lpref = length ($pref); $alleq = 1; $ils = $id; while (substr ($txt[$ils+1], 0, $lpref) eq $pref) { $ils++; if ($permit[$ils] ne $permit[$id]) { undef $alleq; }; }; if ($alleq && $ils != $id) { $txt[$id] = '+' . substr ($txt[$id], 1); splice (@txt, $id+1, $ils-$id); splice (@dir, $id+1, $ils-$id); splice (@permit, $id+1, $ils-$id); }; $id++; }; $maxlen = 0; foreach $it (@txt) { if (length ($it) > $maxlen) { $maxlen = length ($it); }; }; }; # Output list of abbreviations. print "\n"; foreach $key (keys %abbrev) { if ($count{$key}) { $used{$abbrev{$key}} = 1; }; }; $maxpos = 0; foreach $it ('user', ' any', 'auth') { if ($used{$it}) { delete $used{$it}; $pos{$it} = $maxpos; $maxpos += 5; $head .= "$it "; foreach $key (keys %abbrev) { if ($abbrev{$key} eq $it) { print "\t$it = $key\n"; last; }; }; }; }; foreach $it (sort keys %used) { $pos{$it} = $maxpos; $maxpos += 5; $head .= "$it "; foreach $key (keys %abbrev) { if ($abbrev{$key} eq $it) { print "\t$it = $key\n"; last; }; }; }; print "\t*??* = (inaccessible directory)\n\t*ln* = (symbolic link)\n\t*mp* = (volume mount point)\n\t + = (and all subdirectories)\n"; # Compute layout. if ($cPar =~ /^0+$/) { $cPar = 1000000; }; $princs = int ($maxpos / 5); if (! $princs) { $princs = 1; }; if (! $cPar) { $columns = int (($wPar - $maxlen - 1) / 5); if ($columns < 4) { $columns = 4; }; $blocks = int (($princs - 1) / $columns) + 1; $columns = int (($princs - 1) / $blocks) + 1; } else { if ($cPar > 9 && $cPar > $princs) { $columns = $princs; } else { $columns = $cPar; }; $blocks = int (($princs - 1) / $columns) + 1; }; $locmaxpos = $columns * 5; foreach $b (1 .. $columns) { $empty .= '---- '; $blank .= ' '; }; # Output entire list. foreach $b (1 .. $blocks) { $lochead = substr ($head, 0, $locmaxpos); $head = substr ($head, $locmaxpos); print "\n\n$lochead\n\n"; foreach $i (0 .. $#dir) { $line = "$empty $txt[$i]"; if ($permit[$i] =~ /\*/) { substr ($line, 0, $locmaxpos) = $blank; if ($permit[$i] ne '* *') { substr ($line, $locmaxpos-5, 4) = $permit[$i]; }; } else { foreach $p (split (',', $permit[$i])) { $p =~ /^(....) (....)$/; $pos = $pos{$1}; if ($pos < $locmaxpos) { substr ($line, $pos, 4) = $2; }; }; }; print "$line\n"; }; foreach $it (keys %pos) { $pos{$it} -= $locmaxpos; if ($pos{$it} < 0) { $pos{$it} = 1000000; }; }; };