info-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Utility to remove dead watchers


From: Rob Ries
Subject: Utility to remove dead watchers
Date: Fri, 25 Jan 2002 15:02:42 -0500

I wrote a utility that handles the following situation:

1) User X sets up a cvs watch on files in a project.
2) User X leaves company.

[Normally, at this point, you can "su" to that user and do a "cvs watch
remove", and all is well. But what if....(read on)]

3) User X user account has been deleted.

[Now you cannot su to that user anymore.]

4) Some other user commits changes to one of those watched files, and gets
error messages ("dying gasp") related to that missing watcher.
5) That other user complains about the error messages. Continually.

The utility is a perl script / shell script (both below) that gets rid of
that user from the watch lists in a project. I tried to make it as safe as I
could think to make it (given my admittedly non-expert CVS internals
knowledge).

Since I figured that others might be up against this same problem, I posted
a question to gnu.org asking them if they had any ideas as to what I could
do with it. They suggested I post them here. So, here you go. Please don't
hesitate to flame if I've just transgressed some rule that I should already
know about.

Thanks.

- Rob

-----------------------------------------
Rob Ries
The Adrenaline Group, Inc.
1445 New York Avenue
4th Floor
Washington, DC 20005
work: 202.628.4438
fax:  202.628.7120
cell: 703.863.8606
http://www.adrenaline.com | building the next opportunity

=====================================================================
*********************************************************************
=====================================================================

Typical usage - save the fixcvswatchers.sh script, below, as
fixcvswatchers.sh.
Typical usage - save the fixcvswatchers.pl script, below, as
fixcvswatchers.pl.

Then, as root on the box containing the CVSROOT tree:

perl fixcvswatchers.pl -c CVSPROJECTNAME -u USER_TO_BE_AXED_FROM_WATCHERS -r
CVSROOT

That script creates a copy of all of the fileattr files in the target
project tree, without that dead watcher in the watchers list.
At end of that script, you'll get a process ID.
To be extra cautious, you can now do a:

fixcvswatchers.sh -p PROCESSID -x diff -c CVSPROJECTNAME -r CVSROOT | less

This will show you a diff of all of the original fileattr files vs. the new
copies you just created. Finally, to cause CVS to use the new fileattr
files, do a:

fixcvswatchers.sh -p PROCESSID -x move -c CVSPROJECTNAME -r CVSROOT

Until you do that last line, you really haven't changed anything. Look
through the comments at the top of fixcvswatchers.sh for some of its other
functionality.

=====================================================================
*********************************************************************
=====================================================================

use File::Find;
use strict;
use vars qw($opt_c $opt_u $opt_r $opt_d);
use Getopt::Std;

#!/usr/bin/perl
# name: fixcvswatchers.pl
# desc: Situation:      user X has a cvs watch on a bunch of files
#                       in CVSProject
#                       user X leaves company
#                       user X watches trigger error messages whenever
#                       surviving company users screw with watched files.
#       Easy solution:  if userid still exists in /etc/passwd, as root:
#                       su - username
#                       cd /home/username/projects
#                       cvs checkout CVSProject
#                       cd CVSProject
#                       cvs watch remove -a all -l *
#                       cvs watcher | grep username   (to make sure)
#       Problem:        if userid no longer exists, Linux can sometimes
#                       make it difficult to re-add a user who was
#                       deleted prior. So this script will get
#                       rid of the watch for the user.
# environment:
#       Script must be run on same box as cvs master repository tree.
#       Script must be run as root
# parameters:
#       -c CVS project name
#       -u user name
#       -r CVSROOT
#       -d                      (If present, debug mode is on)
# observations:
#       In looking through hundreds or even thousands of fileattr
#       files, it appears to be okay if fileattr files have:
#               _watchers=   without _watched=
#               _watched=    without _watchers=
#       fileattr files do NOT appear to ever have
#               empty _watchers lists - eg: _watchers=; or
#                                           _watchers=<EOL>
# author:
#       F. Rob Ries
#       The Adrenaline Group, Inc.
#       Washington, DC
#       address@hidden
#
# date: January 23, 2002

my $debug = 0;
my $keystring = "^_watchers=";
my $keystringout = "_watchers=";
my $attribseparator = ";";
my $watcherseparator = ",";
my $usage = "usage: perl fixcvswatchers.pl -c cvs_project_name -u
user_name_to_be_removed_from_watchlist -r cvsroot\n";
my $matchuser;

sub prtdebug {
        if ( $debug > 0 )       {
                print "DEBUG: $_[0]\n";
        }
}

sub fixcvswatcher {

        my $outfile;
        my $field1;
        my $field2;
        my $outfield2;

        my $attribidx;
        my $attrib;
        my @attribs;

        my $outidx;
        my @outwatchers;

        my $watcher;
        my @watchers;

        my $needseparator;

        # The find package puts the current file name being looked at in $_.
        prtdebug("Processing $_ in fixcvswatcher sub");

        # Interested only in */CVS/fileattr files.
        if ( $File::Find::name =~ /CVS\/fileattr$/ )    {
                prtdebug("Got a fileattr file!");
                open CVSFILE, $_ || die "Cannot open $_\n";
                # $$ is current process id
                $outfile = $File::Find::name . $$;
                open OUTFILE, ">" . $outfile || die "Cannot open $outfile\n";
                LINE: while (<CVSFILE>) {
                        prtdebug "CURRENT LINE: $_";
                        # Lines begin w "F" for files
                        # Lines begin w "D" for directories
                        # Followed immediately (no spaces) by filename.
                        # Followed by TAB.
                        # Followed by attributes.
                        if (/^([\S ]*)\t(.*)/)  {
                                $field1 = $1;
                                $field2 = $2;
                                print OUTFILE "$field1\t";
                        }
                        else    {
                                print "*** Line format unrecognized:\n";
                                print "***      File: $File::Find::name\n";
                                print "***      Line: $_\n";
                                next LINE;
                        }
                        # Now focus on the string of attributes, in $field2.
                        $attribidx = 0;
                        @attribs = split /$attribseparator/, $field2;
                        foreach $attrib (@attribs)      {
                                prtdebug "ATTRIB $attrib";
                                # Are we looking at "watchers" attribute?
                                if ( $attrib =~ s/$keystring// )        {
                                        prtdebug "SUB ATTRIB $attrib";
                                        @outwatchers = ();
                                        $outidx = 0;
                                        @watchers = split /$watcherseparator/, 
$attrib;
                                        # Go through the list of watchers.
                                        # As long as it it not the user to
                                        # be axed, print him out. Skip the
                                        # user to be axed. Duh.
                                        foreach $watcher (@watchers) {
                                                if ( $watcher !~ /^$matchuser/ 
)        {
                                                        $outwatchers[$outidx] = 
$watcher;
                                                        $outidx++;
                                                }
                                        }
                                        $needseparator = 0;
                                        $outfield2 = "";
                                        foreach $watcher (@outwatchers) {
                                                if ( $needseparator > 0 )       
{
                                                        $outfield2 = $outfield2 
. $watcherseparator;
                                                }
                                                else    {
                                                        $outfield2 = 
$keystringout;
                                                }
                                                $needseparator = 1;
                                                $outfield2 = $outfield2 . 
$watcher;
                                        }
                                        prtdebug("OUTFIELD2: $outfield2");
                                }
                                else    {
                                        $outfield2 = $attrib;
                                }
                                if ( $outfield2 !~ /^$/ )       {
                                        if ( $attribidx > 0 )   {
                                                print OUTFILE $attribseparator;
                                        }
                                        $attribidx++;
                                        print OUTFILE $outfield2;
                                }
                        }
                        print OUTFILE "\n";
                }
        close CVSFILE;
        close OUTFILE;
        }
}

# Start main processing here.

getopts("c:u:r:d");
if (defined $opt_c &&
    defined $opt_u &&
    defined $opt_r )    {
        if ( ! -d "$opt_r/$opt_c" ) {
                warn "$opt_r/$opt_c: no such directory.\n";
                die "$usage";
                }
        }
else    {
        die "$usage";
}
if (defined $opt_d)     {
        $debug = 1;
}
else    {
        $debug = 0;
}

$matchuser = $opt_u . ">";
find(\&fixcvswatcher, "$opt_r/$opt_c");
print "Assuming no errors, the PID for this run is: $$\n";

=====================================================================
*********************************************************************
=====================================================================

# name: fixcvswatchers.sh
# desc: See fixcvswatcher.pl perl script for more notes.
#       After running fixcvswatcher.pl perl script, each CVS directory
#       will have 2 files in it:
#               fileattr        - original cvs file attributes file
#               fileattrNNN     - where NNN is the process id from the
#                                 fixcvswatcher.pl script.
#       This script operates in two modes:
#
#       diff    - shows a quick diff in every CVS directory between
#                 fileattr and fileattrNNN
#                 Screwing with the fileattr files could presumably have
#                 disastrous effects; running this diff, first, gives some
#                 comfort that you are not trashing things.
#       rm      - runs through all the CVS directories removing all
#                 fileattr[0-9]* files. This leaves file named fileattr and
#                 files named fileattrSAVEnnn
#       rm_all  - as above, but removes fileattrSAVEnnn files, too - all
#                 fileattr?* files except fileattr.
#       move    - runs through all the CVS directories doing the following
#                       copy fileattr to fileattrSAVEnnn
#                       mv fileattrNNN fileattr
#                       makes sure that ownership/perms on fileattr are
#                       owner = owner of parent CVS directory
#                       group = group of parent CVS directory
#                       mode = 664
#
# parameters:
#       -p NNN          NNN is the process id from the fixcvswatcher.pl
#                       script. If, for some reason you don't have it,
#                       just go look in all the CVS directories in the
#                       target project tree and you'll see files named
#                       fileattrNNN (assuming you already ran the
#                       perl script fixcvswatchers.pl).
#       -x diff|move|rm|rm_all
#                       diff, move, rm mode (see above)
#       -c cvsprojname
#       -r CVSROOT
#
# environment:
#       Script must be run on same box as cvs master repository tree.
#       Script must be run as root
#
# assumptions:
#       fileattr files are protected 664
#       fileattr files are owned by owner of CVS directory above them
#       fileattr files are in same group as group of CVS directory above them
# author:
#       F. Rob Ries
#       The Adrenaline Group, Inc.
#       Washington, DC
#       address@hidden
#
# date: January 23, 2002

# Argument processing
USAGE="usage: $0 -p PID -x [diff|move|rm|rm_all] -c cvsprojname -r CVSROOT"
PERM=664

while getopts p:x:c:r: o
do
        case "$o" in
        p)      PID="$OPTARG"
                ;;
        x)      ACTION="$OPTARG"
                case "x$ACTION" in
                xmove|xdiff)
                        ;;
                xrm_all)
                        RMSTRING="fileattr?*"
                        ;;
                xrm)
                        RMSTRING="fileattr[0-9]*"
                        ;;
                *)
                        echo $USAGE >&2
                        exit 2
                        ;;
                esac
                ;;
        c)      PROJNAME="$OPTARG"
                ;;
        r)      CVSROOT="$OPTARG"
                ;;
        [?])    echo $USAGE >&2
                exit 2
                ;;
        esac
done
shift `expr $OPTIND - 1`

if test -z "$ACTION" -o -z "$PROJNAME" -o -z "$CVSROOT"
then
        echo $USAGE >&2
        exit 2
fi
if test ! -d $CVSROOT/$PROJNAME
then
        echo "$CVSROOT/$PROJNAME - no such directory." >&2
        echo $USAGE >&2
        exit 2
fi

case "$ACTION" in
rm|rm_all)
        # Do not need or want a PID for this mode.
        if test -n "$PID"
        then
                echo "Remove options do not take a -p NNN arg, too." >&2
                echo $USAGE >&2
                exit 2
        fi
        find $CVSROOT/$PROJNAME -type d -name CVS -print |
        while read CVSDIRNAME
        do
                case "x$RMSTRING" in
                x)
                        # Paranoid check - should never occur.
                        echo "ERROR - empty RMSTRING." >&2
                        exit 2
                        ;;
                esac
                rm -f $CVSDIRNAME/$RMSTRING 2>/dev/null
        done
        ;;
*)
        if test -z "$PID"
        then
                echo "Missing -p NNN argument." >&2
                echo $USAGE >&2
                exit 2
        fi

        echo -n "Verifying existence of CVS/fileattr$PID file in each 
directory..."
        rm -f /tmp/pidcheck.$$
        find $CVSROOT/$PROJNAME -type d -name CVS -print |
        while read CVSDIRNAME
        do
                if test ! -f $CVSDIRNAME/fileattr$PID
                then
                        echo "$CVSDIRNAME/fileattr$PID - no such file." 
>>/tmp/pidcheck.$$
                        echo "Did you run the fixcvswatchers.pl script yet?" 
>>/tmp/pidcheck.$$
                fi
        done

        if test -f /tmp/pidcheck.$$
        then
                cat /tmp/pidcheck.$$ >&2
                rm -f /tmp/pidcheck.$$
                exit 2
        fi
        echo "Done with check."

        case "$ACTION" in
        diff)
                find $CVSROOT/$PROJNAME -type d -name CVS -print |
                while read CVSDIRNAME
                do
                        diff $CVSDIRNAME/fileattr $CVSDIRNAME/fileattr$PID
                done
                ;;
        move)
                find $CVSROOT/$PROJNAME -type d -name CVS -print |
                while read CVSDIRNAME
                do
                        OWNER=`ls -ld $CVSDIRNAME | awk '{ print $3 }'`
                        GROUP=`ls -ld $CVSDIRNAME | awk '{ print $4 }'`
                        mv $CVSDIRNAME/fileattr $CVSDIRNAME/fileattrSAVE$PID
                        mv $CVSDIRNAME/fileattr$PID $CVSDIRNAME/fileattr
                        chmod $PERM $CVSDIRNAME/fileattr
                        chgrp $GROUP $CVSDIRNAME/fileattr
                        chown $OWNER $CVSDIRNAME/fileattr
                done
                ;;
        esac
        ;;
esac
exit 0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]