Listing 9        fchange.sh
:
#######################################################
# fchange.sh: log and report changed files
# Copyright (C) 1996 Steve Isaacson
#######################################################
# fchange.sh - new and improved version.
# How to install. 
# 1) mkdir $ctrldir and set the value below.
# 2) mkdir $ctrldir/logs
# 3) create $ctrldir/fchange.files
# 4) cp cdiff.sh $ctrldir
# 5) add an entry to your crontab

# make sure this is being run by a posix compliant shell
test "$((1))" = 1 || exec ksh $0 "$@"

test "$debugxv" && set -xv # primitive debugger

# set up trap
trap "cleanup 1" 1 2 15

# make sure everything is in the PATH
PATH=/bin:/usr/bin:/usr/ucb:.:/u/stevei/bin/`uname -n`:$PATH 
export PATH

# set up variables
MAILER=/usr/bin/mailx ; export MAILER

# make your changes here
: ${ctrldir:=/u/stevei/fchange}
: ${filesfile:=$ctrldir/fchange.files}
: ${logdir:=$ctrldir/logs}
: ${fnpseudo:=$ctrldir/pseudo.sh}

newlist=$ctrldir/new.list
lastlist=$ctrldir/last.list
difflist=$ctrldir/diff.list
mailout=$ctrldir/mail.out.$$

# If you have access to a decent file locking program, 
# define it here.  If not, a simple locking scheme will 
# be used below. The one I use is called lockfile.
unset LOCKPROG # assume we don't have it
whence lockfile > /dev/null && \
    LOCKPROG="lockfile -n15 -l 0 -r 0"

UNLOCKPROG="rm -f"
LOCKFILE=$ctrldir/fchange.lck

# If abort file is present, exit.
test -f $ctrldir/abort && exit 0

#######################################################
cleanup()
#######################################################
# remove the lock file and exit with the appropriate 
# status 
{
    $UNLOCKPROG $LOCKFILE
    rm -f $mailout $difflist
    exit $1
}
# cleanup()

# Initial sanity check
cd $ctrldir || cleanup 0

# See if we can fork 20 processes.  If not, then bail.
whence fork > /dev/null && {
    fork 20 >/dev/null 2>&1 || exit 0
}

# If file system is full, forget it.
test -x $ctrldir/space.chk && {
    $ctrldir/space.chk || cleanup 0
}

# Make sure we have everything we need
whence $ctrldir/cdiff.sh > /dev/null || {
    echo "Error: could not find $ctrldir/cdiff.sh"
    cleanup 1
}

#######################################################
#                 create lockfile
#######################################################
# primitive locking mechanism

if test "$LOCKPROG"
then
    # try to acquire the lock
    $LOCKPROG $LOCKFILE >/dev/null 2>&1 || exit 0
else
    test -f $LOCKFILE && exit 0 || date > $LOCKFILE
fi

#######################################################
#                 pseudo programs
#######################################################
# If there is a pseudo-file shell script there, run it.

test -x "$fnpseudo" && $fnpseudo

#######################################################
#                    new list
#######################################################
# read files file and create new list.

awk '/^(:|#|$)/ {next}
  {print $1}' $filesfile | sort |
    xargs ls -l > $newlist 2>&1

#######################################################
#                compare last list
#######################################################
# Compare newlist with lastlist.  If they're the same, 
# then there is no work to do and we're done.  If 
# newlist and lastlist are different, then there is work 
# to do and we'll use the difflist below.

# necessary first-time only
test -f $lastlist || > $lastlist

diff $newlist $lastlist > $difflist && {
    rm -f $difflist
    cleanup 0
}

#######################################################
#               there is work to do
#######################################################
# Move the newlist to lastlist so we can use it the next 
# time we're here.

mv $newlist $lastlist

#######################################################
#                   get to work
#######################################################

# read diff list, grabbing only certain lines.
awk '/^< / {print $NF}' $difflist |
while read fn
do
    # grab the line from the files file
    grep "$fn " $filesfile
done |
while read fn mail_to
do
    # set track and showdiff flags.  default is no
    track=no ; showdiff=no

    # now check for the flags
    case "$mail_to" in
      *track)
        # set flag and strip off trailing track
        track=yes ; mail_to=${mail_to%track}    ;;
      *showdiff)
        # set flag and strip off trailing showdiff
        showdiff=yes ; mail_to=${mail_to%showdiff} ;;
    esac

    # build unique log file name using the filename
    sum=$(echo $fn | sum -r |
        awk '{printf("%s_%s\n", $1, $2)}')
    logname=$logdir/$sum
    diffname=$logdir/$sum.diff
    trackname=$logdir/$sum.track

    # get last line in the log, or create the log
    if test -f $logname
    then
        last_line=$(tail -1 $logname)
    else
        last_line=_none_
        echo "#_name:$fn : $(date)" > $logname
    fi

    # get the current information about the file
    if test -f $fn -o -c $fn
    then
        cur_line=$(ls -l $fn)
    else
        cur_line=_no_file_
    fi

    # if current line is same as last line, we're done.
    test "$cur_line" = "$last_line" && continue

    # or else something is different.  so log new 
    # information. 
    echo "$cur_line" >> $logname


    # and start writing our mail message
    {
      echo "$sum: $fn"
      echo $last_line
      echo $cur_line
    } > $mailout

    test "$track" = yes && {
        echo "#_change: $(date)" >> $trackname
        cat $fn >> $trackname
        $ctrldir/cdiff.sh $trackname >> $mailout
    }

    test "$showdiff" = yes && {
        echo "#_change: $(date)" >> $diffname.new
        cat $fn >> $diffname.new

        if test -f "$diffname"
        then
            diff $diffname.new $diffname >> $mailout
        else
            cat $diffname.new >> $mailout
        fi
        mv $diffname.new $diffname
    }

    $MAILER -s "fchange: $fn" "$mail_to" < $mailout \
        > /dev/null
done
cleanup 0
============== END: fchange.sh ==================

