#!/bin/sh -e
#
# Update the McAfee data files.
#
# $Cambridge: hermes/conf/build/bin/uvscan-update,v 1.52 2004/08/18 19:12:02 fanf2 Exp $

# $PREFIX is the directory where the uvscan binary is (NOT a symlink to
# the binary), which is where it looks for its dat files. You may run
# uvscan via a symlink to this place (e.g. from /usr/local/bin/uvscan)
# and it will still look for the dat files here. If uvscan's library
# dependencies can be found in a standard place (e.g. /usr/local/lib)
# then you don't need a wrapper script to set LD_LIBRARY_PATH before
# running it.
#
# The dat files are installed in a subdirectory of $DATDIR named
# according to their version number, with symlinks from $PREFIX into
# the subdirectory via a current link. The current link is updated
# without locking on the assumption that this is sufficiently unlikely
# to cause a problem.

# defaults
OPTS=""
PREFIX=/opt/uvscan
FTPDIR=http://download.nai.com/products/datfiles/4.x/nai
RETRIES=1
INTERVAL=300

# handle the command line
usage () {
        echo "usage: $0 [-dfrtv] [-Rnnn] [-Innn] [proxy] [prefix]"
        echo "  -d      delete old files"
        echo "  -e      get extra.dat"
        echo "  -f      force update"
        echo "  -r      show README"
        echo "  -t      timestamp output"
        echo "  -v      verbose"
        echo "  -R      number of retries"
        echo "  -I      retry interval"
        echo "  proxy   URL of FTP/HTTP proxy server"
        echo "  prefix  uvscan installation directory"
        exit 1
}
case $# in
[012345])
        : ok
        ;;
*)      usage
        ;;
esac
for arg in "$@"
do
        case $arg in
        -I*)    INTERVAL=${arg#-I}
                ;;
        -R*)    RETRIES=${arg#-R}
                ;;
        -*)     OPTS=$arg
                ;;
        /*)     PREFIX=$arg
                ;;
        http:)  ftp_proxy=$arg
                http_proxy=$arg
                export ftp_proxy
                export http_proxy
                ;;
        *)      usage
                ;;
        esac
done
case $OPTS in
*[!-dfrtv]*)
        usage
esac
option () {
        case $OPTS in
        -*$1*)  eval $2=yes
                ;;
        *)      eval $2=no
                ;;
        esac
}
option d DELETE
option e EXTRA
option f FORCE
option r README
option t TIME
option v VERBOSE
case $FORCE in
yes)    VERBOSE=yes
esac

# look for binaries and libraris in plausible places
PATH=$PREFIX:/usr/local/bin:/usr/bin:/bin
# this is only necessary for broken setups
LD_LIBRARY_PATH=$PREFIX
export PATH LD_LIBRARY_PATH

# where this script finds things
DATDIR=$PREFIX/datfiles
DATFILES="clean.dat extra.dat internet.dat names.dat scan.dat"
LINKNAME=current
LINKREL=datfiles/$LINKNAME

# wrapper functions for echo etc.
timestamp () {
        case $TIME in
        yes)    date "+%Y-%m-%d %H:%M:%S "
        esac
}
say () {
        case $VERBOSE in
        yes)    echo "`timestamp`$*"
        esac
}
run () {
        say "> $*"
        "$@"
}
testeval () {
        # ugly workaround
        say "> $*"
        set +e
        eval "$*"
        ret=$?
        set -e
        return $ret
}
is () {
        test "$@" 2>/dev/null
}
say Starting $0
say DELETE=$DELETE
say FORCE=$FORCE
say README=$README
say TIME=$TIME
say VERBOSE=$VERBOSE
say RETRIES=$RETRIES
say INTERVAL=$INTERVAL
say PROXY=$ftp_proxy
say PREFIX=$PREFIX

# check directory setup is correct
for link in $LINKREL $DATFILES
do
        if ! is -h $PREFIX/$link
        then
                say $PREFIX/$link is not set up
                INIT=yes
        fi
done
if ! is -d $DATDIR
then
        say $DATDIR is not set up
        INIT=yes
fi
case $INIT in
yes)
        VERBOSE=yes
        say Doing initial setup of $0
        run mkdir -p $DATDIR
esac
run cd $DATDIR

getver () {
        match="[0-9][0-9][0-9][0-9]"
        err="version.err"
        cmd="$1" out="$2" txt="$3"
        if testeval "$cmd 2>$err 1>&2"
        then
                VER=`cat $out | sed "/^$txt\($match\).*$/!d;s//\1/;q"`
                case $VER in
                $match) run rm -f $out $err
                        return
                esac
        fi
        cat $err
        VER=UNKNOWN
        run rm -f $out $err
}

# work out latest dat version
try=$RETRIES
while :
do      getver "wget --tries=$try --waitretry=$INTERVAL --passive-ftp $FTPDIR/update.ini" update.ini "DATVersion="
        VERSION=$VER
        case $VERSION in
        UNKNOWN)
                if ! try=`expr $try - 1`
                then break
                fi
                say Problem with McAfee datfile update from $FTPDIR
                say Sleeping for $INTERVAL seconds before retrying
                sleep $INTERVAL
                ;;
        *)      break
                ;;
        esac
done

# work out installed dat version
getver "uvscan --version" version.err "Virus data file v"
PREVIOUS=$VER

case $FORCE in
yes)    say Forced update from $PREVIOUS
        PREVIOUS=0000
        ;;
*)      if is $VERSION -eq $PREVIOUS
        then    say Already have $VERSION
                run exit 0
        fi
esac

VERBOSE=yes

say Installed dat file is $PREVIOUS
say Latest dat file is $VERSION

if is $VERSION = UNKNOWN
then    say Problem with McAfee datfile update from $FTPDIR
        run exit 1
elif is $VERSION -lt $PREVIOUS
then    say Remote version $VERSION older than installed version $PREVIOUS
        run exit 1
elif is -d $VERSION
then    say Cleaning away $VERSION directory
        run rm -rf $VERSION
fi

retry () {
        echo "$OUT"
        say Fetch or test failed -- removing bad McAfee data files
        run cd $DATDIR
        run rm -rf $VERSION
        if ! try=`expr $try - 1`
        then    say Giving up
                run exit 1
        fi
        say Sleeping for $INTERVAL seconds before retrying
        sleep $INTERVAL
        continue
}

try=$RETRIES
while :
do
        # fetch and extract dat files
        TARFILE=dat-$VERSION.tar
        run mkdir $VERSION
        run cd $VERSION
        run chmod 700 .
        if ! run wget --tries=$try --waitretry=$INTERVAL --passive-ftp --progress=dot:mega $FTPDIR/$TARFILE
        then retry
        fi
        run tar xvf $TARFILE
        run chmod 644 *
        run chmod 755 .

        # verify the contents
        CMD="uvscan --version --dat ."
        say "> $CMD"
        if ! OUT=`$CMD 2>&1`
        then    retry
        else    break
        fi
done

echo "$OUT"
say Update OK

# show information on this update?
case $README in
yes)    run sed 's/[[:cntrl:]]//g
                1,/^====================/d
                /^====================/,/^NEW VIRUSES DETECTED/d
                /^UNDERSTANDING VIRUS NAMES/,$d
                s/^/# /;/@MM/s/$/ <--/' readme.txt
esac
# remove some crap
run rm -f *.diz *.exe *.ini *.lst *.tar *.txt

# do remaining part of initial setup
case $INIT in
yes)    for file in $DATFILES
        do
                run rm -f $PREFIX/$file
                run ln -s $LINKREL/$file $PREFIX/$file
        done
esac

# update the current version link
run cd $DATDIR
run ln -s $VERSION $VERSION/$LINKNAME
run mv $VERSION/$LINKNAME .

# maybe delete old dat files
case $DELETE in
yes)    run cd $DATDIR
        run rm -rf $PREVIOUS
esac

say Completed OK
run exit 0

# done

