home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- #
- # boss, peon - who works for whom
- #
- # tom christiansen, 25 Oct
- #
- # given a data file with (peon boss) pairs,
- # fetch peons of a given boss, or boss of a
- # given peon boss. recurse all the way with -r,
- # limit depth with -2, -3, etc.
-
-
- $DATA = "/usr/spool/globdata/etc/reports_to";
-
- sub usage {
- print STDERR <<EOM;
- usage: $0 [-$opts] [user ...]
- -# recursion depth
- -r recurse all the way
- -b boss
- -e empl (also -p)
- -a list all
- -s sort
- -v verbose
- -d debug
- -B rebuild databases
- -F db alternate database
- EOM
- exit 2;
- }
-
- MAIN: {
-
- do 'getopts.pl' || die "can't do getopts.pl: " . ($@? $@ : $!);
- $opts = 'vasbBepdr123456789F:';
- &Getopts($opts) || &usage;
-
- if ($opt_r) {
- $maxdepth = 100;
- } else {
- for $i (reverse 1..9) {
- if (eval "defined \$opt_$i") {
- $maxdepth = $i;
- last;
- }
- }
- }
-
- $sort = $opt_s;
- $debug = $opt_d;
- $verbose = $opt_v;
- $listall = $opt_a;
-
- $want = 'boss' if $opt_b;
- $want = 'peon' if $opt_p || $opt_e;
- $rebuild = $opt_B;
-
- if ($0 =~ m#/?boss[^/]*$#) {
- $want = 'boss';
- } elsif ($0 =~ m#/?(empl|peon)[^/]*$#) {
- $want = 'peon';
- } elsif (!$want) {
- warn "$0: neither boss nor empl specified\n";
- &usage;
- }
-
- if ($listall && @ARGV) {
- warn "$0: explicit list conflict with request to list all\n";
- &usage;
- }
-
- $DATA = $opt_F || $ENV{'peersfile'} || $DATA;
-
- &init;
-
- *which = eval "*$want"; # create alias
-
- if ($listall) {
- @ARGV = sort grep (!/ /,keys %which);
- $verbose = 1;
- }
-
- for $target (@ARGV) {
- local(%duplicate);
- if (!defined $boss{$target} && !defined $peon{$target}) {
- warn "$0: $target unknown\n";
- next;
- }
- @list = &traverse($target);
- @list = sort @list if $sort;
- print "$target: " if $verbose;
- print join(' ',@list) if @list;
- print "\n" if $verbose || @list;
- }
-
- exit 0;
- }; # end main
-
- sub traverse {
- local(%seen, @who, $user, @newlist, @tmplist);
-
- $depth++;
-
- @who = @_;
-
- foreach $user (@who) {
- next if $duplicate{$user}++;
-
- @tmplist = split(' ',$which{$user});
- print "$depth $want of $user is <@tmplist>\n"
- if $debug && @tmplist;
-
- push (@tmplist, &traverse(@tmplist)) if $maxdepth > $depth;
- push(@newlist,@tmplist);
- }
-
- print "$depth returning $want of <@who> as <@newlist>\n"
- if $debug && @newlist && @who == 1;
-
- $depth--;
-
- return grep(!$seen{$_}++,@newlist);
- }
-
- sub rebuild {
- warn "$0: rebuilding DB from $DATA\n";
- &opendb('writing');
- %boss = %peon = ();
- open DATA || die "can't open $DATA: $!";
- while (<DATA>) {
- split;
- next if $#_ > 1;
- ($peon, $boss) = @_;
- $peon{$boss} .= ' ' . $peon;
- $boss{$peon} .= ' ' . $boss;
- }
- &closedb;
- }
-
- sub init {
-
- local($data_age, $base, $page);
-
- $data_age = &age($DATA);
- $bage = &age("$DATA.boss.pag");
- $page = &age("$DATA.peon.pag");
-
- if ($rebuild || ($bage < $data_age) || ($page < $data_age)) {
- &rebuild;
- }
- &opendb('reading');
- }
-
- sub closedb {
- dbmclose(boss) || die "$0: can't dbmclose boss: $!\n";
- dbmclose(peon) || die "$0: can't dbmclose peon: $!\n";
- }
-
- sub opendb {
- local($mode) = @_;
-
- do _opendb('boss');
- do _opendb('peon');
- }
-
- sub _opendb {
- local($what) = @_;
- local($file) = $DATA . '.' . $what;
-
- if ($mode eq 'writing') {
- for $ext ('pag', 'dir') {
- open(FILE, ">$file.$ext") || die "can't write $file.$ext\n";
- close FILE;
- }
- }
-
- eval <<EO_EVAL;
- dbmopen($what, "$file", \$mode eq 'writing' ? 0644 : 0444)
- || die "$0: can't dbmopen $file for \$mode: \$!\n";
- EO_EVAL
- die $@ if $@;
-
- }
-
- sub age {
- return (stat($_[0]))[9];
- }
-